kaluga: waiting for all spawnds to be up before starting drivers/apps
[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 #include <if/octopus_defs.h>
25
26 #include <octopus/octopus.h>
27 #include <octopus/trigger.h>
28
29 #include <skb/skb.h>
30 #include <trace/trace.h>
31 #include <barrelfish/spawn_client.h>
32
33 #include <hw_records.h>
34
35 #include "kaluga.h"
36
37 static const char *processor_regex = HW_PROCESSOR_GENERIC_REGEX;
38
39 static void cpu_change_event(octopus_mode_t mode, const char* record, void* state)
40 {
41     if (mode & OCT_ON_SET) {
42         KALUGA_DEBUG("CPU found: %s\n", record);
43
44         /* try to extract basic information from the record */
45         uint64_t barrelfish_id, type, hw_id, enabled = 0;
46         errval_t err = oct_read(record, "_ { " HW_PROCESSOR_GENERIC_FIELDS " }",
47                                 &enabled, &barrelfish_id, &hw_id, &type);
48         if (err_is_fail(err)) {
49             DEBUG_ERR(err, "Cannot read record.");
50             printf("Malformed CPU record. Do not boot discovered CPU %"PRIu64".\n",
51                     barrelfish_id);
52             goto out;
53         }
54
55         /* find the corectrl module for the given cpu type */
56         struct module_info* mi = find_corectrl_for_cpu_type((enum cpu_type)type);
57         if (mi != NULL) {
58             err = mi->start_function(0, mi, (CONST_CAST)record, NULL);
59             if (err_is_fail(err)) {
60                 printf("Boot driver not found. Do not boot discovered CPU %"PRIu64".\n",
61                        barrelfish_id);
62                 goto out;
63             }
64         }
65     }
66     if (mode & OCT_ON_DEL) {
67         KALUGA_DEBUG("CPU removed: %s\n", record);
68         assert(!"NYI");
69     }
70
71 out:
72     assert(!(mode & OCT_REMOVED));
73 }
74
75 errval_t watch_for_cores(void)
76 {
77     octopus_trigger_id_t tid;
78     return oct_trigger_existing_and_watch(processor_regex, cpu_change_event,
79                                           NULL, &tid);
80 }
81
82 // State for delayed cleanup of inherit cnode
83 struct inheritcn_del_st {
84     struct capref        capref;
85     octopus_trigger_id_t tid;
86     coreid_t             coreid;
87 };
88
89 // Trigger function: gets called when spanwd on core n is up to delete
90 // associated inherit cnode that was given to `corectrl boot n`.
91 static void delete_inheritcn(octopus_mode_t mode, const char *record, void *state)
92 {
93     errval_t err;
94     struct inheritcn_del_st *st = state;
95     if (mode & OCT_ON_SET) {
96         KALUGA_DEBUG("spawnd up for %d: deleting inheritcn\n", st->coreid);
97         err = cap_delete(st->capref);
98         if (err_is_fail(err)) {
99             DEBUG_ERR(err, "deleting inheritcn for %d\n", st->coreid);
100         }
101         assert(err_is_ok(err));
102         err = slot_free(st->capref);
103         if (err_is_fail(err)) {
104             DEBUG_ERR(err, "freeing slot for %d\n", st->coreid);
105         }
106         assert(err_is_ok(err));
107         err = oct_remove_trigger(st->tid);
108         if (err_is_fail(err)) {
109             DEBUG_ERR(err, "removing trigger");
110         }
111         assert(err_is_ok(err));
112         free(state);
113     }
114 }
115
116 errval_t start_boot_driver(coreid_t where, struct module_info* mi,
117         char* record, struct driver_argument * int_arg)
118 {
119     assert(mi != NULL);
120     errval_t err;
121
122     if (!is_auto_driver(mi)) {
123         return KALUGA_ERR_DRIVER_NOT_AUTO;
124     }
125
126     // Construct additional command line arguments containing pci-id.
127     // We need one extra entry for the new argument.
128     char **argv = mi->argv;
129     bool cleanup = false;
130     char barrelfish_id_s[10];
131     size_t argc = mi->argc;
132
133     KALUGA_DEBUG("Starting corectrl for %s\n", record);
134     uint64_t barrelfish_id, cpu_type, hw_id, enabled = 0;
135     err = oct_read(record, "_ { " HW_PROCESSOR_GENERIC_FIELDS " }",
136                             &enabled, &barrelfish_id, &hw_id, &cpu_type);
137     if (err_is_ok(err)) {
138         /*
139          * XXX: change this to a generic cpuhwid instead of apic!
140          */
141         skb_add_fact("corename(%"PRIu64", %s, apic(%"PRIu64")).",
142                      barrelfish_id, cpu_type_to_archstr(cpu_type), hw_id);
143
144         /* we are already running */
145         if (barrelfish_id == my_core_id) {
146             return SYS_ERR_OK;
147         }
148
149         if (!enabled) {
150             printf("CPU %" PRIu64 " is not enabled. Skipping driver initialization\n",
151                     barrelfish_id);
152             return SYS_ERR_OK;
153         }
154
155         argv = malloc((argc+5) * sizeof(char *));
156         memcpy(argv, mi->argv, argc * sizeof(char *));
157         snprintf(barrelfish_id_s, 10, "%"PRIu64"", barrelfish_id);
158
159         argv[argc] = "boot";
160         argc += 1;
161         argv[argc] = barrelfish_id_s;
162         argc += 1;
163         // Copy kernel args over to new core
164         struct module_info* cpu_module = find_module("cpu");
165         if (cpu_module != NULL && strlen(cpu_module->args) > 1) {
166             KALUGA_DEBUG("%s:%s:%d: Boot with cpu arg %s and barrelfish_id_s=%s\n",
167                          __FILE__, __FUNCTION__, __LINE__, cpu_module->args, barrelfish_id_s);
168             argv[argc] = "-a";
169             argc += 1;
170             argv[argc] = cpu_module->args;
171             argc += 1;
172         }
173         argv[argc] = NULL;
174
175         cleanup = true;
176     }
177     else {
178         DEBUG_ERR(err, "Malformed CPU record?");
179         return err;
180     }
181
182     struct capref task_cap_kernel;
183     task_cap_kernel.cnode = cnode_task;
184     task_cap_kernel.slot = TASKCN_SLOT_KERNELCAP;
185
186 #ifdef KALUGA_SERVICE_DEBUG
187     struct capability info;
188     err = debug_cap_identify(task_cap_kernel, &info);
189     if (err_is_fail(err)) {
190         USER_PANIC_ERR(err, "Can not identify the capability.");
191     }
192     char buffer[1024];
193     debug_print_cap(buffer, 1024, &info);
194     KALUGA_DEBUG("%s:%d: capability=%s\n", __FILE__, __LINE__, buffer);
195 #endif
196
197     struct capref inheritcn_cap;
198     err = alloc_inheritcn_with_caps(&inheritcn_cap,
199                                     NULL_CAP, NULL_CAP, task_cap_kernel);
200     if (err_is_fail(err)) {
201         DEBUG_ERR(err, "alloc_inheritcn_with_caps failed.");
202     }
203
204     err = spawn_program_with_caps(where, mi->path, argv,
205                                   environ, inheritcn_cap,
206                                   NULL_CAP, SPAWN_FLAGS_NEW_DOMAIN,
207                                   &mi->did[0]);
208     if (err_is_fail(err)) {
209         DEBUG_ERR(err, "Spawning %s failed.", mi->path);
210     }
211
212     if (cleanup) {
213         free(argv);
214     }
215
216     // Cannot just delete inherit cnode capability here, as deleting any CNode
217     // copy will always delete all copies of the CNode. Store inherit cnode
218     // cap in octopus, and delete it when the matching spawnd is up
219     char spawnd[32];
220     snprintf(spawnd, 32, "spawn.%s", barrelfish_id_s);
221     struct inheritcn_del_st *tstate = calloc(1, sizeof(*tstate));
222     tstate->capref = inheritcn_cap;
223     tstate->coreid = barrelfish_id;
224     errval_t err2 = oct_trigger_existing_and_watch(spawnd, delete_inheritcn,
225                                                    tstate, &tstate->tid);
226     if (err_is_fail(err2)) {
227         free(tstate);
228         return err2;
229     }
230
231     return err;
232 }
233
234
235 static void spawnd_change_event(octopus_mode_t mode, const char* record,
236                                 void* state)
237 {
238     size_t count = (size_t) state;
239     static coreid_t spawnd_counter = 0;
240
241     if (mode & OCT_ON_SET) {
242         KALUGA_DEBUG("spawnd found: %s\n", record);
243         spawnd_counter++;
244
245         if (spawnd_counter == count) {
246             KALUGA_DEBUG("Found enough spawnds, setting all_spawnds_up\n");
247             errval_t err = oct_set("all_spawnds_up { iref: 0 }");
248             assert(err_is_ok(err));
249         }
250     }
251 }
252
253 extern size_t cpu_count;
254
255 errval_t wait_for_all_spawnds(void)
256 {
257     // Note: The whole wait for all_spawnds_up thing is a hack.
258     // Our overall design goal is a system where cores
259     // come and go dynamically and we do not want / need
260     // to wait for a stable state.
261     // However, some of our code (for example domain spanning)
262     // still assumes a fixed set of cores and will deadlock
263     // otherwise. Therefore we need to fix those parts first.
264     errval_t err;
265     char* record = NULL;
266 #if !defined(__ARM_ARCH_7A__)
267     KALUGA_DEBUG("Waiting for acpi");
268     err = oct_wait_for(&record, "acpi { iref: _ }");
269     if (err_is_fail(err)) {
270         return err_push(err, KALUGA_ERR_WAITING_FOR_ACPI);
271     }
272 #endif
273
274     // No we should be able to get core count
275     // of all cores to estimate the amount of
276     // spawnd's we have to expect (one per core)
277     char** names;
278     size_t count;
279     err = oct_get_names(&names, &count, processor_regex);
280     if (err_is_fail(err)) {
281         return err_push(err, KALUGA_ERR_QUERY_LOCAL_APIC);
282     }
283     oct_free_names(names, count);
284
285     if (cpu_count) {
286         count = cpu_count;
287     }
288
289     static char* spawnds = "r'spawn.[0-9]+' { iref: _ }";
290     octopus_trigger_id_t tid;
291     err = oct_trigger_existing_and_watch(spawnds, spawnd_change_event, (void*)count, &tid);
292     if (err_is_fail(err)) {
293         return err_push(err, KALUGA_ERR_QUERY_LOCAL_APIC);
294     }
295
296     return oct_wait_for(&record, "all_spawnds_up { iref: 0 }");
297 }