From 2b6ae1af1d7b119ec691e51a318d89b1cc720879 Mon Sep 17 00:00:00 2001 From: jmcneill Date: Sun, 21 Jun 2020 23:53:26 +0000 Subject: [PATCH] Add boot.cfg support. --- sys/stand/efiboot/Makefile.efiboot | 6 +- sys/stand/efiboot/boot.c | 30 +++- sys/stand/efiboot/bootmenu.c | 215 +++++++++++++++++++++++++++++ sys/stand/efiboot/bootmenu.h | 38 +++++ sys/stand/efiboot/efiboot.c | 3 +- sys/stand/efiboot/version | 3 +- 6 files changed, 288 insertions(+), 7 deletions(-) create mode 100644 sys/stand/efiboot/bootmenu.c create mode 100644 sys/stand/efiboot/bootmenu.h diff --git a/sys/stand/efiboot/Makefile.efiboot b/sys/stand/efiboot/Makefile.efiboot index abe81b1da01a..05fc3c72b806 100644 --- a/sys/stand/efiboot/Makefile.efiboot +++ b/sys/stand/efiboot/Makefile.efiboot @@ -1,4 +1,4 @@ -# $NetBSD: Makefile.efiboot,v 1.14 2020/06/21 17:24:26 jmcneill Exp $ +# $NetBSD: Makefile.efiboot,v 1.15 2020/06/21 23:53:26 jmcneill Exp $ S= ${.CURDIR}/../../.. @@ -21,8 +21,8 @@ AFLAGS.start.S= ${${ACTIVE_CC} == "clang":?-no-integrated-as:} .PATH: ${EFIDIR}/gnuefi SOURCES= crt0-efi-${GNUEFIARCH}.S reloc_${GNUEFIARCH}.c -SOURCES+= boot.c conf.c console.c dev_net.c devopen.c exec.c module.c \ - panic.c prompt.c +SOURCES+= boot.c bootmenu.c conf.c console.c dev_net.c devopen.c exec.c \ + module.c panic.c prompt.c SOURCES+= efiboot.c efichar.c efidev.c efienv.c efigetsecs.c efifdt.c \ efifile.c efiblock.c efinet.c efipxe.c efiacpi.c efirng.c smbios.c diff --git a/sys/stand/efiboot/boot.c b/sys/stand/efiboot/boot.c index 2f70058b38b3..2e2f8402409d 100644 --- a/sys/stand/efiboot/boot.c +++ b/sys/stand/efiboot/boot.c @@ -1,4 +1,4 @@ -/* $NetBSD: boot.c,v 1.22 2020/06/21 17:24:26 jmcneill Exp $ */ +/* $NetBSD: boot.c,v 1.23 2020/06/21 23:53:26 jmcneill Exp $ */ /*- * Copyright (c) 2016 Kimihiro Nonaka @@ -34,12 +34,14 @@ #include "efienv.h" #include "efirng.h" #include "module.h" +#include "bootmenu.h" #include #include #include #include +#include extern const char bootprog_name[], bootprog_rev[], bootprog_kernrev[]; @@ -96,6 +98,7 @@ void command_load(char *); void command_unload(char *); void command_ls(char *); void command_mem(char *); +void command_menu(char *); void command_printenv(char *); void command_setenv(char *); void command_clearenv(char *); @@ -116,6 +119,7 @@ const struct boot_command commands[] = { { "unload", command_unload, "unload " }, { "ls", command_ls, "ls [hdNn:/path]" }, { "mem", command_mem, "mem" }, + { "menu", command_menu, "menu" }, { "printenv", command_printenv, "printenv [key]" }, { "setenv", command_setenv, "setenv " }, { "clearenv", command_clearenv, "clearenv " }, @@ -268,6 +272,17 @@ command_mem(char *arg) } } +void +command_menu(char *arg) +{ + if (bootcfg_info.nummenu == 0) { + printf("No menu defined in boot.cfg\n"); + return; + } + + doboottypemenu(); /* Does not return */ +} + void command_printenv(char *arg) { @@ -530,7 +545,20 @@ boot(void) int currname, c; read_env(); + + parsebootconf(BOOTCFG_FILENAME); + + if (bootcfg_info.clear) + uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut); + print_banner(); + + /* Display menu if configured */ + twiddle_toggle = 1; + if (bootcfg_info.nummenu > 0) { + doboottypemenu(); /* No return */ + } + printf("Press return to boot now, any other key for boot prompt\n"); if (netbsd_path[0] != '\0') diff --git a/sys/stand/efiboot/bootmenu.c b/sys/stand/efiboot/bootmenu.c new file mode 100644 index 000000000000..ff74248197bd --- /dev/null +++ b/sys/stand/efiboot/bootmenu.c @@ -0,0 +1,215 @@ +/* $NetBSD: bootmenu.c,v 1.1 2020/06/21 23:53:26 jmcneill Exp $ */ + +/*- + * Copyright (c) 2008 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SMALL + +#include +#include +#include + +#include +#include +#include +#include + +#include "bootmenu.h" +#include "efiboot.h" +#include "module.h" + +static void docommandchoice(int); + +extern const char bootprog_name[], bootprog_rev[], bootprog_kernrev[]; + +#define MENUFORMAT_AUTO 0 +#define MENUFORMAT_NUMBER 1 +#define MENUFORMAT_LETTER 2 + +/* + * XXX + * if module_add, userconf_add are strictly mi they can be folded back + * into sys/lib/libsa/bootcfg.c:perform_bootcfg(). + */ +static void +do_bootcfg_command(const char *cmd, char *arg) +{ + if (strcmp(cmd, BOOTCFG_CMD_LOAD) == 0) + module_add(arg); +#if notyet + else if (strcmp(cmd, BOOTCFG_CMD_USERCONF) == 0) + userconf_add(arg); +#endif +} + +int +parsebootconf(const char *conf) +{ + return perform_bootcfg(conf, &do_bootcfg_command, 32768); +} + +/* + * doboottypemenu will render the menu and parse any user input + */ +static int +getchoicefrominput(char *input, int def) +{ + int choice, usedef; + + choice = -1; + usedef = 0; + + if (*input == '\0' || *input == '\r' || *input == '\n') { + choice = def; + usedef = 1; + } else if (*input >= 'A' && *input < bootcfg_info.nummenu + 'A') + choice = (*input) - 'A'; + else if (*input >= 'a' && *input < bootcfg_info.nummenu + 'a') + choice = (*input) - 'a'; + else if (isdigit(*input)) { + choice = atoi(input) - 1; + if (choice < 0 || choice >= bootcfg_info.nummenu) + choice = -1; + } + + if (bootcfg_info.menuformat != MENUFORMAT_LETTER && + !isdigit(*input) && !usedef) + choice = -1; + + return choice; +} + +static void +docommandchoice(int choice) +{ + char input[80], *ic, *oc; + + ic = bootcfg_info.command[choice]; + /* Split command string at ; into separate commands */ + do { + oc = input; + /* Look for ; separator */ + for (; *ic && *ic != COMMAND_SEPARATOR; ic++) + *oc++ = *ic; + if (*input == '\0') + continue; + /* Strip out any trailing spaces */ + oc--; + for (; *oc == ' ' && oc > input; oc--); + *++oc = '\0'; + if (*ic == COMMAND_SEPARATOR) + ic++; + /* Stop silly command strings like ;;; */ + if (*input != '\0') + docommand(input); + /* Skip leading spaces */ + for (; *ic == ' '; ic++); + } while (*ic); +} + +void +bootdefault(void) +{ + int choice; + static int entered; + + if (bootcfg_info.nummenu > 0) { + if (entered) { + printf("default boot twice, skipping...\n"); + return; + } + entered = 1; + choice = bootcfg_info.def; + printf("command(s): %s\n", bootcfg_info.command[choice]); + docommandchoice(choice); + } +} + +__dead void +doboottypemenu(void) +{ + int choice; + char input[80]; + + printf("\n"); + /* Display menu */ + if (bootcfg_info.menuformat == MENUFORMAT_LETTER) { + for (choice = 0; choice < bootcfg_info.nummenu; choice++) + printf(" %c. %s\n", choice + 'A', + bootcfg_info.desc[choice]); + } else { + /* Can't use %2d format string with libsa */ + for (choice = 0; choice < bootcfg_info.nummenu; choice++) + printf(" %s%d. %s\n", + (choice < 9) ? " " : "", + choice + 1, + bootcfg_info.desc[choice]); + } + choice = -1; + for (;;) { + input[0] = '\0'; + + if (bootcfg_info.timeout < 0) { + if (bootcfg_info.menuformat == MENUFORMAT_LETTER) + printf("\nOption: [%c]:", + bootcfg_info.def + 'A'); + else + printf("\nOption: [%d]:", + bootcfg_info.def + 1); + + kgets(input, sizeof(input)); + choice = getchoicefrominput(input, bootcfg_info.def); + } else if (bootcfg_info.timeout == 0) + choice = bootcfg_info.def; + else { + printf("\nChoose an option; RETURN for default; " + "SPACE to stop countdown.\n"); + if (bootcfg_info.menuformat == MENUFORMAT_LETTER) + printf("Option %c will be chosen in ", + bootcfg_info.def + 'A'); + else + printf("Option %d will be chosen in ", + bootcfg_info.def + 1); + input[0] = awaitkey(bootcfg_info.timeout, 1); + input[1] = '\0'; + choice = getchoicefrominput(input, bootcfg_info.def); + /* If invalid key pressed, drop to menu */ + if (choice == -1) + bootcfg_info.timeout = -1; + } + if (choice < 0) + continue; + if (!strcmp(bootcfg_info.command[choice], "prompt")) { + printf("type \"?\" or \"help\" for help.\n"); + bootprompt(); /* does not return */ + } else { + docommandchoice(choice); + } + + } +} + +#endif /* !SMALL */ diff --git a/sys/stand/efiboot/bootmenu.h b/sys/stand/efiboot/bootmenu.h new file mode 100644 index 000000000000..97e8b043758d --- /dev/null +++ b/sys/stand/efiboot/bootmenu.h @@ -0,0 +1,38 @@ +/* $NetBSD: bootmenu.h,v 1.1 2020/06/21 23:53:26 jmcneill Exp $ */ + +/*- + * Copyright (c) 2008 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _BOOTMENU_H +#define _BOOTMENU_H + +#define COMMAND_SEPARATOR ';' + +int parsebootconf(const char *); +void doboottypemenu(void); +void bootdefault(void); + +#endif /* !_BOOTMENU_H */ diff --git a/sys/stand/efiboot/efiboot.c b/sys/stand/efiboot/efiboot.c index 31711a11431e..f4b552f8d5da 100644 --- a/sys/stand/efiboot/efiboot.c +++ b/sys/stand/efiboot/efiboot.c @@ -1,4 +1,4 @@ -/* $NetBSD: efiboot.c,v 1.18 2020/05/14 19:20:08 riastradh Exp $ */ +/* $NetBSD: efiboot.c,v 1.19 2020/06/21 23:53:26 jmcneill Exp $ */ /*- * Copyright (c) 2018 Jared McNeill @@ -72,7 +72,6 @@ efi_main(EFI_HANDLE imageHandle, EFI_SYSTEM_TABLE *systemTable) uefi_call_wrapper(ST->ConOut->Reset, 2, ST->ConOut, TRUE); uefi_call_wrapper(ST->ConOut->SetMode, 2, ST->ConOut, 0); uefi_call_wrapper(ST->ConOut->EnableCursor, 2, ST->ConOut, TRUE); - uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut); status = uefi_call_wrapper(BS->AllocatePages, 4, AllocateAnyPages, EfiLoaderData, sz, &heap_start); if (EFI_ERROR(status)) diff --git a/sys/stand/efiboot/version b/sys/stand/efiboot/version index c2c6cad5f0f4..cdf45415d648 100644 --- a/sys/stand/efiboot/version +++ b/sys/stand/efiboot/version @@ -1,4 +1,4 @@ -$NetBSD: version,v 1.16 2020/06/21 17:24:26 jmcneill Exp $ +$NetBSD: version,v 1.17 2020/06/21 23:53:26 jmcneill Exp $ NOTE ANY CHANGES YOU MAKE TO THE EFI BOOTLOADER HERE. The format of this file is important - make sure the entries are appended on end, last item @@ -20,3 +20,4 @@ is taken as the current. 1.13: Add rndseed support. 1.14: Add EFI RNG support. 1.15: Add module support. +2.0: Add boot.cfg support.