/** * Decode a list of GPIOs from an FDT. This creates a list of GPIOs with no * terminating item. * * @param blob FDT blob to use * @param node Node to look at * @param prop_name Node property name * @param gpio Array of gpio elements to fill from FDT. This will be * untouched if either 0 or an error is returned * @param max_count Maximum number of elements allowed * @return number of GPIOs read if ok, -FDT_ERR_BADLAYOUT if max_count would * be exceeded, or -FDT_ERR_NOTFOUND if the property is missing. */ int fdtdec_decode_gpios(const void *blob, int node, const char *prop_name, struct fdt_gpio_state *gpio, int max_count) { const struct fdt_property *prop; const u32 *cell; const char *name; int len, i; debug("%s: %s\n", __func__, prop_name); assert(max_count > 0); prop = fdt_get_property(blob, node, prop_name, &len); if (!prop) { debug("%s: property '%s' missing\n", __func__, prop_name); return -FDT_ERR_NOTFOUND; } /* We will use the name to tag the GPIO */ name = fdt_string(blob, fdt32_to_cpu(prop->nameoff)); cell = (u32 *)prop->data; len /= sizeof(u32) * 3; /* 3 cells per GPIO record */ if (len > max_count) { debug(" %s: too many GPIOs / cells for " "property '%s'\n", __func__, prop_name); return -FDT_ERR_BADLAYOUT; } /* Read out the GPIO data from the cells */ for (i = 0; i < len; i++, cell += 3) { gpio[i].gpio = fdt32_to_cpu(cell[1]); gpio[i].flags = fdt32_to_cpu(cell[2]); gpio[i].name = name; } return len; }
static int fdt_nextprop(int offset, char *buf, size_t size) { const struct fdt_property *prop; const char *name; uint32_t tag; int nextoffset, depth; depth = 0; tag = fdt_next_tag(fdtp, offset, &nextoffset); /* Find the next prop */ do { offset = nextoffset; tag = fdt_next_tag(fdtp, offset, &nextoffset); if (tag == FDT_BEGIN_NODE) depth++; else if (tag == FDT_END_NODE) depth--; else if ((tag == FDT_PROP) && (depth == 0)) { prop = (const struct fdt_property *)fdt_offset_ptr(fdtp, offset, sizeof(*prop)); name = fdt_string(fdtp, fdt32_to_cpu(prop->nameoff)); strncpy(buf, name, size); return (strlen(name)); } else depth = -1; } while (depth >= 0); return (-1); }
static int _fdt_string_eq(const void *fdt, int stroffset, const char *s, int len) { const char *p = fdt_string(fdt, stroffset); return (strlen(p) == len) && (memcmp(p, s, len) == 0); }
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); }
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; }
const struct fdt_property *fdt_get_property(const void *fdt, int nodeoffset, const char *name, int *lenp) { uint32_t tag; const struct fdt_property *prop; int namestroff; int offset, nextoffset; int err; if ((err = fdt_check_header(fdt)) != 0) goto fail; err = -FDT_ERR_BADOFFSET; if (nodeoffset % FDT_TAGSIZE) goto fail; tag = fdt_next_tag(fdt, nodeoffset, &nextoffset); if (tag != FDT_BEGIN_NODE) goto fail; do { offset = nextoffset; tag = fdt_next_tag(fdt, offset, &nextoffset); switch (tag) { case FDT_END: err = -FDT_ERR_TRUNCATED; goto fail; case FDT_BEGIN_NODE: case FDT_END_NODE: case FDT_NOP: break; case FDT_PROP: err = -FDT_ERR_BADSTRUCTURE; prop = fdt_offset_ptr(fdt, offset, sizeof(*prop)); if (! prop) goto fail; namestroff = fdt32_to_cpu(prop->nameoff); if (streq(fdt_string(fdt, namestroff), name)) { /* Found it! */ int len = fdt32_to_cpu(prop->len); prop = fdt_offset_ptr(fdt, offset, sizeof(*prop)+len); if (! prop) goto fail; if (lenp) *lenp = len; return prop; } break; default: err = -FDT_ERR_BADSTRUCTURE; goto fail; } } while ((tag != FDT_BEGIN_NODE) && (tag != FDT_END_NODE)); err = -FDT_ERR_NOTFOUND; fail: if (lenp) *lenp = err; return NULL; }
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; }
/* 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; }
static void compare_structure(const void *fdt1, const void *fdt2) { int nextoffset1 = 0, nextoffset2 = 0; int offset1, offset2; uint32_t tag1, tag2; const char *name1, *name2; int err; const struct fdt_property *prop1, *prop2; int len1, len2; while (1) { do { offset1 = nextoffset1; tag1 = fdt_next_tag(fdt1, offset1, &nextoffset1); } while (tag1 == FDT_NOP); do { offset2 = nextoffset2; tag2 = fdt_next_tag(fdt2, offset2, &nextoffset2); } while (tag2 == FDT_NOP); if (tag1 != tag2) MISMATCH("Tag mismatch (%d != %d) at (%d, %d)", tag1, tag2, offset1, offset2); switch (tag1) { case FDT_BEGIN_NODE: name1 = fdt_get_name(fdt1, offset1, &err); if (!name1) FAIL("fdt_get_name(fdt1, %d, ..): %s", offset1, fdt_strerror(err)); name2 = fdt_get_name(fdt2, offset2, NULL); if (!name2) FAIL("fdt_get_name(fdt2, %d, ..): %s", offset2, fdt_strerror(err)); if (!streq(name1, name2)) MISMATCH("Name mismatch (\"%s\" != \"%s\") at (%d, %d)", name1, name2, offset1, offset2); break; case FDT_PROP: prop1 = fdt_offset_ptr(fdt1, offset1, sizeof(*prop1)); if (!prop1) FAIL("Could get fdt1 property at %d", offset1); prop2 = fdt_offset_ptr(fdt2, offset2, sizeof(*prop2)); if (!prop2) FAIL("Could get fdt2 property at %d", offset2); name1 = fdt_string(fdt1, fdt32_to_cpu(prop1->nameoff)); name2 = fdt_string(fdt2, fdt32_to_cpu(prop2->nameoff)); if (!streq(name1, name2)) MISMATCH("Property name mismatch \"%s\" != \"%s\" " "at (%d, %d)", name1, name2, offset1, offset2); len1 = fdt32_to_cpu(prop1->len); len2 = fdt32_to_cpu(prop2->len); if (len1 != len2) MISMATCH("Property length mismatch %u != %u " "at (%d, %d)", len1, len2, offset1, offset2); if (memcmp(prop1->data, prop2->data, len1) != 0) MISMATCH("Property value mismatch at (%d, %d)", offset1, offset2); break; case FDT_END: return; } } }
/** * 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; }
static int nlm_fdt_read(char *page, char **start, off_t off, int count, int *eof, void *data) { static char tabs[MAX_LEVEL+1] = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t" "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"; const void *nodep; /* property node pointer */ int nodeoffset; /* node offset from libfdt */ int nextoffset; /* next node offset from libfdt */ uint32_t tag; /* tag */ int len; /* length of the property */ int level = 0; /* keep track of nesting level */ const struct fdt_property *fdt_prop; int plen = 0; const char *pathp = "/"; int depth = MAX_LEVEL; off_t begin = 0; working_fdt = (struct fdt_header *)fdt; nodeoffset = fdt_path_offset (working_fdt, pathp); if (nodeoffset < 0) { /* * Not found or something else bad happened. */ plen += sprintf(page + plen, "libfdt fdt_path_offset() returned %s\n", fdt_strerror(nodeoffset)); goto out; } /* * The user passed in a node path and no property, * print the node and all subnodes. */ while(level >= 0) { if (!proc_pos_check(&begin, &plen, off, count)) goto out; tag = fdt_next_tag(working_fdt, nodeoffset, &nextoffset); switch(tag) { case FDT_BEGIN_NODE: pathp = fdt_get_name(working_fdt, nodeoffset, NULL); if (level <= depth) { if (pathp == NULL) pathp = "/* NULL pointer error */"; if (*pathp == '\0') pathp = "/"; /* root is nameless */ plen += sprintf(page + plen, "%s%s {\n", &tabs[MAX_LEVEL - level], pathp); } level++; if (level >= MAX_LEVEL) { plen += sprintf(page + plen, "Nested too deep, aborting.\n"); goto out; } break; case FDT_END_NODE: level--; if (level <= depth) plen += sprintf(page + plen, "%s};\n", &tabs[MAX_LEVEL - level]); if (level == 0) { level = -1; /* exit the loop */ } break; case FDT_PROP: fdt_prop = fdt_offset_ptr(working_fdt, nodeoffset, sizeof(*fdt_prop)); pathp = fdt_string(working_fdt, fdt32_to_cpu(fdt_prop->nameoff)); len = fdt32_to_cpu(fdt_prop->len); nodep = fdt_prop->data; if (len < 0) { plen += sprintf (page + plen, "libfdt fdt_getprop(): %s\n", fdt_strerror(len)); goto out; } else if (len == 0) { /* the property has no value */ if (level <= depth) plen += sprintf(page + plen, "%s%s;\n", &tabs[MAX_LEVEL - level], pathp); } else { if (level <= depth) { plen += sprintf(page + plen, "%s%s = ", &tabs[MAX_LEVEL - level], pathp); plen += print_data (page + plen, nodep, len); plen += sprintf(page + plen, ";\n"); } } break; case FDT_NOP: plen += sprintf(page + plen, "%s/* NOP */\n", &tabs[MAX_LEVEL - level]); break; case FDT_END: goto good_out; default: if (level <= depth) plen += sprintf(page + plen, "Unknown tag 0x%08X\n", tag); goto out; } nodeoffset = nextoffset; } good_out: *eof = 1; out: *start = page + (off - begin); plen -= (off - begin); if (plen > count) plen = count; if (plen < 0) plen = 0; return plen; }
/* * Recursively print (a portion of) the fdt. The depth parameter * determines how deeply nested the fdt is printed. */ static int fdt_print(const char *pathp, char *prop, int depth) { static char tabs[MAX_LEVEL+1] = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t" "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"; const void *nodep; /* property node pointer */ int nodeoffset; /* node offset from libfdt */ int nextoffset; /* next node offset from libfdt */ uint32_t tag; /* tag */ int len; /* length of the property */ int level = 0; /* keep track of nesting level */ const struct fdt_property *fdt_prop; nodeoffset = fdt_path_offset (fdt, pathp); if (nodeoffset < 0) { /* * Not found or something else bad happened. */ printf ("libfdt fdt_path_offset() returned %s\n", fdt_strerror(nodeoffset)); return 1; } /* * The user passed in a property as well as node path. * Print only the given property and then return. */ if (prop) { nodep = fdt_getprop (fdt, nodeoffset, prop, &len); if (len == 0) { /* no property value */ printf("%s %s\n", pathp, prop); return 0; } else if (len > 0) { printf("%s=", prop); print_data (nodep, len); printf("\n"); return 0; } else { printf ("libfdt fdt_getprop(): %s\n", fdt_strerror(len)); return 1; } } /* * The user passed in a node path and no property, * print the node and all subnodes. */ while(level >= 0) { tag = fdt_next_tag(fdt, nodeoffset, &nextoffset); switch(tag) { case FDT_BEGIN_NODE: pathp = fdt_get_name(fdt, nodeoffset, NULL); if (level <= depth) { if (pathp == NULL) pathp = "/* NULL pointer error */"; if (*pathp == '\0') pathp = "/"; /* root is nameless */ printf("%s%s {\n", &tabs[MAX_LEVEL - level], pathp); } level++; if (level >= MAX_LEVEL) { printf("Nested too deep, aborting.\n"); return 1; } break; case FDT_END_NODE: level--; if (level <= depth) printf("%s};\n", &tabs[MAX_LEVEL - level]); if (level == 0) { level = -1; /* exit the loop */ } break; case FDT_PROP: fdt_prop = fdt_offset_ptr(fdt, nodeoffset, sizeof(*fdt_prop)); pathp = fdt_string(fdt, fdt32_to_cpu(fdt_prop->nameoff)); len = fdt32_to_cpu(fdt_prop->len); nodep = fdt_prop->data; if (len < 0) { printf ("libfdt fdt_getprop(): %s\n", fdt_strerror(len)); return 1; } else if (len == 0) { /* the property has no value */ if (level <= depth) printf("%s%s;\n", &tabs[MAX_LEVEL - level], pathp); } else { if (level <= depth) { printf("%s%s=", &tabs[MAX_LEVEL - level], pathp); print_data (nodep, len); printf(";\n"); } } break; case FDT_NOP: printf("/* NOP */\n", &tabs[MAX_LEVEL - level]); break; case FDT_END: return 1; default: if (level <= depth) printf("Unknown tag 0x%08X\n", tag); return 1; } nodeoffset = nextoffset; } return 0; }