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);
150 DEBUG("%s:%s:%d: No KCB found?\n",
151 __FILE__, __FUNCTION__, __LINE__);
155 oct_free_names(names, len);
159 static int list_cpu(int argc, char **argv) {
162 errval_t err = oct_get_names(&names, &len, "r'hw\\.processor\\.[0-9]+'");
163 assert(err_is_ok(err));
165 for (size_t i=0; i<len; i++) {
167 err = oct_get(&record, names[i]);
168 assert(err_is_ok(err));
170 uint64_t barrelfish_id, hw_id, enabled, type;
171 err = oct_read(record, "_ { " HW_PROCESSOR_GENERIC_FIELDS "}",
172 &enabled, &barrelfish_id, &hw_id, &type);
173 assert(err_is_ok(err));
175 printf("CPU %"PRIu64": HW_ID=%"PRIu64" TYPE=%s ENABLED=%"PRIu64"\n",
176 barrelfish_id, hw_id, cpu_type_to_archstr(type), enabled);
179 DEBUG("%s:%s:%d: No cpus found?\n",
180 __FILE__, __FUNCTION__, __LINE__);
184 oct_free_names(names, len);
188 static int boot_cpu(int argc, char **argv)
190 coreid_t core_from = 0, core_to = 0, core_step = 0;
191 int parsed = parse_core_list(argv[1], &core_from, &core_to, &core_step);
194 USER_PANIC("invalid CPU ID: %s", argv[1]);
198 if (core_step == 1) {
199 core_max = (core_to - core_from + 1);
201 core_max = (core_to - core_from + core_step) / core_step;
204 for (coreid_t target_id = core_from; target_id<=core_to; target_id += core_step) {
205 assert(target_id < MAX_COREID);
207 archid_t target_apic_id;
208 enum cpu_type cpu_type;
209 errval_t err = get_core_info(target_id, &target_apic_id, &cpu_type);
210 if (err_is_fail(err)) {
211 USER_PANIC_ERR(err, "get_apic_id failed.");
215 err = create_or_get_kcb_cap(target_id, &kcb);
216 if (err_is_fail(err)) {
217 USER_PANIC_ERR(err, "Can not get KCB.");
222 struct frame_identity urpc_frame_id;
223 err = frame_alloc_identify(&frame, MON_URPC_SIZE, &framesize, &urpc_frame_id);
224 if (err_is_fail(err)) {
225 USER_PANIC_ERR(err, "frame_alloc_identify failed.");
228 err = cap_mark_remote(frame);
229 if (err_is_fail(err)) {
230 USER_PANIC_ERR(err, "Can not mark cap remote.");
233 struct monitor_binding *mb = get_monitor_binding();
234 err = mb->tx_vtbl.boot_core_request(mb, NOP_CONT, target_id, frame);
235 if (err_is_fail(err)) {
236 USER_PANIC_ERR(err, "boot_core_request failed");
239 err = spawn_xcore_monitor(target_id, target_apic_id,
240 cpu_type, cmd_kernel_args,
242 if (err_is_fail(err)) {
243 USER_PANIC_ERR(err, "spawn xcore monitor failed.");
251 static int update_cpu(int argc, char** argv)
253 coreid_t target_id = (coreid_t) strtol(argv[1], NULL, 0);
254 assert(target_id < MAX_COREID);
256 archid_t target_apic_id;
257 enum cpu_type cpu_type;
258 errval_t err = get_core_info(target_id, &target_apic_id, &cpu_type);
259 if (err_is_fail(err)) {
260 USER_PANIC_ERR(err, "get_apic_id failed.");
264 err = create_or_get_kcb_cap(target_id, &kcb);
265 if (err_is_fail(err)) {
266 USER_PANIC_ERR(err, "Can not get KCB.");
271 struct frame_identity urpc_frame_id;
272 err = frame_alloc_identify(&frame, MON_URPC_SIZE, &framesize, &urpc_frame_id);
273 if (err_is_fail(err)) {
274 USER_PANIC_ERR(err, "frame_alloc_identify failed.");
276 err = cap_mark_remote(frame);
277 if (err_is_fail(err)) {
278 DEBUG_ERR(err, "Can not mark cap remote.");
283 err = sys_debug_send_ipi(target_apic_id, 0, APIC_INTER_HALT_VECTOR);
284 if (err_is_fail(err)) {
285 USER_PANIC_ERR(err, "debug_send_ipi to power it down failed.");
289 err = spawn_xcore_monitor(target_id, target_apic_id, cpu_type,
292 if (err_is_fail(err)) {
293 USER_PANIC_ERR(err, "spawn xcore monitor failed.");
296 //TODO(gz): while (*ap_dispatch != 1);
300 static int stop_cpu(int argc, char** argv)
302 coreid_t target_id = (coreid_t) strtol(argv[1], NULL, 0);
303 assert(target_id < MAX_COREID);
305 archid_t target_apic_id;
306 enum cpu_type cpu_type;
307 errval_t err = get_core_info(target_id, &target_apic_id, &cpu_type);
308 if (err_is_fail(err)) {
309 USER_PANIC_ERR(err, "get_apic_id failed.");
312 err = sys_debug_send_ipi(target_apic_id, 0, APIC_INTER_HALT_VECTOR);
313 if (err_is_fail(err)) {
314 USER_PANIC_ERR(err, "debug_send_ipi to power it down failed.");
318 // The next line is crucial for harness test to pass
319 printf("Core %"PRIuCOREID" stopped.\n", target_id);
323 static int give_kcb(int argc, char** argv)
326 DEBUG("%s:%d: Give KCB from core %s to core %s...\n",
327 __FILE__, __LINE__, argv[1], argv[2]);
329 coreid_t target_id = (coreid_t) strtol(argv[1], NULL, 0);
330 assert(target_id < MAX_COREID);
332 errval_t err = create_or_get_kcb_cap(target_id, &kcb);
333 if (err_is_fail(err)) {
334 USER_PANIC_ERR(err, "Can not get KCB.");
337 coreid_t destination_id = (coreid_t) strtol(argv[2], NULL, 0);
338 assert(destination_id < MAX_COREID);
340 /*err = sys_debug_send_ipi(target_id, 0, APIC_INTER_HALT_VECTOR);
341 if (err_is_fail(err)) {
342 USER_PANIC_ERR(err, "debug_send_ipi to power it down failed.");
346 err = give_kcb_to_new_core(destination_id, kcb);
347 if (err_is_fail(err)) {
348 USER_PANIC_ERR(err, "Can not send KCB to another core.");
354 static int remove_kcb(int argc, char** argv)
357 DEBUG("%s:%s:%d: Stopping kcb.%s\n", __FILE__,
358 __FUNCTION__, __LINE__, argv[1]);
360 coreid_t target_id = (coreid_t) strtol(argv[1], NULL, 0);
361 assert(target_id < MAX_COREID);
363 errval_t err = create_or_get_kcb_cap(target_id, &kcb);
364 if (err_is_fail(err)) {
365 USER_PANIC_ERR(err, "Can not get KCB.");
368 struct monitor_blocking_rpc_client *mc = get_monitor_blocking_rpc_client();
369 // send message to monitor to be relocated -> don't switch kcb ->
370 // remove kcb from ring -> msg ->
371 // (disp_save_rm_kcb -> next/home/... kcb -> enable switching)
373 err = mc->vtbl.forward_kcb_rm_request(mc, target_id, kcb, &ret_err);
374 if (err_is_fail(err)) {
375 USER_PANIC_ERR(err, "forward_kcb_request failed.");
377 if (err_is_fail(ret_err)) {
378 USER_PANIC_ERR(ret_err, "forward_kcb_request failed.");
382 //coreid_t destination_id = (coreid_t) strtol(argv[3], NULL, 0);
383 //assert(destination_id < MAX_COREID);
385 // Move KCB to a core that is currently running
388 err = give_kcb_to_new_core(destination_id, kcb);
389 if (err_is_fail(err)) {
390 USER_PANIC_ERR(err, "Can not send KCB to another core.");
395 // Boot the removed KCB on a core that is currently not running
400 struct frame_identity urpc_frame_id;
401 err = frame_alloc_identify(&frame, MON_URPC_SIZE, &framesize, &urpc_frame_id);
402 if (err_is_fail(err)) {
403 USER_PANIC_ERR(err, "frame_alloc_identify failed.");
405 err = cap_mark_remote(frame);
406 if (err_is_fail(err)) {
407 DEBUG_ERR(err, "Can not mark cap remote.");
411 struct monitor_binding *mb = get_monitor_binding();
412 err = mb->tx_vtbl.boot_core_request(mb, NOP_CONT, target_id, frame);
413 if (err_is_fail(err)) {
414 USER_PANIC_ERR(err, "boot_core_request failed");
417 err = spawn_xcore_monitor(target_id, target_id,
421 if (err_is_fail(err)) {
422 USER_PANIC_ERR(err, "spawn xcore monitor failed.");
429 * Do stop and then give in one call to corectrl
430 * args: <kcb_id to stop> <kcb_id to give to>
432 static int park_kcb(int argc, char *argv[])
436 printf("Stopping core %lu\n", strtol(argv[1], NULL, 0));
437 r = stop_cpu(2, argv);
439 printf("Parking KCB on core %lu\n", strtol(argv[2], NULL, 0));
440 return give_kcb(3, argv);
444 * Do rm and boot -m in one call to corectrl
445 * args: <kcb_id to remove> <core_id to boot>
447 static int unpark_kcb(int argc, char *argv[])
451 coreid_t c = (coreid_t)strtol(argv[1], NULL, 0);
452 printf("Removing KCB %u from its core\n", c);
453 r = remove_kcb(2, argv);
455 // set nomsg_flag to emulate -m option for boot
457 printf("Booting KCB %u on core %u\n", c,c);
458 return boot_cpu(2, argv);
461 static struct cmd commands[] = {
464 "Boot a fresh core with a KCB.",
465 "boot <target core_id>",
471 "Update the kernel on an existing core.",
472 "update <target core_id>",
478 "Stop execution on an existing core.",
479 "stop <target core_id>",
485 "Give kcb from one core to another.",
486 "give <from kcb_id> <to kcb_id>",
492 "Remove a running KCB from a core.",
499 "Stop execution on an existing core and park KCB on another core.",
500 "park <kcb_id to stop> <recv kcb_id>",
506 "Reestablish parked KCB on its original core.",
507 "unpark <kcb_id to unpark>",
513 "List current status of all cores.",
520 "List current KCBs.",
525 {NULL, NULL, NULL, NULL, 0},
528 static struct option long_options[] = {
529 {"debug", no_argument, 0, 'd'},
530 {"kernel", required_argument, 0, 'k'},
531 {"monitor", required_argument, 0, 'x'},
532 {"kargs", required_argument, 0, 'a'},
533 {"newkcb", no_argument, 0, 'n'},
534 {"nomsg", no_argument, 0, 'm'},
535 {"help", no_argument, 0, 'h'},
539 static void print_help(char* argv0)
541 printf("Usage: %s [OPTIONS] <COMMAND> [<args>]\n", argv0);
542 printf("Options:\n");
543 printf("\t -d, --debug\n");
544 printf("\t\t Print debug information\n");
545 printf("\t -k, --kernel\n");
546 printf("\t\t Overwrite default kernel binary\n");
547 printf("\t -x, --monitor\n");
548 printf("\t\t Overwrite default monitor binary\n");
549 printf("\t -a, --kargs\n");
550 printf("\t\t Overwrite default kernel cmd arguments\n");
551 printf("\t -n, --newkcb\n");
552 printf("\t\t Create a new KCB even if there is already one for that core\n");
553 printf("\t -m, --nomsg\n");
554 printf("\t\t Don't wait for monitor message at the end\n");
556 printf("Commands:\n");
557 for (size_t i = 0; commands[i].name != NULL; i++) {
558 printf("\t %s\t\t%s\n", commands[i].name, commands[i].desc);
562 static void print_cmd_help(char* cmd)
565 for (; commands[i].name != NULL; i++) {
566 if (strcmp(cmd, commands[i].name) == 0) {
571 printf("%s - %s\n", commands[i].name, commands[i].desc);
572 printf("%s\n", commands[i].help);
575 int main (int argc, char **argv)
582 DEBUG("corectrl start\n");
584 #if defined(__x86__) && !defined(__k1om__)
587 err = oct_lock("corectrl.lock", &lock);
588 if (err_is_fail(err)) {
589 USER_PANIC_ERR(err, "can lock corectrl.");
594 for (int i=0; i<argc; i++) {
595 DEBUG("%s:%s:%d: argv[%d] = %s\n",
596 __FILE__, __FUNCTION__, __LINE__, i, argv[i]);
600 DEBUG("corectrl got lock\n");
601 // Parse arguments, call handler function
604 /* getopt_long stores the option index here. */
605 int option_index = 0;
607 c = getopt_long (argc, argv, "k:a:x:hnmd",
608 long_options, &option_index);
610 break; // End of the options
615 // Long options handled by their short handles
619 cmd_kernel_binary = optarg;
623 cmd_kernel_args = optarg;
627 cmd_monitor_binary = optarg;
654 for (; optind < argc; optind++) {
655 for (size_t i = 0; commands[i].name != NULL; i++) {
656 if (strcmp(argv[optind], commands[i].name) == 0) {
657 if (argc - optind < commands[i].argc) {
658 print_cmd_help(commands[i].name);
662 ret = commands[i].fn(argc-optind, argv+optind);
673 else if (!nomsg_flag) {
674 DEBUG("%s:%s:%d: Wait for message.\n",
675 __FILE__, __FUNCTION__, __LINE__);
677 err = event_dispatch(get_default_waitset());
678 if (err_is_fail(err)) {
679 USER_PANIC_ERR(err, "error in event_dispatch");
685 #if defined(__x86__) && !defined(__k1om__)
686 // END ENSURE SEQUENTIAL
687 err = oct_unlock(lock);
688 if (err_is_fail(err)) {
689 USER_PANIC_ERR(err, "can not unlock corectrl.");
694 DEBUG("corectrl is done.");