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_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_create(void *buf, int bufsize) { void *fdt = buf; if (bufsize < (int)sizeof(struct fdt_header)) return -FDT_ERR_NOSPACE; memset(buf, 0, bufsize); fdt_set_magic(fdt, FDT_SW_MAGIC); fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION); fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION); fdt_set_totalsize(fdt, bufsize); fdt_set_off_mem_rsvmap(fdt, FDT_ALIGN(sizeof(struct fdt_header), sizeof(struct fdt_reserve_entry))); fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt)); fdt_set_off_dt_strings(fdt, bufsize); return 0; }
/** * dump_fdt_regions() - Dump regions of an FDT as binary data * * This dumps an FDT as binary, but only certain regions of it. This is the * final stage of the grep - we have a list of regions we want to dump, * and this function dumps them. * * The output of this function may or may not be a valid FDT. To ensure it * is, these disp->flags must be set: * * FDT_REG_SUPERNODES: ensures that subnodes are preceeded by their * parents. Without this option, fragments of subnode data may be * output without the supernodes above them. This is useful for * hashing but cannot produce a valid FDT. * FDT_REG_ADD_STRING_TAB: Adds a string table to the end of the FDT. * Without this none of the properties will have names * FDT_REG_ADD_MEM_RSVMAP: Adds a mem_rsvmap table - an FDT is invalid * without this. * * @disp: Display structure, holding info about our options * @blob: FDT blob to display * @region: List of regions to display * @count: Number of regions * @out: Output destination */ static int dump_fdt_regions(struct display_info *disp, const void *blob, struct fdt_region region[], int count, char *out) { struct fdt_header *fdt; int size, struct_start; int ptr; int i; /* Set up a basic header (even if we don't actually write it) */ fdt = (struct fdt_header *)out; memset(fdt, '\0', sizeof(*fdt)); fdt_set_magic(fdt, FDT_MAGIC); struct_start = FDT_ALIGN(sizeof(struct fdt_header), sizeof(struct fdt_reserve_entry)); fdt_set_off_mem_rsvmap(fdt, struct_start); fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION); fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION); /* * Calculate the total size of the regions we are writing out. The * first will be the mem_rsvmap if the FDT_REG_ADD_MEM_RSVMAP flag * is set. The last will be the string table if FDT_REG_ADD_STRING_TAB * is set. */ for (i = size = 0; i < count; i++) size += region[i].size; /* Bring in the mem_rsvmap section from the old file if requested */ if (count > 0 && (disp->flags & FDT_REG_ADD_MEM_RSVMAP)) { struct_start += region[0].size; size -= region[0].size; } fdt_set_off_dt_struct(fdt, struct_start); /* Update the header to have the correct offsets/sizes */ if (count >= 2 && (disp->flags & FDT_REG_ADD_STRING_TAB)) { int str_size; str_size = region[count - 1].size; fdt_set_size_dt_struct(fdt, size - str_size); fdt_set_off_dt_strings(fdt, struct_start + size - str_size); fdt_set_size_dt_strings(fdt, str_size); fdt_set_totalsize(fdt, struct_start + size); } /* Write the header if required */ ptr = 0; if (disp->header) { ptr = sizeof(*fdt); while (ptr < fdt_off_mem_rsvmap(fdt)) out[ptr++] = '\0'; } /* Output all the nodes including any mem_rsvmap/string table */ for (i = 0; i < count; i++) { struct fdt_region *reg = ®ion[i]; memcpy(out + ptr, (const char *)blob + reg->offset, reg->size); ptr += reg->size; } return ptr; }