1 /* 2 * libfdt - Flat Device Tree manipulation 3 * Copyright (C) 2006 David Gibson, IBM Corporation. 4 * SPDX-License-Identifier: GPL-2.0+ BSD-2-Clause 5 */ 6 #include <libfdt_env.h> 7 8 #ifndef USE_HOSTCC 9 #include <fdt.h> 10 #include <libfdt.h> 11 #else 12 #include "fdt_host.h" 13 #endif 14 15 #include "libfdt_internal.h" 16 17 int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset, 18 const char *name, int namelen, 19 uint32_t idx, const void *val, 20 int len) 21 { 22 void *propval; 23 int proplen; 24 25 propval = fdt_getprop_namelen_w(fdt, nodeoffset, name, namelen, 26 &proplen); 27 if (!propval) 28 return proplen; 29 30 if (proplen < (len + idx)) 31 return -FDT_ERR_NOSPACE; 32 33 memcpy((char *)propval + idx, val, len); 34 return 0; 35 } 36 37 int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, 38 const void *val, int len) 39 { 40 const void *propval; 41 int proplen; 42 43 propval = fdt_getprop(fdt, nodeoffset, name, &proplen); 44 if (!propval) 45 return proplen; 46 47 if (proplen != len) 48 return -FDT_ERR_NOSPACE; 49 50 return fdt_setprop_inplace_namelen_partial(fdt, nodeoffset, name, 51 strlen(name), 0, 52 val, len); 53 } 54 55 static void _fdt_nop_region(void *start, int len) 56 { 57 fdt32_t *p; 58 59 for (p = start; (char *)p < ((char *)start + len); p++) 60 *p = cpu_to_fdt32(FDT_NOP); 61 } 62 63 int fdt_nop_property(void *fdt, int nodeoffset, const char *name) 64 { 65 struct fdt_property *prop; 66 int len; 67 68 prop = fdt_get_property_w(fdt, nodeoffset, name, &len); 69 if (!prop) 70 return len; 71 72 _fdt_nop_region(prop, len + sizeof(*prop)); 73 74 return 0; 75 } 76 77 int _fdt_node_end_offset(void *fdt, int offset) 78 { 79 int depth = 0; 80 81 while ((offset >= 0) && (depth >= 0)) 82 offset = fdt_next_node(fdt, offset, &depth); 83 84 return offset; 85 } 86 87 int fdt_nop_node(void *fdt, int nodeoffset) 88 { 89 int endoffset; 90 91 endoffset = _fdt_node_end_offset(fdt, nodeoffset); 92 if (endoffset < 0) 93 return endoffset; 94 95 _fdt_nop_region(fdt_offset_ptr_w(fdt, nodeoffset, 0), 96 endoffset - nodeoffset); 97 return 0; 98 } 99 100 #define FDT_MAX_DEPTH 32 101 102 static int str_in_list(const char *str, char * const list[], int count) 103 { 104 int i; 105 106 for (i = 0; i < count; i++) 107 if (!strcmp(list[i], str)) 108 return 1; 109 110 return 0; 111 } 112 113 int fdt_find_regions(const void *fdt, char * const inc[], int inc_count, 114 char * const exc_prop[], int exc_prop_count, 115 struct fdt_region region[], int max_regions, 116 char *path, int path_len, int add_string_tab) 117 { 118 int stack[FDT_MAX_DEPTH]; 119 char *end; 120 int nextoffset = 0; 121 uint32_t tag; 122 int count = 0; 123 int start = -1; 124 int depth = -1; 125 int want = 0; 126 int base = fdt_off_dt_struct(fdt); 127 128 end = path; 129 *end = '\0'; 130 do { 131 const struct fdt_property *prop; 132 const char *name; 133 const char *str; 134 int include = 0; 135 int stop_at = 0; 136 int offset; 137 int len; 138 139 offset = nextoffset; 140 tag = fdt_next_tag(fdt, offset, &nextoffset); 141 stop_at = nextoffset; 142 143 switch (tag) { 144 case FDT_PROP: 145 include = want >= 2; 146 stop_at = offset; 147 prop = fdt_get_property_by_offset(fdt, offset, NULL); 148 str = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); 149 if (str_in_list(str, exc_prop, exc_prop_count)) 150 include = 0; 151 break; 152 153 case FDT_NOP: 154 include = want >= 2; 155 stop_at = offset; 156 break; 157 158 case FDT_BEGIN_NODE: 159 depth++; 160 if (depth == FDT_MAX_DEPTH) 161 return -FDT_ERR_BADSTRUCTURE; 162 name = fdt_get_name(fdt, offset, &len); 163 if (end - path + 2 + len >= path_len) 164 return -FDT_ERR_NOSPACE; 165 if (end != path + 1) 166 *end++ = '/'; 167 strcpy(end, name); 168 end += len; 169 stack[depth] = want; 170 if (want == 1) 171 stop_at = offset; 172 if (str_in_list(path, inc, inc_count)) 173 want = 2; 174 else if (want) 175 want--; 176 else 177 stop_at = offset; 178 include = want; 179 break; 180 181 case FDT_END_NODE: 182 include = want; 183 want = stack[depth--]; 184 while (end > path && *--end != '/') 185 ; 186 *end = '\0'; 187 break; 188 189 case FDT_END: 190 include = 1; 191 break; 192 } 193 194 if (include && start == -1) { 195 /* Should we merge with previous? */ 196 if (count && count <= max_regions && 197 offset == region[count - 1].offset + 198 region[count - 1].size - base) 199 start = region[--count].offset - base; 200 else 201 start = offset; 202 } 203 204 if (!include && start != -1) { 205 if (count < max_regions) { 206 region[count].offset = base + start; 207 region[count].size = stop_at - start; 208 } 209 count++; 210 start = -1; 211 } 212 } while (tag != FDT_END); 213 214 if (nextoffset != fdt_size_dt_struct(fdt)) 215 return -FDT_ERR_BADLAYOUT; 216 217 /* Add a region for the END tag and the string table */ 218 if (count < max_regions) { 219 region[count].offset = base + start; 220 region[count].size = nextoffset - start; 221 if (add_string_tab) 222 region[count].size += fdt_size_dt_strings(fdt); 223 } 224 count++; 225 226 return count; 227 } 228