Adjustments of IPC to match new convention (static buffers).
[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 #include <trace/trace.h>
28 #include <barrelfish/spawn_client.h>
29
30 #include "kaluga.h"
31
32 static void cpu_change_event(octopus_mode_t mode, char* record, void* state)
33 {
34     if (mode & OCT_ON_SET) {
35         KALUGA_DEBUG("CPU found: %s\n", record);
36         assert(my_core_id == 0); // TODO(gz): why?
37
38         uint64_t barrelfish_id, arch_id, enabled = 0;
39         errval_t err = oct_read(record, "_ { barrelfish_id: %d, apic_id: %d, enabled: %d }",
40                 &barrelfish_id, &arch_id, &enabled);
41         if (err_is_fail(err)) {
42             DEBUG_ERR(err, "Cannot read record.");
43             assert(!"Illformed core record received");
44             goto out;
45         }
46
47         struct module_info* mi = find_module("corectrl");
48         if (mi != NULL) {
49             err = mi->start_function(0, mi, record);
50             if (err_is_fail(err)) {
51                 printf("Boot driver not found. Do not boot discovered CPU %"PRIu64".\n",
52                        barrelfish_id);
53                 goto out;
54             }
55             assert(err_is_ok(err));
56         }
57
58     }
59     if (mode & OCT_ON_DEL) {
60         KALUGA_DEBUG("CPU removed: %s\n", record);
61         assert(!"NYI");
62     }
63
64 out:
65     assert(!(mode & OCT_REMOVED));
66 }
67
68 static char* local_apics = "r'hw\\.processor\\.[0-9]+' { processor_id: _, "
69                            "                             enabled: 1, "
70                            "                             apic_id: _, "
71                            "                             barrelfish_id: _ }";
72
73 errval_t watch_for_cores(void)
74 {
75     octopus_trigger_id_t tid;
76     return oct_trigger_existing_and_watch(local_apics, cpu_change_event, NULL, &tid);
77 }
78
79 errval_t start_boot_driver(coreid_t where, struct module_info* mi,
80         char* record)
81 {
82     assert(mi != NULL);
83     errval_t err = SYS_ERR_OK;
84
85     if (!is_auto_driver(mi)) {
86         return KALUGA_ERR_DRIVER_NOT_AUTO;
87     }
88
89     // Construct additional command line arguments containing pci-id.
90     // We need one extra entry for the new argument.
91     uint64_t barrelfish_id, apic_id, cpu_type;
92     char **argv = mi->argv;
93     bool cleanup = false;
94     char barrelfish_id_s[10];
95     size_t argc = mi->argc;
96
97     KALUGA_DEBUG("Starting corectrl for %s\n", record);
98     err = oct_read(record, "_ { apic_id: %d, barrelfish_id: %d, type: %d }",
99             &apic_id, &barrelfish_id, &cpu_type);
100     if (err_is_ok(err)) {
101         skb_add_fact("corename(%"PRIu64", %s, apic(%"PRIu64")).",
102                      barrelfish_id, cpu_type_to_archstr(cpu_type), apic_id);
103         if (barrelfish_id == my_core_id) {
104             return SYS_ERR_OK;
105         }
106
107         argv = malloc((argc+5) * sizeof(char *));
108         memcpy(argv, mi->argv, argc * sizeof(char *));
109         snprintf(barrelfish_id_s, 10, "%"PRIu64"", barrelfish_id);
110
111         argv[argc] = "boot";
112         argc += 1;
113         argv[argc] = barrelfish_id_s;
114         argc += 1;
115         // Copy kernel args over to new core
116         struct module_info* cpu_module = find_module("cpu");
117         if (cpu_module != NULL && strlen(cpu_module->args) > 1) {
118             KALUGA_DEBUG("%s:%s:%d: Boot with cpu arg %s and barrelfish_id_s=%s\n",
119                          __FILE__, __FUNCTION__, __LINE__, cpu_module->args, barrelfish_id_s);
120             argv[argc] = "-a";
121             argc += 1;
122             argv[argc] = cpu_module->args;
123             argc += 1;
124         }
125         argv[argc] = NULL;
126
127         cleanup = true;
128     }
129     else {
130         DEBUG_ERR(err, "Malformed CPU record?");
131         return err;
132     }
133
134     struct capref task_cap_kernel;
135     task_cap_kernel.cnode = cnode_task;
136     task_cap_kernel.slot = TASKCN_SLOT_KERNELCAP;
137
138 #ifdef KALUGA_SERVICE_DEBUG
139     struct capability info;
140     err = debug_cap_identify(task_cap_kernel, &info);
141     if (err_is_fail(err)) {
142         USER_PANIC_ERR(err, "Can not identify the capability.");
143     }
144     char buffer[1024];
145     debug_print_cap(buffer, 1024, &info);
146     KALUGA_DEBUG("%s:%d: capability=%s\n", __FILE__, __LINE__, buffer);
147 #endif
148
149     struct capref inheritcn_cap;
150     err = alloc_inheritcn_with_caps(&inheritcn_cap,
151                                     NULL_CAP, NULL_CAP, task_cap_kernel);
152     if (err_is_fail(err)) {
153         DEBUG_ERR(err, "alloc_inheritcn_with_caps failed.");
154     }
155
156     err = spawn_program_with_caps(where, mi->path, argv,
157                                   environ, inheritcn_cap,
158                                   NULL_CAP, SPAWN_FLAGS_NEW_DOMAIN,
159                                   &mi->did[0]);
160     if (err_is_fail(err)) {
161         DEBUG_ERR(err, "Spawning %s failed.", mi->path);
162     }
163
164     if (cleanup) {
165         free(argv);
166     }
167
168     return err;
169 }
170
171
172 static void spawnd_change_event(octopus_mode_t mode, char* record, void* state)
173 {
174     size_t count = (size_t) state;
175     static coreid_t spawnd_counter = 0;
176
177     if (mode & OCT_ON_SET) {
178         KALUGA_DEBUG("spawnd found: %s\n", record);
179         spawnd_counter++;
180
181         if (spawnd_counter == count) {
182             KALUGA_DEBUG("Found enough spawnds, setting all_spawnds_up\n");
183             errval_t err = oct_set("all_spawnds_up { iref: 0 }");
184             assert(err_is_ok(err));
185         }
186     }
187 }
188
189 errval_t wait_for_all_spawnds(void)
190 {
191     // Note: The whole wait for all_spawnds_up thing is a hack.
192     // Our overall design goal is a system where cores
193     // come and go dynamically and we do not want / need
194     // to wait for a stable state.
195     // However, some of our code (for example domain spanning)
196     // still assumes a fixed set of cores and will deadlock
197     // otherwise. Therefore we need to fix those parts first.
198     KALUGA_DEBUG("Waiting for acpi");
199     char* record = NULL;
200     errval_t err = oct_wait_for(&record, "acpi { iref: _ }");
201     if (err_is_fail(err)) {
202         return err_push(err, KALUGA_ERR_WAITING_FOR_ACPI);
203     }
204
205     // No we should be able to get core count
206     // of all cores to estimate the amount of
207     // spawnd's we have to expect (one per core)
208     char** names;
209     size_t count;
210     err = oct_get_names(&names, &count, local_apics);
211     if (err_is_fail(err)) {
212         return err_push(err, KALUGA_ERR_QUERY_LOCAL_APIC);
213     }
214     oct_free_names(names, count);
215
216     static char* spawnds = "r'spawn.[0-9]+' { iref: _ }";
217     octopus_trigger_id_t tid;
218     return oct_trigger_existing_and_watch(spawnds, spawnd_change_event, (void*)count, &tid);
219 }