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