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, ¬ify_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