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