Adjustments of IPC to match new convention (static buffers).
[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
17 coreid_t my_arch_id;
18 struct capref ipi_cap;
19
20 coreid_t core_count = 0;
21 coreid_t core_max = 0;
22 bool done = false;
23
24 bool benchmark_flag = false;
25 bool debug_flag = false;
26 bool new_kcb_flag = false;
27 bool nomsg_flag = false;
28
29 struct bench_data *bench_data = NULL;
30
31 char* cmd_kernel_binary = NULL;
32 char* cmd_monitor_binary = NULL;
33 char* cmd_kernel_args = "loglevel=2 logmask=0";
34
35 #define APIC_INTER_HALT_VECTOR 248
36
37 static void load_arch_id(void)
38 {
39     struct monitor_blocking_rpc_client *mc = get_monitor_blocking_rpc_client();
40     errval_t err = mc->vtbl.get_arch_core_id(mc, (uintptr_t *)&my_arch_id);
41     if (err_is_fail(err)) {
42         USER_PANIC_ERR(err, "get_arch_core_id failed.");
43     }
44     DEBUG("%s:%d: my_arch_id is %"PRIuCOREID"\n", __FILE__, __LINE__, my_arch_id);
45 }
46
47 static void setup_monitor_messaging(void)
48 {
49     struct monitor_binding *st = get_monitor_binding();
50     st->rx_vtbl.boot_core_reply = boot_core_reply;
51 }
52
53 static void load_ipi_cap(void)
54 {
55     struct monitor_blocking_rpc_client *mc = get_monitor_blocking_rpc_client();
56     errval_t err = mc->vtbl.get_ipi_cap(mc, &ipi_cap);
57     if (err_is_fail(err)) {
58         USER_PANIC_ERR(err, "get_ipi_cap failed.");
59     }
60 }
61
62 static void initialize(void)
63 {
64     errval_t err;
65
66     vfs_init();
67     bench_init();
68
69 #if defined(__x86__) && !defined(__k1om__)
70     err = connect_to_acpi();
71     if (err_is_fail(err)) {
72         USER_PANIC_ERR(err, "connect to acpi failed.");
73     }
74 #endif
75
76     err = oct_init();
77     if (err_is_fail(err)) {
78         USER_PANIC_ERR(err, "Octopus initialization failed.");
79     }
80
81     setup_monitor_messaging();
82     load_arch_id();
83     load_ipi_cap();
84 }
85
86
87 typedef int(*cmd_fn)(int argc, char** argv);
88 struct cmd {
89     char* name;
90     char* desc;
91     char* help;
92     cmd_fn fn;
93     int argc;
94 };
95
96 static int parse_core_list(char *list, coreid_t *from, coreid_t *to, coreid_t *step)
97 {
98     assert(from && to && step);
99
100     int num, parsed_from,parsed_to,parsed_step;
101     num = sscanf(list, "%i:%i:%i", &parsed_from, &parsed_to, &parsed_step);
102     switch(num) {
103         case 1:
104             *from = (coreid_t)parsed_from;
105             *to = (coreid_t)parsed_from;
106             *step = 1;
107             break;
108         case 2:
109             *from = (coreid_t)parsed_from;
110             *to = (coreid_t)parsed_to;
111             *step = 1;
112             break;
113         case 3:
114             *from = (coreid_t)parsed_from;
115             *to = (coreid_t)parsed_to;
116             *step = (coreid_t)parsed_step;
117             break;
118         default:
119             return 0;
120             break;
121     }
122     return num;
123 }
124
125 static int list_kcb(int argc, char **argv) {
126     char** names;
127     size_t len;
128     errval_t err = oct_get_names(&names, &len, "r'kcb\\.[0-9]+'");
129     assert(err_is_ok(err));
130
131     for (size_t i=0; i<len; i++) {
132         char* record;
133         err = oct_get(&record, names[i]);
134         assert(err_is_ok(err));
135
136         uint64_t barrelfish_id, kcb_id;
137         char* cap_key;
138         err = oct_read(record, "_ { kcb_id: %d, barrelfish_id: %d, cap_key: %s }",
139                        &barrelfish_id, &kcb_id, &cap_key);
140         assert(err_is_ok(err));
141
142         printf("KCB %"PRIu64": CORE_ID=%"PRIu64" CAP_STORAGE_KEY=%s\n",
143                kcb_id, barrelfish_id, cap_key);
144
145         free(cap_key);
146     }
147     if (len == 0) {
148         DEBUG("%s:%s:%d: No KCB found?\n",
149               __FILE__, __FUNCTION__, __LINE__);
150     }
151
152     done = true;
153     oct_free_names(names, len);
154     return 0;
155 }
156
157 static int list_cpu(int argc, char **argv) {
158     char** names;
159     size_t len;
160     errval_t err = oct_get_names(&names, &len, "r'hw\\.processor\\.[0-9]+'");
161     assert(err_is_ok(err));
162
163     for (size_t i=0; i<len; i++) {
164         char* record;
165         err = oct_get(&record, names[i]);
166         assert(err_is_ok(err));
167
168         uint64_t barrelfish_id, apic_id, processor_id, enabled;
169         err = oct_read(record, "_ { barrelfish_id: %d, apic_id: %d, processor_id: %d, enabled: %d }",
170                        &barrelfish_id, &apic_id, &processor_id, &enabled);
171         assert(err_is_ok(err));
172
173         printf("CPU %"PRIu64": APIC_ID=%"PRIu64" APIC_PROCESSOR_ID=%"PRIu64" ENABLED=%"PRIu64"\n",
174                barrelfish_id, apic_id, processor_id, enabled);
175     }
176     if (len == 0) {
177         DEBUG("%s:%s:%d: No cpus found?\n",
178               __FILE__, __FUNCTION__, __LINE__);
179     }
180
181     done = true;
182     oct_free_names(names, len);
183     return 0;
184 }
185
186 static int boot_cpu(int argc, char **argv)
187 {
188     coreid_t core_from = 0, core_to = 0, core_step = 0;
189     int parsed = parse_core_list(argv[1], &core_from, &core_to, &core_step);
190
191     if (parsed == 0) {
192         USER_PANIC("invalid CPU ID: %s", argv[1]);
193     }
194
195     core_count = 0;
196     if (core_step == 1) {
197         core_max = (core_to - core_from + 1);
198     } else {
199         core_max = (core_to - core_from + core_step) / core_step;
200     }
201
202     for (coreid_t target_id = core_from; target_id<=core_to; target_id += core_step) {
203         assert(target_id < MAX_COREID);
204
205         archid_t target_apic_id;
206         enum cpu_type cpu_type;
207         errval_t err = get_core_info(target_id, &target_apic_id, &cpu_type);
208         if (err_is_fail(err)) {
209             USER_PANIC_ERR(err, "get_apic_id failed.");
210         }
211
212         struct capref kcb;
213         err = create_or_get_kcb_cap(target_id, &kcb);
214         if (err_is_fail(err)) {
215             USER_PANIC_ERR(err, "Can not get KCB.");
216         }
217
218         struct capref frame;
219         size_t framesize;
220         struct frame_identity urpc_frame_id;
221         err = frame_alloc_identify(&frame, MON_URPC_SIZE, &framesize, &urpc_frame_id);
222         if (err_is_fail(err)) {
223             USER_PANIC_ERR(err, "frame_alloc_identify failed.");
224         }
225
226         err = cap_mark_remote(frame);
227         if (err_is_fail(err)) {
228             USER_PANIC_ERR(err, "Can not mark cap remote.");
229         }
230
231         struct monitor_binding *mb = get_monitor_binding();
232         err = mb->tx_vtbl.boot_core_request(mb, NOP_CONT, target_id, frame);
233         if (err_is_fail(err)) {
234             USER_PANIC_ERR(err, "boot_core_request failed");
235         }
236
237         err = spawn_xcore_monitor(target_id, target_apic_id,
238                                   cpu_type, cmd_kernel_args,
239                                   urpc_frame_id, kcb);
240         if (err_is_fail(err)) {
241             USER_PANIC_ERR(err, "spawn xcore monitor failed.");
242         }
243
244     }
245     return 0;
246 }
247
248
249 static int update_cpu(int argc, char** argv)
250 {
251     coreid_t target_id = (coreid_t) strtol(argv[1], NULL, 0);
252     assert(target_id < MAX_COREID);
253
254     archid_t target_apic_id;
255     enum cpu_type cpu_type;
256     errval_t err = get_core_info(target_id, &target_apic_id, &cpu_type);
257     if (err_is_fail(err)) {
258         USER_PANIC_ERR(err, "get_apic_id failed.");
259     }
260
261     struct capref kcb;
262     err = create_or_get_kcb_cap(target_id, &kcb);
263     if (err_is_fail(err)) {
264         USER_PANIC_ERR(err, "Can not get KCB.");
265     }
266
267     struct capref frame;
268     size_t framesize;
269     struct frame_identity urpc_frame_id;
270     err = frame_alloc_identify(&frame, MON_URPC_SIZE, &framesize, &urpc_frame_id);
271     if (err_is_fail(err)) {
272         USER_PANIC_ERR(err, "frame_alloc_identify  failed.");
273     }
274     err = cap_mark_remote(frame);
275     if (err_is_fail(err)) {
276         DEBUG_ERR(err, "Can not mark cap remote.");
277         return err;
278     }
279
280     // do clean shutdown
281     err = sys_debug_send_ipi(target_apic_id, 0, APIC_INTER_HALT_VECTOR);
282     if (err_is_fail(err)) {
283         USER_PANIC_ERR(err, "debug_send_ipi to power it down failed.");
284     }
285
286     done = true;
287     err = spawn_xcore_monitor(target_id, target_apic_id, cpu_type,
288                               cmd_kernel_args,
289                               urpc_frame_id, kcb);
290     if (err_is_fail(err)) {
291         USER_PANIC_ERR(err, "spawn xcore monitor failed.");
292     }
293
294     //TODO(gz): while (*ap_dispatch != 1);
295     return 0;
296 }
297
298 static int stop_cpu(int argc, char** argv)
299 {
300     coreid_t target_id = (coreid_t) strtol(argv[1], NULL, 0);
301     assert(target_id < MAX_COREID);
302
303     archid_t target_apic_id;
304     enum cpu_type cpu_type;
305     errval_t err = get_core_info(target_id, &target_apic_id, &cpu_type);
306     if (err_is_fail(err)) {
307         USER_PANIC_ERR(err, "get_apic_id failed.");
308     }
309
310     err = sys_debug_send_ipi(target_apic_id, 0, APIC_INTER_HALT_VECTOR);
311     if (err_is_fail(err)) {
312         USER_PANIC_ERR(err, "debug_send_ipi to power it down failed.");
313     }
314     done = true;
315
316     // The next line is crucial for harness test to pass
317     printf("Core %"PRIuCOREID" stopped.\n", target_id);
318     return 0;
319 }
320
321 static int give_kcb(int argc, char** argv)
322 {
323     assert (argc == 3);
324     DEBUG("%s:%d: Give KCB from core %s to core %s...\n",
325           __FILE__, __LINE__, argv[1], argv[2]);
326
327     coreid_t target_id = (coreid_t) strtol(argv[1], NULL, 0);
328     assert(target_id < MAX_COREID);
329     struct capref kcb;
330     errval_t err = create_or_get_kcb_cap(target_id, &kcb);
331     if (err_is_fail(err)) {
332         USER_PANIC_ERR(err, "Can not get KCB.");
333     }
334
335     coreid_t destination_id = (coreid_t) strtol(argv[2], NULL, 0);
336     assert(destination_id < MAX_COREID);
337
338     /*err = sys_debug_send_ipi(target_id, 0, APIC_INTER_HALT_VECTOR);
339     if (err_is_fail(err)) {
340         USER_PANIC_ERR(err, "debug_send_ipi to power it down failed.");
341     }*/
342     done = true;
343
344     err = give_kcb_to_new_core(destination_id, kcb);
345     if (err_is_fail(err)) {
346         USER_PANIC_ERR(err, "Can not send KCB to another core.");
347     }
348
349     return 0;
350 }
351
352 static int remove_kcb(int argc, char** argv)
353 {
354     assert (argc == 2);
355     DEBUG("%s:%s:%d: Stopping kcb.%s\n", __FILE__,
356           __FUNCTION__, __LINE__, argv[1]);
357
358     coreid_t target_id = (coreid_t) strtol(argv[1], NULL, 0);
359     assert(target_id < MAX_COREID);
360     struct capref kcb;
361     errval_t err = create_or_get_kcb_cap(target_id, &kcb);
362     if (err_is_fail(err)) {
363         USER_PANIC_ERR(err, "Can not get KCB.");
364     }
365
366     struct monitor_blocking_rpc_client *mc = get_monitor_blocking_rpc_client();
367     // send message to monitor to be relocated -> don't switch kcb ->
368     // remove kcb from ring -> msg ->
369     // (disp_save_rm_kcb -> next/home/... kcb -> enable switching)
370     errval_t ret_err;
371     err = mc->vtbl.forward_kcb_rm_request(mc, target_id, kcb, &ret_err);
372     if (err_is_fail(err)) {
373         USER_PANIC_ERR(err, "forward_kcb_request failed.");
374     }
375     if (err_is_fail(ret_err)) {
376         USER_PANIC_ERR(ret_err, "forward_kcb_request failed.");
377     }
378     done = true;
379
380     //coreid_t destination_id = (coreid_t) strtol(argv[3], NULL, 0);
381     //assert(destination_id < MAX_COREID);
382     //
383     // Move KCB to a core that is currently running
384     //
385     /*
386     err = give_kcb_to_new_core(destination_id, kcb);
387     if (err_is_fail(err)) {
388         USER_PANIC_ERR(err, "Can not send KCB to another core.");
389     }
390     */
391
392     //
393     // Boot the removed KCB on a core that is currently not running
394     //
395     /*
396     struct capref frame;
397     size_t framesize;
398     struct frame_identity urpc_frame_id;
399     err = frame_alloc_identify(&frame, MON_URPC_SIZE, &framesize, &urpc_frame_id);
400     if (err_is_fail(err)) {
401         USER_PANIC_ERR(err, "frame_alloc_identify failed.");
402     }
403     err = cap_mark_remote(frame);
404     if (err_is_fail(err)) {
405         DEBUG_ERR(err, "Can not mark cap remote.");
406         return err;
407     }
408
409     struct monitor_binding *mb = get_monitor_binding();
410     err = mb->tx_vtbl.boot_core_request(mb, NOP_CONT, target_id, frame);
411     if (err_is_fail(err)) {
412         USER_PANIC_ERR(err, "boot_core_request failed");
413     }
414
415     err = spawn_xcore_monitor(target_id, target_id,
416                               CPU_X86_64,
417                               cmd_kernel_args,
418                               urpc_frame_id, kcb);
419     if (err_is_fail(err)) {
420         USER_PANIC_ERR(err, "spawn xcore monitor failed.");
421     }*/
422
423     return 0;
424 }
425
426 /*
427  * Do stop and then give in one call to corectrl
428  * args: <kcb_id to stop> <kcb_id to give to>
429  */
430 static int park_kcb(int argc, char *argv[])
431 {
432     int r;
433     assert (argc == 3);
434     printf("Stopping core %lu\n", strtol(argv[1], NULL, 0));
435     r = stop_cpu(2, argv);
436     if (r) { return r; }
437     printf("Parking KCB on core %lu\n", strtol(argv[2], NULL, 0));
438     return give_kcb(3, argv);
439 }
440
441 /*
442  * Do rm and boot -m in one call to corectrl
443  * args: <kcb_id to remove> <core_id to boot>
444  */
445 static int unpark_kcb(int argc, char *argv[])
446 {
447     int r;
448     assert (argc == 2);
449     coreid_t c = (coreid_t)strtol(argv[1], NULL, 0);
450     printf("Removing KCB %u from its core\n", c);
451     r = remove_kcb(2, argv);
452     if (r) { return r; }
453     // set nomsg_flag to emulate -m option for boot
454     nomsg_flag = true;
455     printf("Booting KCB %u on core %u\n", c,c);
456     return boot_cpu(2, argv);
457 }
458
459 static struct cmd commands[] = {
460     {
461         "boot",
462         "Boot a fresh core with a KCB.",
463         "boot <target core_id>",
464         boot_cpu,
465         2
466     },
467     {
468         "update",
469         "Update the kernel on an existing core.",
470         "update <target core_id>",
471         update_cpu,
472         2
473     },
474     {
475         "stop",
476         "Stop execution on an existing core.",
477         "stop <target core_id>",
478         stop_cpu,
479         2
480     },
481     {
482         "give",
483         "Give kcb from one core to another.",
484         "give <from kcb_id> <to kcb_id>",
485         give_kcb,
486         3
487     },
488     {
489         "rmkcb",
490         "Remove a running KCB from a core.",
491         "rm <kcb_id>",
492         remove_kcb,
493         2
494     },
495     {
496         "park",
497         "Stop execution on an existing core and park KCB on another core.",
498         "park <kcb_id to stop> <recv kcb_id>",
499         park_kcb,
500         3
501     },
502     {
503         "unpark",
504         "Reestablish parked KCB on its original core.",
505         "unpark <kcb_id to unpark>",
506         unpark_kcb,
507         2
508     },
509     {
510         "lscpu",
511         "List current status of all cores.",
512         "lscpu",
513         list_cpu,
514         1
515     },
516     {
517         "lskcb",
518         "List current KCBs.",
519         "lskcb",
520         list_kcb,
521         1
522     },
523     {NULL, NULL, NULL, NULL, 0},
524 };
525
526 static struct option long_options[] = {
527     {"debug",   no_argument,       0, 'd'},
528     {"kernel",  required_argument, 0, 'k'},
529     {"monitor", required_argument, 0, 'x'},
530     {"kargs",   required_argument, 0, 'a'},
531     {"newkcb",  no_argument,       0, 'n'},
532     {"nomsg",   no_argument,       0, 'm'},
533     {"help",    no_argument,       0, 'h'},
534     {0, 0, 0, 0}
535 };
536
537 static void print_help(char* argv0)
538 {
539     printf("Usage: %s [OPTIONS] <COMMAND> [<args>]\n", argv0);
540     printf("Options:\n");
541     printf("\t -d, --debug\n");
542     printf("\t\t Print debug information\n");
543     printf("\t -k, --kernel\n");
544     printf("\t\t Overwrite default kernel binary\n");
545     printf("\t -x, --monitor\n");
546     printf("\t\t Overwrite default monitor binary\n");
547     printf("\t -a, --kargs\n");
548     printf("\t\t Overwrite default kernel cmd arguments\n");
549     printf("\t -n, --newkcb\n");
550     printf("\t\t Create a new KCB even if there is already one for that core\n");
551     printf("\t -m, --nomsg\n");
552     printf("\t\t Don't wait for monitor message at the end\n");
553     printf("\n");
554     printf("Commands:\n");
555     for (size_t i = 0; commands[i].name != NULL; i++) {
556         printf("\t %s\t\t%s\n", commands[i].name, commands[i].desc);
557     }
558 }
559
560 static void print_cmd_help(char* cmd)
561 {
562     size_t i = 0;
563     for (; commands[i].name != NULL; i++) {
564         if (strcmp(cmd, commands[i].name) == 0) {
565             break;
566         }
567     }
568
569     printf("%s - %s\n", commands[i].name, commands[i].desc);
570     printf("%s\n", commands[i].help);
571 }
572
573 int main (int argc, char **argv)
574 {
575     errval_t err;
576
577     initialize();
578     int ret = -1;
579
580     DEBUG("corectrl start\n");
581
582 #if defined(__x86__) && !defined(__k1om__)
583     // ENSURE_SEQUENTIAL
584     char *lock;
585     err = oct_lock("corectrl.lock", &lock);
586     if (err_is_fail(err)) {
587         USER_PANIC_ERR(err, "can lock corectrl.");
588     }
589     //
590 #endif
591
592     for (int i=0; i<argc; i++) {
593         DEBUG("%s:%s:%d: argv[%d] = %s\n",
594                __FILE__, __FUNCTION__, __LINE__, i, argv[i]);
595     }
596
597
598     DEBUG("corectrl got lock\n");
599     // Parse arguments, call handler function
600     int c;
601     while (1) {
602         /* getopt_long stores the option index here. */
603         int option_index = 0;
604
605         c = getopt_long (argc, argv, "k:a:x:hnmd",
606                          long_options, &option_index);
607         if (c == -1) {
608             break; // End of the options
609         }
610
611         switch (c) {
612         case 0:
613             // Long options handled by their short handles
614             break;
615
616         case 'k':
617             cmd_kernel_binary = optarg;
618             break;
619
620         case 'a':
621             cmd_kernel_args = optarg;
622             break;
623
624         case 'x':
625             cmd_monitor_binary = optarg;
626             break;
627
628         case 'm':
629             nomsg_flag = true;
630             break;
631
632         case 'n':
633             new_kcb_flag = true;
634             break;
635
636         case 'd':
637             debug_flag = true;
638             break;
639
640         case '?':
641         case 'h':
642             print_help(argv[0]);
643             goto out;
644             break;
645         default:
646             abort();
647             break;
648         }
649     }
650
651     if (optind < argc) {
652         for (; optind < argc; optind++) {
653             for (size_t i = 0; commands[i].name != NULL; i++) {
654                 if (strcmp(argv[optind], commands[i].name) == 0) {
655                     if (argc - optind < commands[i].argc) {
656                         print_cmd_help(commands[i].name);
657                         goto out;
658                     }
659                     else {
660                         ret = commands[i].fn(argc-optind, argv+optind);
661                         break;
662                     }
663                 }
664             }
665         }
666     }
667
668     if (ret == -1) {
669         print_help(argv[0]);
670     }
671     else if (!nomsg_flag) {
672         DEBUG("%s:%s:%d: Wait for message.\n",
673               __FILE__, __FUNCTION__, __LINE__);
674         while(!done) {
675             err = event_dispatch(get_default_waitset());
676             if (err_is_fail(err)) {
677                 USER_PANIC_ERR(err, "error in event_dispatch");
678             }
679         }
680     }
681
682 out:
683 #if defined(__x86__) && !defined(__k1om__)
684     // END ENSURE SEQUENTIAL
685     err = oct_unlock(lock);
686     if (err_is_fail(err)) {
687         USER_PANIC_ERR(err, "can not unlock corectrl.");
688     }
689     //
690 #endif
691
692     DEBUG("corectrl is done.");
693     return ret;
694 }