7444cb67c67e5f029461ca0d4ef9c89230424118
[barrelfish] / usr / kaluga / start_cpu.c
1 /**
2  * \file
3  * \brief Code responsible for booting application cores
4  */
5
6 /*
7  * Copyright (c) 2007, 2008, 2009, 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 <stdlib.h>
16 #include <stdbool.h>
17 #include <stdio.h>
18 #include <assert.h>
19
20 #include <barrelfish/barrelfish.h>
21 #include <barrelfish/cpu_arch.h>
22
23 #include <if/monitor_defs.h>
24
25 #include <octopus/octopus.h>
26 #include <skb/skb.h>
27
28 #include "kaluga.h"
29
30 // TODO: Needed because of we have to send
31 // boot_initialize_request after all cores have booted
32 // It's a hack (see monitors boot.c)
33 static coreid_t cores_on_boot = 0;
34 static coreid_t core_counter = 1; // BSP already up
35 static bool cores_booted = false;
36
37 static errval_t new_mon_msg(struct mon_msg_state** mms, send_handler_fn s)
38 {
39     *mms = malloc(sizeof(struct mon_msg_state));
40     if (*mms == NULL) {
41         return LIB_ERR_MALLOC_FAIL;
42     }
43
44     (*mms)->send = s;
45     (*mms)->next = NULL;
46
47     return SYS_ERR_OK;
48 }
49
50 static void send_boot_initialize_request(struct monitor_binding* b,
51         struct mon_msg_state* mm)
52 {
53     errval_t err;
54
55     err = b->tx_vtbl.boot_initialize_request(b,
56             MKCONT(free, mm));
57
58     if (err_is_fail(err)) {
59         if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
60             enqueue_msg_state(b, mm);
61             return;
62         }
63         USER_PANIC_ERR(err, "kaluga: sending %s failed!", __FUNCTION__);
64     }
65 }
66
67 static void boot_core_reply(struct monitor_binding *st, errval_t msgerr)
68 {
69     static coreid_t core_boot_replies = 1; // BSP Monitor already running
70     if (err_is_fail(msgerr)) {
71         USER_PANIC_ERR(msgerr, "msgerr in boot_core_reply, exiting\n");
72     }
73
74     KALUGA_DEBUG("boot_core_reply: core_boot_replies=%d, cores_on_boot=%d\n",
75             core_boot_replies+1, cores_on_boot);
76
77     if (++core_boot_replies == cores_on_boot) {
78         struct monitor_binding *mb = get_monitor_binding();
79         struct mon_msg_state *mms = NULL;
80         errval_t err = new_mon_msg(&mms, send_boot_initialize_request);
81         assert(err_is_ok(err));
82
83         KALUGA_DEBUG("before boot send...\n");
84         mms->send(mb, mms);
85     }
86 }
87
88 static void boot_initialize_reply(struct monitor_binding *st)
89 {
90     KALUGA_DEBUG("boot_initialize_reply\n");
91     cores_booted = true;
92     errval_t err = oct_set("all_spawnds_up { iref: 0 }");
93     assert(err_is_ok(err));
94 }
95
96
97 static void send_boot_core_request(struct monitor_binding* b,
98         struct mon_msg_state* mm)
99 {
100     errval_t err;
101
102     struct module_info* mi = find_module("cpu");
103     err = b->tx_vtbl.boot_core_request(b, MKCONT(free, mm), mm->core_id,
104             mm->arch_id, CURRENT_CPU_TYPE, mi->complete_line);
105
106     if (err_is_fail(err)) {
107         if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
108             enqueue_msg_state(b, mm);
109             return;
110         }
111         USER_PANIC_ERR(err, "device_manager: sending %s failed!", __FUNCTION__);
112     }
113 }
114
115 static inline void configure_monitor_binding(void)
116 {
117     struct monitor_binding* mb = get_monitor_binding();
118     mb->rx_vtbl.boot_core_reply = boot_core_reply;
119     mb->rx_vtbl.boot_initialize_reply = boot_initialize_reply;
120     mb->st = NULL;
121 }
122
123 static void cpu_change_event(octopus_mode_t mode, char* record, void* state)
124 {
125     if (mode & DIST_ON_SET) {
126         KALUGA_DEBUG("CPU found: %s\n", record);
127
128         uint64_t cpu_id, arch_id, enabled = 0;
129         errval_t err = oct_read(record, "_ { cpu_id: %d, id: %d, enabled: %d }",
130                 &cpu_id, &arch_id, &enabled);
131         if (err_is_fail(err)) {
132             DEBUG_ERR(err, "Cannot read record.");
133             assert(!"Illformed core record received");
134             goto out;
135         }
136
137         // cpu_id may vary so we can't really use this
138         // to enumerate cores...
139         assert(my_core_id == 0);
140         static coreid_t core_id = 1;
141
142         if (arch_id != my_arch_id && enabled) {
143             struct monitor_binding* mb = get_monitor_binding();
144
145             struct mon_msg_state* mms = NULL;
146             err = new_mon_msg(&mms, send_boot_core_request);
147             assert(err_is_ok(err));
148            
149             mms->core_id = core_id++;
150             mms->arch_id = arch_id;
151             mms->send(mb, mms);
152             (*(coreid_t*) state) += 1;
153
154             // XXX: copied this line from spawnd bsp_bootup,
155             // not sure why x86_64 is hardcoded here but it
156             // seems broken...
157             skb_add_fact("corename(%d, x86_64, apic(%lu)).",
158                     mms->core_id, mms->arch_id);
159         }
160
161     }
162     if (mode & DIST_ON_DEL) {
163         KALUGA_DEBUG("CPU removed: %s\n", record);
164         assert(!"NYI");
165     }
166
167 out:
168     assert(!(mode & DIST_REMOVED));
169     free(record);
170 }
171
172 errval_t watch_for_cores(void)
173 {
174     configure_monitor_binding();
175
176     static char* local_apics = "r'hw\\.apic\\.[0-9]+' { cpu_id: _, "
177                                "                        enabled: 1, "
178                                "                        id: _ }";
179     octopus_trigger_id_t tid;
180     errval_t err = trigger_existing_and_watch(local_apics, cpu_change_event,
181             &core_counter, &tid);
182     cores_on_boot = core_counter;
183
184     if (err_is_ok(err)) {
185         if (cores_on_boot == 1) {
186             // No additional cores found
187             // XXX: We simulate a boot initialize reply to set the
188             // all_spawnds_up record. The whole app monitor boot protocol will
189             // most likely change in the future and render this unnecessary.
190             boot_initialize_reply(NULL);
191         }
192     }
193
194     // Wait until all cores found are booted, this ensures
195     // we won't deadlock in case we start a driver on
196     // a core that is not ready
197     /*
198     while (!cores_booted) {
199         messages_wait_and_handle_next();
200     }*/
201
202     return err;
203 }
204
205 static void ioapic_change_event(octopus_mode_t mode, char* record, void* state)
206 {
207     if (mode & DIST_ON_SET) {
208         struct module_info* mi = find_module("ioapic");
209         if (mi != NULL) {
210             // Pass apic id as 1st argument
211             static const char* fmt = "apicid=%u";
212             int len = snprintf(NULL, 0, fmt, my_arch_id);
213             char* apic_arg = malloc(len+1);
214             snprintf(apic_arg, len+1, fmt, my_arch_id);
215
216             mi->argv[2] = apic_arg;
217             errval_t err = mi->start_function(my_core_id, mi, record);
218             free(apic_arg);
219
220             switch (err_no(err)) {
221             case SYS_ERR_OK:
222                 KALUGA_DEBUG("Spawned I/O APIC driver: %s\n", mi->binary);
223                 break;
224
225             case KALUGA_ERR_DRIVER_ALREADY_STARTED:
226                 KALUGA_DEBUG("%s already running.\n", mi->binary);
227                 break;
228
229             case KALUGA_ERR_DRIVER_NOT_AUTO:
230                 KALUGA_DEBUG("%s not declared as auto, ignore.\n", mi->binary);
231                 break;
232
233             default:
234                 DEBUG_ERR(err, "Unhandled error while starting %s\n", mi->binary);
235                 break;
236             }
237         }
238     }
239     else if (mode & DIST_ON_DEL) {
240         KALUGA_DEBUG("Removed I/O APIC?");
241         assert(!"NYI");
242     }
243
244     free(record);
245 }
246
247
248 errval_t watch_for_ioapic(void)
249 {
250     KALUGA_DEBUG("watch_for_ioapic\n");
251     static char* io_apics = "r'hw.ioapic.[0-9]+' { id: _, address: _, "
252                             "irqbase: _ }";
253
254     octopus_trigger_id_t tid;
255     return trigger_existing_and_watch(io_apics, ioapic_change_event,
256             &core_counter, &tid);
257 }