void dump_fdt(const void *fdt) { int err; dprintf("FDT @ %p:\n", fdt); if (!fdt) return; err = fdt_check_header(fdt); if (err) { dprintf("fdt error: %s\n", fdt_strerror(err)); return; } dprintf("fdt_totalsize: %d\n", fdt_totalsize(fdt)); dprintf("fdt_off_dt_struct: %d\n", fdt_off_dt_struct(fdt)); dprintf("fdt_off_dt_strings: %d\n", fdt_off_dt_strings(fdt)); dprintf("fdt_off_mem_rsvmap: %d\n", fdt_off_mem_rsvmap(fdt)); dprintf("fdt_version: %d\n", fdt_version(fdt)); dprintf("fdt_last_comp_version: %d\n", fdt_last_comp_version(fdt)); dprintf("fdt_boot_cpuid_phys: %d\n", fdt_boot_cpuid_phys(fdt)); dprintf("fdt_size_dt_strings: %d\n", fdt_size_dt_strings(fdt)); dprintf("fdt_size_dt_struct: %d\n", fdt_size_dt_struct(fdt)); #ifdef FDT_DUMP_NODES dprintf("fdt tree:\n"); int node = -1; int depth = 0; while ((node = fdt_next_node(fdt, node, &depth)) >= 0) { dprintf(DS"node at %d: '%s'\n", DA, node, fdt_get_name(fdt, node, NULL)); #ifdef FDT_DUMP_PROPS int prop, len; const struct fdt_property *property; prop = fdt_first_property_offset(fdt, node); while (prop >= 0) { property = fdt_get_property_by_offset(fdt, prop, &len); if (property == NULL) { dprintf("getting prop at %d: %s\n", prop, fdt_strerror(len)); break; } dprintf(DS" prop at %d: '%s', len %d\n", DA, prop, fdt_string(fdt, fdt32_to_cpu(property->nameoff)), fdt32_to_cpu(property->len)); #ifdef FDT_DUMP_PROP_VALUES dump_hex(property->data, fdt32_to_cpu(property->len), depth); #endif prop = fdt_next_property_offset(fdt, prop); } #endif } #endif }
/* * Get the next property of a package. Return values: * -1: package or previous property does not exist * 0: no more properties * 1: success */ static int ofw_fdt_nextprop(ofw_t ofw, phandle_t package, const char *previous, char *buf, size_t size) { const struct fdt_property *prop; const char *name; int offset; offset = fdt_phandle_offset(package); if (offset < 0) return (-1); /* Find the first prop in the node */ offset = fdt_first_property_offset(fdtp, offset); if (offset < 0) return (0); /* No properties */ if (previous != NULL) { while (offset >= 0) { prop = fdt_get_property_by_offset(fdtp, offset, NULL); if (prop == NULL) return (-1); /* Internal error */ offset = fdt_next_property_offset(fdtp, offset); if (offset < 0) return (0); /* No more properties */ /* Check if the last one was the one we wanted */ name = fdt_string(fdtp, fdt32_to_cpu(prop->nameoff)); if (strcmp(name, previous) == 0) break; } } prop = fdt_get_property_by_offset(fdtp, offset, &offset); if (prop == NULL) return (-1); /* Internal error */ strncpy(buf, fdt_string(fdtp, fdt32_to_cpu(prop->nameoff)), size); return (1); }
/** * h_include() - Include handler function for fdt_find_regions() * * This function decides whether to include or exclude a node, property or * compatible string. The function is defined by fdt_find_regions(). * * The algorithm is documented in the code - disp->invert is 0 for normal * operation, and 1 to invert the sense of all matches. * * See */ static int h_include(void *priv, const void *fdt, int offset, int type, const char *data, int size) { struct display_info *disp = priv; int inc, len; inc = check_type_include(priv, type, data, size); if (disp->include_root && type == FDT_IS_PROP && offset == 0 && inc) return 1; /* * If the node name does not tell us anything, check the * compatible string */ if (inc == -1 && type == FDT_IS_NODE) { debug(" - checking compatible2\n"); data = fdt_getprop(fdt, offset, "compatible", &len); inc = check_type_include(priv, FDT_IS_COMPAT, data, len); } /* If we still have no idea, check for properties in the node */ if (inc != 1 && type == FDT_IS_NODE && (disp->types_inc & FDT_NODE_HAS_PROP)) { debug(" - checking node '%s'\n", fdt_get_name(fdt, offset, NULL)); for (offset = fdt_first_property_offset(fdt, offset); offset > 0 && inc != 1; offset = fdt_next_property_offset(fdt, offset)) { const struct fdt_property *prop; const char *str; prop = fdt_get_property_by_offset(fdt, offset, NULL); if (!prop) continue; str = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); inc = check_type_include(priv, FDT_NODE_HAS_PROP, str, strlen(str)); } if (inc == -1) inc = 0; } switch (inc) { case 1: inc = !disp->invert; break; case 0: inc = disp->invert; break; } debug(" - returning %d\n", inc); return inc; }
const void *fdt_getprop_by_offset(const void *fdt, int offset, const char **namep, int *lenp) { const struct fdt_property *prop; prop = fdt_get_property_by_offset(fdt, offset, lenp); if (!prop) return NULL; if (namep) *namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); return prop->data; }
static void prop_get_fdt(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(obj); int fdt_offset_next, fdt_offset, fdt_depth; void *fdt; if (!drc->fdt) { return; } fdt = drc->fdt; fdt_offset = drc->fdt_start_offset; fdt_depth = 0; do { const char *name = NULL; const struct fdt_property *prop = NULL; int prop_len = 0, name_len = 0; uint32_t tag; tag = fdt_next_tag(fdt, fdt_offset, &fdt_offset_next); switch (tag) { case FDT_BEGIN_NODE: fdt_depth++; name = fdt_get_name(fdt, fdt_offset, &name_len); visit_start_struct(v, NULL, NULL, name, 0, NULL); break; case FDT_END_NODE: /* shouldn't ever see an FDT_END_NODE before FDT_BEGIN_NODE */ g_assert(fdt_depth > 0); visit_end_struct(v, NULL); fdt_depth--; break; case FDT_PROP: { int i; prop = fdt_get_property_by_offset(fdt, fdt_offset, &prop_len); name = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); visit_start_list(v, name, NULL); for (i = 0; i < prop_len; i++) { visit_type_uint8(v, (uint8_t *)&prop->data[i], NULL, NULL); } visit_end_list(v, NULL); break; } default: error_setg(&error_abort, "device FDT in unexpected state: %d", tag); } fdt_offset = fdt_offset_next; } while (fdt_depth != 0); }
static int list_properties(const void *blob, int node) { const struct fdt_property *data; const char *name; int prop; prop = fdt_first_property_offset(blob, node); do { /* */ if (prop < 0) return prop == -FDT_ERR_NOTFOUND ? 0 : prop; data = fdt_get_property_by_offset(blob, prop, NULL); name = fdt_string(blob, fdt32_to_cpu(data->nameoff)); if (name) puts(name); prop = fdt_next_property_offset(blob, prop); } while (1); }
/* * chosen { * bootargs="console=ttyS0,115200 ubi.mtd=4 root=ubi0:rootfs rootfstype=ubifs"; * }; * offset: node "/chosen"의 offset * name: property "bootargs" * namelen: property "bootargs" 길이 * lenp: property 내용의 길이 */ const struct fdt_property *fdt_get_property_namelen(const void *fdt, int offset, const char *name, int namelen, int *lenp) { /* * node안의 property들을 순회하면서 찾고자 하는 name의 property 리턴 * 참고로 아래 for문에서 offset을 계속 받아오면서 값을 체크하고 있음 * 즉, 순회하면서 찾는 property가 없거나 탐색시 에러가 나면 탐색 중단 */ for (offset = fdt_first_property_offset(fdt, offset); (offset >= 0); (offset = fdt_next_property_offset(fdt, offset))) { const struct fdt_property *prop; /* * offset만큼 위치한 property에 접근해서 * lenp에 property의 value의 길이를 저장 * 하지만 에러가 나는 경우엔 for문을 빠져나감 */ if (!(prop = fdt_get_property_by_offset(fdt, offset, lenp))) { offset = -FDT_ERR_INTERNAL; break; } /* * 찾고자 하는 property가 맞는지 확인하고 * 맞다면 가져온 property 구조체를 리턴 */ if (_fdt_string_eq(fdt, fdt32_to_cpu(prop->nameoff), name, namelen)) return prop; } /* * 찾는 property가 없는경우 or property 접근하다 에러가 난 경우 * lenp에 에러값 저장 */ if (lenp) *lenp = offset; return NULL; }
const struct fdt_property *fdt_get_property_namelen(const void *fdt, int offset, const char *name, int namelen, int *lenp) { for (offset = fdt_first_property_offset(fdt, offset); (offset >= 0); (offset = fdt_next_property_offset(fdt, offset))) { const struct fdt_property *prop; if (!(prop = fdt_get_property_by_offset(fdt, offset, lenp))) { offset = -FDT_ERR_INTERNAL; break; } if (_fdt_string_eq(fdt, fdt32_to_cpu(prop->nameoff), name, namelen)) return prop; } if (lenp) *lenp = offset; return NULL; }
static dt_node_t add_device_fdt(dt_node_t parent, void *fdt, int fdt_node, int depth) { const char *name = fdt_get_name(fdt, fdt_node, NULL); printf("%*cEnumerating \"%s\"\n", depth, ' ', name); dt_node_t n = dt_node_alloc(parent, name); if (!n) panic("Out of memory enumerating node \"%s\"\n", name); for (int propoff = fdt_first_property_offset(fdt, fdt_node); propoff >= 0; propoff = fdt_next_property_offset(fdt, propoff)) { int len; const struct fdt_property *fdt_prop = fdt_get_property_by_offset(fdt, propoff, &len); if (!fdt_prop) { panic("Error getting property of \"%s\": %s\n", name, fdt_strerror(len)); } const char *prop_name = fdt_string(fdt, fdt32_to_cpu(fdt_prop->nameoff)); printf("%*c \"%s\" = \"", depth, ' ', prop_name); print_dtval(fdt_prop->data, len); printf("\"\n"); if (!dt_node_set_property(n, prop_name, fdt_prop->data, len)) panic("Out of memory allocating \"%s\":\"%s\"", name, prop_name); } for (int suboff = fdt_first_subnode(fdt, fdt_node); suboff != -FDT_ERR_NOTFOUND; suboff = fdt_next_subnode(fdt, suboff)) { add_device_fdt(n, fdt, suboff, depth + 2); } return n; }
/* TODO: Can we tighten this code up a little? */ int fdtdec_add_aliases_for_id(const void *blob, const char *name, enum fdt_compat_id id, int *node_list, int maxcount) { int name_len = strlen(name); int nodes[maxcount]; int num_found = 0; int offset, node; int alias_node; int count; int i, j; /* find the alias node if present */ alias_node = fdt_path_offset(blob, "/aliases"); /* * start with nothing, and we can assume that the root node can't * match */ memset(nodes, '\0', sizeof(nodes)); /* First find all the compatible nodes */ for (node = count = 0; node >= 0 && count < maxcount;) { node = fdtdec_next_compatible(blob, node, id); if (node >= 0) nodes[count++] = node; } if (node >= 0) debug("%s: warning: maxcount exceeded with alias '%s'\n", __func__, name); /* Now find all the aliases */ for (offset = fdt_first_property_offset(blob, alias_node); offset > 0; offset = fdt_next_property_offset(blob, offset)) { const struct fdt_property *prop; const char *path; int number; int found; node = 0; prop = fdt_get_property_by_offset(blob, offset, NULL); path = fdt_string(blob, fdt32_to_cpu(prop->nameoff)); if (prop->len && 0 == strncmp(path, name, name_len)) node = fdt_path_offset(blob, prop->data); if (node <= 0) continue; /* Get the alias number */ number = simple_strtoul(path + name_len, NULL, 10); if (number < 0 || number >= maxcount) { debug("%s: warning: alias '%s' is out of range\n", __func__, path); continue; } /* Make sure the node we found is actually in our list! */ found = -1; for (j = 0; j < count; j++) if (nodes[j] == node) { found = j; break; } if (found == -1) { debug("%s: warning: alias '%s' points to a node " "'%s' that is missing or is not compatible " " with '%s'\n", __func__, path, fdt_get_name(blob, node, NULL), compat_names[id]); continue; } /* * Add this node to our list in the right place, and mark * it as done. */ if (fdtdec_get_is_enabled(blob, node)) { if (node_list[number]) { debug("%s: warning: alias '%s' requires that " "a node be placed in the list in a " "position which is already filled by " "node '%s'\n", __func__, path, fdt_get_name(blob, node, NULL)); continue; } node_list[number] = node; if (number >= num_found) num_found = number + 1; } nodes[found] = 0; } /* Add any nodes not mentioned by an alias */ for (i = j = 0; i < maxcount; i++) { if (!node_list[i]) { for (; j < maxcount; j++) if (nodes[j] && fdtdec_get_is_enabled(blob, nodes[j])) break; /* Have we run out of nodes to add? */ if (j == maxcount) break; assert(!node_list[i]); node_list[i] = nodes[j++]; if (i >= num_found) num_found = i + 1; } } return num_found; }
/** * display_fdt_by_regions() - Display regions of an FDT source * * This dumps an FDT as source, but only certain regions of it. This is the * final stage of the grep - we have a list of regions we want to display, * and this function displays them. * * @disp: Display structure, holding info about our options * @blob: FDT blob to display * @region: List of regions to display * @count: Number of regions */ static int display_fdt_by_regions(struct display_info *disp, const void *blob, struct fdt_region region[], int count) { struct fdt_region *reg = region, *reg_end = region + count; uint32_t off_mem_rsvmap = fdt_off_mem_rsvmap(blob); int base = fdt_off_dt_struct(blob); int version = fdt_version(blob); int offset, nextoffset; int tag, depth, shift; FILE *f = disp->fout; uint64_t addr, size; int in_region; int file_ofs; int i; if (disp->show_dts_version) fprintf(f, "/dts-v1/;\n"); if (disp->header) { fprintf(f, "// magic:\t\t0x%x\n", fdt_magic(blob)); fprintf(f, "// totalsize:\t\t0x%x (%d)\n", fdt_totalsize(blob), fdt_totalsize(blob)); fprintf(f, "// off_dt_struct:\t0x%x\n", fdt_off_dt_struct(blob)); fprintf(f, "// off_dt_strings:\t0x%x\n", fdt_off_dt_strings(blob)); fprintf(f, "// off_mem_rsvmap:\t0x%x\n", off_mem_rsvmap); fprintf(f, "// version:\t\t%d\n", version); fprintf(f, "// last_comp_version:\t%d\n", fdt_last_comp_version(blob)); if (version >= 2) { fprintf(f, "// boot_cpuid_phys:\t0x%x\n", fdt_boot_cpuid_phys(blob)); } if (version >= 3) { fprintf(f, "// size_dt_strings:\t0x%x\n", fdt_size_dt_strings(blob)); } if (version >= 17) { fprintf(f, "// size_dt_struct:\t0x%x\n", fdt_size_dt_struct(blob)); } fprintf(f, "\n"); } if (disp->flags & FDT_REG_ADD_MEM_RSVMAP) { const struct fdt_reserve_entry *p_rsvmap; p_rsvmap = (const struct fdt_reserve_entry *) ((const char *)blob + off_mem_rsvmap); for (i = 0; ; i++) { addr = fdt64_to_cpu(p_rsvmap[i].address); size = fdt64_to_cpu(p_rsvmap[i].size); if (addr == 0 && size == 0) break; fprintf(f, "/memreserve/ %llx %llx;\n", (unsigned long long)addr, (unsigned long long)size); } } depth = 0; nextoffset = 0; shift = 4; /* 4 spaces per indent */ do { const struct fdt_property *prop; const char *name; int show; int len; offset = nextoffset; /* * Work out the file offset of this offset, and decide * whether it is in the region list or not */ file_ofs = base + offset; if (reg < reg_end && file_ofs >= reg->offset + reg->size) reg++; in_region = reg < reg_end && file_ofs >= reg->offset && file_ofs < reg->offset + reg->size; tag = fdt_next_tag(blob, offset, &nextoffset); if (tag == FDT_END) break; show = in_region || disp->all; if (show && disp->diff) fprintf(f, "%c", in_region ? '+' : '-'); if (!show) { /* Do this here to avoid 'if (show)' in every 'case' */ if (tag == FDT_BEGIN_NODE) depth++; else if (tag == FDT_END_NODE) depth--; continue; } if (tag != FDT_END) { if (disp->show_addr) fprintf(f, "%4x: ", file_ofs); if (disp->show_offset) fprintf(f, "%4x: ", file_ofs - base); } /* Green means included, red means excluded */ if (disp->colour) print_ansi_colour(f, in_region ? COL_GREEN : COL_RED); switch (tag) { case FDT_PROP: prop = fdt_get_property_by_offset(blob, offset, NULL); name = fdt_string(blob, fdt32_to_cpu(prop->nameoff)); fprintf(f, "%*s%s", depth * shift, "", name); utilfdt_print_data(prop->data, fdt32_to_cpu(prop->len)); fprintf(f, ";"); break; case FDT_NOP: fprintf(f, "%*s// [NOP]", depth * shift, ""); break; case FDT_BEGIN_NODE: name = fdt_get_name(blob, offset, &len); fprintf(f, "%*s%s {", depth++ * shift, "", *name ? name : "/"); break; case FDT_END_NODE: fprintf(f, "%*s};", --depth * shift, ""); break; } /* Reset colour back to normal before end of line */ if (disp->colour) print_ansi_colour(f, COL_NONE); fprintf(f, "\n"); } while (1); /* Print a list of strings if requested */ if (disp->list_strings) { const char *str; int str_base = fdt_off_dt_strings(blob); for (offset = 0; offset < fdt_size_dt_strings(blob); offset += strlen(str) + 1) { str = fdt_string(blob, offset); int len = strlen(str) + 1; int show; /* Only print strings that are in the region */ file_ofs = str_base + offset; in_region = reg < reg_end && file_ofs >= reg->offset && file_ofs + len < reg->offset + reg->size; show = in_region || disp->all; if (show && disp->diff) printf("%c", in_region ? '+' : '-'); if (disp->show_addr) printf("%4x: ", file_ofs); if (disp->show_offset) printf("%4x: ", offset); printf("%s\n", str); } } return 0; }
int fdt_find_regions(const void *fdt, char * const inc[], int inc_count, char * const exc_prop[], int exc_prop_count, struct fdt_region region[], int max_regions, char *path, int path_len, int add_string_tab) { int stack[FDT_MAX_DEPTH]; char *end; int nextoffset = 0; uint32_t tag; int count = 0; int start = -1; int depth = -1; int want = 0; int base = fdt_off_dt_struct(fdt); end = path; *end = '\0'; do { const struct fdt_property *prop; const char *name; const char *str; int include = 0; int stop_at = 0; int offset; int len; offset = nextoffset; tag = fdt_next_tag(fdt, offset, &nextoffset); stop_at = nextoffset; switch (tag) { case FDT_PROP: include = want >= 2; stop_at = offset; prop = fdt_get_property_by_offset(fdt, offset, NULL); str = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); if (str_in_list(str, exc_prop, exc_prop_count)) include = 0; break; case FDT_NOP: include = want >= 2; stop_at = offset; break; case FDT_BEGIN_NODE: depth++; if (depth == FDT_MAX_DEPTH) return -FDT_ERR_BADSTRUCTURE; name = fdt_get_name(fdt, offset, &len); if (end - path + 2 + len >= path_len) return -FDT_ERR_NOSPACE; if (end != path + 1) *end++ = '/'; strcpy(end, name); end += len; stack[depth] = want; if (want == 1) stop_at = offset; if (str_in_list(path, inc, inc_count)) want = 2; else if (want) want--; else stop_at = offset; include = want; break; case FDT_END_NODE: include = want; want = stack[depth--]; while (end > path && *--end != '/') ; *end = '\0'; break; case FDT_END: include = 1; break; } if (include && start == -1) { /* Should we merge with previous? */ if (count && count <= max_regions && offset == region[count - 1].offset + region[count - 1].size - base) start = region[--count].offset - base; else start = offset; } if (!include && start != -1) { if (count < max_regions) { region[count].offset = base + start; region[count].size = stop_at - start; } count++; start = -1; } } while (tag != FDT_END); if (nextoffset != fdt_size_dt_struct(fdt)) return -FDT_ERR_BADLAYOUT; /* Add a region for the END tag and the string table */ if (count < max_regions) { region[count].offset = base + start; region[count].size = nextoffset - start; if (add_string_tab) region[count].size += fdt_size_dt_strings(fdt); } count++; return count; }