uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) { const fdt32_t *tagp, *lenp; uint32_t tag; int offset = startoffset; const char *p; *nextoffset = -FDT_ERR_TRUNCATED; tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE); if (!tagp) return FDT_END; /* premature end */ tag = fdt32_to_cpu(*tagp); offset += FDT_TAGSIZE; *nextoffset = -FDT_ERR_BADSTRUCTURE; switch (tag) { case FDT_BEGIN_NODE: /* skip name */ do { p = fdt_offset_ptr(fdt, offset++, 1); } while (p && (*p != '\0')); if (!p) return FDT_END; /* premature end */ break; case FDT_PROP: lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp)); if (!lenp) return FDT_END; /* premature end */ /* skip-name offset, length and value */ offset += sizeof(struct fdt_property) - FDT_TAGSIZE + fdt32_to_cpu(*lenp); break; case FDT_END: case FDT_END_NODE: case FDT_NOP: break; default: return FDT_END; } if (!fdt_offset_ptr(fdt, startoffset, offset - startoffset)) return FDT_END; /* premature end */ *nextoffset = FDT_TAGALIGN(offset); return tag; }
static int check_subnode(struct fdt_header *fdt, int parent, const char *name) { int offset; const struct fdt_node_header *nh; uint32_t tag; verbose_printf("Checking subnode \"%s\" of %d...", name, parent); offset = fdt_subnode_offset(fdt, parent, name); verbose_printf("offset %d...", offset); if (offset < 0) FAIL("fdt_subnode_offset(\"%s\"): %s", name, fdt_strerror(offset)); nh = fdt_offset_ptr(fdt, offset, sizeof(*nh)); verbose_printf("pointer %p\n", nh); if (! nh) FAIL("NULL retrieving subnode \"%s\"", name); tag = fdt32_to_cpu(nh->tag); if (tag != FDT_BEGIN_NODE) FAIL("Incorrect tag 0x%08x on property \"%s\"", tag, name); if (!nodename_eq(nh->name, name)) FAIL("Subnode name mismatch \"%s\" instead of \"%s\"", nh->name, name); return offset; }
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_nodename_eq(const void *fdt, int offset, const char *s, int len) { /* * struct fdt_node_header { * uint32_t tag; * char name[0]; * }; * fdt_node_header의 name을 가져옴 * (len+1)만큼 가져오는 것은 밑에서 '@'을 체크하기 위해? */ const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1); if (! p) /* short match */ return 0; if (memcmp(p, s, len) != 0) return 0; if (p[len] == '\0') return 1; else if (!memchr(s, '@', len) && (p[len] == '@')) return 1; else return 0; }
int fdt_nop_node(void *fdt, int nodeoffset) { int endoffset; endoffset = _fdt_node_end_offset(fdt, nodeoffset); if (endoffset < 0) return endoffset; nop_region(fdt_offset_ptr(fdt, nodeoffset, 0), endoffset - nodeoffset); return 0; }
uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset) { const uint32_t *tagp, *lenp; uint32_t tag; const char *p; if (offset % FDT_TAGSIZE) return -1; tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE); if (! tagp) return FDT_END; /* premature end */ tag = fdt32_to_cpu(*tagp); offset += FDT_TAGSIZE; switch (tag) { case FDT_BEGIN_NODE: /* skip name */ do { p = fdt_offset_ptr(fdt, offset++, 1); } while (p && (*p != '\0')); if (! p) return FDT_END; break; case FDT_PROP: lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp)); if (! lenp) return FDT_END; /* skip name offset, length and value */ offset += 2*FDT_TAGSIZE + fdt32_to_cpu(*lenp); break; } if (nextoffset) *nextoffset = FDT_TAGALIGN(offset); return tag; }
static int _fdt_nodename_eq(const void *fdt, int offset, const char *s, int len) { const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len + 1); if (!p) /* short match */ return 0; if (memcmp(p, s, len) != 0) return 0; if (p[len] == '\0') return 1; else if (!memchr(s, '@', len) && (p[len] == '@')) return 1; else return 0; }
int main(int argc, char *argv[]) { void *fdt; const struct fdt_node_header *nh; test_init(argc, argv); fdt = load_blob_arg(argc, argv); nh = fdt_offset_ptr(fdt, 0, sizeof(*nh)); if (! nh) FAIL("NULL retrieving root node"); if (fdt32_to_cpu(nh->tag) != FDT_BEGIN_NODE) FAIL("Wrong tag on root node"); if (strlen(nh->name) != 0) FAIL("Wrong name for root node, \"%s\" instead of empty", nh->name); PASS(); }
const char *fdt_get_name(const void *fdt, int nodeoffset, int *len) { const struct fdt_node_header *nh; int err; if ((err = fdt_check_header(fdt)) != 0) goto fail; err = -FDT_ERR_BADOFFSET; nh = fdt_offset_ptr(fdt, nodeoffset, sizeof(*nh)); if (!nh || (fdt32_to_cpu(nh->tag) != FDT_BEGIN_NODE)) goto fail; if (len) *len = strlen(nh->name); return nh->name; fail: if (len) *len = err; return NULL; }
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; }
/* * 다음 tag의 Offset를 찾는다.(nextoffset갱신) * in startoffset 현재 시작 offset * out nextoffset 다음 시작 offset * return FDT_END 에러 혹은 현재의 tag값 * tag 구분값 * define FDT_BEGIN_NODE 0x1 * #define FDT_END_NODE 0x2 * #define FDT_PROP 0x3 */ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) { const uint32_t *tagp, *lenp; uint32_t tag; int offset = startoffset; const char *p; *nextoffset = -FDT_ERR_TRUNCATED; /* FDT_TAGSIZE: sizeof(uint32_t) word사이즈 */ tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE); if (!tagp) return FDT_END; /* premature end */ tag = fdt32_to_cpu(*tagp); offset += FDT_TAGSIZE; *nextoffset = -FDT_ERR_BADSTRUCTURE; switch (tag) { /* #define FDT_BEGIN_NODE 0x1 #define FDT_END_NODE 0x2 #define FDT_PROP 0x3 [2015-11-07 여기까지 함] */ case FDT_BEGIN_NODE: /* skip name */ /* struct fdt_node_header { uint32_t tag; char name[0]; }; */ do { p = fdt_offset_ptr(fdt, offset++, 1); } while (p && (*p != '\0')); if (!p) return FDT_END; /* premature end */ break; case FDT_PROP: /* struct fdt_property { uint32_t tag; uint32_t len; uint32_t nameoff; char data[0]; }; */ lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp)); if (!lenp) return FDT_END; /* premature end */ /* skip-name offset, length and value */ /* offset += 12 - 4 + (*lenp) sizeof(struct fdt_property) 는 12이다. */ offset += sizeof(struct fdt_property) - FDT_TAGSIZE + fdt32_to_cpu(*lenp); break; case FDT_END: case FDT_END_NODE: case FDT_NOP: break; default: return FDT_END; } // offset값 범위체크 if (!fdt_offset_ptr(fdt, startoffset, offset - startoffset)) return FDT_END; /* premature end */ /* 4 byte align을 맞추기위해 #define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) #define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE)) ex) FDT_TAGALIGN(10) FDT_ALIGN(10, 4) ((10 + 4 - 1) & ~(4 - 1)) = 12 (13 & ~3) = 0b1101 & ~0b0011 = 0b1100 = 12 */ *nextoffset = FDT_TAGALIGN(offset); return tag; }
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; }
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; } } }
/* * 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; }