summaryrefslogtreecommitdiffstats
path: root/common/bootm.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/bootm.c')
-rw-r--r--common/bootm.c265
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");