diff options
author | AKASHI Takahiro <takahiro.akashi@linaro.org> | 2019-03-27 15:15:52 +0900 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2020-03-02 07:52:19 +0100 |
commit | d5203fed1025d02e704bcf74f982a979797c8ec6 (patch) | |
tree | ec0b91a708a324ce47ceb9206984a8e1f92ab3d7 | |
parent | Revert "libfdt: Add phandle generation helper" (diff) | |
download | rtems-d5203fed1025d02e704bcf74f982a979797c8ec6.tar.bz2 |
libfdt: add fdt_append_addrrange()
This function will append an address range property using parent node's
"#address-cells" and "#size-cells" properties.
It will be used in implementing kdump with kexec_file_load system call
at linux kernel for arm64 once it is merged into kernel tree.
Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
Message-Id: <20190327061552.17170-2-takahiro.akashi@linaro.org>
[dwg: Correct a SEGV error in the testcase]
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
-rw-r--r-- | cpukit/dtc/libfdt/fdt_addresses.c | 47 | ||||
-rw-r--r-- | cpukit/include/libfdt.h | 61 |
2 files changed, 108 insertions, 0 deletions
diff --git a/cpukit/dtc/libfdt/fdt_addresses.c b/cpukit/dtc/libfdt/fdt_addresses.c index f13a87dfa0..2cc997ea50 100644 --- a/cpukit/dtc/libfdt/fdt_addresses.c +++ b/cpukit/dtc/libfdt/fdt_addresses.c @@ -95,3 +95,50 @@ int fdt_size_cells(const void *fdt, int nodeoffset) return 1; return val; } + +/* This function assumes that [address|size]_cells is 1 or 2 */ +int fdt_appendprop_addrrange(void *fdt, int parent, int nodeoffset, + const char *name, uint64_t addr, uint64_t size) +{ + int addr_cells, size_cells, ret; + uint8_t data[sizeof(fdt64_t) * 2], *prop; + + ret = fdt_address_cells(fdt, parent); + if (ret < 0) + return ret; + addr_cells = ret; + + ret = fdt_size_cells(fdt, parent); + if (ret < 0) + return ret; + size_cells = ret; + + /* check validity of address */ + prop = data; + if (addr_cells == 1) { + if ((addr > UINT32_MAX) || ((UINT32_MAX + 1 - addr) < size)) + return -FDT_ERR_BADVALUE; + + fdt32_st(prop, (uint32_t)addr); + } else if (addr_cells == 2) { + fdt64_st(prop, addr); + } else { + return -FDT_ERR_BADNCELLS; + } + + /* check validity of size */ + prop += addr_cells * sizeof(fdt32_t); + if (size_cells == 1) { + if (size > UINT32_MAX) + return -FDT_ERR_BADVALUE; + + fdt32_st(prop, (uint32_t)size); + } else if (size_cells == 2) { + fdt64_st(prop, size); + } else { + return -FDT_ERR_BADNCELLS; + } + + return fdt_appendprop(fdt, nodeoffset, name, data, + (addr_cells + size_cells) * sizeof(fdt32_t)); +} diff --git a/cpukit/include/libfdt.h b/cpukit/include/libfdt.h index a470d1df6d..e70f5bf7e8 100644 --- a/cpukit/include/libfdt.h +++ b/cpukit/include/libfdt.h @@ -171,6 +171,16 @@ static inline uint32_t fdt32_ld(const fdt32_t *p) | bp[3]; } +static inline void fdt32_st(void *property, uint32_t value) +{ + uint8_t *bp = property; + + bp[0] = value >> 24; + bp[1] = (value >> 16) & 0xff; + bp[2] = (value >> 8) & 0xff; + bp[3] = value & 0xff; +} + static inline uint64_t fdt64_ld(const fdt64_t *p) { const uint8_t *bp = (const uint8_t *)p; @@ -185,6 +195,20 @@ static inline uint64_t fdt64_ld(const fdt64_t *p) | bp[7]; } +static inline void fdt64_st(void *property, uint64_t value) +{ + uint8_t *bp = property; + + bp[0] = value >> 56; + bp[1] = (value >> 48) & 0xff; + bp[2] = (value >> 40) & 0xff; + bp[3] = (value >> 32) & 0xff; + bp[4] = (value >> 24) & 0xff; + bp[5] = (value >> 16) & 0xff; + bp[6] = (value >> 8) & 0xff; + bp[7] = value & 0xff; +} + /**********************************************************************/ /* Traversal functions */ /**********************************************************************/ @@ -1832,6 +1856,43 @@ static inline int fdt_appendprop_cell(void *fdt, int nodeoffset, fdt_appendprop((fdt), (nodeoffset), (name), (str), strlen(str)+1) /** + * fdt_appendprop_addrrange - append a address range property + * @fdt: pointer to the device tree blob + * @parent: offset of the parent node + * @nodeoffset: offset of the node to add a property at + * @name: name of property + * @addr: start address of a given range + * @size: size of a given range + * + * fdt_appendprop_addrrange() appends an address range value (start + * address and size) to the value of the named property in the given + * node, or creates a new property with that value if it does not + * already exist. + * If "name" is not specified, a default "reg" is used. + * Cell sizes are determined by parent's #address-cells and #size-cells. + * + * This function may insert data into the blob, and will therefore + * change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid + * #address-cells property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADVALUE, addr or size doesn't fit to respective cells size + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain a new property + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_appendprop_addrrange(void *fdt, int parent, int nodeoffset, + const char *name, uint64_t addr, uint64_t size); + +/** * fdt_delprop - delete a property * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to nop |