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