Merge branch 'master' of ssh://code.systems.ethz.ch:8006/diffusion/BFI/barrelfish
[barrelfish] / usr / drivers / cpuboot / main.c
1 /**
2  * \file
3  * \brief Core boot main
4  */
5 /*
6  * Copyright (c) 2013, ETH Zurich.
7  * All rights reserved.
8  *
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.
12  */
13
14 #include <getopt.h>
15 #include "coreboot.h"
16 #include <hw_records.h>
17
18
19 coreid_t my_arch_id;
20 struct capref ipi_cap;
21
22 coreid_t core_count = 0;
23 coreid_t core_max = 0;
24 bool done = false;
25
26 bool benchmark_flag = false;
27 bool debug_flag = false;
28 bool new_kcb_flag = false;
29 bool nomsg_flag = false;
30
31 struct bench_data *bench_data = NULL;
32
33 char* cmd_kernel_binary = NULL;
34 char* cmd_monitor_binary = NULL;
35 char* cmd_kernel_args = "loglevel=2 logmask=0";
36
37 #define APIC_INTER_HALT_VECTOR 248
38
39 static void load_arch_id(void)
40 {
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.");
45     }
46     DEBUG("%s:%d: my_arch_id is %"PRIuCOREID"\n", __FILE__, __LINE__, my_arch_id);
47 }
48
49 static void setup_monitor_messaging(void)
50 {
51     struct monitor_binding *st = get_monitor_binding();
52     st->rx_vtbl.boot_core_reply = boot_core_reply;
53 }
54
55 static void load_ipi_cap(void)
56 {
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.");
61     }
62 }
63
64 static void initialize(void)
65 {
66     errval_t err;
67
68     vfs_init();
69     bench_init();
70
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.");
75     }
76 #endif
77
78     err = oct_init();
79     if (err_is_fail(err)) {
80         USER_PANIC_ERR(err, "Octopus initialization failed.");
81     }
82
83     setup_monitor_messaging();
84     load_arch_id();
85     load_ipi_cap();
86 }
87
88
89 typedef int(*cmd_fn)(int argc, char** argv);
90 struct cmd {
91     char* name;
92     char* desc;
93     char* help;
94     cmd_fn fn;
95     int argc;
96 };
97
98 static int parse_core_list(char *list, coreid_t *from, coreid_t *to, coreid_t *step)
99 {
100     assert(from && to && step);
101
102     int num, parsed_from,parsed_to,parsed_step;
103     num = sscanf(list, "%i:%i:%i", &parsed_from, &parsed_to, &parsed_step);
104     switch(num) {
105         case 1:
106             *from = (coreid_t)parsed_from;
107             *to = (coreid_t)parsed_from;
108             *step = 1;
109             break;
110         case 2:
111             *from = (coreid_t)parsed_from;
112             *to = (coreid_t)parsed_to;
113             *step = 1;
114             break;
115         case 3:
116             *from = (coreid_t)parsed_from;
117             *to = (coreid_t)parsed_to;
118             *step = (coreid_t)parsed_step;
119             break;
120         default:
121             return 0;
122             break;
123     }
124     return num;
125 }
126
127 static int list_kcb(int argc, char **argv) {
128     char** names;
129     size_t len;
130     errval_t err = oct_get_names(&names, &len, "r'kcb\\.[0-9]+'");
131     assert(err_is_ok(err));
132
133     for (size_t i=0; i<len; i++) {
134         char* record;
135         err = oct_get(&record, names[i]);
136         assert(err_is_ok(err));
137
138         uint64_t barrelfish_id, kcb_id;
139         char* cap_key;
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));
143
144         printf("KCB %"PRIu64": CORE_ID=%"PRIu64" CAP_STORAGE_KEY=%s\n",
145                kcb_id, barrelfish_id, cap_key);
146
147         free(cap_key);
148     }
149     if (len == 0) {
150         DEBUG("%s:%s:%d: No KCB found?\n",
151               __FILE__, __FUNCTION__, __LINE__);
152     }
153
154     done = true;
155     oct_free_names(names, len);
156     return 0;
157 }
158
159 static int list_cpu(int argc, char **argv) {
160     char** names;
161     size_t len;
162     errval_t err = oct_get_names(&names, &len, "r'hw\\.processor\\.[0-9]+'");
163     assert(err_is_ok(err));
164
165     for (size_t i=0; i<len; i++) {
166         char* record;
167         err = oct_get(&record, names[i]);
168         assert(err_is_ok(err));
169
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));
174
175         printf("CPU %"PRIu64": HW_ID=%"PRIu64" TYPE=%s ENABLED=%"PRIu64"\n",
176                barrelfish_id, hw_id, cpu_type_to_archstr(type), enabled);
177     }
178     if (len == 0) {
179         DEBUG("%s:%s:%d: No cpus found?\n",
180               __FILE__, __FUNCTION__, __LINE__);
181     }
182
183     done = true;
184     oct_free_names(names, len);
185     return 0;
186 }
187
188 static int boot_cpu(int argc, char **argv)
189 {
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);
192
193     if (parsed == 0) {
194         USER_PANIC("invalid CPU ID: %s", argv[1]);
195     }
196
197     core_count = 0;
198     if (core_step == 1) {
199         core_max = (core_to - core_from + 1);
200     } else {
201         core_max = (core_to - core_from + core_step) / core_step;
202     }
203
204     for (coreid_t target_id = core_from; target_id<=core_to; target_id += core_step) {
205         assert(target_id < MAX_COREID);
206
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.");
212         }
213
214         struct capref kcb;
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.");
218         }
219
220         struct capref frame;
221         size_t framesize;
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.");
226         }
227
228         err = cap_mark_remote(frame);
229         if (err_is_fail(err)) {
230             USER_PANIC_ERR(err, "Can not mark cap remote.");
231         }
232
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");
237         }
238
239         err = spawn_xcore_monitor(target_id, target_apic_id,
240                                   cpu_type, cmd_kernel_args,
241                                   urpc_frame_id, kcb);
242         if (err_is_fail(err)) {
243             USER_PANIC_ERR(err, "spawn xcore monitor failed.");
244         }
245
246     }
247     return 0;
248 }
249
250
251 static int update_cpu(int argc, char** argv)
252 {
253     coreid_t target_id = (coreid_t) strtol(argv[1], NULL, 0);
254     assert(target_id < MAX_COREID);
255
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.");
261     }
262
263     struct capref kcb;
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.");
267     }
268
269     struct capref frame;
270     size_t framesize;
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.");
275     }
276     err = cap_mark_remote(frame);
277     if (err_is_fail(err)) {
278         DEBUG_ERR(err, "Can not mark cap remote.");
279         return err;
280     }
281
282     // do clean shutdown
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.");
286     }
287
288     done = true;
289     err = spawn_xcore_monitor(target_id, target_apic_id, cpu_type,
290                               cmd_kernel_args,
291                               urpc_frame_id, kcb);
292     if (err_is_fail(err)) {
293         USER_PANIC_ERR(err, "spawn xcore monitor failed.");
294     }
295
296     //TODO(gz): while (*ap_dispatch != 1);
297     return 0;
298 }
299
300 static int stop_cpu(int argc, char** argv)
301 {
302     coreid_t target_id = (coreid_t) strtol(argv[1], NULL, 0);
303     assert(target_id < MAX_COREID);
304
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.");
310     }
311
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.");
315     }
316     done = true;
317
318     // The next line is crucial for harness test to pass
319     printf("Core %"PRIuCOREID" stopped.\n", target_id);
320     return 0;
321 }
322
323 static int give_kcb(int argc, char** argv)
324 {
325     assert (argc == 3);
326     DEBUG("%s:%d: Give KCB from core %s to core %s...\n",
327           __FILE__, __LINE__, argv[1], argv[2]);
328
329     coreid_t target_id = (coreid_t) strtol(argv[1], NULL, 0);
330     assert(target_id < MAX_COREID);
331     struct capref kcb;
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.");
335     }
336
337     coreid_t destination_id = (coreid_t) strtol(argv[2], NULL, 0);
338     assert(destination_id < MAX_COREID);
339
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.");
343     }*/
344     done = true;
345
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.");
349     }
350
351     return 0;
352 }
353
354 static int remove_kcb(int argc, char** argv)
355 {
356     assert (argc == 2);
357     DEBUG("%s:%s:%d: Stopping kcb.%s\n", __FILE__,
358           __FUNCTION__, __LINE__, argv[1]);
359
360     coreid_t target_id = (coreid_t) strtol(argv[1], NULL, 0);
361     assert(target_id < MAX_COREID);
362     struct capref kcb;
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.");
366     }
367
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)
372     errval_t ret_err;
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.");
376     }
377     if (err_is_fail(ret_err)) {
378         USER_PANIC_ERR(ret_err, "forward_kcb_request failed.");
379     }
380     done = true;
381
382     //coreid_t destination_id = (coreid_t) strtol(argv[3], NULL, 0);
383     //assert(destination_id < MAX_COREID);
384     //
385     // Move KCB to a core that is currently running
386     //
387     /*
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.");
391     }
392     */
393
394     //
395     // Boot the removed KCB on a core that is currently not running
396     //
397     /*
398     struct capref frame;
399     size_t framesize;
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.");
404     }
405     err = cap_mark_remote(frame);
406     if (err_is_fail(err)) {
407         DEBUG_ERR(err, "Can not mark cap remote.");
408         return err;
409     }
410
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");
415     }
416
417     err = spawn_xcore_monitor(target_id, target_id,
418                               CPU_X86_64,
419                               cmd_kernel_args,
420                               urpc_frame_id, kcb);
421     if (err_is_fail(err)) {
422         USER_PANIC_ERR(err, "spawn xcore monitor failed.");
423     }*/
424
425     return 0;
426 }
427
428 /*
429  * Do stop and then give in one call to corectrl
430  * args: <kcb_id to stop> <kcb_id to give to>
431  */
432 static int park_kcb(int argc, char *argv[])
433 {
434     int r;
435     assert (argc == 3);
436     printf("Stopping core %lu\n", strtol(argv[1], NULL, 0));
437     r = stop_cpu(2, argv);
438     if (r) { return r; }
439     printf("Parking KCB on core %lu\n", strtol(argv[2], NULL, 0));
440     return give_kcb(3, argv);
441 }
442
443 /*
444  * Do rm and boot -m in one call to corectrl
445  * args: <kcb_id to remove> <core_id to boot>
446  */
447 static int unpark_kcb(int argc, char *argv[])
448 {
449     int r;
450     assert (argc == 2);
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);
454     if (r) { return r; }
455     // set nomsg_flag to emulate -m option for boot
456     nomsg_flag = true;
457     printf("Booting KCB %u on core %u\n", c,c);
458     return boot_cpu(2, argv);
459 }
460
461 static struct cmd commands[] = {
462     {
463         "boot",
464         "Boot a fresh core with a KCB.",
465         "boot <target core_id>",
466         boot_cpu,
467         2
468     },
469     {
470         "update",
471         "Update the kernel on an existing core.",
472         "update <target core_id>",
473         update_cpu,
474         2
475     },
476     {
477         "stop",
478         "Stop execution on an existing core.",
479         "stop <target core_id>",
480         stop_cpu,
481         2
482     },
483     {
484         "give",
485         "Give kcb from one core to another.",
486         "give <from kcb_id> <to kcb_id>",
487         give_kcb,
488         3
489     },
490     {
491         "rmkcb",
492         "Remove a running KCB from a core.",
493         "rm <kcb_id>",
494         remove_kcb,
495         2
496     },
497     {
498         "park",
499         "Stop execution on an existing core and park KCB on another core.",
500         "park <kcb_id to stop> <recv kcb_id>",
501         park_kcb,
502         3
503     },
504     {
505         "unpark",
506         "Reestablish parked KCB on its original core.",
507         "unpark <kcb_id to unpark>",
508         unpark_kcb,
509         2
510     },
511     {
512         "lscpu",
513         "List current status of all cores.",
514         "lscpu",
515         list_cpu,
516         1
517     },
518     {
519         "lskcb",
520         "List current KCBs.",
521         "lskcb",
522         list_kcb,
523         1
524     },
525     {NULL, NULL, NULL, NULL, 0},
526 };
527
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'},
536     {0, 0, 0, 0}
537 };
538
539 static void print_help(char* argv0)
540 {
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");
555     printf("\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);
559     }
560 }
561
562 static void print_cmd_help(char* cmd)
563 {
564     size_t i = 0;
565     for (; commands[i].name != NULL; i++) {
566         if (strcmp(cmd, commands[i].name) == 0) {
567             break;
568         }
569     }
570
571     printf("%s - %s\n", commands[i].name, commands[i].desc);
572     printf("%s\n", commands[i].help);
573 }
574
575 int main (int argc, char **argv)
576 {
577     errval_t err;
578
579     initialize();
580     int ret = -1;
581
582     DEBUG("corectrl start\n");
583
584 #if defined(__x86__) && !defined(__k1om__)
585     // ENSURE_SEQUENTIAL
586     char *lock;
587     err = oct_lock("corectrl.lock", &lock);
588     if (err_is_fail(err)) {
589         USER_PANIC_ERR(err, "can lock corectrl.");
590     }
591     //
592 #endif
593
594     for (int i=0; i<argc; i++) {
595         DEBUG("%s:%s:%d: argv[%d] = %s\n",
596                __FILE__, __FUNCTION__, __LINE__, i, argv[i]);
597     }
598
599
600     DEBUG("corectrl got lock\n");
601     // Parse arguments, call handler function
602     int c;
603     while (1) {
604         /* getopt_long stores the option index here. */
605         int option_index = 0;
606
607         c = getopt_long (argc, argv, "k:a:x:hnmd",
608                          long_options, &option_index);
609         if (c == -1) {
610             break; // End of the options
611         }
612
613         switch (c) {
614         case 0:
615             // Long options handled by their short handles
616             break;
617
618         case 'k':
619             cmd_kernel_binary = optarg;
620             break;
621
622         case 'a':
623             cmd_kernel_args = optarg;
624             break;
625
626         case 'x':
627             cmd_monitor_binary = optarg;
628             break;
629
630         case 'm':
631             nomsg_flag = true;
632             break;
633
634         case 'n':
635             new_kcb_flag = true;
636             break;
637
638         case 'd':
639             debug_flag = true;
640             break;
641
642         case '?':
643         case 'h':
644             print_help(argv[0]);
645             goto out;
646             break;
647         default:
648             abort();
649             break;
650         }
651     }
652
653     if (optind < argc) {
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);
659                         goto out;
660                     }
661                     else {
662                         ret = commands[i].fn(argc-optind, argv+optind);
663                         break;
664                     }
665                 }
666             }
667         }
668     }
669
670     if (ret == -1) {
671         print_help(argv[0]);
672     }
673     else if (!nomsg_flag) {
674         DEBUG("%s:%s:%d: Wait for message.\n",
675               __FILE__, __FUNCTION__, __LINE__);
676         while(!done) {
677             err = event_dispatch(get_default_waitset());
678             if (err_is_fail(err)) {
679                 USER_PANIC_ERR(err, "error in event_dispatch");
680             }
681         }
682     }
683
684 out:
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.");
690     }
691     //
692 #endif
693
694     DEBUG("corectrl is done.");
695     return ret;
696 }