1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright (c) 2016, Linaro Limited 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright notice, 10 * this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright notice, 13 * this list of conditions and the following disclaimer in the documentation 14 * and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <assert.h> 30 #include <kernel/dt.h> 31 #include <kernel/linker.h> 32 #include <libfdt.h> 33 #include <mm/core_memprot.h> 34 #include <mm/core_mmu.h> 35 #include <string.h> 36 #include <trace.h> 37 38 const struct dt_driver *dt_find_compatible_driver(const void *fdt, int offs) 39 { 40 const struct dt_device_match *dm; 41 const struct dt_driver *drv; 42 43 for_each_dt_driver(drv) 44 for (dm = drv->match_table; dm; dm++) 45 if (!fdt_node_check_compatible(fdt, offs, 46 dm->compatible)) 47 return drv; 48 49 return NULL; 50 } 51 52 const struct dt_driver *__dt_driver_start(void) 53 { 54 return &__rodata_dtdrv_start; 55 } 56 57 const struct dt_driver *__dt_driver_end(void) 58 { 59 return &__rodata_dtdrv_end; 60 } 61 62 bool dt_have_prop(const void *fdt, int offs, const char *propname) 63 { 64 const void *prop; 65 66 prop = fdt_getprop(fdt, offs, propname, NULL); 67 68 return prop; 69 } 70 71 int dt_map_dev(const void *fdt, int offs, vaddr_t *base, size_t *size) 72 { 73 enum teecore_memtypes mtype; 74 paddr_t pbase; 75 vaddr_t vbase; 76 ssize_t sz; 77 int st; 78 79 assert(cpu_mmu_enabled()); 80 81 st = _fdt_get_status(fdt, offs); 82 if (st == DT_STATUS_DISABLED) 83 return -1; 84 85 pbase = _fdt_reg_base_address(fdt, offs); 86 if (pbase == (paddr_t)-1) 87 return -1; 88 sz = _fdt_reg_size(fdt, offs); 89 if (sz < 0) 90 return -1; 91 92 if ((st & DT_STATUS_OK_SEC) && !(st & DT_STATUS_OK_NSEC)) 93 mtype = MEM_AREA_IO_SEC; 94 else 95 mtype = MEM_AREA_IO_NSEC; 96 97 /* Check if we have a mapping, create one if needed */ 98 if (!core_mmu_add_mapping(mtype, pbase, sz)) { 99 EMSG("Failed to map %zu bytes at PA 0x%"PRIxPA, 100 (size_t)sz, pbase); 101 return -1; 102 } 103 vbase = (vaddr_t)phys_to_virt(pbase, mtype); 104 if (!vbase) { 105 EMSG("Failed to get VA for PA 0x%"PRIxPA, pbase); 106 return -1; 107 } 108 109 *base = vbase; 110 *size = sz; 111 return 0; 112 } 113 114 /* Read a physical address (n=1 or 2 cells) */ 115 static paddr_t _fdt_read_paddr(const uint32_t *cell, int n) 116 { 117 paddr_t addr; 118 119 if (n < 1 || n > 2) 120 goto bad; 121 122 addr = fdt32_to_cpu(*cell); 123 cell++; 124 if (n == 2) { 125 #ifdef ARM32 126 if (addr) { 127 /* High order 32 bits can't be nonzero */ 128 goto bad; 129 } 130 addr = fdt32_to_cpu(*cell); 131 #else 132 addr = (addr << 32) | fdt32_to_cpu(*cell); 133 #endif 134 } 135 136 if (!addr) 137 goto bad; 138 139 return addr; 140 bad: 141 return (paddr_t)-1; 142 143 } 144 145 paddr_t _fdt_reg_base_address(const void *fdt, int offs) 146 { 147 const void *reg; 148 int ncells; 149 int len; 150 int parent; 151 152 parent = fdt_parent_offset(fdt, offs); 153 if (parent < 0) 154 return (paddr_t)-1; 155 156 reg = fdt_getprop(fdt, offs, "reg", &len); 157 if (!reg) 158 return (paddr_t)-1; 159 160 ncells = fdt_address_cells(fdt, parent); 161 if (ncells < 0) 162 return (paddr_t)-1; 163 164 return _fdt_read_paddr(reg, ncells); 165 } 166 167 ssize_t _fdt_reg_size(const void *fdt, int offs) 168 { 169 const uint32_t *reg; 170 uint32_t sz; 171 int n; 172 int len; 173 int parent; 174 175 parent = fdt_parent_offset(fdt, offs); 176 if (parent < 0) 177 return (paddr_t)-1; 178 179 reg = (const uint32_t *)fdt_getprop(fdt, offs, "reg", &len); 180 if (!reg) 181 return -1; 182 183 n = fdt_address_cells(fdt, parent); 184 if (n < 1 || n > 2) 185 return -1; 186 187 reg += n; 188 189 n = fdt_size_cells(fdt, parent); 190 if (n < 1 || n > 2) 191 return -1; 192 193 sz = fdt32_to_cpu(*reg); 194 if (n == 2) { 195 if (sz) 196 return -1; 197 reg++; 198 sz = fdt32_to_cpu(*reg); 199 } 200 201 return sz; 202 } 203 204 static bool is_okay(const char *st, int len) 205 { 206 return !strncmp(st, "ok", len) || !strncmp(st, "okay", len); 207 } 208 209 int _fdt_get_status(const void *fdt, int offs) 210 { 211 const char *prop; 212 int st = 0; 213 int len; 214 215 prop = fdt_getprop(fdt, offs, "status", &len); 216 if (!prop || is_okay(prop, len)) { 217 /* If status is not specified, it defaults to "okay" */ 218 st |= DT_STATUS_OK_NSEC; 219 } 220 221 prop = fdt_getprop(fdt, offs, "secure-status", &len); 222 if (!prop) { 223 /* 224 * When secure-status is not specified it defaults to the same 225 * value as status 226 */ 227 if (st & DT_STATUS_OK_NSEC) 228 st |= DT_STATUS_OK_SEC; 229 } else { 230 if (is_okay(prop, len)) 231 st |= DT_STATUS_OK_SEC; 232 } 233 234 return st; 235 } 236