diff options
Diffstat (limited to 'common/bootm.c')
-rw-r--r-- | common/bootm.c | 265 |
1 files changed, 174 insertions, 91 deletions
diff --git a/common/bootm.c b/common/bootm.c index 2f02c156e5..c851ab0456 100644 --- a/common/bootm.c +++ b/common/bootm.c @@ -13,6 +13,7 @@ #include <linux/stat.h> #include <magicvar.h> #include <uncompress.h> +#include <zero_page.h> static LIST_HEAD(handler_list); @@ -43,6 +44,7 @@ static struct image_handler *bootm_find_handler(enum filetype filetype, static int bootm_appendroot; static int bootm_earlycon; static int bootm_provide_machine_id; +static int bootm_provide_hostname; static int bootm_verbosity; void bootm_data_init_defaults(struct bootm_data *data) @@ -60,6 +62,7 @@ void bootm_data_init_defaults(struct bootm_data *data) data->verify = bootm_get_verify_mode(); data->appendroot = bootm_appendroot; data->provide_machine_id = bootm_provide_machine_id; + data->provide_hostname = bootm_provide_hostname; data->verbose = bootm_verbosity; } @@ -70,6 +73,11 @@ enum bootm_verify bootm_get_verify_mode(void) return bootm_verify_mode; } +void bootm_set_verify_mode(enum bootm_verify mode) +{ + bootm_verify_mode = mode; +} + static const char * const bootm_verify_names[] = { #ifndef CONFIG_BOOTM_FORCE_SIGNED_IMAGES [BOOTM_VERIFY_NONE] = "none", @@ -79,6 +87,29 @@ static const char * const bootm_verify_names[] = { [BOOTM_VERIFY_SIGNATURE] = "signature", }; +static bool force_signed_images = IS_ENABLED(CONFIG_BOOTM_FORCE_SIGNED_IMAGES); + +void bootm_force_signed_images(void) +{ + static unsigned int verify_mode = 0; + + if (force_signed_images) + return; + + /* recreate bootm.verify with a single enumeration as option */ + globalvar_remove("bootm.verify"); + globalvar_add_simple_enum("bootm.verify", &verify_mode, + &bootm_verify_names[BOOTM_VERIFY_SIGNATURE], 1); + + bootm_verify_mode = BOOTM_VERIFY_SIGNATURE; + force_signed_images = true; +} + +bool bootm_signed_images_are_forced(void) +{ + return force_signed_images; +} + static int uimage_part_num(const char *partname) { if (!partname) @@ -119,7 +150,7 @@ int bootm_load_os(struct image_data *data, unsigned long load_address) (unsigned long long)load_address + kernel_size - 1); return -ENOMEM; } - memcpy((void *)load_address, kernel, kernel_size); + zero_page_memcpy((void *)load_address, kernel, kernel_size); return 0; } @@ -244,12 +275,10 @@ int bootm_load_initrd(struct image_data *data, unsigned long load_address) goto done1; } - type = file_name_detect_type(data->initrd_file); - - if ((int)type < 0) { - pr_err("could not open %s: %s\n", data->initrd_file, - strerror(-type)); - return (int)type; + ret = file_name_detect_type(data->initrd_file, &type); + if (ret) { + pr_err("could not open initrd \"%s\": %s\n", data->initrd_file, strerror(-ret)); + return ret; } if (type == filetype_uimage) { @@ -366,12 +395,11 @@ void *bootm_get_devicetree(struct image_data *data) } else if (data->oftree_file) { size_t size; - type = file_name_detect_type(data->oftree_file); - - if ((int)type < 0) { - pr_err("could not open %s: %s\n", data->oftree_file, - strerror(-type)); - return ERR_PTR((int)type); + ret = file_name_detect_type(data->oftree_file, &type); + if (ret) { + pr_err("could not open device tree \"%s\": %s\n", data->oftree_file, + strerror(-ret)); + return ERR_PTR(ret); } switch (type) { @@ -401,10 +429,13 @@ void *bootm_get_devicetree(struct image_data *data) } } else { - data->of_root_node = of_get_root_node(); - if (!data->of_root_node) + struct device_node *root = of_get_root_node(); + + if (!root) return NULL; + data->of_root_node = of_dup(root); + if (bootm_verbose(data) > 1 && data->of_root_node) printf("using internal devicetree\n"); } @@ -415,7 +446,9 @@ void *bootm_get_devicetree(struct image_data *data) of_add_reserve_entry(data->initrd_res->start, data->initrd_res->end); } - oftree = of_get_fixed_tree(data->of_root_node); + of_fix_tree(data->of_root_node); + + oftree = of_flatten_dtb(data->of_root_node); if (!oftree) return ERR_PTR(-EINVAL); @@ -460,8 +493,10 @@ int bootm_load_devicetree(struct image_data *data, void *fdt, memcpy((void *)data->oftree_res->start, fdt, fdt_size); of_print_cmdline(data->of_root_node); - if (bootm_verbose(data) > 1) + if (bootm_verbose(data) > 1) { of_print_nodes(data->of_root_node, 0, ~0); + fdt_print_reserve_map(fdt); + } return 0; } @@ -519,18 +554,84 @@ static int bootm_open_os_uimage(struct image_data *data) return 0; } +static int bootm_open_fit(struct image_data *data) +{ + struct fit_handle *fit; + struct fdt_header *header; + static const char *kernel_img = "kernel"; + size_t flen, hlen; + int ret; + + if (!IS_ENABLED(CONFIG_FITIMAGE)) + return 0; + + header = (struct fdt_header *)data->os_header; + flen = bootm_get_os_size(data); + hlen = fdt32_to_cpu(header->totalsize); + + fit = fit_open(data->os_file, data->verbose, data->verify, + min(flen, hlen)); + if (IS_ERR(fit)) { + pr_err("Loading FIT image %s failed with: %pe\n", data->os_file, fit); + return PTR_ERR(fit); + } + + data->os_fit = fit; + + data->fit_config = fit_open_configuration(data->os_fit, + data->os_part); + if (IS_ERR(data->fit_config)) { + pr_err("Cannot open FIT image configuration '%s'\n", + data->os_part ? data->os_part : "default"); + return PTR_ERR(data->fit_config); + } + + ret = fit_open_image(data->os_fit, data->fit_config, kernel_img, + &data->fit_kernel, &data->fit_kernel_size); + if (ret) + return ret; + if (data->os_address == UIMAGE_SOME_ADDRESS) { + ret = fit_get_image_address(data->os_fit, + data->fit_config, + kernel_img, + "load", &data->os_address); + if (!ret) + pr_info("Load address from FIT '%s': 0x%lx\n", + kernel_img, data->os_address); + /* Note: Error case uses default value. */ + } + if (data->os_entry == UIMAGE_SOME_ADDRESS) { + unsigned long entry; + ret = fit_get_image_address(data->os_fit, + data->fit_config, + kernel_img, + "entry", &entry); + if (!ret) { + data->os_entry = entry - data->os_address; + pr_info("Entry address from FIT '%s': 0x%lx\n", + kernel_img, entry); + } + /* Note: Error case uses default value. */ + } + + return 0; +} + static int bootm_open_elf(struct image_data *data) { + struct elf_image *elf; + if (!IS_ENABLED(CONFIG_ELF)) return -ENOSYS; - data->elf = elf_open(data->os_file); - if (IS_ERR(data->elf)) - return PTR_ERR(data->elf); + elf = elf_open(data->os_file); + if (IS_ERR(elf)) + return PTR_ERR(elf); - pr_info("Entry Point: %08llx\n", data->elf->entry); + pr_info("Entry Point: %08llx\n", elf->entry); - data->os_address = data->elf->entry; + data->os_address = elf->entry; + data->elf = elf; return 0; } @@ -616,7 +717,7 @@ int bootm_boot(struct bootm_data *bootm_data) goto err_out; } - if (IS_ENABLED(CONFIG_BOOTM_FORCE_SIGNED_IMAGES)) { + if (bootm_signed_images_are_forced()) { data->verify = BOOTM_VERIFY_SIGNATURE; /* @@ -633,74 +734,25 @@ int bootm_boot(struct bootm_data *bootm_data) } } - if (IS_ENABLED(CONFIG_FITIMAGE) && os_type == filetype_oftree) { - struct fit_handle *fit; - static const char *kernel_img = "kernel"; - - fit = fit_open(data->os_file, data->verbose, data->verify); - if (IS_ERR(fit)) { - pr_err("Loading FIT image %s failed with: %pe\n", data->os_file, fit); - ret = PTR_ERR(fit); - goto err_out; - } - - data->os_fit = fit; - - data->fit_config = fit_open_configuration(data->os_fit, - data->os_part); - if (IS_ERR(data->fit_config)) { - pr_err("Cannot open FIT image configuration '%s'\n", - data->os_part ? data->os_part : "default"); - ret = PTR_ERR(data->fit_config); - goto err_out; - } - - ret = fit_open_image(data->os_fit, data->fit_config, kernel_img, - &data->fit_kernel, &data->fit_kernel_size); - if (ret) - goto err_out; - if (data->os_address == UIMAGE_SOME_ADDRESS) { - ret = fit_get_image_address(data->os_fit, - data->fit_config, - kernel_img, - "load", &data->os_address); - if (!ret) - pr_info("Load address from FIT '%s': 0x%lx\n", - kernel_img, data->os_address); - /* Note: Error case uses default value. */ - } - if (data->os_entry == UIMAGE_SOME_ADDRESS) { - unsigned long entry; - ret = fit_get_image_address(data->os_fit, - data->fit_config, - kernel_img, - "entry", &entry); - if (!ret) { - data->os_entry = entry - data->os_address; - pr_info("Entry address from FIT '%s': 0x%lx\n", - kernel_img, entry); - } - /* Note: Error case uses default value. */ - } - } - - if (os_type == filetype_uimage) { + switch (os_type) { + case filetype_oftree: + ret = bootm_open_fit(data); + break; + case filetype_uimage: ret = bootm_open_os_uimage(data); - if (ret) { - pr_err("Loading OS image failed with: %s\n", - strerror(-ret)); - goto err_out; - } + break; + case filetype_elf: + ret = bootm_open_elf(data); + break; + default: + ret = 0; + break; } - if (os_type == filetype_elf) { - ret = bootm_open_elf(data); - if (ret) { - pr_err("Loading ELF image failed with: %s\n", - strerror(-ret)); - data->elf = NULL; - goto err_out; - } + if (ret) { + pr_err("Loading %s image failed with: %pe\n", + file_type_to_short_string(os_type), ERR_PTR(ret)); + goto err_out; } if (bootm_data->appendroot) { @@ -717,7 +769,7 @@ int bootm_boot(struct bootm_data *bootm_data) if (!root_cdev) pr_err("no cdev found for %s, cannot set root= option\n", root_dev_name); - else if (!root_cdev->uuid[0]) + else if (!root_cdev->partuuid[0]) pr_err("%s doesn't have a PARTUUID, cannot set root= option\n", root_dev_name); } @@ -770,6 +822,27 @@ int bootm_boot(struct bootm_data *bootm_data) free(machine_id_bootarg); } + if (bootm_data->provide_hostname) { + const char *hostname = getenv_nonempty("global.hostname"); + char *hostname_bootarg; + + if (!hostname) { + pr_err("Providing hostname is enabled but no hostname is set\n"); + ret = -EINVAL; + goto err_out; + } + + if (!barebox_hostname_is_valid(hostname)) { + pr_err("Provided hostname is not compatible to systemd hostname requirements\n"); + ret = -EINVAL; + goto err_out; + } + + hostname_bootarg = basprintf("systemd.hostname=%s", hostname); + globalvar_add_simple("linux.bootargs.hostname", hostname_bootarg); + free(hostname_bootarg); + } + pr_info("\nLoading %s '%s'", file_type_to_string(os_type), data->os_file); if (os_type == filetype_uimage && @@ -818,7 +891,7 @@ err_out: elf_close(data->elf); if (IS_ENABLED(CONFIG_FITIMAGE) && data->os_fit) fit_close(data->os_fit); - if (data->of_root_node && data->of_root_node != of_get_root_node()) + if (data->of_root_node) of_delete_node(data->of_root_node); globalvar_remove("linux.bootargs.bootm.earlycon"); @@ -913,6 +986,12 @@ static struct image_handler xz_bootm_handler = { .filetype = filetype_xz_compressed, }; +static struct image_handler zstd_bootm_handler = { + .name = "ZSTD compressed file", + .bootm = do_bootm_compressed, + .filetype = filetype_zstd_compressed, +}; + static int bootm_init(void) { globalvar_add_simple("bootm.image", NULL); @@ -923,12 +1002,13 @@ static int bootm_init(void) globalvar_add_simple_bool("bootm.appendroot", &bootm_appendroot); globalvar_add_simple_bool("bootm.earlycon", &bootm_earlycon); globalvar_add_simple_bool("bootm.provide_machine_id", &bootm_provide_machine_id); + globalvar_add_simple_bool("bootm.provide_hostname", &bootm_provide_hostname); if (IS_ENABLED(CONFIG_BOOTM_INITRD)) { globalvar_add_simple("bootm.initrd", NULL); globalvar_add_simple("bootm.initrd.loadaddr", NULL); } - if (IS_ENABLED(CONFIG_BOOTM_FORCE_SIGNED_IMAGES)) + if (bootm_signed_images_are_forced()) bootm_verify_mode = BOOTM_VERIFY_SIGNATURE; globalvar_add_simple_int("bootm.verbose", &bootm_verbosity, "%u"); @@ -947,6 +1027,8 @@ static int bootm_init(void) register_image_handler(&lz4_bootm_handler); if (IS_ENABLED(CONFIG_XZ_DECOMPRESS)) register_image_handler(&xz_bootm_handler); + if (IS_ENABLED(CONFIG_ZSTD_DECOMPRESS)) + register_image_handler(&zstd_bootm_handler); return 0; } @@ -965,3 +1047,4 @@ BAREBOX_MAGICVAR(global.bootm.earlycon, "Add earlycon option to Kernel for early BAREBOX_MAGICVAR(global.bootm.appendroot, "Add root= option to Kernel to mount rootfs from the device the Kernel comes from (default, device can be overridden via global.bootm.root_dev)"); BAREBOX_MAGICVAR(global.bootm.root_dev, "bootm default root device (overrides default device in global.bootm.appendroot)"); BAREBOX_MAGICVAR(global.bootm.provide_machine_id, "If true, append systemd.machine_id=$global.machine_id to Kernel command line"); +BAREBOX_MAGICVAR(global.bootm.provide_hostname, "If true, append systemd.hostname=$global.hostname to Kernel command line"); |