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