1/**
2 * \file
3 * \brief Code for handling booting additional cores
4 */
5
6/*
7 * Copyright (c) 2010, 2011, 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 <elf/elf.h>
18#include <target/x86/barrelfish_kpi/coredata_target.h>
19#include <target/x86_32/barrelfish_kpi/paging_target.h>
20#include <target/x86_64/barrelfish_kpi/paging_target.h>
21#include <notify_ipi.h>
22
23/**
24 * \brief Initialize monitor running on app cores
25 */
26errval_t boot_arch_app_core(int argc, char *argv[],
27                            coreid_t *ret_parent_coreid,
28                            struct intermon_binding **ret_binding)
29
30{
31    errval_t err;
32
33    assert(argc == 4);
34
35    // core_id of the core that booted this core
36    coreid_t core_id = strtol(argv[1], NULL, 10);
37    *ret_parent_coreid = core_id;
38
39#ifdef CONFIG_FLOUNDER_BACKEND_UMP_IPI
40    // other monitor's channel id
41    assert(strncmp("chanid", argv[2], strlen("chanid")) == 0);
42    int chan_id = strtol(strchr(argv[2], '=') + 1, NULL, 10);
43
44    // arch id of the core that booted us
45    assert(strncmp("archid", argv[3], strlen("archid")) == 0);
46    int arch_id = strtol(strchr(argv[3], '=') + 1, NULL, 10);
47#endif
48
49    // check that the frame is big enough
50    struct capref frame = {
51        .cnode = cnode_task,
52        .slot  = TASKCN_SLOT_MON_URPC,
53    };
54    struct frame_identity frameid;
55    err = invoke_frame_identify(frame, &frameid);
56    if (err_is_fail(err)) {
57        err = err_push(err, LIB_ERR_FRAME_IDENTIFY);
58        return err;
59    }
60
61    size_t framesize = frameid.bytes;
62    if (framesize < 2 * MON_URPC_CHANNEL_LEN) {
63        return LIB_ERR_UMP_FRAME_OVERFLOW;
64    }
65
66    // map it in
67    void *buf;
68    err = vspace_map_one_frame(&buf, framesize, frame, NULL, NULL);
69    if (err_is_fail(err)) {
70        err = err_push(err, LIB_ERR_VSPACE_MAP);
71        return err;
72    }
73
74#ifdef CONFIG_FLOUNDER_BACKEND_UMP_IPI
75    // Create notify cap to other monitor
76    struct capref notify_cap;
77    err = notification_create_cap(chan_id, arch_id, &notify_cap);
78    assert(err == SYS_ERR_OK);
79
80    // Allocate my own notification caps
81    struct capref ep, my_notify_cap;
82    struct lmp_endpoint *iep;
83    int chanid;
84    err = endpoint_create(LMP_RECV_LENGTH, &ep, &iep);
85    assert(err_is_ok(err));
86    err = notification_allocate(ep, &chanid);
87    assert(err == SYS_ERR_OK);
88    assert(chanid == 1);        // Make sure it's channel 1
89    uintptr_t my_arch_id;
90    err = invoke_monitor_get_arch_id(&my_arch_id);
91    assert(err == SYS_ERR_OK);
92    err = notification_create_cap(chanid, my_arch_id, &my_notify_cap);
93    assert(err == SYS_ERR_OK);
94
95    // setup our side of the binding
96    struct intermon_ump_ipi_binding *umpb =
97        malloc(sizeof(struct intermon_ump_ipi_binding));
98    assert(umpb != NULL);
99
100    err = intermon_ump_ipi_init(umpb, get_default_waitset(),
101                                buf + MON_URPC_CHANNEL_LEN,
102                                MON_URPC_CHANNEL_LEN,
103                                buf, MON_URPC_CHANNEL_LEN, notify_cap,
104                                my_notify_cap, ep, iep);
105#else
106    struct intermon_ump_binding *umpb;
107    umpb = malloc(sizeof(struct intermon_ump_binding));
108    assert(umpb != NULL);
109
110    err = intermon_ump_init(umpb, get_default_waitset(),
111                            (char *)buf + MON_URPC_CHANNEL_LEN,
112                            MON_URPC_CHANNEL_LEN,
113                            buf, MON_URPC_CHANNEL_LEN);
114#endif
115    if (err_is_fail(err)) {
116        err = err_push(err, LIB_ERR_UMP_CHAN_BIND);
117        return err;
118    }
119
120    // Identify UMP frame for tracing
121    umpb->ump_state.chan.sendid = (uintptr_t)frameid.base;
122    umpb->ump_state.chan.recvid =
123        (uintptr_t)(frameid.base + MON_URPC_CHANNEL_LEN);
124
125    *ret_binding = &umpb->b;
126
127    return SYS_ERR_OK;
128}
129