diff --git a/arch/arm/lib32/bootm.c b/arch/arm/lib32/bootm.c index a280795..b1ac2df 100644 --- a/arch/arm/lib32/bootm.c +++ b/arch/arm/lib32/bootm.c @@ -165,11 +165,18 @@ free_mem = PAGE_ALIGN(initrd_end + 1); } + if (!fdt) { + fdt = bootm_get_devicetree(data); + if (IS_ERR(fdt)) + return PTR_ERR(fdt); + } + if (fdt) { - fdt_load_address = fdt; - } else { fdt_load_address = (void *)free_mem; - ret = bootm_load_devicetree(data, free_mem); + ret = bootm_load_devicetree(data, fdt, free_mem); + + free(fdt); + if (ret) return ret; } diff --git a/arch/arm/lib64/armlinux.c b/arch/arm/lib64/armlinux.c index 238e8b6..afa5679 100644 --- a/arch/arm/lib64/armlinux.c +++ b/arch/arm/lib64/armlinux.c @@ -38,6 +38,7 @@ resource_size_t start, end; unsigned long text_offset, image_size, devicetree, kernel; int ret; + void *fdt; text_offset = le64_to_cpup(data->os_header + 8); image_size = le64_to_cpup(data->os_header + 16); @@ -54,7 +55,16 @@ devicetree = ALIGN(kernel + image_size, PAGE_SIZE); - ret = bootm_load_devicetree(data, devicetree); + fdt = bootm_get_devicetree(data); + if (IS_ERR(fdt)) { + ret = PTR_ERR(fdt); + goto out; + } + + ret = bootm_load_devicetree(data, fdt, devicetree); + + free(fdt); + if (ret) goto out; diff --git a/common/bootm.c b/common/bootm.c index 8167c3a..169000c 100644 --- a/common/bootm.c +++ b/common/bootm.c @@ -320,25 +320,24 @@ } /* - * bootm_load_devicetree() - load devicetree + * bootm_get_devicetree() - get devicetree * * @data: image data context - * @load_address: The address where the devicetree should be loaded to * - * This loads the devicetree to a RAM location. load_address must be a valid - * address. The resulting devicetree will be found at data->oftree. + * This gets the fixed devicetree from the various image sources or the internal + * devicetree. It returns a pointer to the allocated devicetree which must be + * freed after use. * - * Return: 0 on success, negative error code otherwise + * Return: pointer to the fixed devicetree or a ERR_PTR() on failure. */ -int bootm_load_devicetree(struct image_data *data, unsigned long load_address) +void *bootm_get_devicetree(struct image_data *data) { enum filetype type; - int fdt_size; struct fdt_header *oftree; int ret; if (!IS_ENABLED(CONFIG_OFTREE)) - return 0; + return ERR_PTR(-ENOSYS); if (IS_ENABLED(CONFIG_FITIMAGE) && data->os_fit && fit_has_image(data->os_fit, data->fit_config, "fdt")) { @@ -348,7 +347,7 @@ ret = fit_open_image(data->os_fit, data->fit_config, "fdt", &of_tree, &of_size); if (ret) - return ret; + return ERR_PTR(ret); data->of_root_node = of_unflatten_dtb(of_tree); } else if (data->oftree_file) { @@ -359,7 +358,7 @@ if ((int)type < 0) { printf("could not open %s: %s\n", data->oftree_file, strerror(-type)); - return (int)type; + return ERR_PTR((int)type); } switch (type) { @@ -372,11 +371,11 @@ FILESIZE_MAX); break; default: - return -EINVAL; + return ERR_PTR(-EINVAL); } if (ret) - return ret; + return ERR_PTR(ret); data->of_root_node = of_unflatten_dtb(oftree); @@ -385,13 +384,13 @@ if (IS_ERR(data->of_root_node)) { data->of_root_node = NULL; pr_err("unable to unflatten devicetree\n"); - return -EINVAL; + return ERR_PTR(-EINVAL); } } else { data->of_root_node = of_get_root_node(); if (!data->of_root_node) - return 0; + return NULL; if (bootm_verbose(data) > 1 && data->of_root_node) printf("using internal devicetree\n"); @@ -405,24 +404,42 @@ oftree = of_get_fixed_tree(data->of_root_node); if (!oftree) - return -EINVAL; + return ERR_PTR(-EINVAL); - fdt_size = be32_to_cpu(oftree->totalsize); + fdt_add_reserve_map(oftree); + + return oftree; +} + +/* + * bootm_load_devicetree() - load devicetree + * + * @data: image data context + * @fdt: The flat device tree to load + * @load_address: The address where the devicetree should be loaded to + * + * This loads the devicetree to a RAM location. load_address must be a valid + * address which is requested with request_sdram_region. The associated region + * is released automatically in the bootm error path. + * + * Return: 0 on success, negative error code otherwise + */ +int bootm_load_devicetree(struct image_data *data, void *fdt, + unsigned long load_address) +{ + int fdt_size; + + if (!IS_ENABLED(CONFIG_OFTREE)) + return -ENOSYS; + + fdt_size = be32_to_cpu(((struct fdt_header *)fdt)->totalsize); data->oftree_res = request_sdram_region("oftree", load_address, fdt_size); - if (!data->oftree_res) { - free(oftree); + if (!data->oftree_res) return -ENOMEM; - } - memcpy((void *)data->oftree_res->start, oftree, fdt_size); - - free(oftree); - - oftree = (void *)data->oftree_res->start; - - fdt_add_reserve_map(oftree); + memcpy((void *)data->oftree_res->start, fdt, fdt_size); of_print_cmdline(data->of_root_node); if (bootm_verbose(data) > 1) diff --git a/include/bootm.h b/include/bootm.h index 0377977..fdc73f7 100644 --- a/include/bootm.h +++ b/include/bootm.h @@ -125,7 +125,9 @@ bool bootm_has_initrd(struct image_data *data); int bootm_load_initrd(struct image_data *data, unsigned long load_address); -int bootm_load_devicetree(struct image_data *data, unsigned long load_address); +void *bootm_get_devicetree(struct image_data *data); +int bootm_load_devicetree(struct image_data *data, void *fdt, + unsigned long load_address); int bootm_get_os_size(struct image_data *data); enum bootm_verify bootm_get_verify_mode(void);