diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2013-09-27 16:35:46 +0200 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2013-10-14 14:04:20 +0200 |
commit | ef5dac9c2bf7ac7ceb3027d75dadb5c52e633572 (patch) | |
tree | feb68df17a7b53f794a0caf76b7836fdc26ded93 /commands | |
parent | 1369bfd44f2393893036ee50f81e0104f7fb6416 (diff) | |
download | barebox-ef5dac9c2bf7ac7ceb3027d75dadb5c52e633572.tar.gz barebox-ef5dac9c2bf7ac7ceb3027d75dadb5c52e633572.tar.xz |
Implement bootloader spec support for barebox
The Bootloader Specification describes a way how kernels can
be installed on devices and how they can be started by the bootloader.
The bootloader spec is currently supported by (x86) gummiboot and
by systemd which provides a kernel-install script. With the bootloader
spec it's possible for the Operating system to install a new kernel
without knowing about the bootloader and for the bootloader it's possible
to discover and start Operating Systems on a media without being
configured.
For more details about the spec see:
http://www.freedesktop.org/wiki/Specifications/BootLoaderSpec/
This patch adds barebox support for the spec. It enhances the 'boot'
command so that not only boot script names can be given, but also
devices containing bootloader spec entries. With this it's possible
to call the 'boot' command like: 'boot sd emmc net'. It would then
first look for bootloader spec entries on the (removable) sd card,
then, is nothing is found, on the internal emmc and if still
unsuccessful would call the 'net' bootscript.
The bootloader Spec currently doesn't specify which entry should be
default if multiple entries are found on a single device. Therefore
barebox currently has two extensions of the spec. The $BOOT diretory
can contain a file named 'default'. If present, the content of the
file is treated as a filename under $BOOT/loader/entries/ which is
used as default. Similarly if a file named 'once' is present, the
entry is started once and the file is removed afterwards. This is
useful for testing if a newly installed kernel works before making
it the default.
As on ARM and other Architectures a devicetree has to be specified
for the kernel, the 'devicetree' property is used to specify a
devicetree. Like 'kernel' and 'initrd' this also contains a pth
relative to $BOOT.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'commands')
-rw-r--r-- | commands/boot.c | 168 |
1 files changed, 145 insertions, 23 deletions
diff --git a/commands/boot.c b/commands/boot.c index 33d1177861..78508056e6 100644 --- a/commands/boot.c +++ b/commands/boot.c @@ -15,51 +15,155 @@ #include <globalvar.h> #include <magicvar.h> #include <command.h> +#include <readkey.h> #include <common.h> #include <getopt.h> +#include <blspec.h> #include <libgen.h> #include <malloc.h> #include <boot.h> +#include <menu.h> #include <fs.h> +#include <complete.h> #include <linux/stat.h> +static int boot_script(char *path); + static int verbose; static int dryrun; -static void bootsources_list(void) +static void bootsource_action(struct menu *m, struct menu_entry *me) +{ + struct blspec_entry *be = container_of(me, struct blspec_entry, me); + int ret; + + if (be->scriptpath) { + ret = boot_script(be->scriptpath); + } else { + if (IS_ENABLED(CONFIG_BLSPEC)) + ret = blspec_boot(be, 0, 0); + else + ret = -ENOSYS; + } + + if (ret) + printf("Booting failed with: %s\n", strerror(-ret)); + + printf("Press any key to continue\n"); + + read_key(); +} + +static int bootsources_menu_env_entries(struct blspec *blspec) { + const char *path = "/env/boot", *title; DIR *dir; struct dirent *d; - const char *path = "/env/boot"; + struct blspec_entry *be; + char *cmd; dir = opendir(path); - if (!dir) { - printf("cannot open %s: %s\n", path, strerror(-errno)); - return; - } - - printf("Bootsources: "); + if (!dir) + return -errno; while ((d = readdir(dir))) { + if (*d->d_name == '.') continue; - printf("%s ", d->d_name); - } + be = blspec_entry_alloc(blspec); + be->me.type = MENU_ENTRY_NORMAL; + be->scriptpath = asprintf("/env/boot/%s", d->d_name); + + cmd = asprintf(". %s menu", be->scriptpath); + setenv("title", ""); + run_command(cmd, 0); + free(cmd); + title = getenv("title"); - printf("\n"); + if (title) + be->me.display = xstrdup(title); + else + be->me.display = xstrdup(d->d_name); + } closedir(dir); + + return 0; } -static const char *getenv_or_null(const char *var) +static struct blspec *bootentries_collect(void) { - const char *val = getenv(var); + struct blspec *blspec; + + blspec = blspec_alloc(); + blspec->menu->display = asprintf("boot"); + bootsources_menu_env_entries(blspec); + if (IS_ENABLED(CONFIG_BLSPEC)) + blspec_scan_devices(blspec); + return blspec; +} - if (val && *val) - return val; - return NULL; +static void bootsources_menu(void) +{ + struct blspec *blspec = NULL; + struct blspec_entry *entry; + struct menu_entry *back_entry; + + if (!IS_ENABLED(CONFIG_MENU)) { + printf("no menu support available\n"); + return; + } + + blspec = bootentries_collect(); + + blspec_for_each_entry(blspec, entry) { + entry->me.action = bootsource_action; + menu_add_entry(blspec->menu, &entry->me); + } + + back_entry = xzalloc(sizeof(*back_entry)); + back_entry->display = "back"; + back_entry->type = MENU_ENTRY_NORMAL; + back_entry->non_re_ent = 1; + menu_add_entry(blspec->menu, back_entry); + + menu_show(blspec->menu); + + free(back_entry); + + blspec_free(blspec); +} + +static void bootsources_list(void) +{ + struct blspec *blspec; + struct blspec_entry *entry; + + blspec = bootentries_collect(); + + printf("\nBootscripts:\n\n"); + printf("%-40s %-20s\n", "name", "title"); + printf("%-40s %-20s\n", "----", "-----"); + + blspec_for_each_entry(blspec, entry) { + if (entry->scriptpath) + printf("%-40s %s\n", basename(entry->scriptpath), entry->me.display); + } + + if (!IS_ENABLED(CONFIG_BLSPEC)) + return; + + printf("\nBootloader spec entries:\n\n"); + printf("%-20s %-20s %s\n", "device", "hwdevice", "title"); + printf("%-20s %-20s %s\n", "------", "--------", "-----"); + + blspec_for_each_entry(blspec, entry) + if (!entry->scriptpath) + printf("%s\n", entry->me.display); + + blspec_free(blspec); } /* @@ -67,8 +171,11 @@ static const char *getenv_or_null(const char *var) */ static int boot_script(char *path) { - struct bootm_data data = {}; int ret; + struct bootm_data data = { + .os_address = UIMAGE_SOME_ADDRESS, + .initrd_address = UIMAGE_SOME_ADDRESS, + }; printf("booting %s...\n", basename(path)); @@ -83,11 +190,11 @@ static int boot_script(char *path) data.initrd_address = UIMAGE_INVALID_ADDRESS; data.os_address = UIMAGE_SOME_ADDRESS; - data.oftree_file = getenv_or_null("global.bootm.oftree"); - data.os_file = getenv_or_null("global.bootm.image"); + data.oftree_file = getenv_nonempty("global.bootm.oftree"); + data.os_file = getenv_nonempty("global.bootm.image"); getenv_ul("global.bootm.image.loadaddr", &data.os_address); getenv_ul("global.bootm.initrd.loadaddr", &data.initrd_address); - data.initrd_file = getenv_or_null("global.bootm.initrd"); + data.initrd_file = getenv_nonempty("global.bootm.initrd"); data.verbose = verbose; data.dryrun = dryrun; @@ -118,7 +225,13 @@ static int boot(const char *name) ret = stat(path, &s); if (ret) { - pr_err("%s: %s\n", path, strerror(-ret)); + if (!IS_ENABLED(CONFIG_BLSPEC)) { + pr_err("%s: %s\n", path, strerror(-ret)); + goto out; + } + + ret = blspec_boot_hwdevice(name, verbose, dryrun); + pr_err("%s: %s\n", name, strerror(-ret)); goto out; } @@ -173,12 +286,12 @@ static int do_boot(int argc, char *argv[]) { const char *sources = NULL; char *source, *freep; - int opt, ret = 0, do_list = 0; + int opt, ret = 0, do_list = 0, do_menu = 0; verbose = 0; dryrun = 0; - while ((opt = getopt(argc, argv, "vld")) > 0) { + while ((opt = getopt(argc, argv, "vldm")) > 0) { switch (opt) { case 'v': verbose++; @@ -189,6 +302,9 @@ static int do_boot(int argc, char *argv[]) case 'd': dryrun = 1; break; + case 'm': + do_menu = 1; + break; } } @@ -197,6 +313,11 @@ static int do_boot(int argc, char *argv[]) return 0; } + if (do_menu) { + bootsources_menu(); + return 0; + } + if (optind < argc) { while (optind < argc) { source = argv[optind]; @@ -247,6 +368,7 @@ BAREBOX_CMD_HELP_SHORT("\nOptions:\n") BAREBOX_CMD_HELP_OPT ("-v","Increase verbosity\n") BAREBOX_CMD_HELP_OPT ("-d","Dryrun. See what happens but do no actually boot\n") BAREBOX_CMD_HELP_OPT ("-l","List available boot sources\n") +BAREBOX_CMD_HELP_OPT ("-m","Show a menu with boot options\n") BAREBOX_CMD_HELP_END BAREBOX_CMD_START(boot) |