1 // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) 2 /* 3 * libfdt - Flat Device Tree manipulation 4 * Copyright (C) 2014 David Gibson <david@gibson.dropbear.id.au> 5 * Copyright (C) 2018 embedded brains GmbH 6 */ 7 #include "libfdt_env.h" 8 9 #include <fdt.h> 10 #include <libfdt.h> 11 12 #include "libfdt_internal.h" 13 14 static int fdt_cells(const void *fdt, int nodeoffset, const char *name) 15 { 16 const fdt32_t *c; 17 uint32_t val; 18 int len; 19 20 c = fdt_getprop(fdt, nodeoffset, name, &len); 21 if (!c) 22 return len; 23 24 if (len != sizeof(*c)) 25 return -FDT_ERR_BADNCELLS; 26 27 val = fdt32_to_cpu(*c); 28 if (val > FDT_MAX_NCELLS) 29 return -FDT_ERR_BADNCELLS; 30 31 return (int)val; 32 } 33 34 int fdt_address_cells(const void *fdt, int nodeoffset) 35 { 36 int val; 37 38 val = fdt_cells(fdt, nodeoffset, "#address-cells"); 39 if (val == 0) 40 return -FDT_ERR_BADNCELLS; 41 if (val == -FDT_ERR_NOTFOUND) 42 return 2; 43 return val; 44 } 45 46 int fdt_size_cells(const void *fdt, int nodeoffset) 47 { 48 int val; 49 50 val = fdt_cells(fdt, nodeoffset, "#size-cells"); 51 if (val == -FDT_ERR_NOTFOUND) 52 return 1; 53 return val; 54 } 55 56 /* This function assumes that [address|size]_cells is 1 or 2 */ 57 int fdt_appendprop_addrrange(void *fdt, int parent, int nodeoffset, 58 const char *name, uint64_t addr, uint64_t size) 59 { 60 int addr_cells, size_cells, ret; 61 uint8_t data[sizeof(fdt64_t) * 2], *prop; 62 63 ret = fdt_address_cells(fdt, parent); 64 if (ret < 0) 65 return ret; 66 addr_cells = ret; 67 68 ret = fdt_size_cells(fdt, parent); 69 if (ret < 0) 70 return ret; 71 size_cells = ret; 72 73 /* check validity of address */ 74 prop = data; 75 if (addr_cells == 1) { 76 if ((addr > UINT32_MAX) || (((uint64_t) UINT32_MAX + 1 - addr) < size)) 77 return -FDT_ERR_BADVALUE; 78 79 fdt32_st(prop, (uint32_t)addr); 80 } else if (addr_cells == 2) { 81 fdt64_st(prop, addr); 82 } else { 83 return -FDT_ERR_BADNCELLS; 84 } 85 86 /* check validity of size */ 87 prop += addr_cells * sizeof(fdt32_t); 88 if (size_cells == 1) { 89 if (size > UINT32_MAX) 90 return -FDT_ERR_BADVALUE; 91 92 fdt32_st(prop, (uint32_t)size); 93 } else if (size_cells == 2) { 94 fdt64_st(prop, size); 95 } else { 96 return -FDT_ERR_BADNCELLS; 97 } 98 99 return fdt_appendprop(fdt, nodeoffset, name, data, 100 (addr_cells + size_cells) * sizeof(fdt32_t)); 101 } 102