3 * \brief Core boot main
6 * Copyright (c) 2013, ETH Zurich.
9 * This file is distributed under the terms in the attached LICENSE file.
10 * If you do not find this file, copies can be found by writing to:
11 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
16 #include <hw_records.h>
20 struct capref ipi_cap;
22 coreid_t core_count = 0;
23 coreid_t core_max = 0;
26 bool benchmark_flag = false;
27 bool debug_flag = false;
28 bool new_kcb_flag = false;
29 bool nomsg_flag = false;
31 struct bench_data *bench_data = NULL;
33 char* cmd_kernel_binary = NULL;
34 char* cmd_monitor_binary = NULL;
35 char* cmd_kernel_args = "loglevel=2 logmask=0";
37 #define APIC_INTER_HALT_VECTOR 248
39 static void load_arch_id(void)
41 struct monitor_blocking_rpc_client *mc = get_monitor_blocking_rpc_client();
42 errval_t err = mc->vtbl.get_arch_core_id(mc, (uintptr_t *)&my_arch_id);
43 if (err_is_fail(err)) {
44 USER_PANIC_ERR(err, "get_arch_core_id failed.");
46 DEBUG("%s:%d: my_arch_id is %"PRIuCOREID"\n", __FILE__, __LINE__, my_arch_id);
49 static void setup_monitor_messaging(void)
51 struct monitor_binding *st = get_monitor_binding();
52 st->rx_vtbl.boot_core_reply = boot_core_reply;
55 static void load_ipi_cap(void)
57 struct monitor_blocking_rpc_client *mc = get_monitor_blocking_rpc_client();
58 errval_t err = mc->vtbl.get_ipi_cap(mc, &ipi_cap);
59 if (err_is_fail(err)) {
60 USER_PANIC_ERR(err, "get_ipi_cap failed.");
64 static void initialize(void)
71 #if defined(__x86__) && !defined(__k1om__)
72 err = connect_to_acpi();
73 if (err_is_fail(err)) {
74 USER_PANIC_ERR(err, "connect to acpi failed.");
79 if (err_is_fail(err)) {
80 USER_PANIC_ERR(err, "Octopus initialization failed.");
83 setup_monitor_messaging();
89 typedef int(*cmd_fn)(int argc, char** argv);
98 static int parse_core_list(char *list, coreid_t *from, coreid_t *to, coreid_t *step)
100 assert(from && to && step);
102 int num, parsed_from,parsed_to,parsed_step;
103 num = sscanf(list, "%i:%i:%i", &parsed_from, &parsed_to, &parsed_step);
106 *from = (coreid_t)parsed_from;
107 *to = (coreid_t)parsed_from;
111 *from = (coreid_t)parsed_from;
112 *to = (coreid_t)parsed_to;
116 *from = (coreid_t)parsed_from;
117 *to = (coreid_t)parsed_to;
118 *step = (coreid_t)parsed_step;
127 static int list_kcb(int argc, char **argv) {
130 errval_t err = oct_get_names(&names, &len, "r'kcb\\.[0-9]+'");
131 assert(err_is_ok(err));
133 for (size_t i=0; i<len; i++) {
135 err = oct_get(&record, names[i]);
136 assert(err_is_ok(err));
138 uint64_t barrelfish_id, kcb_id;
140 err = oct_read(record, "_ { kcb_id: %d, barrelfish_id: %d, cap_key: %s }",
141 &barrelfish_id, &kcb_id, &cap_key);
142 assert(err_is_ok(err));
144 printf("KCB %"PRIu64": CORE_ID=%"PRIu64" CAP_STORAGE_KEY=%s\n",
145 kcb_id, barrelfish_id, cap_key);
151 DEBUG("%s:%s:%d: No KCB found?\n",
152 __FILE__, __FUNCTION__, __LINE__);
156 oct_free_names(names, len);
160 static int list_cpu(int argc, char **argv) {
163 errval_t err = oct_get_names(&names, &len, "r'hw\\.processor\\.[0-9]+'");
164 assert(err_is_ok(err));
166 for (size_t i=0; i<len; i++) {
168 err = oct_get(&record, names[i]);
169 assert(err_is_ok(err));
171 uint64_t barrelfish_id, hw_id, enabled, type;
172 err = oct_read(record, "_ { " HW_PROCESSOR_GENERIC_FIELDS "}",
173 &enabled, &barrelfish_id, &hw_id, &type);
174 assert(err_is_ok(err));
176 printf("CPU %"PRIu64": HW_ID=%"PRIu64" TYPE=%s ENABLED=%"PRIu64"\n",
177 barrelfish_id, hw_id, cpu_type_to_archstr(type), enabled);
182 DEBUG("%s:%s:%d: No cpus found?\n",
183 __FILE__, __FUNCTION__, __LINE__);
187 oct_free_names(names, len);
191 static int boot_cpu(int argc, char **argv)
193 coreid_t core_from = 0, core_to = 0, core_step = 0;
194 int parsed = parse_core_list(argv[1], &core_from, &core_to, &core_step);
197 USER_PANIC("invalid CPU ID: %s", argv[1]);
201 if (core_step == 1) {
202 core_max = (core_to - core_from + 1);
204 core_max = (core_to - core_from + core_step) / core_step;
207 for (coreid_t target_id = core_from; target_id<=core_to; target_id += core_step) {
208 assert(target_id < MAX_COREID);
210 archid_t target_apic_id;
211 enum cpu_type cpu_type;
212 errval_t err = get_core_info(target_id, &target_apic_id, &cpu_type);
213 if (err_is_fail(err)) {
214 USER_PANIC_ERR(err, "get_apic_id failed.");
218 err = create_or_get_kcb_cap(target_id, &kcb);
219 if (err_is_fail(err)) {
220 USER_PANIC_ERR(err, "Can not get KCB.");
225 struct frame_identity urpc_frame_id;
226 err = frame_alloc_identify(&frame, MON_URPC_SIZE, &framesize, &urpc_frame_id);
227 if (err_is_fail(err)) {
228 USER_PANIC_ERR(err, "frame_alloc_identify failed.");
231 err = cap_mark_remote(frame);
232 if (err_is_fail(err)) {
233 USER_PANIC_ERR(err, "Can not mark cap remote.");
236 struct monitor_binding *mb = get_monitor_binding();
237 err = mb->tx_vtbl.boot_core_request(mb, NOP_CONT, target_id, frame);
238 if (err_is_fail(err)) {
239 USER_PANIC_ERR(err, "boot_core_request failed");
242 err = spawn_xcore_monitor(target_id, target_apic_id,
243 cpu_type, cmd_kernel_args,
245 if (err_is_fail(err)) {
246 USER_PANIC_ERR(err, "spawn xcore monitor failed.");
254 static int update_cpu(int argc, char** argv)
256 coreid_t target_id = (coreid_t) strtol(argv[1], NULL, 0);
257 assert(target_id < MAX_COREID);
259 archid_t target_apic_id;
260 enum cpu_type cpu_type;
261 errval_t err = get_core_info(target_id, &target_apic_id, &cpu_type);
262 if (err_is_fail(err)) {
263 USER_PANIC_ERR(err, "get_apic_id failed.");
267 err = create_or_get_kcb_cap(target_id, &kcb);
268 if (err_is_fail(err)) {
269 USER_PANIC_ERR(err, "Can not get KCB.");
274 struct frame_identity urpc_frame_id;
275 err = frame_alloc_identify(&frame, MON_URPC_SIZE, &framesize, &urpc_frame_id);
276 if (err_is_fail(err)) {
277 USER_PANIC_ERR(err, "frame_alloc_identify failed.");
279 err = cap_mark_remote(frame);
280 if (err_is_fail(err)) {
281 DEBUG_ERR(err, "Can not mark cap remote.");
286 err = sys_debug_send_ipi(target_apic_id, 0, APIC_INTER_HALT_VECTOR);
287 if (err_is_fail(err)) {
288 USER_PANIC_ERR(err, "debug_send_ipi to power it down failed.");
292 err = spawn_xcore_monitor(target_id, target_apic_id, cpu_type,
295 if (err_is_fail(err)) {
296 USER_PANIC_ERR(err, "spawn xcore monitor failed.");
299 //TODO(gz): while (*ap_dispatch != 1);
303 static int stop_cpu(int argc, char** argv)
305 coreid_t target_id = (coreid_t) strtol(argv[1], NULL, 0);
306 assert(target_id < MAX_COREID);
308 archid_t target_apic_id;
309 enum cpu_type cpu_type;
310 errval_t err = get_core_info(target_id, &target_apic_id, &cpu_type);
311 if (err_is_fail(err)) {
312 USER_PANIC_ERR(err, "get_apic_id failed.");
315 err = sys_debug_send_ipi(target_apic_id, 0, APIC_INTER_HALT_VECTOR);
316 if (err_is_fail(err)) {
317 USER_PANIC_ERR(err, "debug_send_ipi to power it down failed.");
321 // The next line is crucial for harness test to pass
322 printf("Core %"PRIuCOREID" stopped.\n", target_id);
326 static int give_kcb(int argc, char** argv)
329 DEBUG("%s:%d: Give KCB from core %s to core %s...\n",
330 __FILE__, __LINE__, argv[1], argv[2]);
332 coreid_t target_id = (coreid_t) strtol(argv[1], NULL, 0);
333 assert(target_id < MAX_COREID);
335 errval_t err = create_or_get_kcb_cap(target_id, &kcb);
336 if (err_is_fail(err)) {
337 USER_PANIC_ERR(err, "Can not get KCB.");
340 coreid_t destination_id = (coreid_t) strtol(argv[2], NULL, 0);
341 assert(destination_id < MAX_COREID);
343 /*err = sys_debug_send_ipi(target_id, 0, APIC_INTER_HALT_VECTOR);
344 if (err_is_fail(err)) {
345 USER_PANIC_ERR(err, "debug_send_ipi to power it down failed.");
349 err = give_kcb_to_new_core(destination_id, kcb);
350 if (err_is_fail(err)) {
351 USER_PANIC_ERR(err, "Can not send KCB to another core.");
357 static int remove_kcb(int argc, char** argv)
360 DEBUG("%s:%s:%d: Stopping kcb.%s\n", __FILE__,
361 __FUNCTION__, __LINE__, argv[1]);
363 coreid_t target_id = (coreid_t) strtol(argv[1], NULL, 0);
364 assert(target_id < MAX_COREID);
366 errval_t err = create_or_get_kcb_cap(target_id, &kcb);
367 if (err_is_fail(err)) {
368 USER_PANIC_ERR(err, "Can not get KCB.");
371 struct monitor_blocking_rpc_client *mc = get_monitor_blocking_rpc_client();
372 // send message to monitor to be relocated -> don't switch kcb ->
373 // remove kcb from ring -> msg ->
374 // (disp_save_rm_kcb -> next/home/... kcb -> enable switching)
376 err = mc->vtbl.forward_kcb_rm_request(mc, target_id, kcb, &ret_err);
377 if (err_is_fail(err)) {
378 USER_PANIC_ERR(err, "forward_kcb_request failed.");
380 if (err_is_fail(ret_err)) {
381 USER_PANIC_ERR(ret_err, "forward_kcb_request failed.");
385 //coreid_t destination_id = (coreid_t) strtol(argv[3], NULL, 0);
386 //assert(destination_id < MAX_COREID);
388 // Move KCB to a core that is currently running
391 err = give_kcb_to_new_core(destination_id, kcb);
392 if (err_is_fail(err)) {
393 USER_PANIC_ERR(err, "Can not send KCB to another core.");
398 // Boot the removed KCB on a core that is currently not running
403 struct frame_identity urpc_frame_id;
404 err = frame_alloc_identify(&frame, MON_URPC_SIZE, &framesize, &urpc_frame_id);
405 if (err_is_fail(err)) {
406 USER_PANIC_ERR(err, "frame_alloc_identify failed.");
408 err = cap_mark_remote(frame);
409 if (err_is_fail(err)) {
410 DEBUG_ERR(err, "Can not mark cap remote.");
414 struct monitor_binding *mb = get_monitor_binding();
415 err = mb->tx_vtbl.boot_core_request(mb, NOP_CONT, target_id, frame);
416 if (err_is_fail(err)) {
417 USER_PANIC_ERR(err, "boot_core_request failed");
420 err = spawn_xcore_monitor(target_id, target_id,
424 if (err_is_fail(err)) {
425 USER_PANIC_ERR(err, "spawn xcore monitor failed.");
432 * Do stop and then give in one call to corectrl
433 * args: <kcb_id to stop> <kcb_id to give to>
435 static int park_kcb(int argc, char *argv[])
439 printf("Stopping core %lu\n", strtol(argv[1], NULL, 0));
440 r = stop_cpu(2, argv);
442 printf("Parking KCB on core %lu\n", strtol(argv[2], NULL, 0));
443 return give_kcb(3, argv);
447 * Do rm and boot -m in one call to corectrl
448 * args: <kcb_id to remove> <core_id to boot>
450 static int unpark_kcb(int argc, char *argv[])
454 coreid_t c = (coreid_t)strtol(argv[1], NULL, 0);
455 printf("Removing KCB %u from its core\n", c);
456 r = remove_kcb(2, argv);
458 // set nomsg_flag to emulate -m option for boot
460 printf("Booting KCB %u on core %u\n", c,c);
461 return boot_cpu(2, argv);
464 static struct cmd commands[] = {
467 "Boot a fresh core with a KCB.",
468 "boot <target core_id>",
474 "Update the kernel on an existing core.",
475 "update <target core_id>",
481 "Stop execution on an existing core.",
482 "stop <target core_id>",
488 "Give kcb from one core to another.",
489 "give <from kcb_id> <to kcb_id>",
495 "Remove a running KCB from a core.",
502 "Stop execution on an existing core and park KCB on another core.",
503 "park <kcb_id to stop> <recv kcb_id>",
509 "Reestablish parked KCB on its original core.",
510 "unpark <kcb_id to unpark>",
516 "List current status of all cores.",
523 "List current KCBs.",
528 {NULL, NULL, NULL, NULL, 0},
531 static struct option long_options[] = {
532 {"debug", no_argument, 0, 'd'},
533 {"kernel", required_argument, 0, 'k'},
534 {"monitor", required_argument, 0, 'x'},
535 {"kargs", required_argument, 0, 'a'},
536 {"newkcb", no_argument, 0, 'n'},
537 {"nomsg", no_argument, 0, 'm'},
538 {"help", no_argument, 0, 'h'},
542 static void print_help(char* argv0)
544 printf("Usage: %s [OPTIONS] <COMMAND> [<args>]\n", argv0);
545 printf("Options:\n");
546 printf("\t -d, --debug\n");
547 printf("\t\t Print debug information\n");
548 printf("\t -k, --kernel\n");
549 printf("\t\t Overwrite default kernel binary\n");
550 printf("\t -x, --monitor\n");
551 printf("\t\t Overwrite default monitor binary\n");
552 printf("\t -a, --kargs\n");
553 printf("\t\t Overwrite default kernel cmd arguments\n");
554 printf("\t -n, --newkcb\n");
555 printf("\t\t Create a new KCB even if there is already one for that core\n");
556 printf("\t -m, --nomsg\n");
557 printf("\t\t Don't wait for monitor message at the end\n");
559 printf("Commands:\n");
560 for (size_t i = 0; commands[i].name != NULL; i++) {
561 printf("\t %s\t\t%s\n", commands[i].name, commands[i].desc);
565 static void print_cmd_help(char* cmd)
568 for (; commands[i].name != NULL; i++) {
569 if (strcmp(cmd, commands[i].name) == 0) {
574 printf("%s - %s\n", commands[i].name, commands[i].desc);
575 printf("%s\n", commands[i].help);
578 int main (int argc, char **argv)
585 DEBUG("corectrl start\n");
587 #if defined(__x86__) && !defined(__k1om__)
590 err = oct_lock("corectrl.lock", &lock);
591 if (err_is_fail(err)) {
592 USER_PANIC_ERR(err, "can lock corectrl.");
597 for (int i=0; i<argc; i++) {
598 DEBUG("%s:%s:%d: argv[%d] = %s\n",
599 __FILE__, __FUNCTION__, __LINE__, i, argv[i]);
603 DEBUG("corectrl got lock\n");
604 // Parse arguments, call handler function
607 /* getopt_long stores the option index here. */
608 int option_index = 0;
610 c = getopt_long (argc, argv, "k:a:x:hnmd",
611 long_options, &option_index);
613 break; // End of the options
618 // Long options handled by their short handles
622 cmd_kernel_binary = optarg;
626 cmd_kernel_args = optarg;
630 cmd_monitor_binary = optarg;
657 for (; optind < argc; optind++) {
658 for (size_t i = 0; commands[i].name != NULL; i++) {
659 if (strcmp(argv[optind], commands[i].name) == 0) {
660 if (argc - optind < commands[i].argc) {
661 print_cmd_help(commands[i].name);
665 ret = commands[i].fn(argc-optind, argv+optind);
676 else if (!nomsg_flag) {
677 DEBUG("%s:%s:%d: Wait for message.\n",
678 __FILE__, __FUNCTION__, __LINE__);
680 err = event_dispatch(get_default_waitset());
681 if (err_is_fail(err)) {
682 USER_PANIC_ERR(err, "error in event_dispatch");
688 #if defined(__x86__) && !defined(__k1om__)
689 // END ENSURE SEQUENTIAL
690 err = oct_unlock(lock);
691 if (err_is_fail(err)) {
692 USER_PANIC_ERR(err, "can not unlock corectrl.");
697 DEBUG("corectrl is done.");