diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Kconfig | 17 | ||||
-rw-r--r-- | lib/efi_driver/efi_uclass.c | 3 | ||||
-rw-r--r-- | lib/efi_loader/Kconfig | 17 | ||||
-rw-r--r-- | lib/efi_loader/efi_boottime.c | 22 | ||||
-rw-r--r-- | lib/efi_loader/efi_device_path.c | 4 | ||||
-rw-r--r-- | lib/efi_loader/efi_memory.c | 2 | ||||
-rw-r--r-- | lib/efi_loader/efi_root_node.c | 60 | ||||
-rw-r--r-- | lib/efi_loader/efi_setup.c | 75 | ||||
-rw-r--r-- | lib/efi_selftest/efi_selftest_memory.c | 11 | ||||
-rw-r--r-- | lib/fdtdec.c | 277 | ||||
-rw-r--r-- | lib/fdtdec_test.c | 216 | ||||
-rw-r--r-- | lib/libfdt/fdt_ro.c | 31 | ||||
-rw-r--r-- | lib/lz4_wrapper.c | 3 | ||||
-rw-r--r-- | lib/vsprintf.c | 2 |
14 files changed, 591 insertions, 149 deletions
diff --git a/lib/Kconfig b/lib/Kconfig index 366d164cd7..2120216593 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -301,6 +301,19 @@ config LZO help This enables support for LZO compression algorithm.r +config GZIP + bool "Enable gzip decompression support for SPL build" + select ZLIB + default y + help + This enables support for GZIP compression algorithm. + +config ZLIB + bool + default y + help + This enables ZLIB compression lib. + config SPL_LZ4 bool "Enable LZ4 decompression support in SPL" help @@ -423,4 +436,8 @@ source lib/efi/Kconfig source lib/efi_loader/Kconfig source lib/optee/Kconfig +config TEST_FDTDEC + bool "enable fdtdec test" + depends on OF_LIBFDT + endmenu diff --git a/lib/efi_driver/efi_uclass.c b/lib/efi_driver/efi_uclass.c index 7cdf81f40c..b14746e6b1 100644 --- a/lib/efi_driver/efi_uclass.c +++ b/lib/efi_driver/efi_uclass.c @@ -300,9 +300,6 @@ efi_status_t efi_driver_init(void) struct driver *drv; efi_status_t ret = EFI_SUCCESS; - /* Save 'gd' pointer */ - efi_save_gd(); - debug("EFI: Initializing EFI driver framework\n"); for (drv = ll_entry_start(struct driver, driver); drv < ll_entry_end(struct driver, driver); ++drv) { diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index 23487b8130..50b050159c 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -26,6 +26,16 @@ config EFI_UNICODE_CAPITALIZATION set, only the the correct handling of the letters of the codepage used by the FAT file system is ensured. +config EFI_PLATFORM_LANG_CODES + string "Language codes supported by firmware" + depends on EFI_LOADER + default "en-US" + help + This value is used to initialize the PlatformLangCodes variable. Its + value is a semicolon (;) separated list of language codes in native + RFC 4646 format, e.g. "en-US;de-DE". The first language code is used + to initialize the PlatformLang variable. + config EFI_LOADER_BOUNCE_BUFFER bool "EFI Applications use bounce buffers for DMA operations" depends on EFI_LOADER && ARM64 @@ -38,14 +48,11 @@ config EFI_LOADER_BOUNCE_BUFFER config EFI_LOADER_HII bool "Expose HII protocols to EFI applications" depends on EFI_LOADER - default n + default y help The Human Interface Infrastructure is a complicated framework that allows UEFI applications to draw fancy menus and hook strings using a translation framework. U-Boot implements enough of its features to be able to run the UEFI - Shell, but not more than that. The code is experimental still, so - beware that your system might break with HII enabled. - - If unsure, say n. + Shell, but not more than that. diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index b215bd7723..abc295e392 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -1569,26 +1569,6 @@ efi_status_t efi_setup_loaded_image(struct efi_device_path *device_path, if (ret != EFI_SUCCESS) goto failure; -#if CONFIG_IS_ENABLED(EFI_LOADER_HII) - ret = efi_add_protocol(&obj->header, - &efi_guid_hii_string_protocol, - (void *)&efi_hii_string); - if (ret != EFI_SUCCESS) - goto failure; - - ret = efi_add_protocol(&obj->header, - &efi_guid_hii_database_protocol, - (void *)&efi_hii_database); - if (ret != EFI_SUCCESS) - goto failure; - - ret = efi_add_protocol(&obj->header, - &efi_guid_hii_config_routing_protocol, - (void *)&efi_hii_config_routing); - if (ret != EFI_SUCCESS) - goto failure; -#endif - *info_ptr = info; *handle_ptr = obj; @@ -2287,7 +2267,7 @@ out: * * Return: status code */ -static efi_status_t EFIAPI efi_install_multiple_protocol_interfaces +efi_status_t EFIAPI efi_install_multiple_protocol_interfaces (efi_handle_t *handle, ...) { EFI_ENTRY("%p", handle); diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c index 53b40c8c3c..d8c052d6ec 100644 --- a/lib/efi_loader/efi_device_path.c +++ b/lib/efi_loader/efi_device_path.c @@ -5,8 +5,6 @@ * (C) Copyright 2017 Rob Clark */ -#define LOG_CATEGORY LOGL_ERR - #include <common.h> #include <blk.h> #include <dm.h> @@ -970,7 +968,7 @@ efi_status_t efi_dp_from_name(const char *dev, const char *devnr, if (!is_net) { part = blk_get_device_part_str(dev, devnr, &desc, &fs_partition, 1); - if (part < 0) + if (part < 0 || !desc) return EFI_INVALID_PARAMETER; if (device) diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index dbe29b8960..46681dc208 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -193,6 +193,7 @@ static s64 efi_mem_carve_out(struct efi_mem_list *map, free(map); } else { map->desc.physical_start = carve_end; + map->desc.virtual_start = carve_end; map->desc.num_pages = (map_end - carve_end) >> EFI_PAGE_SHIFT; } @@ -211,6 +212,7 @@ static s64 efi_mem_carve_out(struct efi_mem_list *map, newmap = calloc(1, sizeof(*newmap)); newmap->desc = map->desc; newmap->desc.physical_start = carve_start; + newmap->desc.virtual_start = carve_start; newmap->desc.num_pages = (map_end - carve_start) >> EFI_PAGE_SHIFT; /* Insert before current entry (descending address order) */ list_add_tail(&newmap->link, &map->link); diff --git a/lib/efi_loader/efi_root_node.c b/lib/efi_loader/efi_root_node.c index b056ba3ee8..392f5c4951 100644 --- a/lib/efi_loader/efi_root_node.c +++ b/lib/efi_loader/efi_root_node.c @@ -26,16 +26,10 @@ struct efi_root_dp { */ efi_status_t efi_root_node_register(void) { - efi_handle_t root; - efi_status_t ret; + efi_handle_t root = NULL; struct efi_root_dp *dp; - /* Create handle */ - ret = efi_create_handle(&root); - if (ret != EFI_SUCCESS) - return ret; - - /* Install device path protocol */ + /* Create device path protocol */ dp = calloc(1, sizeof(*dp)); if (!dp) return EFI_OUT_OF_RESOURCES; @@ -51,29 +45,29 @@ efi_status_t efi_root_node_register(void) dp->end.sub_type = DEVICE_PATH_SUB_TYPE_END; dp->end.length = sizeof(struct efi_device_path); - /* Install device path protocol */ - ret = efi_add_protocol(root, &efi_guid_device_path, dp); - if (ret != EFI_SUCCESS) - goto failure; - - /* Install device path to text protocol */ - ret = efi_add_protocol(root, &efi_guid_device_path_to_text_protocol, - (void *)&efi_device_path_to_text); - if (ret != EFI_SUCCESS) - goto failure; - - /* Install device path utilities protocol */ - ret = efi_add_protocol(root, &efi_guid_device_path_utilities_protocol, - (void *)&efi_device_path_utilities); - if (ret != EFI_SUCCESS) - goto failure; - - /* Install Unicode collation protocol */ - ret = efi_add_protocol(root, &efi_guid_unicode_collation_protocol, - (void *)&efi_unicode_collation_protocol); - if (ret != EFI_SUCCESS) - goto failure; - -failure: - return ret; + /* Create root node and install protocols */ + return EFI_CALL(efi_install_multiple_protocol_interfaces(&root, + /* Device path protocol */ + &efi_guid_device_path, dp, + /* Device path to text protocol */ + &efi_guid_device_path_to_text_protocol, + (void *)&efi_device_path_to_text, + /* Device path utilities protocol */ + &efi_guid_device_path_utilities_protocol, + (void *)&efi_device_path_utilities, + /* Unicode collation protocol */ + &efi_guid_unicode_collation_protocol, + (void *)&efi_unicode_collation_protocol, +#if CONFIG_IS_ENABLED(EFI_LOADER_HII) + /* HII string protocol */ + &efi_guid_hii_string_protocol, + (void *)&efi_hii_string, + /* HII database protocol */ + &efi_guid_hii_database_protocol, + (void *)&efi_hii_database, + /* HII configuration routing protocol */ + &efi_guid_hii_config_routing_protocol, + (void *)&efi_hii_config_routing, +#endif + NULL)); } diff --git a/lib/efi_loader/efi_setup.c b/lib/efi_loader/efi_setup.c index a908843d87..b32a7b3f93 100644 --- a/lib/efi_loader/efi_setup.c +++ b/lib/efi_loader/efi_setup.c @@ -10,51 +10,86 @@ #define OBJ_LIST_NOT_INITIALIZED 1 -/* Language code for American English according to RFC 4646 */ -#define EN_US L"en-US" - static efi_status_t efi_obj_list_initialized = OBJ_LIST_NOT_INITIALIZED; -/* Initialize and populate EFI object list */ -efi_status_t efi_init_obj_list(void) +/** + * efi_init_platform_lang() - define supported languages + * + * Set the PlatformLangCodes and PlatformLang variables. + * + * Return: status code + */ +static efi_status_t efi_init_platform_lang(void) { - efi_status_t ret = EFI_SUCCESS; + efi_status_t ret; + efi_uintn_t data_size = 0; + char *lang = CONFIG_EFI_PLATFORM_LANG_CODES; + char *pos; /* - * On the ARM architecture gd is mapped to a fixed register (r9 or x18). - * As this register may be overwritten by an EFI payload we save it here - * and restore it on every callback entered. + * Variable PlatformLangCodes defines the language codes that the + * machine can support. */ - efi_save_gd(); + ret = EFI_CALL(efi_set_variable(L"PlatformLangCodes", + &efi_global_variable_guid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS, + sizeof(CONFIG_EFI_PLATFORM_LANG_CODES), + CONFIG_EFI_PLATFORM_LANG_CODES)); + if (ret != EFI_SUCCESS) + goto out; /* * Variable PlatformLang defines the language that the machine has been * configured for. */ - ret = EFI_CALL(efi_set_variable(L"PlatformLang", + ret = EFI_CALL(efi_get_variable(L"PlatformLang", &efi_global_variable_guid, - EFI_VARIABLE_BOOTSERVICE_ACCESS | - EFI_VARIABLE_RUNTIME_ACCESS, - sizeof(EN_US), EN_US)); - if (ret != EFI_SUCCESS) + NULL, &data_size, &pos)); + if (ret == EFI_BUFFER_TOO_SMALL) { + /* The variable is already set. Do not change it. */ + ret = EFI_SUCCESS; goto out; + } /* - * Variable PlatformLangCodes defines the language codes that the - * machine can support. + * The list of supported languages is semicolon separated. Use the first + * language to initialize PlatformLang. */ - ret = EFI_CALL(efi_set_variable(L"PlatformLangCodes", + pos = strchr(lang, ';'); + if (pos) + *pos = 0; + + ret = EFI_CALL(efi_set_variable(L"PlatformLang", &efi_global_variable_guid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, - sizeof(EN_US), EN_US)); + 1 + strlen(lang), lang)); +out: if (ret != EFI_SUCCESS) - goto out; + printf("EFI: cannot initialize platform language settings\n"); + return ret; +} + +/** + * efi_init_obj_list() - Initialize and populate EFI object list + * + * Return: status code + */ +efi_status_t efi_init_obj_list(void) +{ + efi_status_t ret = EFI_SUCCESS; /* Initialize once only */ if (efi_obj_list_initialized != OBJ_LIST_NOT_INITIALIZED) return efi_obj_list_initialized; + /* Define supported languages */ + ret = efi_init_platform_lang(); + if (ret != EFI_SUCCESS) + goto out; + /* Initialize system table */ ret = efi_initialize_system_table(); if (ret != EFI_SUCCESS) diff --git a/lib/efi_selftest/efi_selftest_memory.c b/lib/efi_selftest/efi_selftest_memory.c index 24b4438ce4..5eeb42a9be 100644 --- a/lib/efi_selftest/efi_selftest_memory.c +++ b/lib/efi_selftest/efi_selftest_memory.c @@ -4,7 +4,7 @@ * * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de> * - * This unit test checks the following runtime services: + * This unit test checks the following boottime services: * AllocatePages, FreePages, GetMemoryMap * * The memory type used for the device tree is checked. @@ -65,6 +65,11 @@ static int find_in_memory_map(efi_uintn_t map_size, for (i = 0; map_size; ++i, map_size -= desc_size) { struct efi_mem_desc *entry = &memory_map[i]; + if (entry->physical_start != entry->virtual_start) { + efi_st_error("Physical and virtual addresses do not match\n"); + return EFI_ST_FAILURE; + } + if (addr >= entry->physical_start && addr < entry->physical_start + (entry->num_pages << EFI_PAGE_SHIFT)) { @@ -171,9 +176,9 @@ static int execute(void) /* Check memory reservation for the device tree */ if (fdt_addr && find_in_memory_map(map_size, memory_map, desc_size, fdt_addr, - EFI_RUNTIME_SERVICES_DATA) != EFI_ST_SUCCESS) { + EFI_BOOT_SERVICES_DATA) != EFI_ST_SUCCESS) { efi_st_error - ("Device tree not marked as runtime services data\n"); + ("Device tree not marked as boot services data\n"); return EFI_ST_FAILURE; } return EFI_ST_SUCCESS; diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 09a7e133a5..9c9c302347 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -45,7 +45,7 @@ static const char * const compat_names[COMPAT_COUNT] = { COMPAT(SAMSUNG_EXYNOS_TMU, "samsung,exynos-tmu"), COMPAT(SAMSUNG_EXYNOS_MIPI_DSI, "samsung,exynos-mipi-dsi"), COMPAT(SAMSUNG_EXYNOS_DWMMC, "samsung,exynos-dwmmc"), - COMPAT(GENERIC_SPI_FLASH, "spi-flash"), + COMPAT(GENERIC_SPI_FLASH, "jedec,spi-nor"), COMPAT(SAMSUNG_EXYNOS_SYSMMU, "samsung,sysmmu-v3.3"), COMPAT(INTEL_MICROCODE, "intel,microcode"), COMPAT(INTEL_QRK_MRC, "intel,quark-mrc"), @@ -1088,18 +1088,18 @@ int fdtdec_decode_display_timing(const void *blob, int parent, int index, return ret; } -int fdtdec_setup_mem_size_base(void) +int fdtdec_setup_mem_size_base_fdt(const void *blob) { int ret, mem; struct fdt_resource res; - mem = fdt_path_offset(gd->fdt_blob, "/memory"); + mem = fdt_path_offset(blob, "/memory"); if (mem < 0) { debug("%s: Missing /memory node\n", __func__); return -EINVAL; } - ret = fdt_get_resource(gd->fdt_blob, mem, "reg", 0, &res); + ret = fdt_get_resource(blob, mem, "reg", 0, &res); if (ret != 0) { debug("%s: Unable to decode first memory bank\n", __func__); return -EINVAL; @@ -1113,38 +1113,43 @@ int fdtdec_setup_mem_size_base(void) return 0; } +int fdtdec_setup_mem_size_base(void) +{ + return fdtdec_setup_mem_size_base_fdt(gd->fdt_blob); +} + #if defined(CONFIG_NR_DRAM_BANKS) static int get_next_memory_node(const void *blob, int mem) { do { - mem = fdt_node_offset_by_prop_value(gd->fdt_blob, mem, + mem = fdt_node_offset_by_prop_value(blob, mem, "device_type", "memory", 7); } while (!fdtdec_get_is_enabled(blob, mem)); return mem; } -int fdtdec_setup_memory_banksize(void) +int fdtdec_setup_memory_banksize_fdt(const void *blob) { int bank, ret, mem, reg = 0; struct fdt_resource res; - mem = get_next_memory_node(gd->fdt_blob, -1); + mem = get_next_memory_node(blob, -1); if (mem < 0) { debug("%s: Missing /memory node\n", __func__); return -EINVAL; } for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) { - ret = fdt_get_resource(gd->fdt_blob, mem, "reg", reg++, &res); + ret = fdt_get_resource(blob, mem, "reg", reg++, &res); if (ret == -FDT_ERR_NOTFOUND) { reg = 0; - mem = get_next_memory_node(gd->fdt_blob, mem); + mem = get_next_memory_node(blob, mem); if (mem == -FDT_ERR_NOTFOUND) break; - ret = fdt_get_resource(gd->fdt_blob, mem, "reg", reg++, &res); + ret = fdt_get_resource(blob, mem, "reg", reg++, &res); if (ret == -FDT_ERR_NOTFOUND) break; } @@ -1164,6 +1169,12 @@ int fdtdec_setup_memory_banksize(void) return 0; } + +int fdtdec_setup_memory_banksize(void) +{ + return fdtdec_setup_memory_banksize_fdt(gd->fdt_blob); + +} #endif #if CONFIG_IS_ENABLED(MULTI_DTB_FIT) @@ -1171,17 +1182,22 @@ int fdtdec_setup_memory_banksize(void) CONFIG_IS_ENABLED(MULTI_DTB_FIT_LZO) static int uncompress_blob(const void *src, ulong sz_src, void **dstp) { - size_t sz_out = CONFIG_SPL_MULTI_DTB_FIT_UNCOMPRESS_SZ; + size_t sz_out = CONFIG_VAL(MULTI_DTB_FIT_UNCOMPRESS_SZ); + bool gzip = 0, lzo = 0; ulong sz_in = sz_src; void *dst; int rc; if (CONFIG_IS_ENABLED(GZIP)) - if (gzip_parse_header(src, sz_in) < 0) - return -1; + if (gzip_parse_header(src, sz_in) >= 0) + gzip = 1; if (CONFIG_IS_ENABLED(LZO)) - if (!lzop_is_valid_header(src)) - return -EBADMSG; + if (!gzip && lzop_is_valid_header(src)) + lzo = 1; + + if (!gzip && !lzo) + return -EBADMSG; + if (CONFIG_IS_ENABLED(MULTI_DTB_FIT_DYN_ALLOC)) { dst = malloc(sz_out); @@ -1197,10 +1213,12 @@ static int uncompress_blob(const void *src, ulong sz_src, void **dstp) # endif } - if (CONFIG_IS_ENABLED(GZIP)) + if (CONFIG_IS_ENABLED(GZIP) && gzip) rc = gunzip(dst, sz_out, (u8 *)src, &sz_in); - else if (CONFIG_IS_ENABLED(LZO)) + else if (CONFIG_IS_ENABLED(LZO) && lzo) rc = lzop_decompress(src, sz_in, dst, &sz_out); + else + hang(); if (rc < 0) { /* not a valid compressed blob */ @@ -1243,6 +1261,231 @@ __weak void *board_fdt_blob_setup(void) } #endif +int fdtdec_set_phandle(void *blob, int node, uint32_t phandle) +{ + fdt32_t value = cpu_to_fdt32(phandle); + + return fdt_setprop(blob, node, "phandle", &value, sizeof(value)); +} + +static int fdtdec_init_reserved_memory(void *blob) +{ + int na, ns, node, err; + fdt32_t value; + + /* inherit #address-cells and #size-cells from the root node */ + na = fdt_address_cells(blob, 0); + ns = fdt_size_cells(blob, 0); + + node = fdt_add_subnode(blob, 0, "reserved-memory"); + if (node < 0) + return node; + + err = fdt_setprop(blob, node, "ranges", NULL, 0); + if (err < 0) + return err; + + value = cpu_to_fdt32(ns); + + err = fdt_setprop(blob, node, "#size-cells", &value, sizeof(value)); + if (err < 0) + return err; + + value = cpu_to_fdt32(na); + + err = fdt_setprop(blob, node, "#address-cells", &value, sizeof(value)); + if (err < 0) + return err; + + return node; +} + +int fdtdec_add_reserved_memory(void *blob, const char *basename, + const struct fdt_memory *carveout, + uint32_t *phandlep) +{ + fdt32_t cells[4] = {}, *ptr = cells; + uint32_t upper, lower, phandle; + int parent, node, na, ns, err; + char name[64]; + + /* create an empty /reserved-memory node if one doesn't exist */ + parent = fdt_path_offset(blob, "/reserved-memory"); + if (parent < 0) { + parent = fdtdec_init_reserved_memory(blob); + if (parent < 0) + return parent; + } + + /* only 1 or 2 #address-cells and #size-cells are supported */ + na = fdt_address_cells(blob, parent); + if (na < 1 || na > 2) + return -FDT_ERR_BADNCELLS; + + ns = fdt_size_cells(blob, parent); + if (ns < 1 || ns > 2) + return -FDT_ERR_BADNCELLS; + + /* find a matching node and return the phandle to that */ + fdt_for_each_subnode(node, blob, parent) { + const char *name = fdt_get_name(blob, node, NULL); + phys_addr_t addr, size; + + addr = fdtdec_get_addr_size(blob, node, "reg", &size); + if (addr == FDT_ADDR_T_NONE) { + debug("failed to read address/size for %s\n", name); + continue; + } + + if (addr == carveout->start && (addr + size) == carveout->end) { + *phandlep = fdt_get_phandle(blob, node); + return 0; + } + } + + /* + * Unpack the start address and generate the name of the new node + * base on the basename and the unit-address. + */ + lower = fdt_addr_unpack(carveout->start, &upper); + + if (na > 1 && upper > 0) + snprintf(name, sizeof(name), "%s@%x,%x", basename, upper, + lower); + else { + if (upper > 0) { + debug("address %08x:%08x exceeds addressable space\n", + upper, lower); + return -FDT_ERR_BADVALUE; + } + + snprintf(name, sizeof(name), "%s@%x", basename, lower); + } + + node = fdt_add_subnode(blob, parent, name); + if (node < 0) + return node; + + err = fdt_generate_phandle(blob, &phandle); + if (err < 0) + return err; + + err = fdtdec_set_phandle(blob, node, phandle); + if (err < 0) + return err; + + /* store one or two address cells */ + if (na > 1) + *ptr++ = cpu_to_fdt32(upper); + + *ptr++ = cpu_to_fdt32(lower); + + /* store one or two size cells */ + lower = fdt_size_unpack(carveout->end - carveout->start + 1, &upper); + + if (ns > 1) + *ptr++ = cpu_to_fdt32(upper); + + *ptr++ = cpu_to_fdt32(lower); + + err = fdt_setprop(blob, node, "reg", cells, (na + ns) * sizeof(*cells)); + if (err < 0) + return err; + + /* return the phandle for the new node for the caller to use */ + if (phandlep) + *phandlep = phandle; + + return 0; +} + +int fdtdec_get_carveout(const void *blob, const char *node, const char *name, + unsigned int index, struct fdt_memory *carveout) +{ + const fdt32_t *prop; + uint32_t phandle; + int offset, len; + fdt_size_t size; + + offset = fdt_path_offset(blob, node); + if (offset < 0) + return offset; + + prop = fdt_getprop(blob, offset, name, &len); + if (!prop) { + debug("failed to get %s for %s\n", name, node); + return -FDT_ERR_NOTFOUND; + } + + if ((len % sizeof(phandle)) != 0) { + debug("invalid phandle property\n"); + return -FDT_ERR_BADPHANDLE; + } + + if (len < (sizeof(phandle) * (index + 1))) { + debug("invalid phandle index\n"); + return -FDT_ERR_BADPHANDLE; + } + + phandle = fdt32_to_cpu(prop[index]); + + offset = fdt_node_offset_by_phandle(blob, phandle); + if (offset < 0) { + debug("failed to find node for phandle %u\n", phandle); + return offset; + } + + carveout->start = fdtdec_get_addr_size_auto_noparent(blob, offset, + "reg", 0, &size, + true); + if (carveout->start == FDT_ADDR_T_NONE) { + debug("failed to read address/size from \"reg\" property\n"); + return -FDT_ERR_NOTFOUND; + } + + carveout->end = carveout->start + size - 1; + + return 0; +} + +int fdtdec_set_carveout(void *blob, const char *node, const char *prop_name, + unsigned int index, const char *name, + const struct fdt_memory *carveout) +{ + uint32_t phandle; + int err, offset; + fdt32_t value; + + /* XXX implement support for multiple phandles */ + if (index > 0) { + debug("invalid index %u\n", index); + return -FDT_ERR_BADOFFSET; + } + + err = fdtdec_add_reserved_memory(blob, name, carveout, &phandle); + if (err < 0) { + debug("failed to add reserved memory: %d\n", err); + return err; + } + + offset = fdt_path_offset(blob, node); + if (offset < 0) { + debug("failed to find offset for node %s: %d\n", node, offset); + return offset; + } + + value = cpu_to_fdt32(phandle); + + err = fdt_setprop(blob, offset, prop_name, &value, sizeof(value)); + if (err < 0) { + debug("failed to set %s property for node %s: %d\n", prop_name, + node, err); + return err; + } + + return 0; +} + int fdtdec_setup(void) { #if CONFIG_IS_ENABLED(OF_CONTROL) diff --git a/lib/fdtdec_test.c b/lib/fdtdec_test.c index a82e27de94..f6defe16c5 100644 --- a/lib/fdtdec_test.c +++ b/lib/fdtdec_test.c @@ -15,48 +15,28 @@ /* The size of our test fdt blob */ #define FDT_SIZE (16 * 1024) -/** - * Check if an operation failed, and if so, print an error - * - * @param oper_name Name of operation - * @param err Error code to check - * - * @return 0 if ok, -1 if there was an error - */ -static int fdt_checkerr(const char *oper_name, int err) -{ - if (err) { - printf("%s: %s: %s\n", __func__, oper_name, fdt_strerror(err)); - return -1; - } +#define CHECK(op) ({ \ + int err = op; \ + if (err < 0) { \ + printf("%s: %s: %s\n", __func__, #op, \ + fdt_strerror(err)); \ + return err; \ + } \ + \ + err; \ + }) - return 0; -} +#define CHECKVAL(op, expected) ({ \ + int err = op; \ + if (err != expected) { \ + printf("%s: %s: expected %d, but returned %d\n",\ + __func__, #op, expected, err); \ + return err; \ + } \ + \ + err; \ + }) -/** - * Check the result of an operation and if incorrect, print an error - * - * @param oper_name Name of operation - * @param expected Expected value - * @param value Actual value - * - * @return 0 if ok, -1 if there was an error - */ -static int checkval(const char *oper_name, int expected, int value) -{ - if (expected != value) { - printf("%s: %s: expected %d, but returned %d\n", __func__, - oper_name, expected, value); - return -1; - } - - return 0; -} - -#define CHECK(op) if (fdt_checkerr(#op, op)) return -1 -#define CHECKVAL(op, expected) \ - if (checkval(#op, expected, op)) \ - return -1 #define CHECKOK(op) CHECKVAL(op, 0) /* maximum number of nodes / aliases to generate */ @@ -79,7 +59,9 @@ static int make_fdt(void *fdt, int size, const char *aliases, { char name[20], value[20]; const char *s; +#if defined(DEBUG) && defined(CONFIG_SANDBOX) int fd; +#endif CHECK(fdt_create(fdt, size)); CHECK(fdt_finish_reservemap(fdt)); @@ -136,7 +118,7 @@ static int run_test(const char *aliases, const char *nodes, const char *expect) CHECKVAL(make_fdt(blob, FDT_SIZE, aliases, nodes), 0); CHECKVAL(fdtdec_find_aliases_for_id(blob, "i2c", COMPAT_UNKNOWN, - list, ARRAY_SIZE(list)), strlen(expect)); + list, ARRAY_SIZE(list)), (int)strlen(expect)); /* Check we got the right ones */ for (i = 0, s = expect; *s; s++, i++) { @@ -159,6 +141,156 @@ static int run_test(const char *aliases, const char *nodes, const char *expect) return 0; } +static int make_fdt_carveout_device(void *fdt, uint32_t na, uint32_t ns) +{ + const char *basename = "/display"; + struct fdt_memory carveout = { +#ifdef CONFIG_PHYS_64BIT + .start = 0x180000000, + .end = 0x18fffffff, +#else + .start = 0x80000000, + .end = 0x8fffffff, +#endif + }; + fdt32_t cells[4], *ptr = cells; + uint32_t upper, lower; + char name[32]; + int offset; + + /* store one or two address cells */ + lower = fdt_addr_unpack(carveout.start, &upper); + + if (na > 1 && upper > 0) + snprintf(name, sizeof(name), "%s@%x,%x", basename, upper, + lower); + else + snprintf(name, sizeof(name), "%s@%x", basename, lower); + + if (na > 1) + *ptr++ = cpu_to_fdt32(upper); + + *ptr++ = cpu_to_fdt32(lower); + + /* store one or two size cells */ + lower = fdt_size_unpack(carveout.end - carveout.start + 1, &upper); + + if (ns > 1) + *ptr++ = cpu_to_fdt32(upper); + + *ptr++ = cpu_to_fdt32(lower); + + offset = CHECK(fdt_add_subnode(fdt, 0, name + 1)); + CHECK(fdt_setprop(fdt, offset, "reg", cells, (na + ns) * sizeof(*cells))); + + return fdtdec_set_carveout(fdt, name, "memory-region", 0, + "framebuffer", &carveout); +} + +static int check_fdt_carveout(void *fdt, uint32_t address_cells, + uint32_t size_cells) +{ +#ifdef CONFIG_PHYS_64BIT + const char *name = "/display@1,80000000"; + const struct fdt_memory expected = { + .start = 0x180000000, + .end = 0x18fffffff, + }; +#else + const char *name = "/display@80000000"; + const struct fdt_memory expected = { + .start = 0x80000000, + .end = 0x8fffffff, + }; +#endif + struct fdt_memory carveout; + + printf("carveout: %pap-%pap na=%u ns=%u: ", &expected.start, + &expected.end, address_cells, size_cells); + + CHECK(fdtdec_get_carveout(fdt, name, "memory-region", 0, &carveout)); + + if ((carveout.start != expected.start) || + (carveout.end != expected.end)) { + printf("carveout: %pap-%pap, expected %pap-%pap\n", + &carveout.start, &carveout.end, + &expected.start, &expected.end); + return 1; + } + + printf("pass\n"); + return 0; +} + +static int make_fdt_carveout(void *fdt, int size, uint32_t address_cells, + uint32_t size_cells) +{ + fdt32_t na = cpu_to_fdt32(address_cells); + fdt32_t ns = cpu_to_fdt32(size_cells); +#if defined(DEBUG) && defined(CONFIG_SANDBOX) + char filename[512]; + int fd; +#endif + int err; + + CHECK(fdt_create(fdt, size)); + CHECK(fdt_finish_reservemap(fdt)); + CHECK(fdt_begin_node(fdt, "")); + CHECK(fdt_property(fdt, "#address-cells", &na, sizeof(na))); + CHECK(fdt_property(fdt, "#size-cells", &ns, sizeof(ns))); + CHECK(fdt_end_node(fdt)); + CHECK(fdt_finish(fdt)); + CHECK(fdt_pack(fdt)); + + CHECK(fdt_open_into(fdt, fdt, FDT_SIZE)); + + err = make_fdt_carveout_device(fdt, address_cells, size_cells); + +#if defined(DEBUG) && defined(CONFIG_SANDBOX) + snprintf(filename, sizeof(filename), "/tmp/fdtdec-carveout-%u-%u.dtb", + address_cells, size_cells); + + fd = os_open(filename, OS_O_CREAT | OS_O_WRONLY); + if (fd < 0) { + printf("could not open .dtb file to write\n"); + goto out; + } + + os_write(fd, fdt, size); + os_close(fd); + +out: +#endif + return err; +} + +static int check_carveout(void) +{ + void *fdt; + + fdt = malloc(FDT_SIZE); + if (!fdt) { + printf("%s: out of memory\n", __func__); + return 1; + } + +#ifndef CONFIG_PHYS_64BIT + CHECKVAL(make_fdt_carveout(fdt, FDT_SIZE, 1, 1), 0); + CHECKOK(check_fdt_carveout(fdt, 1, 1)); + CHECKVAL(make_fdt_carveout(fdt, FDT_SIZE, 1, 2), 0); + CHECKOK(check_fdt_carveout(fdt, 1, 2)); +#else + CHECKVAL(make_fdt_carveout(fdt, FDT_SIZE, 1, 1), -FDT_ERR_BADVALUE); + CHECKVAL(make_fdt_carveout(fdt, FDT_SIZE, 1, 2), -FDT_ERR_BADVALUE); +#endif + CHECKVAL(make_fdt_carveout(fdt, FDT_SIZE, 2, 1), 0); + CHECKOK(check_fdt_carveout(fdt, 2, 1)); + CHECKVAL(make_fdt_carveout(fdt, FDT_SIZE, 2, 2), 0); + CHECKOK(check_fdt_carveout(fdt, 2, 2)); + + return 0; +} + static int do_test_fdtdec(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { @@ -200,6 +332,8 @@ static int do_test_fdtdec(cmd_tbl_t *cmdtp, int flag, int argc, CHECKOK(run_test("2a 1a 0a", "a", " a")); CHECKOK(run_test("0a 1a 2a", "a", "a")); + CHECKOK(check_carveout()); + printf("Test passed\n"); return 0; } diff --git a/lib/libfdt/fdt_ro.c b/lib/libfdt/fdt_ro.c index b6ca4e0b0c..693de9aa5a 100644 --- a/lib/libfdt/fdt_ro.c +++ b/lib/libfdt/fdt_ro.c @@ -73,6 +73,37 @@ uint32_t fdt_get_max_phandle(const void *fdt) return 0; } +int fdt_generate_phandle(const void *fdt, uint32_t *phandle) +{ + uint32_t max = 0; + int offset = -1; + + while (true) { + uint32_t value; + + offset = fdt_next_node(fdt, offset, NULL); + if (offset < 0) { + if (offset == -FDT_ERR_NOTFOUND) + break; + + return offset; + } + + value = fdt_get_phandle(fdt, offset); + + if (value > max) + max = value; + } + + if (max == FDT_MAX_PHANDLE) + return -FDT_ERR_NOPHANDLES; + + if (phandle) + *phandle = max + 1; + + return 0; +} + int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) { FDT_CHECK_HEADER(fdt); diff --git a/lib/lz4_wrapper.c b/lib/lz4_wrapper.c index 487d39ef02..1c68e67452 100644 --- a/lib/lz4_wrapper.c +++ b/lib/lz4_wrapper.c @@ -5,6 +5,7 @@ #include <common.h> #include <compiler.h> +#include <image.h> #include <linux/kernel.h> #include <linux/types.h> @@ -23,8 +24,6 @@ typedef uint64_t U64; /* Unaltered (except removing unrelated code) from github.com/Cyan4973/lz4. */ #include "lz4.c" /* #include for inlining, do not link! */ -#define LZ4F_MAGIC 0x184D2204 - struct lz4_frame_header { u32 magic; union { diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 1b6c154d8d..2403825dc9 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -457,7 +457,6 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr, return device_path_string(buf, end, ptr, field_width, precision, flags); #endif -#ifdef CONFIG_CMD_NET case 'a': flags |= SPECIAL | ZEROPAD; @@ -469,6 +468,7 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr, break; } break; +#ifdef CONFIG_CMD_NET case 'm': flags |= SPECIAL; /* Fallthrough */ |