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); }
int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, const char *propname, const void *propval, int proplen) { uint32_t tag; int offset, nextoffset; const void *val; int len; CHECK_HEADER(fdt); if (startoffset >= 0) { tag = fdt_next_tag(fdt, startoffset, &nextoffset); if (tag != FDT_BEGIN_NODE) return -FDT_ERR_BADOFFSET; } else { nextoffset = 0; } /* FIXME: The algorithm here is pretty horrible: we scan each * property of a node in fdt_getprop(), then if that didn't * find what we want, we scan over them again making our way * to the next node. Still it's the easiest to implement * approach; performance can come later. */ do { offset = nextoffset; tag = fdt_next_tag(fdt, offset, &nextoffset); switch (tag) { case FDT_BEGIN_NODE: val = fdt_getprop(fdt, offset, propname, &len); if (val && (len == proplen) && (memcmp(val, propval, len) == 0)) return offset; break; case FDT_PROP: case FDT_END: case FDT_END_NODE: case FDT_NOP: break; default: return -FDT_ERR_BADSTRUCTURE; } } while (tag != FDT_END); return -FDT_ERR_NOTFOUND; }
int fdt_node_offset_by_compatible(const void *fdt, int startoffset, const char *compatible) { uint32_t tag; int offset, nextoffset; int err; CHECK_HEADER(fdt); if (startoffset >= 0) { tag = fdt_next_tag(fdt, startoffset, &nextoffset); if (tag != FDT_BEGIN_NODE) return -FDT_ERR_BADOFFSET; } else { nextoffset = 0; } /* FIXME: The algorithm here is pretty horrible: we scan each * property of a node in fdt_node_check_compatible(), then if * that didn't find what we want, we scan over them again * making our way to the next node. Still it's the easiest to * implement approach; performance can come later. */ do { offset = nextoffset; tag = fdt_next_tag(fdt, offset, &nextoffset); switch (tag) { case FDT_BEGIN_NODE: err = fdt_node_check_compatible(fdt, offset, compatible); if ((err < 0) && (err != -FDT_ERR_NOTFOUND)) return err; else if (err == 0) return offset; break; case FDT_PROP: case FDT_END: case FDT_END_NODE: case FDT_NOP: break; default: return -FDT_ERR_BADSTRUCTURE; } } while (tag != FDT_END); return -FDT_ERR_NOTFOUND; }
/* * 다음 property를 찾아서 해당 offset을 리턴 */ static int _nextprop(const void *fdt, int offset) { uint32_t tag; int nextoffset; do { /* * offset: property의 offset * nextoffset: property offset의 다음 offset */ tag = fdt_next_tag(fdt, offset, &nextoffset); switch (tag) { case FDT_END: /* * 이미 FDT_END인데 nextoffset이 있다면 에러 * (FDT_END인데 다음 offset이 있다가 말이 안됨) * nextoffset<0 라면 에러값이 들어가 있음 */ if (nextoffset >= 0) return -FDT_ERR_BADSTRUCTURE; else return nextoffset; // property라면 해당 offset 리턴 case FDT_PROP: return offset; } // property를 찾을때까지 다음 offset으로 이동 offset = nextoffset; } while (tag == FDT_NOP); return -FDT_ERR_NOTFOUND; }
int _fdt_check_prop_offset(const void *fdt, int offset) { if ((offset < 0) || (offset % FDT_TAGSIZE) || (fdt_next_tag(fdt, offset, &offset) != FDT_PROP)) return -FDT_ERR_BADOFFSET; return offset; }
int _fdt_check_node_offset(const void *fdt, int offset) { if ((offset < 0) || (offset % FDT_TAGSIZE) || (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE)) return -FDT_ERR_BADOFFSET; return offset; }
int fdt_subnode_offset_namelen(const void *fdt, int parentoffset, const char *name, int namelen) { int level = 0; uint32_t tag; int offset, nextoffset; CHECK_HEADER(fdt); tag = fdt_next_tag(fdt, parentoffset, &nextoffset); if (tag != FDT_BEGIN_NODE) return -FDT_ERR_BADOFFSET; do { offset = nextoffset; tag = fdt_next_tag(fdt, offset, &nextoffset); switch (tag) { case FDT_END: return -FDT_ERR_TRUNCATED; case FDT_BEGIN_NODE: level++; if (level != 1) continue; if (nodename_eq(fdt, offset+FDT_TAGSIZE, name, namelen)) /* Found it! */ return offset; break; case FDT_END_NODE: level--; break; case FDT_PROP: case FDT_NOP: break; default: return -FDT_ERR_BADSTRUCTURE; } } while (level >= 0); return -FDT_ERR_NOTFOUND; }
/* * offset을 기준으로 다음 노드를 가져옴 * 현재 탐색중인 node의 depth를 저장 */ int fdt_next_node(const void *fdt, int offset, int *depth) { int nextoffset = 0; uint32_t tag; // "chosen" 맨 처음에는 offset는 0 if (offset >= 0) /* * offset의 유효성 체크 * 참고:http://iamroot.org/wiki/lib/exe/fetch.php?media=%EC%8A%A4%ED%84%B0%EB%94%94:dtb_structure.png */ if ((nextoffset = _fdt_check_node_offset(fdt, offset)) < 0) return nextoffset; /* * FDT_BEGIN_NODE * - 현재 노드의 tag값을 찾는데 만약에 새로운 노드가 시작되면 depth++ * FDT_END_NODE * - 탐색중인 노드가 끝난 경우 depth를 -- * depth를 감소했을때 음수가 아닌경우 * - childNode가 더이상 없는 경우 nextoffset(0) 리턴 * childNode안에 또 childNode가 있을수 있으니 depth로 판별? */ do { offset = nextoffset; tag = fdt_next_tag(fdt, offset, &nextoffset); switch (tag) { case FDT_PROP: case FDT_NOP: break; case FDT_BEGIN_NODE: if (depth) (*depth)++; break; case FDT_END_NODE: if (depth && ((--(*depth)) < 0)) return nextoffset; break; case FDT_END: if ((nextoffset >= 0) || ((nextoffset == -FDT_ERR_TRUNCATED) && !depth)) return -FDT_ERR_NOTFOUND; else return nextoffset; } } while (tag != FDT_BEGIN_NODE); return offset; }
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); }
int _fdt_node_end_offset(void *fdt, int nodeoffset) { int level = 0; uint32_t tag; int offset, nextoffset; tag = fdt_next_tag(fdt, nodeoffset, &nextoffset, NULL); if (tag != FDT_BEGIN_NODE) return -FDT_ERR_BADOFFSET; do { offset = nextoffset; tag = fdt_next_tag(fdt, offset, &nextoffset, NULL); switch (tag) { case FDT_END: return offset; case FDT_BEGIN_NODE: level++; break; case FDT_END_NODE: level--; break; case FDT_PROP: case FDT_NOP: break; default: return -FDT_ERR_BADSTRUCTURE; } } while (level >= 0); return nextoffset; }
const struct fdt_property *fdt_get_property_namelen(const void *fdt, int nodeoffset, const char *name, int namelen, int *lenp) { uint32_t tag; const struct fdt_property *prop; int offset, nextoffset; int err; if (((err = fdt_check_header(fdt)) != 0) || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0)) goto fail; nextoffset = err; do { offset = nextoffset; tag = fdt_next_tag(fdt, offset, &nextoffset); switch (tag) { case FDT_END: if (nextoffset < 0) err = nextoffset; else /* FDT_END tag with unclosed nodes */ err = -FDT_ERR_BADSTRUCTURE; goto fail; case FDT_PROP: prop = _fdt_offset_ptr(fdt, offset); if (_fdt_string_eq(fdt, fdt32_to_cpu(prop->nameoff), name, namelen)) { /* Found it! */ if (lenp) *lenp = fdt32_to_cpu(prop->len); return prop; } break; } } while ((tag != FDT_BEGIN_NODE) && (tag != FDT_END_NODE)); err = -FDT_ERR_NOTFOUND; fail: if (lenp) *lenp = err; return NULL; }
int fdt_finish(void *fdt) { int err = check_header_sw(fdt); char *p = (char *)fdt; uint32_t *end; int oldstroffset, newstroffset; uint32_t tag; int offset, nextoffset; if (err) return err; /* Add terminator */ end = grab_space(fdt, sizeof(*end)); if (! end) return -FDT_ERR_NOSPACE; *end = cpu_to_fdt32(FDT_END); /* Relocate the string table */ oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt); newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt)); fdt_set_off_dt_strings(fdt, newstroffset); /* Walk the structure, correcting string offsets */ offset = 0; while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) { if (tag == FDT_PROP) { struct fdt_property *prop = fdt_offset_ptr_w(fdt, offset, sizeof(*prop)); int nameoff; if (! prop) return -FDT_ERR_BADSTRUCTURE; nameoff = fdt32_to_cpu(prop->nameoff); nameoff += fdt_size_dt_strings(fdt); prop->nameoff = cpu_to_fdt32(nameoff); } offset = nextoffset; } /* Finally, adjust the header */ fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt)); fdt_set_magic(fdt, FDT_MAGIC); return 0; }
int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, int supernodedepth, int *nodedepth) { int level = -1; uint32_t tag; int offset, nextoffset = 0; int supernodeoffset = -FDT_ERR_INTERNAL; CHECK_HEADER(fdt); if (supernodedepth < 0) return -FDT_ERR_NOTFOUND; do { offset = nextoffset; tag = fdt_next_tag(fdt, offset, &nextoffset); switch (tag) { case FDT_END: return -FDT_ERR_BADOFFSET; case FDT_BEGIN_NODE: level++; if (level == supernodedepth) supernodeoffset = offset; break; case FDT_END_NODE: level--; break; case FDT_PROP: case FDT_NOP: break; default: return -FDT_ERR_BADSTRUCTURE; } } while (offset < nodeoffset); if (nodedepth) *nodedepth = level; if (supernodedepth > level) return -FDT_ERR_NOTFOUND; return supernodeoffset; }
static int list_subnodes(const void *blob, int node) { int nextoffset; /* */ uint32_t tag; /* */ int level = 0; /* */ const char *pathp; int depth = 1; /* */ while (level >= 0) { tag = fdt_next_tag(blob, node, &nextoffset); switch (tag) { case FDT_BEGIN_NODE: pathp = fdt_get_name(blob, node, NULL); if (level <= depth) { if (pathp == NULL) pathp = "/* NULL pointer error */"; if (*pathp == '\0') pathp = "/"; /* */ if (level == 1) puts(pathp); } level++; if (level >= MAX_LEVEL) { printf("Nested too deep, aborting.\n"); return 1; } break; case FDT_END_NODE: level--; if (level == 0) level = -1; /* */ break; case FDT_END: return 1; case FDT_PROP: break; default: if (level <= depth) printf("Unknown tag 0x%08X\n", tag); return 1; } node = nextoffset; } return 0; }
int fdt_finish(void *fdt) { char *p = (char *)fdt; uint32_t *end; int oldstroffset, newstroffset; uint32_t tag; int offset, nextoffset; FDT_SW_CHECK_HEADER(fdt); end = _fdt_grab_space(fdt, sizeof(*end)); if (! end) return -FDT_ERR_NOSPACE; *end = cpu_to_fdt32(FDT_END); oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt); newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt)); fdt_set_off_dt_strings(fdt, newstroffset); offset = 0; while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) { if (tag == FDT_PROP) { struct fdt_property *prop = _fdt_offset_ptr_w(fdt, offset); int nameoff; nameoff = fdt32_to_cpu(prop->nameoff); nameoff += fdt_size_dt_strings(fdt); prop->nameoff = cpu_to_fdt32(nameoff); } offset = nextoffset; } if (nextoffset < 0) return nextoffset; fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt)); fdt_set_magic(fdt, FDT_MAGIC); return 0; }
int fdt_next_node(const void *fdt, int offset, int *depth) { int nextoffset = 0; uint32_t tag; if (offset >= 0) if ((nextoffset = _fdt_check_node_offset(fdt, offset)) < 0) return nextoffset; do { offset = nextoffset; tag = fdt_next_tag(fdt, offset, &nextoffset); switch (tag) { case FDT_PROP: case FDT_NOP: break; case FDT_BEGIN_NODE: if (depth) (*depth)++; break; case FDT_END_NODE: if (depth && ((--(*depth)) < 0)) return nextoffset; break; case FDT_END: if ((nextoffset >= 0) || ((nextoffset == -FDT_ERR_TRUNCATED) && !depth)) return -FDT_ERR_NOTFOUND; else return nextoffset; } } while (tag != FDT_BEGIN_NODE); return offset; }
int fdt_next_node(const void *fdt, int offset, int *depth) { int nextoffset = 0; uint32_t tag; if (offset >= 0) if ((nextoffset = _fdt_check_node_offset(fdt, offset)) < 0) return nextoffset; do { offset = nextoffset; tag = fdt_next_tag(fdt, offset, &nextoffset); switch (tag) { case FDT_PROP: case FDT_NOP: break; case FDT_BEGIN_NODE: if (depth) (*depth)++; break; case FDT_END_NODE: if (depth) (*depth)--; break; case FDT_END: return -FDT_ERR_NOTFOUND; default: return -FDT_ERR_BADSTRUCTURE; } } while (tag != FDT_BEGIN_NODE); return offset; }
static int _nextprop(const void *fdt, int offset) { uint32_t tag; int nextoffset; do { tag = fdt_next_tag(fdt, offset, &nextoffset); switch (tag) { case FDT_END: if (nextoffset >= 0) return -FDT_ERR_BADSTRUCTURE; else return nextoffset; case FDT_PROP: return offset; } offset = nextoffset; } while (tag == FDT_NOP); return -FDT_ERR_NOTFOUND; }
/* * 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; }
int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) { uint32_t tag; int p = 0, overflow = 0; int offset, nextoffset, namelen; const char *name; CHECK_HEADER(fdt); tag = fdt_next_tag(fdt, 0, &nextoffset); if (tag != FDT_BEGIN_NODE) return -FDT_ERR_BADSTRUCTURE; if (buflen < 2) return -FDT_ERR_NOSPACE; buf[0] = '/'; p = 1; while (nextoffset <= nodeoffset) { offset = nextoffset; tag = fdt_next_tag(fdt, offset, &nextoffset); switch (tag) { case FDT_END: return -FDT_ERR_BADOFFSET; case FDT_BEGIN_NODE: name = fdt_get_name(fdt, offset, &namelen); if (!name) return namelen; if (overflow || ((p + namelen + 1) > buflen)) { overflow++; break; } memcpy(buf + p, name, namelen); p += namelen; buf[p++] = '/'; break; case FDT_END_NODE: if (overflow) { overflow--; break; } do { p--; } while (buf[p-1] != '/'); break; case FDT_PROP: case FDT_NOP: break; default: return -FDT_ERR_BADSTRUCTURE; } } if (overflow) return -FDT_ERR_NOSPACE; if (p > 1) /* special case so that root path is "/", not "" */ p--; buf[p] = '\0'; return p; }
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; }
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; } } }
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; }
/** * 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; }
/* * Flattened Device Tree command, see the help for parameter definitions. */ int do_fdt (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) { char op; if (argc < 2) { printf ("Usage:\n%s\n", cmdtp->usage); return 1; } /* * Figure out which subcommand was given */ op = argv[1][0]; /******************************************************************** * Set the address of the fdt ********************************************************************/ if (op == 'a') { /* * Set the address [and length] of the fdt. */ fdt = (struct fdt_header *)simple_strtoul(argv[2], NULL, 16); if (!fdt_valid()) { return 1; } if (argc >= 4) { int len; int err; /* * Optional new length */ len = simple_strtoul(argv[3], NULL, 16); if (len < fdt_totalsize(fdt)) { printf ("New length %d < existing length %d, ignoring.\n", len, fdt_totalsize(fdt)); } else { /* * Open in place with a new length. */ err = fdt_open_into(fdt, fdt, len); if (err != 0) { printf ("libfdt: %s\n", fdt_strerror(err)); } } } /******************************************************************** * Move the fdt ********************************************************************/ } else if (op == 'm' && argv[1][1] == 'o') { struct fdt_header *newaddr; int len; int err; if (argc != 5) { printf ("Usage:\n%s\n", cmdtp->usage); return 1; } /* * Set the address and length of the fdt. */ fdt = (struct fdt_header *)simple_strtoul(argv[2], NULL, 16); if (!fdt_valid()) { return 1; } newaddr = (struct fdt_header *)simple_strtoul(argv[3], NULL, 16); len = simple_strtoul(argv[4], NULL, 16); if (len < fdt_totalsize(fdt)) { printf ("New length %d < existing length %d, aborting.\n", len, fdt_totalsize(fdt)); return 1; } /* * Copy to the new location. */ err = fdt_open_into(fdt, newaddr, len); if (err != 0) { printf ("libfdt: %s\n", fdt_strerror(err)); return 1; } fdt = newaddr; /******************************************************************** * mknode ********************************************************************/ } else if (op == 'm' && argv[1][1] == 'k') { char *pathp = argv[2]; char *node = argv[3]; int nodeoffset; if (argc != 4) { printf ("Usage:\n%s\n", cmdtp->usage); return 1; } /* * See if the node already exists */ if (strcmp(pathp, "/") == 0) nodeoffset = 0; else nodeoffset = fdt_path_offset (fdt, pathp); if (nodeoffset < 0) { printf("parent node %s doesn't exist\n", pathp); return 1; } /* * Create the new node */ nodeoffset = fdt_add_subnode(fdt, nodeoffset, node); if (nodeoffset < 0) { printf("libfdt: %s\n", fdt_strerror(nodeoffset)); return 1; } /******************************************************************** * Set the value of a node in the fdt. ********************************************************************/ } else if (op == 's') { char *pathp; /* path */ char *prop; /* property */ struct fdt_property *nodep; /* node struct pointer */ char *newval; /* value from the user (as a string) */ char *vp; /* temporary value pointer */ char *cp; /* temporary char pointer */ int nodeoffset; /* node offset from libfdt */ int len; /* new length of the property */ int oldlen; /* original length of the property */ unsigned long tmp; /* holds converted values */ int ret; /* return value */ /* * Parameters: Node path, property, value. */ if (argc < 5) { printf ("Usage:\n%s\n", cmdtp->usage); return 1; } pathp = argv[2]; prop = argv[3]; newval = argv[4]; if (strcmp(pathp, "/") == 0) { nodeoffset = 0; } else { nodeoffset = fdt_path_offset (fdt, pathp); if (nodeoffset < 0) { /* * Not found or something else bad happened. */ printf ("libfdt: %s\n", fdt_strerror(nodeoffset)); return 1; } } nodep = fdt_getprop (fdt, nodeoffset, prop, &oldlen); if (oldlen == 0) { /* * The specified property has no value */ printf("%s has no value, cannot set one (yet).\n", prop); return 1; } else { /* * Convert the new property */ vp = data; if (*newval == '<') { /* * Bigger values than bytes. */ len = 0; newval++; while ((*newval != '>') && (*newval != '\0')) { cp = newval; tmp = simple_strtoul(cp, &newval, 16); if ((newval - cp) <= 2) { *vp = tmp & 0xFF; vp += 1; len += 1; } else if ((newval - cp) <= 4) { *(uint16_t *)vp = __cpu_to_be16(tmp); vp += 2; len += 2; } else if ((newval - cp) <= 8) { *(uint32_t *)vp = __cpu_to_be32(tmp); vp += 4; len += 4; } else { printf("Sorry, I could not convert \"%s\"\n", cp); return 1; } while (*newval == ' ') newval++; } if (*newval != '>') { printf("Unexpected character '%c'\n", *newval); return 1; } } else if (*newval == '[') { /* * Byte stream. Convert the values. */ len = 0; newval++; while ((*newval != ']') && (*newval != '\0')) { tmp = simple_strtoul(newval, &newval, 16); *vp++ = tmp & 0xFF; len++; while (*newval == ' ') newval++; } if (*newval != ']') { printf("Unexpected character '%c'\n", *newval); return 1; } } else { /* * Assume it is a string. Copy it into our data area for * convenience (including the terminating '\0'). */ len = strlen(newval) + 1; strcpy(data, newval); } ret = fdt_setprop(fdt, nodeoffset, prop, data, len); if (ret < 0) { printf ("libfdt %s\n", fdt_strerror(ret)); return 1; } } /******************************************************************** * Print (recursive) / List (single level) ********************************************************************/ } else if ((op == 'p') || (op == 'l')) { /* * Recursively print (a portion of) the fdt. */ static int offstack[MAX_LEVEL]; 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"; int depth = MAX_LEVEL; /* how deep to print */ char *pathp; /* path */ char *prop; /* property */ 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 */ /* * list is an alias for print, but limited to 1 level */ if (op == 'l') { depth = 1; } /* * Get the starting path. The root node is an oddball, * the offset is zero and has no name. */ pathp = argv[2]; if (argc > 3) prop = argv[3]; else prop = NULL; if (strcmp(pathp, "/") == 0) { nodeoffset = 0; printf("/"); } else { nodeoffset = fdt_path_offset (fdt, pathp); if (nodeoffset < 0) { /* * Not found or something else bad happened. */ printf ("libfdt %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) { printf("%s %s\n", pathp, prop); /* no property value */ return 0; } else if (len > 0) { printf("%s=", prop); print_data (nodep, len); printf("\n"); return 0; } else { printf ("libfdt %s\n", fdt_strerror(len)); return 1; } } /* * The user passed in a node path and no property, print the node * and all subnodes. */ offstack[0] = nodeoffset; while(level >= 0) { tag = fdt_next_tag(fdt, nodeoffset, &nextoffset, &pathp); switch(tag) { case FDT_BEGIN_NODE: if(level <= depth) printf("%s%s {\n", &tabs[MAX_LEVEL - level], pathp); level++; offstack[level] = nodeoffset; if (level >= MAX_LEVEL) { printf("Aaaiii <splat> nested too deep.\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: nodep = fdt_getprop (fdt, offstack[level], pathp, &len); if (len < 0) { printf ("libfdt %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: break; case FDT_END: return 1; default: if(level <= depth) printf("Unknown tag 0x%08X\n", tag); return 1; } nodeoffset = nextoffset; } /******************************************************************** * Remove a property/node ********************************************************************/ } else if (op == 'r') { int nodeoffset; /* node offset from libfdt */ int err; /* * Get the path. The root node is an oddball, the offset * is zero and has no name. */ if (strcmp(argv[2], "/") == 0) { nodeoffset = 0; } else { nodeoffset = fdt_path_offset (fdt, argv[2]); if (nodeoffset < 0) { /* * Not found or something else bad happened. */ printf ("libfdt %s\n", fdt_strerror(nodeoffset)); return 1; } } /* * Do the delete. A fourth parameter means delete a property, * otherwise delete the node. */ if (argc > 3) { err = fdt_delprop(fdt, nodeoffset, argv[3]); if (err < 0) { printf("fdt_delprop libfdt: %s\n", fdt_strerror(err)); return err; } } else { err = fdt_del_node(fdt, nodeoffset); if (err < 0) { printf("fdt_del_node libfdt: %s\n", fdt_strerror(err)); return err; } } /******************************************************************** * Create a chosen node ********************************************************************/ } else if (op == 'c') { fdt_chosen(fdt, 0, 0, 1); #ifdef CONFIG_OF_HAS_UBOOT_ENV /******************************************************************** * Create a u-boot-env node ********************************************************************/ } else if (op == 'e') { fdt_env(fdt); #endif #ifdef CONFIG_OF_HAS_BD_T /******************************************************************** * Create a bd_t node ********************************************************************/ } else if (op == 'b') { fdt_bd_t(fdt); #endif /******************************************************************** * Unrecognized command ********************************************************************/ } else { printf ("Usage:\n%s\n", cmdtp->usage); return 1; } return 0; }