drm/linux: Add dma_map_sg and dma_unmap_sg()
[dragonfly.git] / sys / boot / dloader / cmds.c
blob16ea658001d4060a9d962d6b3e3bc5ee36a3e824
1 /*
2 * Copyright (c) 2010 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
35 #include <stand.h>
36 #include <string.h>
37 #include "bootstrap.h"
38 #include "dloader.h"
40 static void menu_display(void);
41 static int menu_execute(int);
44 * This is called from common and must reference files to bring
45 * library modules into common during linking.
47 void
48 dloader_init_cmds(void)
53 * "local" intercepts assignments: lines of the form 'a=b'
55 COMMAND_SET(local, "local", "List local variables", command_local);
56 COMMAND_SET(lunset, "lunset", "Unset local variable", command_lunset);
57 COMMAND_SET(lunsetif, "lunsetif", "Unset local variable if kenv variable is true", command_lunsetif);
58 COMMAND_SET(loadall, "loadall", "Load kernel + modules", command_loadall);
59 COMMAND_SET(menuclear, "menuclear", "Clear all menus", command_menuclear);
60 COMMAND_SET(menuitem, "menuitem", "Add menu bullet", command_menuitem);
61 COMMAND_SET(menuadd, "menuadd", "Add script line for bullet", command_menuadd);
62 COMMAND_SET(menu, "menu", "Run menu system", command_menu);
64 static int curitem;
65 static int curadd;
67 static char *kenv_vars[] = {
68 "LINES",
69 "acpi_load",
70 "autoboot_delay",
71 "boot_askname",
72 "boot_cdrom",
73 "boot_ddb",
74 "boot_gdb",
75 "boot_serial",
76 "boot_single",
77 "boot_verbose",
78 "boot_vidcons",
79 "bootfile",
80 "console",
81 "currdev",
82 "default_kernel",
83 "dumpdev",
84 "ehci_load",
85 "interpret",
86 "init_chroot",
87 "init_path",
88 "kernel_options",
89 "kernelname",
90 "loaddev",
91 "module_path",
92 "num_ide_disks",
93 "prompt",
94 "rootdev",
95 "root_disk_unit",
96 "xhci_load",
97 NULL
101 * List or set local variable. Sniff assignment of kenv_vars[] and
102 * loader tunables (recognized by '.' in name).
104 * format for av[0]:
105 * - List: local
106 * - Set: var=val
108 static int
109 command_local(int ac, char **av)
111 char *name;
112 char *data;
113 dvar_t dvar;
114 int i;
115 int j;
118 * local command executed directly.
120 if (strcmp(av[0], "local") == 0) {
121 pager_open();
122 for (dvar = dvar_first(); dvar; dvar = dvar_next(dvar)) {
123 for (j = 1; j < ac; ++j) {
124 if (!strncmp(dvar->name, av[j], strlen(av[j])))
125 break;
127 if (ac > 1 && j == ac)
128 continue;
130 pager_output(dvar->name);
131 pager_output("=");
132 for (i = 0; i < dvar->count; ++i) {
133 if (i)
134 pager_output(",");
135 pager_output("\"");
136 pager_output(dvar->data[i]);
137 pager_output("\"");
139 pager_output("\n");
141 pager_close();
142 return(CMD_OK);
146 * local command intercept for 'var=val'
148 name = av[0];
149 data = strchr(name, '=');
150 if (data == NULL) {
151 sprintf(command_errbuf, "Bad variable syntax");
152 return (CMD_ERROR);
154 *data++ = 0;
156 if (*data)
157 dvar_set(name, &data, 1);
158 else
159 dvar_unset(name);
162 * Take care of loader tunables and several other variables,
163 * all of which have to mirror to kenv because libstand or
164 * other consumers may have hooks into them.
166 if (strchr(name, '.')) {
167 setenv(name, data, 1);
168 } else {
169 for (i = 0; kenv_vars[i] != NULL; i++) {
170 if (strcmp(name, kenv_vars[i]) == 0) {
171 setenv(name, data, 1);
172 return(CMD_OK);
176 return(CMD_OK);
180 * Unset local variables
182 static int
183 command_lunset(int ac, char **av)
185 int i;
187 for (i = 1; i < ac; ++i)
188 dvar_unset(av[i]);
189 return(0);
192 static int
193 command_lunsetif(int ac, char **av)
195 char *envdata;
197 if (ac != 3) {
198 sprintf(command_errbuf,
199 "syntax error use lunsetif lname envname");
200 return(CMD_ERROR);
202 envdata = getenv(av[2]);
203 if (strcmp(envdata, "yes") == 0 ||
204 strcmp(envdata, "YES") == 0 ||
205 strtol(envdata, NULL, 0)) {
206 dvar_unset(av[1]);
208 return (CMD_OK);
212 * Load the kernel + all modules specified with MODULE_load="YES"
214 static int
215 command_loadall(int ac, char **av)
217 char *argv[4];
218 char *mod_name;
219 char *mod_fname;
220 char *mod_type;
221 char *tmp_str;
222 dvar_t dvar, dvar2;
223 int len;
224 int argc;
225 int res;
226 int tmp;
228 argv[0] = "unload";
229 (void)perform(1, argv);
232 * Load kernel
234 argv[0] = "load";
235 argv[1] = getenv("kernelname");
236 argv[2] = getenv("kernel_options");
237 if (argv[1] == NULL)
238 argv[1] = strdup("kernel");
239 res = perform((argv[2] == NULL)?2:3, argv);
240 free(argv[1]);
241 if (argv[2])
242 free(argv[2]);
244 if (res != CMD_OK) {
245 printf("Unable to load %s%s\n", DirBase, argv[1]);
246 return(res);
250 * Load modules
252 for (dvar = dvar_first(); dvar; dvar = dvar_next(dvar)) {
253 len = strlen(dvar->name);
254 if (len <= 5 || strcmp(dvar->name + len - 5, "_load"))
255 continue;
256 if (strcmp(dvar->data[0], "yes") != 0 &&
257 strcmp(dvar->data[0], "YES") != 0) {
258 continue;
261 mod_name = strdup(dvar->name);
262 mod_name[len - 5] = 0;
263 mod_type = NULL;
264 mod_fname = NULL;
266 /* Check if there's a matching foo_type */
267 for (dvar2 = dvar_first();
268 dvar2 && (mod_type == NULL);
269 dvar2 = dvar_next(dvar2)) {
270 len = strlen(dvar2->name);
271 if (len <= 5 || strcmp(dvar2->name + len - 5, "_type"))
272 continue;
273 tmp_str = strdup(dvar2->name);
274 tmp_str[len - 5] = 0;
275 if (strcmp(tmp_str, mod_name) == 0)
276 mod_type = dvar2->data[0];
278 free(tmp_str);
281 /* Check if there's a matching foo_name */
282 for (dvar2 = dvar_first();
283 dvar2 && (mod_fname == NULL);
284 dvar2 = dvar_next(dvar2)) {
285 len = strlen(dvar2->name);
286 if (len <= 5 || strcmp(dvar2->name + len - 5, "_name"))
287 continue;
288 tmp_str = strdup(dvar2->name);
289 tmp_str[len - 5] = 0;
290 if (strcmp(tmp_str, mod_name) == 0) {
291 mod_fname = dvar2->data[0];
292 free(mod_name);
293 mod_name = strdup(mod_fname);
296 free(tmp_str);
299 argv[0] = "load";
300 if (mod_type) {
301 argc = 4;
302 argv[1] = "-t";
303 argv[2] = mod_type;
304 argv[3] = mod_name;
305 } else {
306 argc = 2;
307 argv[1] = mod_name;
309 tmp = perform(argc, argv);
310 if (tmp != CMD_OK) {
311 time_t t = time(NULL);
312 printf("Unable to load %s%s\n", DirBase, mod_name);
313 while (time(NULL) == t)
315 /* don't kill the boot sequence */
316 /* res = tmp; */
318 free(mod_name);
320 return(res);
324 * Clear all menus
326 static int
327 command_menuclear(int ac, char **av)
329 dvar_unset("menu_*");
330 dvar_unset("item_*");
331 curitem = 0;
332 curadd = 0;
333 return(0);
337 * Add menu bullet
339 static int
340 command_menuitem(int ac, char **av)
342 char namebuf[32];
344 if (ac != 3) {
345 sprintf(command_errbuf, "Bad menuitem syntax");
346 return (CMD_ERROR);
348 curitem = (unsigned char)av[1][0];
349 if (curitem == 0) {
350 sprintf(command_errbuf, "Bad menuitem syntax");
351 return (CMD_ERROR);
353 snprintf(namebuf, sizeof(namebuf), "menu_%c", curitem);
354 dvar_set(namebuf, &av[2], 1);
355 curadd = 0;
357 return(CMD_OK);
361 * Add execution item
363 static int
364 command_menuadd(int ac, char **av)
366 char namebuf[32];
368 if (ac == 1)
369 return(CMD_OK);
370 if (curitem == 0) {
371 sprintf(command_errbuf, "Missing menuitem for menuadd");
372 return(CMD_ERROR);
374 snprintf(namebuf, sizeof(namebuf), "item_%c_%d", curitem, curadd);
375 dvar_set(namebuf, &av[1], ac - 1);
376 ++curadd;
377 return (CMD_OK);
381 * Execute menu system
383 static int
384 command_menu(int ac, char **av)
386 int timeout = -1;
387 time_t time_target;
388 time_t time_last;
389 time_t t;
390 char *cp;
391 int c;
392 int res;
393 int counting = 1;
395 menu_display();
396 if ((cp = getenv("autoboot_delay")) != NULL)
397 timeout = strtol(cp, NULL, 0);
398 if (timeout <= 0)
399 timeout = 10;
400 if (timeout > 24 * 60 * 60)
401 timeout = 24 * 60 * 60;
403 time_target = time(NULL) + timeout;
404 time_last = 0;
405 c = '1';
406 for (;;) {
407 if (ischar()) {
408 c = getchar();
409 if (c == '\r' || c == '\n') {
410 c = '1';
411 break;
413 if (c == ' ') {
414 if (counting) {
415 printf("\rCountdown halted by "
416 "space ");
418 counting = 0;
419 continue;
421 if (c == 0x1b) {
422 setenv("autoboot_delay", "NO", 1);
423 return(CMD_OK);
425 res = menu_execute(c);
426 if (res >= 0) {
427 setenv("autoboot_delay", "NO", 1);
428 return(CMD_OK);
430 /* else ignore char */
432 if (counting) {
433 t = time(NULL);
434 if (time_last == t)
435 continue;
436 time_last = t;
437 printf("\rBooting in %d second%s... ",
438 (int)(time_target - t),
439 ((time_target - t) == 1 ? "" : "s"));
440 if ((int)(time_target - t) <= 0) {
441 c = '1';
442 break;
446 res = menu_execute(c);
447 if (res != CMD_OK)
448 setenv("autoboot_delay", "NO", 1);
449 return (res);
452 #define LOGO_LINES 16
453 #define FRED_LEFT 0
454 #define FRED_RIGHT 1
455 static char *logo_blank_line = " ";
457 static char *logo_color[LOGO_LINES] = {
458 "\e[31;1m ,--, ,--, \e[0m",
459 "\e[31;1m | `-, \e[33;1m_\e[31m:\e[33;1m_\e[31;1m ,-' | \e[0m",
460 "\e[31;1m `, `-, \e[33;1m(\e[31m/ \\\e[33;1m)\e[31;1m ,-' ,' \e[0m",
461 "\e[31;1m `-, `-,\e[31m/ \\\e[31;1m,-' ,-' \e[0m",
462 "\e[31;1m `------\e[31m{ }\e[31;1m------' \e[0m",
463 "\e[31;1m ,----------\e[31m{ }\e[31;1m----------, \e[0m",
464 "\e[31;1m | _,-\e[31m{ }\e[31;1m-,_ | \e[0m",
465 "\e[31;1m `-,__,-' \e[31m\\ /\e[31;1m `-,__,-' \e[0m",
466 "\e[31m | | \e[0m",
467 "\e[31m | | \e[0m",
468 "\e[31m | | \e[0m",
469 "\e[31m | | \e[0m",
470 "\e[31m | | \e[0m",
471 "\e[31m | | \e[0m",
472 "\e[31m `,' \e[0m",
473 " " };
475 static char *logo_indigo[LOGO_LINES] = {
476 "\e[36m ,--, ,--\e[36;1m, \e[0m",
477 "\e[36m | `-, \e[34;1m_\e[34m:\e[34;1m_\e[36m ,-' \e[36;1m| \e[0m",
478 "\e[36m `, `-, \e[34;1m(\e[34m/ \\\e[34;1m)\e[36m ,-' \e[36;1m,' \e[0m",
479 "\e[36m `-, `-,\e[34m/ \\\e[36m,-' \e[36;1m,-' \e[0m",
480 "\e[36m `------\e[34m{ }\e[36m------\e[36;1m' \e[0m",
481 "\e[36m ,----------\e[34m{ }\e[36m----------\e[36;1m, \e[0m",
482 "\e[36m | \e[36;1m_,-\e[34m{ }\e[36m-,_ \e[36;1m| \e[0m",
483 "\e[36m `-,__\e[36;1m,-' \e[34m\\ /\e[36m `-,__\e[36;1m,-' \e[0m",
484 "\e[34m | | \e[0m",
485 "\e[34m | | \e[0m",
486 "\e[34m | | \e[0m",
487 "\e[34m | | \e[0m",
488 "\e[34m | | \e[0m",
489 "\e[34m | | \e[0m",
490 "\e[34m `,' \e[0m",
491 " " };
493 static char *logo_mono[LOGO_LINES] = {
494 " ,--, ,--, ",
495 " | `-, _:_ ,-' | ",
496 " `, `-, (/ \\) ,-' ,' ",
497 " `-, `-,/ \\,-' ,-' ",
498 " `------{ }------' ",
499 " ,----------{ }----------, ",
500 " | _,-{ }-,_ | ",
501 " `-,__,-' \\ / `-,__,-' ",
502 " | | ",
503 " | | ",
504 " | | ",
505 " | | ",
506 " | | ",
507 " | | ",
508 " `,' ",
509 " " };
511 static void
512 logo_display(char **logo, int line, int orientation, int barrier)
514 const char *fmt;
516 if (orientation == FRED_LEFT)
517 fmt = barrier ? "%s | " : " %s ";
518 else
519 fmt = barrier ? " | %s" : " %s ";
521 if (logo != NULL) {
522 if (line < LOGO_LINES)
523 printf(fmt, logo[line]);
524 else
525 printf(fmt, logo_blank_line);
529 static void
530 menu_display(void)
532 dvar_t dvar;
533 int i;
534 int logo_left = 0; /* default to fred on right */
535 int separated = 0; /* default blue fred without line */
536 char **logo = logo_indigo;
537 char *console_val = getenv("console");
539 if (dvar_istrue(dvar_get("fred_is_red")))
540 logo = logo_color;
542 if (dvar_istrue(dvar_get("loader_plain")))
543 logo = logo_mono;
545 if (strcmp(console_val, "comconsole") == 0)
546 logo = logo_mono;
548 if (dvar_istrue(dvar_get("fred_disable")))
549 logo = NULL;
551 if (dvar_istrue(dvar_get("fred_on_left")))
552 logo_left = 1;
554 if (dvar_istrue(dvar_get("fred_separated")))
555 separated = 1;
557 dvar = dvar_first();
558 i = 0;
560 if (logo != NULL) {
561 if (logo_left)
562 printf(separated ? "%35s|%43s\n" : "%35s %43s\n",
563 " ", " ");
564 else
565 printf(separated ? "%43s|%35s\n" : "%43s %35s\n",
566 " ", " ");
569 while (dvar || i < LOGO_LINES) {
570 if (logo_left)
571 logo_display(logo, i, FRED_LEFT, separated);
573 while (dvar) {
574 if (strncmp(dvar->name, "menu_", 5) == 0) {
575 printf(" %c. %-38.38s",
576 dvar->name[5], dvar->data[0]);
577 dvar = dvar_next(dvar);
578 break;
580 dvar = dvar_next(dvar);
583 * Pad when the number of menu entries is less than
584 * LOGO_LINES.
586 if (dvar == NULL)
587 printf(" %38.38s", " ");
589 if (!logo_left)
590 logo_display(logo, i, FRED_RIGHT, separated);
591 printf("\n");
592 i++;
596 static int
597 menu_execute(int c)
599 dvar_t dvar;
600 dvar_t dvar_exec = NULL;
601 dvar_t *dvar_execp = &dvar_exec;
602 char namebuf[32];
603 int res;
605 snprintf(namebuf, sizeof(namebuf), "item_%c_0", c);
608 * Does this menu option exist?
610 if (dvar_get(namebuf) == NULL)
611 return(-1);
613 snprintf(namebuf, sizeof(namebuf), "item_%c", c);
614 res = CMD_OK;
615 printf("\n");
618 * Copy the items to execute (the act of execution may modify our
619 * local variables so we need to copy).
621 for (dvar = dvar_first(); dvar; dvar = dvar_next(dvar)) {
622 if (strncmp(dvar->name, namebuf, 6) == 0) {
623 *dvar_execp = dvar_copy(dvar);
624 dvar_execp = &(*dvar_execp)->next;
629 * Execute items
631 for (dvar = dvar_exec; dvar; dvar = dvar->next) {
632 res = perform(dvar->count, dvar->data);
633 if (res != CMD_OK) {
634 printf("%s: %s\n",
635 dvar->data[0], command_errmsg);
636 setenv("autoboot_delay", "NO", 1);
637 break;
642 * Free items
644 while (dvar_exec)
645 dvar_free(&dvar_exec);
647 return(res);