1/* Copyright (c) 2010-2017, The Regents of the University of California 2 * (Regents). All Rights Reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are met: 6 * 1. Redistributions of source code must retain the above copyright 7 * notice, this list of conditions and the following disclaimer. 8 * 2. Redistributions in binary form must reproduce the above copyright 9 * notice, this list of conditions and the following disclaimer in the 10 * documentation and/or other materials provided with the distribution. 11 * 3. Neither the name of the Regents nor the 12 * names of its contributors may be used to endorse or promote products 13 * derived from this software without specific prior written permission. 14 * 15 * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, 16 * SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING 17 * OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS 18 * BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 19 * 20 * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED 23 * HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE 24 * MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 25 */ 26 27/* This file is copied from RISC-V tools. It's modified to work with seL4 */ 28 29#include <stdint.h> 30#include <string.h> 31#include <stdint.h> 32#include <string.h> 33#include <plat/machine/fdt.h> 34#include <config.h> 35#include <util.h> 36 37#define FDT_MAGIC 0xd00dfeed 38#define FDT_VERSION 17 39 40#define FDT_BEGIN_NODE 1 41#define FDT_END_NODE 2 42#define FDT_PROP 3 43#define FDT_NOP 4 44#define FDT_END 9 45 46struct fdt_header { 47 uint32_t magic; 48 uint32_t totalsize; 49 uint32_t off_dt_struct; 50 uint32_t off_dt_strings; 51 uint32_t off_mem_rsvmap; 52 uint32_t version; 53 uint32_t last_comp_version; /* <= 17 */ 54 uint32_t boot_cpuid_phys; 55 uint32_t size_dt_strings; 56 uint32_t size_dt_struct; 57}; 58 59struct fdt_scan_node { 60 const struct fdt_scan_node *parent; 61 const char *name; 62 int address_cells; 63 int size_cells; 64}; 65 66struct fdt_scan_prop { 67 const struct fdt_scan_node *node; 68 const char *name; 69 uint32_t *value; 70 int len; // in bytes of value 71}; 72 73/* workaround because string literals are not supported by the C parser */ 74const char fdt_address_cells[] = {'#', 'a', 'd', 'd', 'r', 'e', 's', 's', '-', 'c', 'e', 'l', 'l', 's', 0}; 75const char fdt_size_cells[] = {'#', 's', 'i', 'z', 'e', '-', 'c', 'e', 'l', 'l', 's', 0}; 76const char fdt_reg[] = {'r', 'e', 'g', 0}; 77const char fdt_device_type[] = {'d', 'e', 'v', 'i', 'c', 'e', '_', 't', 'y', 'p', 'e', 0}; 78const char fdt_memory[] = {'m', 'e', 'm', 'o', 'r', 'y', 0}; 79 80static inline uint32_t bswap(uint32_t x) 81{ 82 uint32_t y = (x & 0x00FF00FF) << 8 | (x & 0xFF00FF00) >> 8; 83 uint32_t z = (y & 0x0000FFFF) << 16 | (y & 0xFFFF0000) >> 16; 84 return z; 85} 86 87struct scan_state { 88 int found_memory; 89 const uint32_t *reg_value; 90 int reg_len; 91}; 92 93static const uint32_t *fdt_get_address(const struct fdt_scan_node *node, const uint32_t *value, uint64_t *result) 94{ 95 *result = 0; 96 for (int cells = node->address_cells; cells > 0; --cells) { 97 *result = (*result << 32) + bswap(*value++); 98 } 99 return value; 100} 101 102static const uint32_t *fdt_get_size(const struct fdt_scan_node *node, const uint32_t *value, uint64_t *result) 103{ 104 *result = 0; 105 for (int cells = node->size_cells; cells > 0; --cells) { 106 *result = (*result << 32) + bswap(*value++); 107 } 108 return value; 109} 110 111static uint32_t *fdt_scan_helper( 112 uint32_t *lex, 113 const char *strings, 114 struct fdt_scan_node *node, 115 struct scan_state *state) 116{ 117 struct fdt_scan_node child; 118 struct fdt_scan_prop prop; 119 int UNUSED last = 0; 120 121 child.parent = node; 122 // these are the default cell counts, as per the FDT spec 123 child.address_cells = 2; 124 child.size_cells = 1; 125 prop.node = node; 126 127 while (1) { 128 switch (bswap(lex[0])) { 129 case FDT_NOP: { 130 lex += 1; 131 break; 132 } 133 case FDT_PROP: { 134 assert (!last); 135 prop.name = strings + bswap(lex[2]); 136 prop.len = bswap(lex[1]); 137 prop.value = lex + 3; 138 if (node && !strncmp(prop.name, fdt_address_cells, 14)) { 139 node->address_cells = bswap(lex[3]); 140 } 141 if (node && !strncmp(prop.name, fdt_size_cells, 11)) { 142 node->size_cells = bswap(lex[3]); 143 } 144 lex += 3 + (prop.len + 3) / 4; 145 if (state->found_memory && strncmp(prop.name, fdt_reg, 3) == 0) { 146 state->reg_value = prop.value; 147 state->reg_len = prop.len; 148 } 149 if (strncmp(prop.name, fdt_device_type, 11) == 0 && strncmp((const char*)prop.value, fdt_memory, 6) == 0) { 150 state->found_memory = 1; 151 } 152 break; 153 } 154 case FDT_BEGIN_NODE: { 155 uint32_t *lex_next; 156 last = 1; 157 child.name = (const char *)(lex + 1); 158 lex_next = fdt_scan_helper( 159 lex + 2 + strnlen(child.name, 1024) / 4, 160 strings, &child, state); 161 lex = lex_next; 162 break; 163 } 164 case FDT_END_NODE: { 165 if (state->found_memory) { 166 const uint32_t *value = state->reg_value; 167 const uint32_t *end = value + state->reg_len / 4; 168 169 assert (state->reg_value && state->reg_len % 4 == 0); 170 171 while (end - value > 0) { 172 uint64_t base, size; 173 value = fdt_get_address(node->parent, value, &base); 174 value = fdt_get_size (node->parent, value, &size); 175 if (!add_avail_p_reg((p_region_t) { 176 base, base + size 177 })) { 178 printf("Failed to add physical memory region %llu-%llu\n", (unsigned long long)base, (unsigned long long)(base + size)); 179 } 180 } 181 state->found_memory = 0; 182 } 183 return lex + 1; 184 } 185 default: { // FDT_END 186 return lex; 187 } 188 } 189 } 190} 191 192void parseFDT(void *fdt) 193{ 194 struct fdt_header *header = (struct fdt_header *)fdt; 195 196 // Only process FDT that we understand 197 if (bswap(header->magic) != FDT_MAGIC || 198 bswap(header->last_comp_version) > FDT_VERSION) { 199 return; 200 } 201 202 const char *strings = (const char *)((word_t)fdt + bswap(header->off_dt_strings)); 203 uint32_t *lex = (uint32_t *)((word_t)fdt + bswap(header->off_dt_struct)); 204 205 struct scan_state state; 206 state.found_memory = 0; 207 208 fdt_scan_helper(lex, strings, 0, &state); 209} 210 211uint32_t fdt_size(void *fdt) 212{ 213 struct fdt_header *header = (struct fdt_header *)fdt; 214 215 // Only process FDT that we understand 216 if (bswap(header->magic) != FDT_MAGIC || 217 bswap(header->last_comp_version) > FDT_VERSION) { 218 return 0; 219 } 220 return bswap(header->totalsize); 221} 222