📄 flatdevtree.c
字号:
static int is_printable_string(const void *data, int len){ const char *s = data; const char *ss; /* zero length is not */ if (len == 0) return 0; /* must terminate with zero */ if (s[len - 1] != '\0') return 0; ss = s; while (*s && isprint(*s)) s++; /* not zero, or not done yet */ if (*s != '\0' || (s + 1 - ss) < len) return 0; return 1;}static void print_data(const void *data, int len){ int i; const char *s; /* no data, don't print */ if (len == 0) return; if (is_printable_string(data, len)) { printf(" = \"%s\"", (char *)data); return; } switch (len) { case 1: /* byte */ printf(" = <0x%02x>", (*(char *) data) & 0xff); break; case 2: /* half-word */ printf(" = <0x%04x>", be16_to_cpu(*(u16 *) data) & 0xffff); break; case 4: /* word */ printf(" = <0x%08x>", be32_to_cpu(*(u32 *) data) & 0xffffffffU); break; case 8: /* double-word */ printf(" = <0x%16llx>", be64_to_cpu(*(u64 *) data)); break; default: /* anything else... hexdump */ printf(" = ["); for (i = 0, s = data; i < len; i++) printf("%02x%s", s[i], i < len - 1 ? " " : ""); printf("]"); break; }}void ft_dump_blob(const void *bphp){ const struct boot_param_header *bph = bphp; const u64 *p_rsvmap = (const u64 *) ((const char *)bph + be32_to_cpu(bph->off_mem_rsvmap)); const u32 *p_struct = (const u32 *) ((const char *)bph + be32_to_cpu(bph->off_dt_struct)); const u32 *p_strings = (const u32 *) ((const char *)bph + be32_to_cpu(bph->off_dt_strings)); const u32 version = be32_to_cpu(bph->version); u32 i, *p, *tagp, *sizep; char *namep, *datap; int depth, shift; u64 addr, size; if (be32_to_cpu(bph->magic) != OF_DT_HEADER) { /* not valid tree */ return; } depth = 0; shift = 4; for (i = 0;; i++) { addr = be64_to_cpu(p_rsvmap[i * 2]); size = be64_to_cpu(p_rsvmap[i * 2 + 1]); if (addr == 0 && size == 0) break; printf("/memreserve/ 0x%llx 0x%llx;\n", addr, size); } p = (u32 *)p_struct; while ((p = ft_next(p, p_strings, version, &tagp, &namep, &datap, &sizep)) != NULL) switch (be32_to_cpu(*tagp)) { case OF_DT_BEGIN_NODE: printf("%*s%s {\n", depth * shift, "", namep); depth++; break; case OF_DT_END_NODE: depth--; printf("%*s};\n", depth * shift, ""); break; case OF_DT_NOP: printf("%*s[NOP]\n", depth * shift, ""); break; case OF_DT_END: break; case OF_DT_PROP: printf("%*s%s", depth * shift, "", namep); print_data(datap, *sizep); printf(";\n"); break; default: fprintf(stderr, "%*s ** Unknown tag 0x%08x\n", depth * shift, "", *tagp); return; }}void ft_backtrack_node(struct ft_cxt *cxt){ if (be32_to_cpu(*(u32 *) (cxt->p - 4)) != OF_DT_END_NODE) return; /* XXX only for node */ cxt->p -= 4;}/* note that the root node of the blob is "peeled" off */void ft_merge_blob(struct ft_cxt *cxt, void *blob){ struct boot_param_header *bph = (struct boot_param_header *)blob; u32 *p_struct = (u32 *) ((char *)bph + be32_to_cpu(bph->off_dt_struct)); u32 *p_strings = (u32 *) ((char *)bph + be32_to_cpu(bph->off_dt_strings)); const u32 version = be32_to_cpu(bph->version); u32 *p, *tagp, *sizep; char *namep, *datap; int depth; if (be32_to_cpu(*(u32 *) (cxt->p - 4)) != OF_DT_END_NODE) return; /* XXX only for node */ cxt->p -= 4; depth = 0; p = p_struct; while ((p = ft_next(p, p_strings, version, &tagp, &namep, &datap, &sizep)) != NULL) switch (be32_to_cpu(*tagp)) { case OF_DT_BEGIN_NODE: if (depth++ > 0) ft_begin_node(cxt, namep); break; case OF_DT_END_NODE: ft_end_node(cxt); if (--depth == 0) return; break; case OF_DT_PROP: ft_prop(cxt, namep, datap, *sizep); break; }}/**********************************************************************/void *ft_find_node(const void *bphp, const char *srch_path){ const struct boot_param_header *bph = bphp; u32 *p_struct = (u32 *)((char *)bph + be32_to_cpu(bph->off_dt_struct)); u32 *p_strings= (u32 *)((char *)bph + be32_to_cpu(bph->off_dt_strings)); u32 version = be32_to_cpu(bph->version); u32 *p, *tagp, *sizep; char *namep, *datap; static char path[MAX_PATH_LEN]; path[0] = '\0'; p = p_struct; while ((p = ft_next(p, p_strings, version, &tagp, &namep, &datap, &sizep)) != NULL) switch (be32_to_cpu(*tagp)) { case OF_DT_BEGIN_NODE: strcat(path, namep); if (!strcmp(path, srch_path)) return tagp; strcat(path, "/"); break; case OF_DT_END_NODE: ft_parentize(path, 1); break; } return NULL;}int ft_get_prop(const void *bphp, const void *node, const char *propname, void *buf, const unsigned int buflen){ const struct boot_param_header *bph = bphp; u32 *p_strings= (u32 *)((char *)bph + be32_to_cpu(bph->off_dt_strings)); u32 version = be32_to_cpu(bph->version); u32 *p, *tagp, *sizep, size; char *namep, *datap; int depth; depth = 0; p = (u32 *)node; while ((p = ft_next(p, p_strings, version, &tagp, &namep, &datap, &sizep)) != NULL) switch (be32_to_cpu(*tagp)) { case OF_DT_BEGIN_NODE: depth++; break; case OF_DT_PROP: if ((depth == 1) && !strcmp(namep, propname)) { size = min(be32_to_cpu(*sizep), (u32)buflen); memcpy(buf, datap, size); return size; } break; case OF_DT_END_NODE: if (--depth <= 0) return -1; break; } return -1;}static void ft_modify_prop(void **bphpp, char *datap, u32 *old_prop_sizep, const char *buf, const unsigned int buflen){ u32 old_prop_data_len, new_prop_data_len; old_prop_data_len = _ALIGN(be32_to_cpu(*old_prop_sizep), 4); new_prop_data_len = _ALIGN(buflen, 4); /* Check if new prop data fits in old prop data area */ if (new_prop_data_len == old_prop_data_len) { memcpy(datap, buf, buflen); *old_prop_sizep = cpu_to_be32(buflen); } else { /* Need to alloc new area to put larger or smaller ft */ struct boot_param_header *old_bph = *bphpp, *new_bph; u32 *old_tailp, *new_tailp, *new_datap; u32 old_total_size, new_total_size, head_len, tail_len, diff, v; old_total_size = be32_to_cpu(old_bph->totalsize); head_len = (u32)(datap - (char *)old_bph); tail_len = old_total_size - (head_len + old_prop_data_len); old_tailp = (u32 *)(datap + old_prop_data_len); new_total_size = head_len + new_prop_data_len + tail_len; if (!(new_bph = malloc(new_total_size))) { printf("Can't alloc space for new ft\n"); ft_exit(-ENOSPC); } new_datap = (u32 *)((char *)new_bph + head_len); new_tailp = (u32 *)((char *)new_datap + new_prop_data_len); memcpy(new_bph, *bphpp, head_len); memcpy(new_datap, buf, buflen); memcpy(new_tailp, old_tailp, tail_len); *(new_datap - 2) = cpu_to_be32(buflen); /* Set prop size */ new_bph->totalsize = cpu_to_be32(new_total_size); diff = new_prop_data_len - old_prop_data_len; if (be32_to_cpu(old_bph->off_dt_strings) > be32_to_cpu(old_bph->off_dt_struct)) { v = be32_to_cpu(new_bph->off_dt_strings); new_bph->off_dt_strings = cpu_to_be32(v + diff); } if (be32_to_cpu(old_bph->off_mem_rsvmap) > be32_to_cpu(old_bph->off_dt_struct)) { v = be32_to_cpu(new_bph->off_mem_rsvmap); new_bph->off_mem_rsvmap = cpu_to_be32(v + diff); } ft_free(*bphpp, old_total_size); *bphpp = new_bph; }}/* * - Only modifies existing properties. * - The dev tree passed in may be freed and a new one allocated * (and *bphpp set to location of new dev tree). */int ft_set_prop(void **bphpp, const void *node, const char *propname, const void *buf, const unsigned int buflen){ struct boot_param_header *bph = *bphpp; u32 *p_strings= (u32 *)((char *)bph + be32_to_cpu(bph->off_dt_strings)); u32 version = be32_to_cpu(bph->version); u32 *p, *tagp, *sizep; char *namep, *datap; int depth; depth = 0; p = (u32 *)node; while ((p = ft_next(p, p_strings, version, &tagp, &namep, &datap, &sizep)) != NULL) switch (be32_to_cpu(*tagp)) { case OF_DT_BEGIN_NODE: depth++; break; case OF_DT_PROP: if ((depth == 1) && !strcmp(namep, propname)) { ft_modify_prop(bphpp, datap, sizep, buf, buflen); return be32_to_cpu(*sizep); } break; case OF_DT_END_NODE: if (--depth <= 0) return -1; break; } return -1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -