int fdt_reg_valid(uint32_t *reg, int len, int addr_cells, int size_cells) { int cells_in_tuple, i, tuples, tuple_size; uint32_t cur_start, cur_size; cells_in_tuple = (addr_cells + size_cells); tuple_size = cells_in_tuple * sizeof(uint32_t); tuples = len / tuple_size; if (tuples == 0) return (EINVAL); for (i = 0; i < tuples; i++) { if (addr_cells == 2) cur_start = fdt64_to_cpu(reg[i * cells_in_tuple]); else cur_start = fdt32_to_cpu(reg[i * cells_in_tuple]); if (size_cells == 2) cur_size = fdt64_to_cpu(reg[i * cells_in_tuple + 2]); else cur_size = fdt32_to_cpu(reg[i * cells_in_tuple + 1]); if (cur_size == 0) return (EINVAL); debugf(" reg#%d (start: 0x%0x size: 0x%0x) valid!\n", i, cur_start, cur_size); } return (0); }
int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) { CHECK_HEADER(fdt); *address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address); *size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size); return 0; }
int fdt_num_mem_rsv(const void *fdt) { int i = 0; while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0) i++; return i; }
u_long fdt_data_get(void *data, int cells) { if (cells == 1) return (fdt32_to_cpu(*((uint32_t *)data))); return (fdt64_to_cpu(*((uint64_t *)data))); }
/* memory reserve map의 개수를 구한다.*/ int fdt_num_mem_rsv(const void *fdt) { int i = 0; /* size가 0이 아니면 reserve map이 있다고 판단한다. */ while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0) i++; return i; }
void platform_early_init(void) { /* initialize the interrupt controller */ arm_gic_init(); arm_generic_timer_init(ARM_GENERIC_TIMER_PHYSICAL_INT, 0); uart_init_early(); /* look for a flattened device tree just before the kernel */ const void *fdt = (void *)KERNEL_BASE; int err = fdt_check_header(fdt); if (err >= 0) { /* walk the nodes, looking for 'memory' */ int depth = 0; int offset = 0; for (;;) { offset = fdt_next_node(fdt, offset, &depth); if (offset < 0) break; /* get the name */ const char *name = fdt_get_name(fdt, offset, NULL); if (!name) continue; /* look for the 'memory' property */ if (strcmp(name, "memory") == 0) { int lenp; const void *prop_ptr = fdt_getprop(fdt, offset, "reg", &lenp); if (prop_ptr && lenp == 0x10) { /* we're looking at a memory descriptor */ //uint64_t base = fdt64_to_cpu(*(uint64_t *)prop_ptr); uint64_t len = fdt64_to_cpu(*((const uint64_t *)prop_ptr + 1)); /* trim size on certain platforms */ #if ARCH_ARM if (len > 1024*1024*1024U) { len = 1024*1024*1024; /* only use the first 1GB on ARM32 */ printf("trimming memory to 1GB\n"); } #endif /* set the size in the pmm arena */ arena.size = len; } } } } /* add the main memory arena */ pmm_add_arena(&arena); /* reserve the first 64k of ram, which should be holding the fdt */ struct list_node list = LIST_INITIAL_VALUE(list); pmm_alloc_range(MEMBASE, 0x10000 / PAGE_SIZE, &list); }
uint64_t fdtdec_get_uint64(const void *blob, int node, const char *prop_name, uint64_t default_val) { const uint64_t *cell64; int length; cell64 = fdt_getprop(blob, node, prop_name, &length); if (!cell64 || length < sizeof(*cell64)) return default_val; return fdt64_to_cpu(*cell64); }
static int mem_rsv_cmp(const void *p1, const void *p2) { const struct fdt_reserve_entry *re1 = p1; const struct fdt_reserve_entry *re2 = p2; if (fdt64_to_cpu(re1->address) < fdt64_to_cpu(re2->address)) return -1; else if (fdt64_to_cpu(re1->address) > fdt64_to_cpu(re2->address)) return 1; if (fdt64_to_cpu(re1->size) < fdt64_to_cpu(re2->size)) return -1; else if (fdt64_to_cpu(re1->size) > fdt64_to_cpu(re2->size)) return 1; return 0; }
static __init u64 get_kaslr_seed(void *fdt) { int node, len; fdt64_t *prop; u64 ret; node = fdt_path_offset(fdt, "/chosen"); if (node < 0) return 0; prop = fdt_getprop_w(fdt, node, "kaslr-seed", &len); if (!prop || len != sizeof(u64)) return 0; ret = fdt64_to_cpu(*prop); *prop = 0; return ret; }
static void bcm2835_late_init(platform_t plat) { phandle_t system; pcell_t cells[2]; int len; system = OF_finddevice("/system"); if (system != 0) { len = OF_getprop(system, "linux,serial", &cells, sizeof(cells)); if (len > 0) board_set_serial(fdt64_to_cpu(*((uint64_t *)cells))); len = OF_getprop(system, "linux,revision", &cells, sizeof(cells)); if (len > 0) board_set_revision(fdt32_to_cpu(*((uint32_t *)cells))); } }
static uint32_t discover_processors(void) { #if defined(HAS_UBOOT) return QORIQ_CPU_COUNT; #elif defined(U_BOOT_USE_FDT) const void *fdt = bsp_fdt_get(); int cpus = fdt_path_offset(fdt, "/cpus"); int node = fdt_first_subnode(fdt, cpus); uint32_t cpu = 0; uintptr_t last = 0; uintptr_t begin = last - 1; while (node >= 0) { int len; fdt64_t *addr_fdt = (fdt64_t *) fdt_getprop(fdt, node, "cpu-release-addr", &len); if ( addr_fdt != NULL && cpu < RTEMS_ARRAY_SIZE(qoriq_start_spin_table_addr) ) { uintptr_t addr = (uintptr_t) fdt64_to_cpu(*addr_fdt); if (addr < begin) { begin = addr; } if (addr > last) { last = addr; } qoriq_start_spin_table_addr[cpu] = (qoriq_start_spin_table *) addr; ++cpu; } node = fdt_next_subnode(fdt, node); } return cpu * QORIQ_THREAD_COUNT; #endif }
static void write_propval_int(FILE *f, const char *p, size_t len, size_t width) { const char *end = p + len; assert(len % width == 0); for (; p < end; p += width) { switch (width) { case 1: fprintf(f, " %02"PRIx8, *(const uint8_t*)p); break; case 2: fprintf(f, " 0x%02"PRIx16, fdt16_to_cpu(*(const fdt16_t*)p)); break; case 4: fprintf(f, " 0x%02"PRIx32, fdt32_to_cpu(*(const fdt32_t*)p)); break; case 8: fprintf(f, " 0x%02"PRIx64, fdt64_to_cpu(*(const fdt64_t*)p)); break; } } }
static int getprop_u64(const void *fdt, int nodeoffset, const char *name, uint64_t *val) { int len; const fdt64_t *prop; prop = fdt_getprop(fdt, nodeoffset, name, &len); if (!prop && len == -FDT_ERR_NOTFOUND) return -1; if (!prop) { fprintf(stderr, "getprop_u64 %s returned %d\n", name, len); return -1; } if (len != sizeof(uint64_t)) { fprintf(stderr, "getprop_u64 %s unexpected length %d\n", name, len); return -1; } *val = fdt64_to_cpu(*prop); return 0; }
static uint64 fdt_get_range_offset(const void* fdt, int32 node) { // Obtain the offset of the device by searching // for the first ranges start in parents. // It could be possible that there are multiple // offset ranges in several parents + children. // Lets hope that no system designer is that insane. int depth = fdt_node_depth(fdt, node); int32 examineNode = node; uint64 pathOffset = 0x0; while (depth > 0) { int len; const void* prop; prop = fdt_getprop(fdt, examineNode, "ranges", &len); if (prop) { int32 regAddressCells = 1; int32 regSizeCells = 1; fdt_get_cell_count(fdt, examineNode, regAddressCells, regSizeCells); const uint32 *p = (const uint32 *)prop; // All we are interested in is the start offset if (regAddressCells == 2) pathOffset = fdt64_to_cpu(*(uint64_t *)p); else pathOffset = fdt32_to_cpu(*(uint32_t *)p); break; } int32 parentNode = fdt_parent_offset(fdt, examineNode); depth = fdt_node_depth(fdt, parentNode); examineNode = parentNode; } TRACE("%s: range offset: 0x%" B_PRIx64 "\n", __func__, pathOffset); return pathOffset; }
static int fit_image_addr(const void *itb, int img, const char *name, hwaddr *addr) { const void *prop; int len; prop = fdt_getprop(itb, img, name, &len); if (!prop) { return -ENOENT; } switch (len) { case 4: *addr = fdt32_to_cpu(*(fdt32_t *)prop); return 0; case 8: *addr = fdt64_to_cpu(*(fdt64_t *)prop); return 0; default: error_printf("invalid %s address length %d\n", name, len); return -EINVAL; } }
static uint32_t discover_processors(void) { const void *fdt = bsp_fdt_get(); int cpus = fdt_path_offset(fdt, "/cpus"); int node = fdt_first_subnode(fdt, cpus); uint32_t cpu = 0; while (node >= 0 && cpu < RTEMS_ARRAY_SIZE(qoriq_start_spin_table_addr)) { int len; fdt64_t *addr_fdt = (fdt64_t *) fdt_getprop(fdt, node, "cpu-release-addr", &len); if (addr_fdt != NULL) { uintptr_t addr = (uintptr_t) fdt64_to_cpu(*addr_fdt); qoriq_start_spin_table_addr[cpu] = (qoriq_start_spin_table *) addr; } ++cpu; node = fdt_next_subnode(fdt, node); } return cpu * QORIQ_THREAD_COUNT; }
phys_addr_t fdt_get_device_reg(const void* fdt, int node, bool physical) { const void *prop = NULL; int len; uint64 baseDevice = 0x0; int32 regAddressCells = 1; int32 regSizeCells = 1; fdt_get_cell_count(fdt, node, regAddressCells, regSizeCells); // TODO: check for virtual-reg, and don't -= fdt_get_range_offset? // XXX: not sure #address-cells & #size-cells actually apply to virtual-reg if (!physical) { prop = fdt_getprop(fdt, node, "virtual-reg", &len); if (prop != NULL) { baseDevice = fdt32_to_cpu(*(uint32_t *)prop); return baseDevice; } } prop = fdt_getprop(fdt, node, "reg", &len); if (!prop) { dprintf("%s: reg property not found on node in FDT!\n", __func__); return 0; } const uint32 *p = (const uint32 *)prop; // soc base address cells if (regAddressCells == 2) baseDevice = fdt64_to_cpu(*(uint64_t *)p); else baseDevice = fdt32_to_cpu(*(uint32_t *)p); //p += regAddressCells; // subtract the range offset (X) on the parent node (ranges = X Y Z) baseDevice -= fdt_get_range_offset(fdt, node); // find the start of the parent (X) and add to base (regs = X Y) int parentNode = fdt_parent_offset(fdt, node); if (!parentNode) return baseDevice; fdt_get_cell_count(fdt, parentNode, regAddressCells, regSizeCells); prop = fdt_getprop(fdt, parentNode, "reg", &len); if (!prop) return baseDevice; p = (const uint32 *)prop; uint64 parentReg = 0x0; // soc base address cells if (regAddressCells == 2) parentReg = fdt64_to_cpu(*(uint64_t *)p); else parentReg = fdt32_to_cpu(*(uint32_t *)p); // add parent reg base to property baseDevice += parentReg; return baseDevice; }
void kexec_memory_map(void *fdt, int reserve_initrd) { uint64_t start, size, end; int nodeoffset; int lpar = 0; kexec_map = simple_init(); /* Work out if we are in LPAR mode */ nodeoffset = fdt_path_offset(fdt, "/rtas"); if (nodeoffset >= 0) { if (fdt_getprop(fdt, nodeoffset, "ibm,hypertas-functions", NULL)) lpar = 1; } /* First find our memory */ nodeoffset = fdt_path_offset(fdt, "/"); if (nodeoffset < 0) { fprintf(stderr, "Device tree has no root node\n"); exit(1); } while (1) { const char *type; int len; const fdt64_t *reg; nodeoffset = fdt_next_node(fdt, nodeoffset, NULL); if (nodeoffset < 0) break; type = fdt_getprop(fdt, nodeoffset, "device_type", NULL); if (!type || strcmp(type, "memory")) continue; reg = fdt_getprop(fdt, nodeoffset, "reg", &len); while (len) { start = fdt64_to_cpu(*reg++); size = fdt64_to_cpu(*reg++); len -= 2 * sizeof(uint64_t); if (lpar == 1) { /* Only use the RMA region for LPAR */ if (start == 0) { if (size > MEMORY_CAP) size = MEMORY_CAP; simple_free(kexec_map, 0, size); mem_top = size; } } else { if (start >= MEMORY_CAP) continue; if ((start + size) > MEMORY_CAP) size = MEMORY_CAP - start; simple_free(kexec_map, start, size); if ((start + size) > mem_top) mem_top = start + size; } } } /* Reserve the kernel */ nodeoffset = fdt_path_offset(fdt, "/chosen"); if (nodeoffset < 0) { fprintf(stderr, "Device tree has no chosen node\n"); exit(1); } /* * XXX FIXME: Need to add linux,kernel-start property to the * kernel to handle relocatable kernels. */ start = 0; if (getprop_u64(fdt, nodeoffset, "linux,kernel-end", &end)) { fprintf(stderr, "getprop linux,kernel-end failed\n"); exit(1); } simple_alloc_at(kexec_map, start, end - start); /* Reserve the MMU hashtable in non LPAR mode */ if (lpar == 0) { if (getprop_u64(fdt, nodeoffset, "linux,htab-base", &start) || getprop_u64(fdt, nodeoffset, "linux,htab-size", &size)) { fprintf(stderr, "Could not find linux,htab-base or " "linux,htab-size properties\n"); exit(1); } if (start < mem_top) simple_alloc_at(kexec_map, start, size); } /* XXX FIXME: Reserve TCEs in kexec_map */ if (new_style_reservation(fdt, reserve_initrd)) return; /* Reserve the initrd if requested */ if (reserve_initrd && !getprop_u64(fdt, nodeoffset, "linux,initrd-start", &start) && !getprop_u64(fdt, nodeoffset, "linux,initrd-end", &end)) { if (start < mem_top) simple_alloc_at(kexec_map, start, end - start); } /* Reserve RTAS */ nodeoffset = fdt_path_offset(fdt, "/rtas"); if (nodeoffset > 0) { uint32_t rtas_start, rtas_size; if (getprop_u32(fdt, nodeoffset, "linux,rtas-base", &rtas_start)) { fprintf(stderr, "getprop linux,rtas-base failed\n"); exit(1); } if (getprop_u32(fdt, nodeoffset, "rtas-size", &rtas_size)) { fprintf(stderr, "getprop rtas-size failed\n"); exit(1); } simple_alloc_at(kexec_map, rtas_start, rtas_size); if (fdt_add_mem_rsv(fdt, rtas_start, rtas_size)) perror("fdt_add_mem_rsv"); } nodeoffset = fdt_path_offset(fdt, "/ibm,opal"); if (nodeoffset > 0) { uint64_t opal_start, opal_size; if (getprop_u64(fdt, nodeoffset, "opal-base-address", &opal_start)) { fprintf(stderr, "getprop opal-base-address failed\n"); exit(1); } if (getprop_u64(fdt, nodeoffset, "opal-runtime-size", &opal_size)) { fprintf(stderr, "getprop opal-runtime-size failed\n"); exit(1); } simple_alloc_at(kexec_map, opal_start, opal_size); if (fdt_add_mem_rsv(fdt, opal_start, opal_size)) perror("fdt_add_mem_rsv"); } }
static int new_style_reservation(void *fdt, int reserve_initrd) { int nodeoffset; const void *p; fdt64_t *ranges, *range; char *names, *name; int ranges_len, names_len; nodeoffset = fdt_path_offset(fdt, "/"); if (nodeoffset < 0) { fprintf(stderr, "Device tree has no root node\n"); exit(1); } p = fdt_getprop(fdt, nodeoffset, "reserved-ranges", &ranges_len); if (!p && ranges_len == -FDT_ERR_NOTFOUND) return 0; if (!p) { fprintf(stderr, "getprop reserved-ranges returned %d\n", ranges_len); exit(1); } ranges = malloc(ranges_len); if (!ranges) { perror("malloc"); exit(1); } memcpy(ranges, p, ranges_len); p = fdt_getprop(fdt, nodeoffset, "reserved-names", &names_len); if (!p && names_len == -FDT_ERR_NOTFOUND) return 0; if (!p) { fprintf(stderr, "getprop reserved-names returned %d\n", names_len); exit(1); } names = malloc(names_len); if (!names) { perror("malloc"); exit(1); } memcpy(names, p, names_len); name = names; range = ranges; while (ranges_len > 0 && names_len > 0) { uint64_t start, size; start = fdt64_to_cpu(*range++); size = fdt64_to_cpu(*range++); #ifdef DEBUG printf("%s %lx %lx\n", name, start, size); #endif if (!reserve_initrd && !strcmp(name, "linux,initramfs")) continue; simple_alloc_at(kexec_map, start, size); if (fdt_add_mem_rsv(fdt, start, size)) perror("fdt_add_mem_rsv"); ranges_len -= 2 * sizeof(uint64_t); names_len -= strlen(name) + 1; name += strlen(name) + 1; } free(ranges); free(names); return 1; }
/** * 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; }
/* * fdt_get_reg - Fill buffer by information from DT */ static phys_size_t fdt_get_reg(const void *fdt, int nodeoffset, void *buf, const u32 *cell, int n) { int i = 0, b, banks; int parent_offset = fdt_parent_offset(fdt, nodeoffset); int address_cells = fdt_address_cells(fdt, parent_offset); int size_cells = fdt_size_cells(fdt, parent_offset); char *p = buf; phys_addr_t val; phys_size_t vals; debug("%s: addr_cells=%x, size_cell=%x, buf=%p, cell=%p\n", __func__, address_cells, size_cells, buf, cell); /* Check memory bank setup */ banks = n % (address_cells + size_cells); if (banks) panic("Incorrect memory setup cells=%d, ac=%d, sc=%d\n", n, address_cells, size_cells); banks = n / (address_cells + size_cells); for (b = 0; b < banks; b++) { debug("%s: Bank #%d:\n", __func__, b); if (address_cells == 2) { val = cell[i + 1]; val <<= 32; val |= cell[i]; val = fdt64_to_cpu(val); debug("%s: addr64=%llx, ptr=%p, cell=%p\n", __func__, val, p, &cell[i]); *(phys_addr_t *)p = val; } else { debug("%s: addr32=%x, ptr=%p\n", __func__, fdt32_to_cpu(cell[i]), p); *(phys_addr_t *)p = fdt32_to_cpu(cell[i]); } p += sizeof(phys_addr_t); i += address_cells; debug("%s: pa=%p, i=%x, size=%zu\n", __func__, p, i, sizeof(phys_addr_t)); if (size_cells == 2) { vals = cell[i + 1]; vals <<= 32; vals |= cell[i]; vals = fdt64_to_cpu(vals); debug("%s: size64=%llx, ptr=%p, cell=%p\n", __func__, vals, p, &cell[i]); *(phys_size_t *)p = vals; } else { debug("%s: size32=%x, ptr=%p\n", __func__, fdt32_to_cpu(cell[i]), p); *(phys_size_t *)p = fdt32_to_cpu(cell[i]); } p += sizeof(phys_size_t); i += size_cells; debug("%s: ps=%p, i=%x, size=%zu\n", __func__, p, i, sizeof(phys_size_t)); } /* Return the first address size */ return *(phys_size_t *)((char *)buf + sizeof(phys_addr_t)); }
void dt_platform_init_fdt(void *fdt) { int rv; system_fdt = fdt; printf("fdt_platform_init %p\n", fdt); // Check header if ((rv = fdt_check_header(fdt))) { panic("Bad FDT: %s\n", fdt_strerror(rv)); } // Process memory reservations printf("rsv %p\n", fdt); int num_rsv = fdt_num_mem_rsv(fdt); for (int i = 0; i < num_rsv; i++) { printf("get\n"); gd_memory_map_entry ent; ent.type = gd_reserved_memory_type; ent.attributes = 0; fdt_get_mem_rsv(fdt, i, &ent.physical_start, &ent.size); printf("got\n"); ent.virtual_start = ent.physical_start; printf("Adding reserved memory region: %" PRIX64 " len=%" PRIX64 "\n", ent.physical_start, ent.size); mmap_add_entry(ent); } // Process root note memory entries printf("root\n"); int root = fdt_next_node(fdt, -1, NULL); unsigned addr_cells = fdt_address_cells(fdt, root); unsigned size_cells = fdt_size_cells(fdt, root); unsigned cells = addr_cells + size_cells; int mem_offs = fdt_subnode_offset(fdt, root, "memory"); if (mem_offs < 0) { panic("Unable to locate memory node (%s)\n", fdt_strerror(mem_offs)); } int memlen; const uint32_t *p = fdt_getprop(system_fdt, mem_offs, "reg", &memlen); for (int i = 0; i < memlen / 4; i+= cells) { uint64_t base_addr = 0, base_size = 0; if (addr_cells == 1) { base_addr = fdt32_to_cpu(p[i]); } else if (addr_cells == 2) { base_addr = fdt64_to_cpu(((uint64_t) p[i + 1]) << 32 | p[i]); } if (size_cells == 1) { base_size = fdt32_to_cpu(p[i + addr_cells]); } else if (size_cells == 2) { base_size = fdt64_to_cpu(((uint64_t) p[i + addr_cells + 1]) << 32 | p[i + addr_cells]); } printf("Adding memory range %16" PRIX64 " len %16" PRIX64 "\n", base_addr, base_size); gd_memory_map_entry ent = { 0 }; ent.type = gd_conventional_memory; ent.attributes = 0; ent.virtual_start = ent.physical_start = base_addr; ent.size = base_size; mmap_add_entry(ent); } dt_root = add_device_fdt(NULL, fdt, root, 0); }
/** Initialize the system (or sometimes called permanent) memory This memory is generally represented by the DRAM. This function is called from InitializeMemory() in MemoryInitPeim, in the PEI phase. **/ VOID ArmPlatformInitializeSystemMemory ( VOID ) { VOID *DeviceTreeBase; INT32 Node, Prev; UINT64 NewBase; UINT64 NewSize; CONST CHAR8 *Type; INT32 Len; CONST UINT64 *RegProp; NewBase = 0; NewSize = 0; DeviceTreeBase = (VOID *)(UINTN)PcdGet64 (PcdDeviceTreeInitialBaseAddress); ASSERT (DeviceTreeBase != NULL); // // Make sure we have a valid device tree blob // ASSERT (fdt_check_header (DeviceTreeBase) == 0); // // Look for a memory node // for (Prev = 0;; Prev = Node) { Node = fdt_next_node (DeviceTreeBase, Prev, NULL); if (Node < 0) { break; } // // Check for memory node // Type = fdt_getprop (DeviceTreeBase, Node, "device_type", &Len); if (Type && AsciiStrnCmp (Type, "memory", Len) == 0) { // // Get the 'reg' property of this node. For now, we will assume // two 8 byte quantities for base and size, respectively. // RegProp = fdt_getprop (DeviceTreeBase, Node, "reg", &Len); if (RegProp != 0 && Len == (2 * sizeof (UINT64))) { NewBase = fdt64_to_cpu (ReadUnaligned64 (RegProp)); NewSize = fdt64_to_cpu (ReadUnaligned64 (RegProp + 1)); // // Make sure the start of DRAM matches our expectation // ASSERT (FixedPcdGet64 (PcdSystemMemoryBase) == NewBase); PcdSet64 (PcdSystemMemorySize, NewSize); DEBUG ((EFI_D_INFO, "%a: System RAM @ 0x%lx - 0x%lx\n", __FUNCTION__, NewBase, NewBase + NewSize - 1)); } else { DEBUG ((EFI_D_ERROR, "%a: Failed to parse FDT memory node\n", __FUNCTION__)); } break; } } // // We need to make sure that the machine we are running on has at least // 128 MB of memory configured, and is currently executing this binary from // NOR flash. This prevents a device tree image in DRAM from getting // clobbered when our caller installs permanent PEI RAM, before we have a // chance of marking its location as reserved or copy it to a freshly // allocated block in the permanent PEI RAM in the platform PEIM. // ASSERT (NewSize >= SIZE_128MB); ASSERT ( (((UINT64)PcdGet64 (PcdFdBaseAddress) + (UINT64)PcdGet32 (PcdFdSize)) <= NewBase) || ((UINT64)PcdGet64 (PcdFdBaseAddress) >= (NewBase + NewSize))); }
STATIC UINT64 SerialPortGetBaseAddress ( VOID ) { UINT64 BaudRate; UINT32 ReceiveFifoDepth; EFI_PARITY_TYPE Parity; UINT8 DataBits; EFI_STOP_BITS_TYPE StopBits; VOID *DeviceTreeBase; INT32 Node, Prev; INT32 Len; CONST CHAR8 *Compatible; CONST CHAR8 *NodeStatus; CONST CHAR8 *CompatibleItem; CONST UINT64 *RegProperty; UINTN UartBase; RETURN_STATUS Status; DeviceTreeBase = (VOID *)(UINTN)PcdGet64 (PcdDeviceTreeInitialBaseAddress); if ((DeviceTreeBase == NULL) || (fdt_check_header (DeviceTreeBase) != 0)) { return 0; } // // Enumerate all FDT nodes looking for a PL011 and capture its base address // for (Prev = 0;; Prev = Node) { Node = fdt_next_node (DeviceTreeBase, Prev, NULL); if (Node < 0) { break; } Compatible = fdt_getprop (DeviceTreeBase, Node, "compatible", &Len); if (Compatible == NULL) { continue; } // // Iterate over the NULL-separated items in the compatible string // for (CompatibleItem = Compatible; CompatibleItem < Compatible + Len; CompatibleItem += 1 + AsciiStrLen (CompatibleItem)) { if (AsciiStrCmp (CompatibleItem, "arm,pl011") == 0) { NodeStatus = fdt_getprop (DeviceTreeBase, Node, "status", &Len); if (NodeStatus != NULL && AsciiStrCmp (NodeStatus, "okay") != 0) { continue; } RegProperty = fdt_getprop (DeviceTreeBase, Node, "reg", &Len); if (Len != 16) { return 0; } UartBase = (UINTN)fdt64_to_cpu (ReadUnaligned64 (RegProperty)); BaudRate = (UINTN)FixedPcdGet64 (PcdUartDefaultBaudRate); ReceiveFifoDepth = 0; // Use the default value for Fifo depth Parity = (EFI_PARITY_TYPE)FixedPcdGet8 (PcdUartDefaultParity); DataBits = FixedPcdGet8 (PcdUartDefaultDataBits); StopBits = (EFI_STOP_BITS_TYPE) FixedPcdGet8 (PcdUartDefaultStopBits); Status = PL011UartInitializePort ( UartBase, FixedPcdGet32 (PL011UartClkInHz), &BaudRate, &ReceiveFifoDepth, &Parity, &DataBits, &StopBits ); if (!EFI_ERROR (Status)) { return UartBase; } } } } return 0; }
static void dump_blob(void *blob) { struct fdt_header *bph = blob; uint32_t off_mem_rsvmap = fdt32_to_cpu(bph->off_mem_rsvmap); uint32_t off_dt = fdt32_to_cpu(bph->off_dt_struct); uint32_t off_str = fdt32_to_cpu(bph->off_dt_strings); struct fdt_reserve_entry *p_rsvmap = (struct fdt_reserve_entry *)((char *)blob + off_mem_rsvmap); const char *p_struct = (const char *)blob + off_dt; const char *p_strings = (const char *)blob + off_str; uint32_t version = fdt32_to_cpu(bph->version); uint32_t totalsize = fdt32_to_cpu(bph->totalsize); uint32_t tag; const char *p, *s, *t; int depth, sz, shift; int i; uint64_t addr, size; depth = 0; shift = 4; printf("/dts-v1/;\n"); printf("// magic:\t\t0x%x\n", fdt32_to_cpu(bph->magic)); printf("// totalsize:\t\t0x%x (%d)\n", totalsize, totalsize); printf("// off_dt_struct:\t0x%x\n", off_dt); printf("// off_dt_strings:\t0x%x\n", off_str); printf("// off_mem_rsvmap:\t0x%x\n", off_mem_rsvmap); printf("// version:\t\t%d\n", version); printf("// last_comp_version:\t%d\n", fdt32_to_cpu(bph->last_comp_version)); if (version >= 2) printf("// boot_cpuid_phys:\t0x%x\n", fdt32_to_cpu(bph->boot_cpuid_phys)); if (version >= 3) printf("// size_dt_strings:\t0x%x\n", fdt32_to_cpu(bph->size_dt_strings)); if (version >= 17) printf("// size_dt_struct:\t0x%x\n", fdt32_to_cpu(bph->size_dt_struct)); printf("\n"); 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; printf("/memreserve/ %llx %llx;\n", (unsigned long long)addr, (unsigned long long)size); } p = p_struct; while ((tag = fdt32_to_cpu(GET_CELL(p))) != FDT_END) { /* printf("tag: 0x%08x (%d)\n", tag, p - p_struct); */ if (tag == FDT_BEGIN_NODE) { s = p; p = PALIGN(p + strlen(s) + 1, 4); if (*s == '\0') s = "/"; printf("%*s%s {\n", depth * shift, "", s); depth++; continue; } if (tag == FDT_END_NODE) { depth--; printf("%*s};\n", depth * shift, ""); continue; } if (tag == FDT_NOP) { printf("%*s// [NOP]\n", depth * shift, ""); continue; } if (tag != FDT_PROP) { fprintf(stderr, "%*s ** Unknown tag 0x%08x\n", depth * shift, "", tag); break; } sz = fdt32_to_cpu(GET_CELL(p)); s = p_strings + fdt32_to_cpu(GET_CELL(p)); if (version < 16 && sz >= 8) p = PALIGN(p, 8); t = p; p = PALIGN(p + sz, 4); printf("%*s%s", depth * shift, "", s); print_data(t, sz); printf(";\n"); } }
static void dump_blob(void *blob, bool debug) { uintptr_t blob_off = (uintptr_t)blob; struct fdt_header *bph = blob; uint32_t off_mem_rsvmap = fdt32_to_cpu(bph->off_mem_rsvmap); uint32_t off_dt = fdt32_to_cpu(bph->off_dt_struct); uint32_t off_str = fdt32_to_cpu(bph->off_dt_strings); struct fdt_reserve_entry *p_rsvmap = (struct fdt_reserve_entry *)((char *)blob + off_mem_rsvmap); const char *p_struct = (const char *)blob + off_dt; /* Get offset to the strings */ const char *p_strings = (const char *)blob + off_str; uint32_t version = fdt32_to_cpu(bph->version); uint32_t totalsize = fdt32_to_cpu(bph->totalsize); uint32_t tag; const char *p, *s, *t; int depth, sz, shift; int i; uint64_t addr, size; char *buffer; buffer = (char *)malloc(MAX_LEN); depth = 0; shift = 4; uint32_t off_total_size = fdt32_to_cpu(bph->totalsize); /* TODO: Remove this additional info. Do I need it? */ dprintf(buffer, "totalsize: %d\n", off_total_size); dprintf(buffer, "// magic:\t\t0x%x\n", fdt32_to_cpu(bph->magic)); dprintf(buffer, "// totalsize:\t\t0x%x (%d)\n", totalsize, totalsize); dprintf(buffer, "// off_dt_struct:\t0x%x\n", off_dt); dprintf(buffer, "// off_dt_strings:\t0x%x\n", off_str); dprintf(buffer, "// off_mem_rsvmap:\t0x%x\n", off_mem_rsvmap); dprintf(buffer, "// version:\t\t%d\n", version); dprintf(buffer, "// last_comp_version:\t%d\n", fdt32_to_cpu(bph->last_comp_version)); if (version >= 2) dprintf(buffer, "// boot_cpuid_phys:\t0x%x\n", fdt32_to_cpu(bph->boot_cpuid_phys)); if (version >= 3) dprintf(buffer, "// size_dt_strings:\t0x%x\n", fdt32_to_cpu(bph->size_dt_strings)); if (version >= 17) dprintf(buffer, "// size_dt_struct:\t0x%x\n", fdt32_to_cpu(bph->size_dt_struct)); dprintf(buffer, "\n"); 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; dprintf(buffer, "/memreserve/ %#llx %#llx;\n", (unsigned long long)addr, (unsigned long long)size); } p = p_struct; while ((tag = fdt32_to_cpu(GET_CELL(p))) != FDT_END) { dumpf("%04zx: tag: 0x%08x (%s)\n", (uintptr_t)p - blob_off - 4, tag, tagname(tag)); if (tag == FDT_BEGIN_NODE) { s = p; p = PALIGN(p + strlen(s) + 1, 4); if (*s == '\0') s = "/"; dprintf(buffer, "%*s%s {\n", depth * shift, "", s); depth++; continue; } if (tag == FDT_END_NODE) { depth--; dprintf(buffer, "%*s};\n", depth * shift, ""); continue; } if (tag == FDT_NOP) { dprintf(buffer, "%*s// [NOP]\n", depth * shift, ""); continue; } if (tag != FDT_PROP) { fprintf(stderr, "%*s ** Unknown tag 0x%08x\n", depth * shift, "", tag); break; } /* sz - length of the returned values in bytes */ sz = fdt32_to_cpu(GET_CELL(p)); /* s - pointer to the property name */ s = p_strings + fdt32_to_cpu(GET_CELL(p)); if (version < 16 && sz >= 8) p = PALIGN(p, 8); t = p; p = PALIGN(p + sz, 4); dumpf("%04zx: string: %s\n", (uintptr_t)s - blob_off, s); dumpf("%04zx: value\n", (uintptr_t)t - blob_off); dprintf(buffer, "%*s%s", depth * shift, "", s); my_utilfdt_print_data(t, sz, buffer); dprintf(buffer, ";\n"); } printf("%s", buffer); }