1/**
2 * \file
3 * \brief Code for handling booting additional cores
4 */
5
6/*
7 * Copyright (c) 2010, 2012, ETH Zurich.
8 * All rights reserved.
9 *
10 * This file is distributed under the terms in the attached LICENSE file.
11 * If you do not find this file, copies can be found by writing to:
12 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15#include "monitor.h"
16#include <inttypes.h>
17#include <barrelfish_kpi/cpu.h> // for cpu_type_to_archstr()
18
19#if defined(CONFIG_FLOUNDER_BACKEND_UMP)
20/* Use to figure out when all monitors initialized. */
21int seen_connections = 0;
22
23static errval_t trace_ump_frame_identify(struct capref frame,
24                                         struct intermon_ump_binding* b,
25                                         size_t channel_length)
26{
27    // Identify UMP frame for tracing
28    struct frame_identity umpid;
29    errval_t err = invoke_frame_identify(frame, &umpid);
30    if (err_is_fail(err)) {
31        DEBUG_ERR(err, "invoke frame identity failed");
32        return err;
33    }
34
35    b->ump_state.chan.recvid = (uintptr_t)umpid.base;
36    b->ump_state.chan.sendid = (uintptr_t)
37        (umpid.base + channel_length);
38
39    return SYS_ERR_OK;
40}
41
42
43/**
44 * \brief Msg handler for booting a given core
45 *
46 * \param id     id of the core to boot
47 * \param hwid   hardware specific id of the core to boot
48 * \param cpu_type  Type of cpu to boot
49 * \param cmdline command-line args for kernel
50 *
51 * \bug Verify that cpu_type matches the elf image
52 */
53void boot_core_request(struct monitor_binding *b, coreid_t id,
54                       struct capref frame)
55{
56    errval_t err;
57    struct intermon_state *imon_st = NULL;
58
59    struct intermon_binding *ibind;
60    err = intermon_binding_get(id, &ibind);
61    if (err_is_ok(err)) {
62        imon_st = ibind->st;
63        imon_st->originating_client = b;
64        imon_st->capops_ready = false;
65        return;
66    }
67
68
69    // Setup new inter-monitor connection to ourselves
70#ifdef CONFIG_FLOUNDER_BACKEND_UMP_IPI
71    struct intermon_ump_ipi_binding *ump_binding = malloc(sizeof(
72                struct intermon_ump_ipi_binding));
73#else
74    struct intermon_ump_binding *ump_binding = malloc(sizeof(
75                struct intermon_ump_binding));
76#endif
77    assert(ump_binding != NULL);
78
79    // map it in
80    void *buf;
81    err = vspace_map_one_frame(&buf, MON_URPC_SIZE, frame, NULL, NULL);
82    if (err_is_fail(err)) {
83        err = err_push(err, LIB_ERR_VSPACE_MAP);
84        goto cleanup;
85    }
86
87#ifdef CONFIG_FLOUNDER_BACKEND_UMP_IPI
88    // Get my arch ID
89    uintptr_t my_arch_id = 0;
90    err = invoke_monitor_get_arch_id(&my_arch_id);
91    assert(err == SYS_ERR_OK);
92
93    // Bootee's notify channel ID is always 1
94    struct capref notify_cap;
95    err = notification_create_cap(1, hwid, &notify_cap);
96    assert(err == SYS_ERR_OK);
97
98    // Allocate my own notification caps
99    struct capref ep, my_notify_cap;
100    struct lmp_endpoint *iep;
101    int chanid;
102    err = endpoint_create(LMP_RECV_LENGTH, &ep, &iep);
103    assert(err_is_ok(err));
104    err = notification_allocate(ep, &chanid);
105    assert(err == SYS_ERR_OK);
106    err = notification_create_cap(chanid, my_arch_id, &my_notify_cap);
107    assert(err == SYS_ERR_OK);
108
109    // init our end of the binding and channel
110    err = intermon_ump_ipi_init(ump_binding, get_default_waitset(),
111                                buf, MON_URPC_CHANNEL_LEN,
112                                buf + MON_URPC_CHANNEL_LEN,
113                                MON_URPC_CHANNEL_LEN, notify_cap,
114                                my_notify_cap, ep, iep);
115#else
116    err = intermon_ump_init(ump_binding, get_default_waitset(),
117                            buf, MON_URPC_CHANNEL_LEN,
118                            (char *)buf + MON_URPC_CHANNEL_LEN,
119                            MON_URPC_CHANNEL_LEN);
120#endif
121    if (err_is_fail(err)) {
122        err = err_push(err, LIB_ERR_UMP_CHAN_BIND);
123        goto cleanup;
124    }
125
126    err = trace_ump_frame_identify(frame, ump_binding,
127                                   MON_URPC_CHANNEL_LEN);
128    if (err_is_fail(err)) {
129        goto cleanup;
130    }
131
132    struct intermon_binding* ib = (struct intermon_binding*)ump_binding;
133    err = intermon_init(ib, id);
134    imon_st = ib->st;
135    imon_st->originating_client = b;
136    imon_st->capops_ready = false;
137
138    return;
139
140cleanup:
141    if (err_is_fail(err)) {
142        // Cleanup
143        DEBUG_ERR(err, "Failed to register intermon binding.");
144        cap_destroy(frame);
145        free(ump_binding);
146    }
147
148    errval_t err2 = b->tx_vtbl.boot_core_reply(b, NOP_CONT, err);
149    if (err_is_fail(err2)) {
150        USER_PANIC_ERR(err2, "sending boot_core_reply failed");
151    }
152}
153#else
154void boot_core_request(struct monitor_binding *b, coreid_t id,
155                       struct capref frame) {
156    printf("%s:%s:%d: unable to handle: boot_core_request\n",
157           __FILE__, __FUNCTION__, __LINE__);
158}
159#endif
160