diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Kconfig | 5 | ||||
-rw-r--r-- | lib/Makefile | 5 | ||||
-rw-r--r-- | lib/efi_loader/efi_disk.c | 24 | ||||
-rw-r--r-- | lib/efi_loader/efi_image_loader.c | 2 | ||||
-rw-r--r-- | lib/efi_loader/efi_memory.c | 3 | ||||
-rw-r--r-- | lib/fdtdec.c | 42 | ||||
-rw-r--r-- | lib/hashtable.c | 12 | ||||
-rw-r--r-- | lib/libfdt/Makefile | 2 | ||||
-rw-r--r-- | lib/libfdt/fdt_overlay.c | 618 | ||||
-rw-r--r-- | lib/libfdt/fdt_ro.c | 46 | ||||
-rw-r--r-- | lib/libfdt/fdt_wip.c | 29 | ||||
-rw-r--r-- | lib/libfdt/libfdt.swig | 89 | ||||
-rw-r--r-- | lib/libfdt/setup.py | 38 | ||||
-rw-r--r-- | lib/libfdt/test_libfdt.py | 14 | ||||
-rw-r--r-- | lib/rsa/rsa-sign.c | 12 | ||||
-rw-r--r-- | lib/tiny-printf.c | 111 |
16 files changed, 954 insertions, 98 deletions
diff --git a/lib/Kconfig b/lib/Kconfig index 02ca4058d3..16ff01a2cd 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -139,6 +139,11 @@ config OF_LIBFDT particular compatible nodes. The library operates on a flattened version of the device tree. +config OF_LIBFDT_OVERLAY + bool "Enable the FDT library overlay support" + help + This enables the FDT library (libfdt) overlay support. + config SPL_OF_LIBFDT bool "Enable the FDT library for SPL" default y if SPL_OF_CONTROL diff --git a/lib/Makefile b/lib/Makefile index f48d90103d..f6a8ba1227 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -48,11 +48,10 @@ obj-$(CONFIG_$(SPL_)SHA1) += sha1.o obj-$(CONFIG_$(SPL_)SHA256) += sha256.o obj-$(CONFIG_$(SPL_)OF_LIBFDT) += libfdt/ -ifdef CONFIG_SPL_OF_CONTROL -obj-$(CONFIG_OF_LIBFDT) += libfdt/ -endif +ifneq ($(CONFIG_SPL_BUILD)$(CONFIG_SPL_OF_PLATDATA),yy) obj-$(CONFIG_$(SPL_)OF_CONTROL) += fdtdec_common.o obj-$(CONFIG_$(SPL_)OF_CONTROL) += fdtdec.o +endif ifdef CONFIG_SPL_BUILD obj-$(CONFIG_SPL_YMODEM_SUPPORT) += crc16.o diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c index c434c92250..d8ddcc9b42 100644 --- a/lib/efi_loader/efi_disk.c +++ b/lib/efi_loader/efi_disk.c @@ -31,6 +31,8 @@ struct efi_disk_obj { struct efi_device_path_file_path *dp; /* Offset into disk for simple partitions */ lbaint_t offset; + /* Internal block device */ + const struct blk_desc *desc; }; static efi_status_t efi_disk_open_block(void *handle, efi_guid_t *protocol, @@ -78,8 +80,7 @@ static efi_status_t EFIAPI efi_disk_rw_blocks(struct efi_block_io *this, unsigned long n; diskobj = container_of(this, struct efi_disk_obj, ops); - if (!(desc = blk_get_dev(diskobj->ifname, diskobj->dev_index))) - return EFI_EXIT(EFI_DEVICE_ERROR); + desc = (struct blk_desc *) diskobj->desc; blksz = desc->blksz; blocks = buffer_size / blksz; lba += diskobj->offset; @@ -201,6 +202,10 @@ static void efi_disk_add_dev(const char *name, struct efi_device_path_file_path *dp; int objlen = sizeof(*diskobj) + (sizeof(*dp) * 2); + /* Don't add empty devices */ + if (!desc->lba) + return; + diskobj = calloc(1, objlen); /* Fill in object data */ @@ -213,13 +218,14 @@ static void efi_disk_add_dev(const char *name, diskobj->ifname = if_typename; diskobj->dev_index = dev_index; diskobj->offset = offset; + diskobj->desc = desc; /* Fill in EFI IO Media info (for read/write callbacks) */ diskobj->media.removable_media = desc->removable; diskobj->media.media_present = 1; diskobj->media.block_size = desc->blksz; diskobj->media.io_align = desc->blksz; - diskobj->media.last_block = desc->lba; + diskobj->media.last_block = desc->lba - offset; diskobj->ops.media = &diskobj->media; /* Fill in device path */ @@ -240,7 +246,8 @@ static void efi_disk_add_dev(const char *name, static int efi_disk_create_eltorito(struct blk_desc *desc, const char *if_typename, - int diskid) + int diskid, + const char *pdevname) { int disks = 0; #ifdef CONFIG_ISO_PARTITION @@ -252,8 +259,8 @@ static int efi_disk_create_eltorito(struct blk_desc *desc, return 0; while (!part_get_info(desc, part, &info)) { - snprintf(devname, sizeof(devname), "%s%d:%d", if_typename, - diskid, part); + snprintf(devname, sizeof(devname), "%s:%d", pdevname, + part); efi_disk_add_dev(devname, if_typename, desc, diskid, info.start); part++; @@ -296,7 +303,7 @@ int efi_disk_register(void) * so let's create them here */ disks += efi_disk_create_eltorito(desc, if_typename, - desc->devnum); + desc->devnum, dev->name); } #else int i, if_type; @@ -331,7 +338,8 @@ int efi_disk_register(void) * El Torito images show up as block devices * in an EFI world, so let's create them here */ - disks += efi_disk_create_eltorito(desc, if_typename, i); + disks += efi_disk_create_eltorito(desc, if_typename, + i, devname); } } #endif diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c index 574b204f23..5165377eee 100644 --- a/lib/efi_loader/efi_image_loader.c +++ b/lib/efi_loader/efi_image_loader.c @@ -37,7 +37,7 @@ static void efi_loader_relocate(const IMAGE_BASE_RELOCATION *rel, const uint16_t *relocs = (const uint16_t *)(rel + 1); i = (rel->SizeOfBlock - sizeof(*rel)) / sizeof(uint16_t); while (i--) { - uint16_t offset = (*relocs & 0xfff) + + uint32_t offset = (uint32_t)(*relocs & 0xfff) + rel->VirtualAddress; int type = *relocs >> EFI_PAGE_SHIFT; unsigned long delta = (unsigned long)efi_reloc; diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index df2381e42c..df3547c47f 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -130,6 +130,9 @@ uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type, bool carve_again; uint64_t carved_pages = 0; + debug("%s: 0x%" PRIx64 " 0x%" PRIx64 " %d %s\n", __func__, + start, pages, memory_type, overlap_only_ram ? "yes" : "no"); + if (!pages) return start; diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 0534c0b767..e638ca5d6a 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -9,6 +9,7 @@ #include <errno.h> #include <serial.h> #include <libfdt.h> +#include <fdt_support.h> #include <fdtdec.h> #include <asm/sections.h> #include <linux/ctype.h> @@ -19,6 +20,11 @@ DECLARE_GLOBAL_DATA_PTR; * Here are the type we know about. One day we might allow drivers to * register. For now we just put them here. The COMPAT macro allows us to * turn this into a sparse list later, and keeps the ID with the name. + * + * NOTE: This list is basically a TODO list for things that need to be + * converted to driver model. So don't add new things here unless there is a + * good reason why driver-model conversion is infeasible. Examples include + * things which are used before driver model is available. */ #define COMPAT(id, name) name static const char * const compat_names[COMPAT_COUNT] = { @@ -39,13 +45,10 @@ static const char * const compat_names[COMPAT_COUNT] = { COMPAT(SAMSUNG_S3C2440_I2C, "samsung,s3c2440-i2c"), COMPAT(SAMSUNG_EXYNOS5_SOUND, "samsung,exynos-sound"), COMPAT(WOLFSON_WM8994_CODEC, "wolfson,wm8994-codec"), - COMPAT(GOOGLE_CROS_EC_KEYB, "google,cros-ec-keyb"), COMPAT(SAMSUNG_EXYNOS_USB_PHY, "samsung,exynos-usb-phy"), COMPAT(SAMSUNG_EXYNOS5_USB3_PHY, "samsung,exynos5250-usb3-phy"), COMPAT(SAMSUNG_EXYNOS_TMU, "samsung,exynos-tmu"), - COMPAT(SAMSUNG_EXYNOS_FIMD, "samsung,exynos-fimd"), COMPAT(SAMSUNG_EXYNOS_MIPI_DSI, "samsung,exynos-mipi-dsi"), - COMPAT(SAMSUNG_EXYNOS5_DP, "samsung,exynos5-dp"), COMPAT(SAMSUNG_EXYNOS_DWMMC, "samsung,exynos-dwmmc"), COMPAT(SAMSUNG_EXYNOS_MMC, "samsung,exynos-mmc"), COMPAT(MAXIM_MAX77686_PMIC, "maxim,max77686"), @@ -54,20 +57,16 @@ static const char * const compat_names[COMPAT_COUNT] = { COMPAT(SAMSUNG_EXYNOS5_I2C, "samsung,exynos5-hsi2c"), COMPAT(SAMSUNG_EXYNOS_SYSMMU, "samsung,sysmmu-v3.3"), COMPAT(INTEL_MICROCODE, "intel,microcode"), - COMPAT(INTEL_PANTHERPOINT_AHCI, "intel,pantherpoint-ahci"), - COMPAT(INTEL_MODEL_206AX, "intel,model-206ax"), - COMPAT(INTEL_GMA, "intel,gma"), COMPAT(AMS_AS3722, "ams,as3722"), - COMPAT(INTEL_ICH_SPI, "intel,ich-spi"), COMPAT(INTEL_QRK_MRC, "intel,quark-mrc"), COMPAT(SOCIONEXT_XHCI, "socionext,uniphier-xhci"), - COMPAT(COMPAT_INTEL_PCH, "intel,bd82x6x"), COMPAT(ALTERA_SOCFPGA_DWMAC, "altr,socfpga-stmmac"), COMPAT(ALTERA_SOCFPGA_DWMMC, "altr,socfpga-dw-mshc"), COMPAT(ALTERA_SOCFPGA_DWC2USB, "snps,dwc2"), - COMPAT(COMPAT_INTEL_BAYTRAIL_FSP, "intel,baytrail-fsp"), - COMPAT(COMPAT_INTEL_BAYTRAIL_FSP_MDP, "intel,baytrail-fsp-mdp"), - COMPAT(COMPAT_INTEL_IVYBRIDGE_FSP, "intel,ivybridge-fsp"), + COMPAT(INTEL_BAYTRAIL_FSP, "intel,baytrail-fsp"), + COMPAT(INTEL_BAYTRAIL_FSP_MDP, "intel,baytrail-fsp-mdp"), + COMPAT(INTEL_IVYBRIDGE_FSP, "intel,ivybridge-fsp"), + COMPAT(COMPAT_SUNXI_NAND, "allwinner,sun4i-a10-nand"), }; const char *fdtdec_get_compatible(enum fdt_compat_id id) @@ -79,7 +78,7 @@ const char *fdtdec_get_compatible(enum fdt_compat_id id) fdt_addr_t fdtdec_get_addr_size_fixed(const void *blob, int node, const char *prop_name, int index, int na, int ns, - fdt_size_t *sizep) + fdt_size_t *sizep, bool translate) { const fdt32_t *prop, *prop_end; const fdt32_t *prop_addr, *prop_size, *prop_after_size; @@ -114,7 +113,12 @@ fdt_addr_t fdtdec_get_addr_size_fixed(const void *blob, int node, return FDT_ADDR_T_NONE; } - addr = fdtdec_get_number(prop_addr, na); +#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_OF_LIBFDT) + if (translate) + addr = fdt_translate_address(blob, node, prop_addr); + else +#endif + addr = fdtdec_get_number(prop_addr, na); if (sizep) { *sizep = fdtdec_get_number(prop_size, ns); @@ -128,7 +132,8 @@ fdt_addr_t fdtdec_get_addr_size_fixed(const void *blob, int node, } fdt_addr_t fdtdec_get_addr_size_auto_parent(const void *blob, int parent, - int node, const char *prop_name, int index, fdt_size_t *sizep) + int node, const char *prop_name, int index, fdt_size_t *sizep, + bool translate) { int na, ns; @@ -149,11 +154,12 @@ fdt_addr_t fdtdec_get_addr_size_auto_parent(const void *blob, int parent, debug("na=%d, ns=%d, ", na, ns); return fdtdec_get_addr_size_fixed(blob, node, prop_name, index, na, - ns, sizep); + ns, sizep, translate); } fdt_addr_t fdtdec_get_addr_size_auto_noparent(const void *blob, int node, - const char *prop_name, int index, fdt_size_t *sizep) + const char *prop_name, int index, fdt_size_t *sizep, + bool translate) { int parent; @@ -166,7 +172,7 @@ fdt_addr_t fdtdec_get_addr_size_auto_noparent(const void *blob, int node, } return fdtdec_get_addr_size_auto_parent(blob, parent, node, prop_name, - index, sizep); + index, sizep, translate); } fdt_addr_t fdtdec_get_addr_size(const void *blob, int node, @@ -176,7 +182,7 @@ fdt_addr_t fdtdec_get_addr_size(const void *blob, int node, return fdtdec_get_addr_size_fixed(blob, node, prop_name, 0, sizeof(fdt_addr_t) / sizeof(fdt32_t), - ns, sizep); + ns, sizep, false); } fdt_addr_t fdtdec_get_addr(const void *blob, int node, diff --git a/lib/hashtable.c b/lib/hashtable.c index 02b41050a4..4e52b368e4 100644 --- a/lib/hashtable.c +++ b/lib/hashtable.c @@ -602,8 +602,8 @@ ssize_t hexport_r(struct hsearch_data *htab, const char sep, int flag, return (-1); } - debug("EXPORT table = %p, htab.size = %d, htab.filled = %d, " - "size = %zu\n", htab, htab->size, htab->filled, size); + debug("EXPORT table = %p, htab.size = %d, htab.filled = %d, size = %lu\n", + htab, htab->size, htab->filled, (ulong)size); /* * Pass 1: * search used entries, @@ -657,8 +657,8 @@ ssize_t hexport_r(struct hsearch_data *htab, const char sep, int flag, /* Check if the user supplied buffer size is sufficient */ if (size) { if (size < totlen + 1) { /* provided buffer too small */ - printf("Env export buffer too small: %zu, " - "but need %zu\n", size, totlen + 1); + printf("Env export buffer too small: %lu, but need %lu\n", + (ulong)size, (ulong)totlen + 1); __set_errno(ENOMEM); return (-1); } @@ -790,7 +790,7 @@ int himport_r(struct hsearch_data *htab, /* we allocate new space to make sure we can write to the array */ if ((data = malloc(size + 1)) == NULL) { - debug("himport_r: can't malloc %zu bytes\n", size + 1); + debug("himport_r: can't malloc %lu bytes\n", (ulong)size + 1); __set_errno(ENOMEM); return 0; } @@ -822,7 +822,7 @@ int himport_r(struct hsearch_data *htab, * (CONFIG_ENV_SIZE). This heuristics will result in * unreasonably large numbers (and thus memory footprint) for * big flash environments (>8,000 entries for 64 KB - * envrionment size), so we clip it to a reasonable value. + * environment size), so we clip it to a reasonable value. * On the other hand we need to add some more entries for free * space when importing very small buffers. Both boundaries can * be overwritten in the board config file if needed. diff --git a/lib/libfdt/Makefile b/lib/libfdt/Makefile index 8b86c15904..6ef8290f4e 100644 --- a/lib/libfdt/Makefile +++ b/lib/libfdt/Makefile @@ -15,3 +15,5 @@ obj-y += \ fdt_empty_tree.o \ fdt_addresses.o \ fdt_region.o + +obj-$(CONFIG_OF_LIBFDT_OVERLAY) += fdt_overlay.o diff --git a/lib/libfdt/fdt_overlay.c b/lib/libfdt/fdt_overlay.c new file mode 100644 index 0000000000..40b6d27455 --- /dev/null +++ b/lib/libfdt/fdt_overlay.c @@ -0,0 +1,618 @@ +#include "libfdt_env.h" + +#include <fdt.h> +#include <libfdt.h> + +#include "libfdt_internal.h" + +/** + * overlay_get_target_phandle - retrieves the target phandle of a fragment + * @fdto: pointer to the device tree overlay blob + * @fragment: node offset of the fragment in the overlay + * + * overlay_get_target_phandle() retrieves the target phandle of an + * overlay fragment when that fragment uses a phandle (target + * property) instead of a path (target-path property). + * + * returns: + * the phandle pointed by the target property + * 0, if the phandle was not found + * -1, if the phandle was malformed + */ +static uint32_t overlay_get_target_phandle(const void *fdto, int fragment) +{ + const uint32_t *val; + int len; + + val = fdt_getprop(fdto, fragment, "target", &len); + if (!val) + return 0; + + if ((*val == (uint32_t)-1) || (len != sizeof(*val))) + return (uint32_t)-1; + + return fdt32_to_cpu(*val); +} + +/** + * overlay_get_target - retrieves the target phandle of a fragment + * @fdt: Base device tree blob + * @fdto: Device tree overlay blob + * @fragment: node offset of the fragment in the overlay + * + * overlay_get_target() retrieves the target phandle in the base + * device tree of a fragment, no matter how the actual targetting is + * done (through a phandle or a path) + * + * returns: + * the targetted node offset in the base device tree + * Negative error code on error + */ +static int overlay_get_target(const void *fdt, const void *fdto, + int fragment) +{ + uint32_t phandle; + const char *path; + + /* Try first to do a phandle based lookup */ + phandle = overlay_get_target_phandle(fdto, fragment); + if (phandle == (uint32_t)-1) + return -FDT_ERR_BADPHANDLE; + + if (phandle) + return fdt_node_offset_by_phandle(fdt, phandle); + + /* And then a path based lookup */ + path = fdt_getprop(fdto, fragment, "target-path", NULL); + if (!path) + return -FDT_ERR_NOTFOUND; + + return fdt_path_offset(fdt, path); +} + +/** + * overlay_phandle_add_offset - Increases a phandle by an offset + * @fdt: Base device tree blob + * @node: Device tree overlay blob + * @name: Name of the property to modify (phandle or linux,phandle) + * @delta: offset to apply + * + * overlay_phandle_add_offset() increments a node phandle by a given + * offset. + * + * returns: + * 0 on success. + * Negative error code on error + */ +static int overlay_phandle_add_offset(void *fdt, int node, + const char *name, uint32_t delta) +{ + const uint32_t *val; + uint32_t adj_val; + int len; + + val = fdt_getprop(fdt, node, name, &len); + if (!val) + return len; + + if (len != sizeof(*val)) + return -FDT_ERR_BADSTRUCTURE; + + adj_val = fdt32_to_cpu(*val); + if ((adj_val + delta) < adj_val) + return -FDT_ERR_BADPHANDLE; + + adj_val += delta; + return fdt_setprop_inplace_u32(fdt, node, name, adj_val); +} + +/** + * overlay_adjust_node_phandles - Offsets the phandles of a node + * @fdto: Device tree overlay blob + * @node: Offset of the node we want to adjust + * @delta: Offset to shift the phandles of + * + * overlay_adjust_node_phandles() adds a constant to all the phandles + * of a given node. This is mainly use as part of the overlay + * application process, when we want to update all the overlay + * phandles to not conflict with the overlays of the base device tree. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_adjust_node_phandles(void *fdto, int node, + uint32_t delta) +{ + bool found = false; + int child; + int ret; + + ret = overlay_phandle_add_offset(fdto, node, "phandle", delta); + if (ret && ret != -FDT_ERR_NOTFOUND) + return ret; + + if (!ret) + found = true; + + ret = overlay_phandle_add_offset(fdto, node, "linux,phandle", delta); + if (ret && ret != -FDT_ERR_NOTFOUND) + return ret; + + /* + * If neither phandle nor linux,phandle have been found return + * an error. + */ + if (!found && !ret) + return ret; + + fdt_for_each_subnode(fdto, child, node) + overlay_adjust_node_phandles(fdto, child, delta); + + return 0; +} + +/** + * overlay_adjust_local_phandles - Adjust the phandles of a whole overlay + * @fdto: Device tree overlay blob + * @delta: Offset to shift the phandles of + * + * overlay_adjust_local_phandles() adds a constant to all the + * phandles of an overlay. This is mainly use as part of the overlay + * application process, when we want to update all the overlay + * phandles to not conflict with the overlays of the base device tree. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_adjust_local_phandles(void *fdto, uint32_t delta) +{ + /* + * Start adjusting the phandles from the overlay root + */ + return overlay_adjust_node_phandles(fdto, 0, delta); +} + +/** + * overlay_update_local_node_references - Adjust the overlay references + * @fdto: Device tree overlay blob + * @tree_node: Node offset of the node to operate on + * @fixup_node: Node offset of the matching local fixups node + * @delta: Offset to shift the phandles of + * + * overlay_update_local_nodes_references() update the phandles + * pointing to a node within the device tree overlay by adding a + * constant delta. + * + * This is mainly used as part of a device tree application process, + * where you want the device tree overlays phandles to not conflict + * with the ones from the base device tree before merging them. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_update_local_node_references(void *fdto, + int tree_node, + int fixup_node, + uint32_t delta) +{ + int fixup_prop; + int fixup_child; + int ret; + + fdt_for_each_property_offset(fixup_prop, fdto, fixup_node) { + const unsigned char *fixup_val, *tree_val; + const char *name; + int fixup_len; + int tree_len; + int i; + + fixup_val = fdt_getprop_by_offset(fdto, fixup_prop, + &name, &fixup_len); + if (!fixup_val) + return fixup_len; + + tree_val = fdt_getprop(fdto, tree_node, name, &tree_len); + if (!tree_val) + return tree_len; + + for (i = 0; i < fixup_len; i += sizeof(uint32_t)) { + uint32_t adj_val, index; + + index = *(uint32_t *)(fixup_val + i); + index = fdt32_to_cpu(index); + + /* + * phandles to fixup can be unaligned. + * + * Use a memcpy for the architectures that do + * not support unaligned accesses. + */ + memcpy(&adj_val, tree_val + index, sizeof(uint32_t)); + + adj_val = fdt32_to_cpu(adj_val); + adj_val += delta; + adj_val = cpu_to_fdt32(adj_val); + + ret = fdt_setprop_inplace_namelen_partial(fdto, + tree_node, + name, + strlen(name), + index, + &adj_val, + sizeof(adj_val)); + if (ret) + return ret; + } + } + + fdt_for_each_subnode(fdto, fixup_child, fixup_node) { + const char *fixup_child_name = fdt_get_name(fdto, fixup_child, + NULL); + int tree_child; + + tree_child = fdt_subnode_offset(fdto, tree_node, + fixup_child_name); + if (tree_child < 0) + return tree_child; + + ret = overlay_update_local_node_references(fdto, + tree_child, + fixup_child, + delta); + if (ret) + return ret; + } + + return 0; +} + +/** + * overlay_update_local_references - Adjust the overlay references + * @fdto: Device tree overlay blob + * @delta: Offset to shift the phandles of + * + * overlay_update_local_references() update all the phandles pointing + * to a node within the device tree overlay by adding a constant + * delta to not conflict with the base overlay. + * + * This is mainly used as part of a device tree application process, + * where you want the device tree overlays phandles to not conflict + * with the ones from the base device tree before merging them. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_update_local_references(void *fdto, uint32_t delta) +{ + int fixups; + + fixups = fdt_path_offset(fdto, "/__local_fixups__"); + if (fixups < 0) { + /* There's no local phandles to adjust, bail out */ + if (fixups == -FDT_ERR_NOTFOUND) + return 0; + + return fixups; + } + + /* + * Update our local references from the root of the tree + */ + return overlay_update_local_node_references(fdto, 0, fixups, + delta); +} + +/** + * overlay_fixup_one_phandle - Set an overlay phandle to the base one + * @fdt: Base Device Tree blob + * @fdto: Device tree overlay blob + * @symbols_off: Node offset of the symbols node in the base device tree + * @path: Path to a node holding a phandle in the overlay + * @path_len: number of path characters to consider + * @name: Name of the property holding the phandle reference in the overlay + * @name_len: number of name characters to consider + * @index: Index in the overlay property where the phandle is stored + * @label: Label of the node referenced by the phandle + * + * overlay_fixup_one_phandle() resolves an overlay phandle pointing to + * a node in the base device tree. + * + * This is part of the device tree overlay application process, when + * you want all the phandles in the overlay to point to the actual + * base dt nodes. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_fixup_one_phandle(void *fdt, void *fdto, + int symbols_off, + const char *path, uint32_t path_len, + const char *name, uint32_t name_len, + int index, const char *label) +{ + const char *symbol_path; + uint32_t phandle; + int symbol_off, fixup_off; + int prop_len; + + symbol_path = fdt_getprop(fdt, symbols_off, label, + &prop_len); + if (!symbol_path) + return -FDT_ERR_NOTFOUND; + + symbol_off = fdt_path_offset(fdt, symbol_path); + if (symbol_off < 0) + return symbol_off; + + phandle = fdt_get_phandle(fdt, symbol_off); + if (!phandle) + return -FDT_ERR_NOTFOUND; + + fixup_off = fdt_path_offset_namelen(fdto, path, path_len); + if (fixup_off < 0) + return fixup_off; + + phandle = cpu_to_fdt32(phandle); + return fdt_setprop_inplace_namelen_partial(fdto, fixup_off, + name, name_len, index, + &phandle, sizeof(phandle)); +}; + +/** + * overlay_fixup_phandle - Set an overlay phandle to the base one + * @fdt: Base Device Tree blob + * @fdto: Device tree overlay blob + * @symbols_off: Node offset of the symbols node in the base device tree + * @property: Property offset in the overlay holding the list of fixups + * + * overlay_fixup_phandle() resolves all the overlay phandles pointed + * to in a __local_fixup__ property, and updates them to match the + * phandles in use in the base device tree. + * + * This is part of the device tree overlay application process, when + * you want all the phandles in the overlay to point to the actual + * base dt nodes. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off, + int property) +{ + const char *value; + const char *label; + int len; + + value = fdt_getprop_by_offset(fdto, property, + &label, &len); + if (!value) + return len; + + do { + const char *prop_string = value; + const char *path, *name; + uint32_t prop_len = strlen(value); + uint32_t path_len, name_len; + char *sep, *endptr; + int index; + int ret; + + path = prop_string; + sep = memchr(prop_string, ':', prop_len); + if (*sep != ':') + return -FDT_ERR_BADSTRUCTURE; + path_len = sep - path; + + name = sep + 1; + sep = memchr(name, ':', prop_len); + if (*sep != ':') + return -FDT_ERR_BADSTRUCTURE; + name_len = sep - name; + + index = strtoul(sep + 1, &endptr, 10); + if ((*endptr != '\0') || (endptr <= (sep + 1))) + return -FDT_ERR_BADSTRUCTURE; + + len -= prop_len + 1; + value += prop_len + 1; + + ret = overlay_fixup_one_phandle(fdt, fdto, symbols_off, + path, path_len, name, name_len, + index, label); + if (ret) + return ret; + } while (len > 0); + + return 0; +} + +/** + * overlay_fixup_phandles - Resolve the overlay phandles to the base + * device tree + * @fdt: Base Device Tree blob + * @fdto: Device tree overlay blob + * + * overlay_fixup_phandles() resolves all the overlay phandles pointing + * to nodes in the base device tree. + * + * This is one of the steps of the device tree overlay application + * process, when you want all the phandles in the overlay to point to + * the actual base dt nodes. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_fixup_phandles(void *fdt, void *fdto) +{ + int fixups_off, symbols_off; + int property; + + symbols_off = fdt_path_offset(fdt, "/__symbols__"); + fixups_off = fdt_path_offset(fdto, "/__fixups__"); + + fdt_for_each_property_offset(property, fdto, fixups_off) { + int ret; + + ret = overlay_fixup_phandle(fdt, fdto, symbols_off, property); + if (ret) + return ret; + } + + return 0; +} + +/** + * overlay_apply_node - Merge an overlay fragment into the base device tree + * @fdt: Base Device Tree blob + * @target: Node offset in the base device tree to apply the fragment to + * @fdto: Device tree overlay blob + * @fragment: Node offset in the overlay holding the changes to merge + * + * overlay_apply_node() merges an overlay fragment into a target base + * device tree node pointed. + * + * This is part of the final step in the device tree overlay + * application process, when all the phandles have been adjusted and + * resolved and you just have to merge overlay into the base device + * tree. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_apply_node(void *fdt, int target, + void *fdto, int fragment) +{ + int property; + int node; + + fdt_for_each_property_offset(property, fdto, fragment) { + const char *name; + const void *prop; + int prop_len; + int ret; + + prop = fdt_getprop_by_offset(fdto, property, &name, + &prop_len); + if (prop_len == -FDT_ERR_NOTFOUND) + return -FDT_ERR_INTERNAL; + if (prop_len < 0) + return prop_len; + + ret = fdt_setprop(fdt, target, name, prop, prop_len); + if (ret) + return ret; + } + + fdt_for_each_subnode(fdto, node, fragment) { + const char *name = fdt_get_name(fdto, node, NULL); + int nnode; + int ret; + + nnode = fdt_add_subnode(fdt, target, name); + if (nnode == -FDT_ERR_EXISTS) + nnode = fdt_subnode_offset(fdt, target, name); + + if (nnode < 0) + return nnode; + + ret = overlay_apply_node(fdt, nnode, fdto, node); + if (ret) + return ret; + } + + return 0; +} + +/** + * overlay_merge - Merge an overlay into its base device tree + * @fdt: Base Device Tree blob + * @fdto: Device tree overlay blob + * + * overlay_merge() merges an overlay into its base device tree. + * + * This is the final step in the device tree overlay application + * process, when all the phandles have been adjusted and resolved and + * you just have to merge overlay into the base device tree. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_merge(void *dt, void *dto) +{ + int fragment; + + fdt_for_each_subnode(dto, fragment, 0) { + int overlay; + int target; + int ret; + + target = overlay_get_target(dt, dto, fragment); + if (target < 0) + continue; + + overlay = fdt_subnode_offset(dto, fragment, "__overlay__"); + if (overlay < 0) + return overlay; + + ret = overlay_apply_node(dt, target, dto, overlay); + if (ret) + return ret; + } + + return 0; +} + +int fdt_overlay_apply(void *fdt, void *fdto) +{ + uint32_t delta = fdt_get_max_phandle(fdt) + 1; + int ret; + + FDT_CHECK_HEADER(fdt); + FDT_CHECK_HEADER(fdto); + + ret = overlay_adjust_local_phandles(fdto, delta); + if (ret) + goto err; + + ret = overlay_update_local_references(fdto, delta); + if (ret) + goto err; + + ret = overlay_fixup_phandles(fdt, fdto); + if (ret) + goto err; + + ret = overlay_merge(fdt, fdto); + if (ret) + goto err; + + /* + * The overlay has been damaged, erase its magic. + */ + fdt_set_magic(fdto, ~0); + + return 0; + +err: + /* + * The overlay might have been damaged, erase its magic. + */ + fdt_set_magic(fdto, ~0); + + /* + * The base device tree might have been damaged, erase its + * magic. + */ + fdt_set_magic(fdt, ~0); + + return ret; +} diff --git a/lib/libfdt/fdt_ro.c b/lib/libfdt/fdt_ro.c index 12214c2dc2..9cc98db6e2 100644 --- a/lib/libfdt/fdt_ro.c +++ b/lib/libfdt/fdt_ro.c @@ -47,6 +47,32 @@ static int _fdt_string_eq(const void *fdt, int stroffset, return (strnlen(p, len + 1) == len) && (memcmp(p, s, len) == 0); } +uint32_t fdt_get_max_phandle(const void *fdt) +{ + uint32_t max_phandle = 0; + int offset; + + for (offset = fdt_next_node(fdt, -1, NULL);; + offset = fdt_next_node(fdt, offset, NULL)) { + uint32_t phandle; + + if (offset == -FDT_ERR_NOTFOUND) + return max_phandle; + + if (offset < 0) + return 0; + + phandle = fdt_get_phandle(fdt, offset); + if (phandle == (uint32_t)-1) + return 0; + + if (phandle > max_phandle) + max_phandle = phandle; + } + + return 0; +} + int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) { FDT_CHECK_HEADER(fdt); @@ -114,15 +140,15 @@ int fdt_subnode_offset(const void *fdt, int parentoffset, } /* - * Find the next of path seperator, note we need to search for both '/' and ':' + * Find the next of path separator, note we need to search for both '/' and ':' * and then take the first one so that we do the right thing for e.g. * "foo/bar:option" and "bar:option/otheroption", both of which happen, so * first searching for either ':' or '/' does not work. */ -static const char *fdt_path_next_seperator(const char *path) +static const char *fdt_path_next_separator(const char *path, int len) { - const char *sep1 = strchr(path, '/'); - const char *sep2 = strchr(path, ':'); + const void *sep1 = memchr(path, '/', len); + const void *sep2 = memchr(path, ':', len); if (sep1 && sep2) return (sep1 < sep2) ? sep1 : sep2; @@ -132,9 +158,9 @@ static const char *fdt_path_next_seperator(const char *path) return sep2; } -int fdt_path_offset(const void *fdt, const char *path) +int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen) { - const char *end = path + strlen(path); + const char *end = path + namelen; const char *p = path; int offset = 0; @@ -142,7 +168,7 @@ int fdt_path_offset(const void *fdt, const char *path) /* see if we have an alias */ if (*path != '/') { - const char *q = fdt_path_next_seperator(path); + const char *q = fdt_path_next_separator(path, namelen); if (!q) q = end; @@ -155,14 +181,16 @@ int fdt_path_offset(const void *fdt, const char *path) p = q; } - while (*p) { + while (*p && (p < end)) { const char *q; while (*p == '/') p++; + if (*p == '\0' || *p == ':') return offset; - q = fdt_path_next_seperator(p); + + q = fdt_path_next_separator(p, end - p); if (!q) q = end; diff --git a/lib/libfdt/fdt_wip.c b/lib/libfdt/fdt_wip.c index 9fe988655f..216c51287d 100644 --- a/lib/libfdt/fdt_wip.c +++ b/lib/libfdt/fdt_wip.c @@ -14,21 +14,42 @@ #include "libfdt_internal.h" +int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset, + const char *name, int namelen, + uint32_t index, const void *val, + int len) +{ + void *propval; + int proplen; + + propval = fdt_getprop_namelen_w(fdt, nodeoffset, name, namelen, + &proplen); + if (!propval) + return proplen; + + if (proplen < (len + index)) + return -FDT_ERR_NOSPACE; + + memcpy(propval + index, val, len); + return 0; +} + int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, const void *val, int len) { - void *propval; + const void *propval; int proplen; - propval = fdt_getprop_w(fdt, nodeoffset, name, &proplen); + propval = fdt_getprop(fdt, nodeoffset, name, &proplen); if (!propval) return proplen; if (proplen != len) return -FDT_ERR_NOSPACE; - memcpy(propval, val, len); - return 0; + return fdt_setprop_inplace_namelen_partial(fdt, nodeoffset, name, + strlen(name), 0, + val, len); } static void _fdt_nop_region(void *start, int len) diff --git a/lib/libfdt/libfdt.swig b/lib/libfdt/libfdt.swig new file mode 100644 index 0000000000..14f583dfbe --- /dev/null +++ b/lib/libfdt/libfdt.swig @@ -0,0 +1,89 @@ +/* File: libfdt.i */ +%module libfdt + +%{ +#define SWIG_FILE_WITH_INIT +#include "libfdt.h" +%} + +%pythoncode %{ +def Raise(errnum): + raise ValueError('Error %s' % fdt_strerror(errnum)) + +def Name(fdt, offset): + name, len = fdt_get_name(fdt, offset) + return name + +def String(fdt, offset): + offset = fdt32_to_cpu(offset) + name = fdt_string(fdt, offset) + return name + +def swap32(x): + return (((x << 24) & 0xFF000000) | + ((x << 8) & 0x00FF0000) | + ((x >> 8) & 0x0000FF00) | + ((x >> 24) & 0x000000FF)) + +def fdt32_to_cpu(x): + return swap32(x) + +def Data(prop): + set_prop(prop) + return get_prop_data() +%} + +%include "typemaps.i" +%include "cstring.i" + +%typemap(in) void* = char*; + +typedef int fdt32_t; + +struct fdt_property { + fdt32_t tag; + fdt32_t len; + fdt32_t nameoff; + char data[0]; +}; + +/* + * This is a work-around since I'm not sure of a better way to copy out the + * contents of a string. This is used in dtoc/GetProps(). The intent is to + * pass in a pointer to a property and access the data field at the end of + * it. Ideally the Data() function above would be able to do this directly, + * but I'm not sure how to do that. + */ +#pragma SWIG nowarn=454 +%inline %{ + static struct fdt_property *cur_prop; + + void set_prop(struct fdt_property *prop) { + cur_prop = prop; + } +%} + +%cstring_output_allocate_size(char **s, int *sz, free(*$1)); +%inline %{ + void get_prop_data(char **s, int *sz) { + *sz = fdt32_to_cpu(cur_prop->len); + *s = (char *)malloc(*sz); + if (!*s) + *sz = 0; + else + memcpy(*s, cur_prop + 1, *sz); + } +%} + +const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int checklen); +int fdt_path_offset(const void *fdt, const char *path); +int fdt_first_property_offset(const void *fdt, int nodeoffset); +int fdt_next_property_offset(const void *fdt, int offset); +const char *fdt_strerror(int errval); +const struct fdt_property *fdt_get_property_by_offset(const void *fdt, + int offset, + int *OUTPUT); +const char *fdt_get_name(const void *fdt, int nodeoffset, int *OUTPUT); +const char *fdt_string(const void *fdt, int stroffset); +int fdt_first_subnode(const void *fdt, int offset); +int fdt_next_subnode(const void *fdt, int offset); diff --git a/lib/libfdt/setup.py b/lib/libfdt/setup.py new file mode 100644 index 0000000000..62e7bcc1ac --- /dev/null +++ b/lib/libfdt/setup.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +""" +setup.py file for SWIG libfdt +""" + +from distutils.core import setup, Extension +import os +import sys + +# Don't cross-compile - always use the host compiler. +del os.environ['CROSS_COMPILE'] +del os.environ['CC'] + +progname = sys.argv[0] +cflags = sys.argv[1] +files = sys.argv[2:] + +if cflags: + cflags = [flag for flag in cflags.split(' ') if flag] +else: + cflags = None + +libfdt_module = Extension( + '_libfdt', + sources = files, + extra_compile_args = cflags +) + +sys.argv = [progname, '--quiet', 'build_ext', '--inplace'] + +setup (name = 'libfdt', + version = '0.1', + author = "SWIG Docs", + description = """Simple swig libfdt from docs""", + ext_modules = [libfdt_module], + py_modules = ["libfdt"], + ) diff --git a/lib/libfdt/test_libfdt.py b/lib/libfdt/test_libfdt.py new file mode 100644 index 0000000000..14d0da4fb3 --- /dev/null +++ b/lib/libfdt/test_libfdt.py @@ -0,0 +1,14 @@ +#!/usr/bin/python + +import os +import sys + +our_path = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(our_path, '../../b/sandbox_spl/tools')) + +import libfdt + +with open('b/sandbox_spl/u-boot.dtb') as fd: + fdt = fd.read() + +print libfdt.fdt_path_offset(fdt, "/aliases") diff --git a/lib/rsa/rsa-sign.c b/lib/rsa/rsa-sign.c index 5d9716f013..c26f74128f 100644 --- a/lib/rsa/rsa-sign.c +++ b/lib/rsa/rsa-sign.c @@ -420,11 +420,13 @@ static int fdt_add_bignum(void *blob, int noffset, const char *prop_name, BN_rshift(num, num, 32); /* N = N/B */ } + /* + * We try signing with successively increasing size values, so this + * might fail several times + */ ret = fdt_setprop(blob, noffset, prop_name, buf, size); - if (ret) { - fprintf(stderr, "Failed to write public key to FIT\n"); - return -ENOSPC; - } + if (ret) + return -FDT_ERR_NOSPACE; free(buf); BN_free(tmp); BN_free(big2); @@ -508,7 +510,7 @@ int rsa_add_verify_data(struct image_sign_info *info, void *keydest) ret = fdt_setprop_string(keydest, node, FIT_ALGO_PROP, info->algo->name); } - if (info->require_keys) { + if (!ret && info->require_keys) { ret = fdt_setprop_string(keydest, node, "required", info->require_keys); } diff --git a/lib/tiny-printf.c b/lib/tiny-printf.c index b334f053cc..30ac7596d3 100644 --- a/lib/tiny-printf.c +++ b/lib/tiny-printf.c @@ -13,29 +13,33 @@ #include <stdarg.h> #include <serial.h> -/* - * This code in here may execute before the DRAM is initialised, so - * we should make sure that it doesn't touch BSS, which some boards - * put in DRAM. - */ -static char *bf __attribute__ ((section(".data"))); -static char zs __attribute__ ((section(".data"))); +struct printf_info { + char *bf; /* Digit buffer */ + char zs; /* non-zero if a digit has been written */ + char *outstr; /* Next output position for sprintf() */ + + /* Output a character */ + void (*putc)(struct printf_info *info, char ch); +}; -/* Current position in sprintf() output string */ -static char *outstr __attribute__ ((section(".data"))); +void putc_normal(struct printf_info *info, char ch) +{ + putc(ch); +} -static void out(char c) +static void out(struct printf_info *info, char c) { - *bf++ = c; + *info->bf++ = c; } -static void out_dgt(char dgt) +static void out_dgt(struct printf_info *info, char dgt) { - out(dgt + (dgt < 10 ? '0' : 'a' - 10)); - zs = 1; + out(info, dgt + (dgt < 10 ? '0' : 'a' - 10)); + info->zs = 1; } -static void div_out(unsigned int *num, unsigned int div) +static void div_out(struct printf_info *info, unsigned int *num, + unsigned int div) { unsigned char dgt = 0; @@ -44,11 +48,11 @@ static void div_out(unsigned int *num, unsigned int div) dgt++; } - if (zs || dgt > 0) - out_dgt(dgt); + if (info->zs || dgt > 0) + out_dgt(info, dgt); } -int _vprintf(const char *fmt, va_list va, void (*putc)(const char ch)) +int _vprintf(struct printf_info *info, const char *fmt, va_list va) { char ch; char *p; @@ -58,7 +62,7 @@ int _vprintf(const char *fmt, va_list va, void (*putc)(const char ch)) while ((ch = *(fmt++))) { if (ch != '%') { - putc(ch); + info->putc(info, ch); } else { bool lz = false; int width = 0; @@ -76,9 +80,9 @@ int _vprintf(const char *fmt, va_list va, void (*putc)(const char ch)) ch = *fmt++; } } - bf = buf; - p = bf; - zs = 0; + info->bf = buf; + p = info->bf; + info->zs = 0; switch (ch) { case '\0': @@ -88,45 +92,45 @@ int _vprintf(const char *fmt, va_list va, void (*putc)(const char ch)) num = va_arg(va, unsigned int); if (ch == 'd' && (int)num < 0) { num = -(int)num; - out('-'); + out(info, '-'); } if (!num) { - out_dgt(0); + out_dgt(info, 0); } else { for (div = 1000000000; div; div /= 10) - div_out(&num, div); + div_out(info, &num, div); } break; case 'x': num = va_arg(va, unsigned int); if (!num) { - out_dgt(0); + out_dgt(info, 0); } else { for (div = 0x10000000; div; div /= 0x10) - div_out(&num, div); + div_out(info, &num, div); } break; case 'c': - out((char)(va_arg(va, int))); + out(info, (char)(va_arg(va, int))); break; case 's': p = va_arg(va, char*); break; case '%': - out('%'); + out(info, '%'); default: break; } - *bf = 0; - bf = p; - while (*bf++ && width > 0) + *info->bf = 0; + info->bf = p; + while (*info->bf++ && width > 0) width--; while (width-- > 0) - putc(lz ? '0' : ' '); + info->putc(info, lz ? '0' : ' '); if (p) { while ((ch = *p++)) - putc(ch); + info->putc(info, ch); } } } @@ -137,36 +141,44 @@ abort: int vprintf(const char *fmt, va_list va) { - return _vprintf(fmt, va, putc); + struct printf_info info; + + info.putc = putc_normal; + return _vprintf(&info, fmt, va); } int printf(const char *fmt, ...) { + struct printf_info info; + va_list va; int ret; + info.putc = putc_normal; va_start(va, fmt); - ret = _vprintf(fmt, va, putc); + ret = _vprintf(&info, fmt, va); va_end(va); return ret; } -static void putc_outstr(char ch) +static void putc_outstr(struct printf_info *info, char ch) { - *outstr++ = ch; + *info->outstr++ = ch; } int sprintf(char *buf, const char *fmt, ...) { + struct printf_info info; va_list va; int ret; va_start(va, fmt); - outstr = buf; - ret = _vprintf(fmt, va, putc_outstr); + info.outstr = buf; + info.putc = putc_outstr; + ret = _vprintf(&info, fmt, va); va_end(va); - *outstr = '\0'; + *info.outstr = '\0'; return ret; } @@ -174,14 +186,25 @@ int sprintf(char *buf, const char *fmt, ...) /* Note that size is ignored */ int snprintf(char *buf, size_t size, const char *fmt, ...) { + struct printf_info info; va_list va; int ret; va_start(va, fmt); - outstr = buf; - ret = _vprintf(fmt, va, putc_outstr); + info.outstr = buf; + info.putc = putc_outstr; + ret = _vprintf(&info, fmt, va); va_end(va); - *outstr = '\0'; + *info.outstr = '\0'; return ret; } + +void __assert_fail(const char *assertion, const char *file, unsigned line, + const char *function) +{ + /* This will not return */ + printf("%s:%u: %s: Assertion `%s' failed.", file, line, function, + assertion); + hang(); +} |