/* * Will relocate the DTB to the tags addr if the device tree is found and return * its address * * Arguments: kernel - Start address of the kernel loaded in RAM * tags - Start address of the tags loaded in RAM * Return Value: DTB address : If appended device tree is found * 'NULL' : Otherwise */ void *dev_tree_appended(void *kernel, void *tags) { uint32_t app_dtb_offset = 0; uint32_t dtb_magic = 0; memcpy((void*) &app_dtb_offset, (void*) (kernel + DTB_OFFSET), sizeof(uint32_t)); memcpy((void*) &dtb_magic, (void*) (kernel + app_dtb_offset), sizeof(uint32_t)); if (dtb_magic == DTB_MAGIC) { void *dtb; int rc; dprintf(INFO, "Found Appeneded Flattened Device tree\n"); dtb = kernel + app_dtb_offset; rc = fdt_open_into(dtb, tags, fdt_totalsize(dtb) + DTB_PAD_SIZE); if (rc == 0) { /* clear out the old DTB magic so kernel doesn't find it */ *((uint32_t *)dtb) = 0; return tags; } } return NULL; }
/** * early_init_fdt_scan_reserved_mem() - create reserved memory regions * * This function grabs memory from early allocator for device exclusive use * defined in device tree structures. It should be called by arch specific code * once the early allocator (i.e. memblock) has been fully activated. */ void __init early_init_fdt_scan_reserved_mem(void) { int n; u64 base, size; if (!initial_boot_params) return; /* Reserve the dtb region */ early_init_dt_reserve_memory_arch(__pa(initial_boot_params), fdt_totalsize(initial_boot_params), 0); /* Process header /memreserve/ fields */ for (n = 0; ; n++) { fdt_get_mem_rsv(initial_boot_params, n, &base, &size); if (!size) break; early_init_dt_reserve_memory_arch(base, size, 0); } of_scan_flat_dt(__fdt_scan_reserved_mem, NULL); fdt_init_reserved_mem(); }
/* * Load an EFI payload into a newly allocated piece of memory, register all * EFI objects it would want to access and jump to it. */ static unsigned long do_bootefi_exec(void *efi, void *fdt) { ulong (*entry)(void *image_handle, struct efi_system_table *st); ulong fdt_pages, fdt_size, fdt_start, fdt_end; bootm_headers_t img = { 0 }; /* * gd lives in a fixed register which may get clobbered while we execute * the payload. So save it here and restore it on every callback entry */ efi_save_gd(); if (fdt && !fdt_check_header(fdt)) { /* Prepare fdt for payload */ fdt = copy_fdt(fdt); if (image_setup_libfdt(&img, fdt, 0, NULL)) { printf("ERROR: Failed to process device tree\n"); return -EINVAL; } /* Link to it in the efi tables */ systab.tables[0].guid = EFI_FDT_GUID; systab.tables[0].table = fdt; systab.nr_tables = 1; /* And reserve the space in the memory map */ fdt_start = ((ulong)fdt) & ~EFI_PAGE_MASK; fdt_end = ((ulong)fdt) + fdt_totalsize(fdt); fdt_size = (fdt_end - fdt_start) + EFI_PAGE_MASK; fdt_pages = fdt_size >> EFI_PAGE_SHIFT; /* Give a bootloader the chance to modify the device tree */ fdt_pages += 2; efi_add_memory_map(fdt_start, fdt_pages, EFI_BOOT_SERVICES_DATA, true); } else {
extern "C" int start_gen(int argc, const char **argv, struct image_header *uimage, void *fdt) { stage2_args args; clear_bss(); // call C++ constructors before doing anything else call_ctors(); args.heap_size = HEAP_SIZE; args.arguments = NULL; args.arguments_count = 0; args.platform.boot_tgz_data = NULL; args.platform.boot_tgz_size = 0; args.platform.fdt_data = NULL; args.platform.fdt_size = 0; gUImage = uimage; gFDT = fdt; //XXX: make a copy? // TODO: check for atags instead and convert them if (argv) { // skip the kernel name ++argv; --argc; } // TODO: Ensure cmdline is mapped into memory by MMU before usage. // if we get passed a uimage, try to find the third blob // only if we do not have FDT data yet if (gUImage != NULL && !gFDT && image_multi_getimg(gUImage, 2, (uint32*)&args.platform.fdt_data, &args.platform.fdt_size)) { // found a blob, assume it is FDT data, when working on a platform // which does not have an FDT enabled U-Boot gFDT = args.platform.fdt_data; } // We have to cpu_init *before* calling FDT functions cpu_init(); serial_init(gFDT); #if defined(__ARM__) arch_mailbox_init(); #endif // initialize the OpenFirmware wrapper of_init(NULL); console_init(); // if we get passed an FDT, check /chosen for initrd and bootargs if (gFDT != NULL) { int node = fdt_path_offset(gFDT, "/chosen"); const void *prop; int len; phys_addr_t initrd_start = 0, initrd_end = 0; if (node >= 0) { prop = fdt_getprop(gFDT, node, "linux,initrd-start", &len); if (prop && len == 4) initrd_start = fdt32_to_cpu(*(uint32_t *)prop); prop = fdt_getprop(gFDT, node, "linux,initrd-end", &len); if (prop && len == 4) initrd_end = fdt32_to_cpu(*(uint32_t *)prop); if (initrd_end > initrd_start) { args.platform.boot_tgz_data = (void *)initrd_start; args.platform.boot_tgz_size = initrd_end - initrd_start; dprintf("Found boot tgz from FDT @ %p, %" B_PRIu32 " bytes\n", args.platform.boot_tgz_data, args.platform.boot_tgz_size); } // we check for bootargs after remapping the FDT } } // if we get passed a uimage, try to find the second blob if (gUImage != NULL && image_multi_getimg(gUImage, 1, (uint32*)&args.platform.boot_tgz_data, &args.platform.boot_tgz_size)) { dprintf("Found boot tgz from uimage @ %p, %" B_PRIu32 " bytes\n", args.platform.boot_tgz_data, args.platform.boot_tgz_size); } { //DEBUG: int i; dprintf("argc = %d\n", argc); for (i = 0; i < argc; i++) dprintf("argv[%d] @%lx = '%s'\n", i, (uint32)argv[i], argv[i]); dprintf("os: %d\n", (int)gUBootOS); dprintf("gd @ %p\n", gUBootGlobalData); if (gUBootGlobalData) { dprintf("gd->bd @ %p\n", gUBootGlobalData->bd); dprintf("gd->fb_base @ %p\n", (void*)gUBootGlobalData->fb_base); } if (gUImage) dump_uimage(gUImage); if (gFDT) dump_fdt(gFDT); } if (args.platform.boot_tgz_size > 0) { insert_physical_allocated_range((addr_t)args.platform.boot_tgz_data, args.platform.boot_tgz_size); } // save the size of the FDT so we can map it easily after mmu_init size_t fdtSize = gFDT ? fdt_totalsize(gFDT) : 0; dprintf("fdtSize: 0x%" B_PRIxSIZE "\n", fdtSize); mmu_init(); // Handle our tarFS post-mmu if (args.platform.boot_tgz_size > 0) { args.platform.boot_tgz_data = (void*)mmu_map_physical_memory((addr_t) args.platform.boot_tgz_data, args.platform.boot_tgz_size, kDefaultPageFlags); } // .. and our FDT if (gFDT != NULL) gFDT = (void*)mmu_map_physical_memory((addr_t)gFDT, fdtSize, kDefaultPageFlags); // if we get passed an FDT, check /chosen for bootargs now // to avoid having to copy them. if (gFDT != NULL) { int node = fdt_path_offset(gFDT, "/chosen"); const void *prop; int len; if (node >= 0) { prop = fdt_getprop(gFDT, node, "bootargs", &len); if (prop) { dprintf("Found bootargs: %s\n", (const char *)prop); static const char *sArgs[] = { NULL, NULL }; sArgs[0] = (const char *)prop; // override main() args args.arguments = sArgs; args.arguments_count = 1; } } dprintf("args.arguments_count = %" B_PRId32 "\n", args.arguments_count); for (int i = 0; i < args.arguments_count; i++) dprintf("args.arguments[%d] @%lx = '%s'\n", i, (uint32)args.arguments[i], args.arguments[i]); } // wait a bit to give the user the opportunity to press a key // spin(750000); // reading the keyboard doesn't seem to work in graphics mode // (maybe a bochs problem) // sBootOptions = check_for_boot_keys(); //if (sBootOptions & BOOT_OPTION_DEBUG_OUTPUT) serial_enable(); main(&args); return 0; }
int zImage_arm_load(int argc, char **argv, const char *buf, off_t len, struct kexec_info *info) { unsigned long base; unsigned int atag_offset = 0x1000; /* 4k offset from memory start */ unsigned int offset = 0x8000; /* 32k offset from memory start */ unsigned int opt_ramdisk_addr; unsigned int opt_atags_addr; const char *command_line; char *modified_cmdline = NULL; off_t command_line_len; const char *ramdisk; char *ramdisk_buf; int opt; char *endptr; int use_dtb; const char *dtb_file; char *dtb_buf; off_t dtb_length; off_t dtb_offset; struct arm_mach *mach; /* See options.h -- add any more there, too. */ static const struct option options[] = { KEXEC_ARCH_OPTIONS { "command-line", 1, 0, OPT_APPEND }, { "append", 1, 0, OPT_APPEND }, { "initrd", 1, 0, OPT_RAMDISK }, { "ramdisk", 1, 0, OPT_RAMDISK }, { "dtb", 2, 0, OPT_DTB }, { "rd-addr", 1, 0, OPT_RD_ADDR }, { "atags-addr", 1, 0, OPT_ATAGS_ADDR }, { "boardname", 1, 0, OPT_BOARDNAME }, { 0, 0, 0, 0 }, }; static const char short_options[] = KEXEC_ARCH_OPT_STR "a:r:d::i:g:b:"; /* * Parse the command line arguments */ command_line = 0; command_line_len = 0; ramdisk = 0; ramdisk_buf = 0; use_dtb = 0; dtb_file = NULL; opt_ramdisk_addr = 0; opt_atags_addr = 0; mach = NULL; while((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) { switch(opt) { default: /* Ignore core options */ if (opt < OPT_ARCH_MAX) { break; } case '?': usage(); return -1; case OPT_APPEND: command_line = optarg; break; case OPT_RAMDISK: ramdisk = optarg; break; case OPT_DTB: use_dtb = 1; if(optarg) dtb_file = optarg; break; case OPT_RD_ADDR: opt_ramdisk_addr = strtoul(optarg, &endptr, 0); if (*endptr) { fprintf(stderr, "Bad option value in --rd-addr=%s\n", optarg); usage(); return -1; } break; case OPT_ATAGS_ADDR: opt_atags_addr = strtoul(optarg, &endptr, 0); if (*endptr) { fprintf(stderr, "Bad option value in --atag-addr=%s\n", optarg); usage(); return -1; } break; case OPT_BOARDNAME: mach = arm_mach_choose(optarg); if(!mach) { fprintf(stderr, "Unknown boardname '%s'!\n", optarg); return -1; } break; } } if (command_line) { command_line_len = strlen(command_line) + 1; if (command_line_len > COMMAND_LINE_SIZE) command_line_len = COMMAND_LINE_SIZE; } if (ramdisk) { ramdisk_buf = slurp_file(ramdisk, &initrd_size); } /* * If we are loading a dump capture kernel, we need to update kernel * command line and also add some additional segments. */ if (info->kexec_flags & KEXEC_ON_CRASH) { uint64_t start, end; modified_cmdline = xmalloc(COMMAND_LINE_SIZE); if (!modified_cmdline) return -1; if (command_line) { (void) strncpy(modified_cmdline, command_line, COMMAND_LINE_SIZE); modified_cmdline[COMMAND_LINE_SIZE - 1] = '\0'; } if (load_crashdump_segments(info, modified_cmdline) < 0) { free(modified_cmdline); return -1; } command_line = modified_cmdline; command_line_len = strlen(command_line) + 1; /* * We put the dump capture kernel at the start of crashkernel * reserved memory. */ if (parse_iomem_single("Crash kernel\n", &start, &end)) { /* * No crash kernel memory reserved. We cannot do more * but just bail out. */ return -1; } base = start; } else { base = locate_hole(info,len+offset,0,0,ULONG_MAX,INT_MAX); } if (base == ULONG_MAX) return -1; /* assume the maximum kernel compression ratio is 4, * and just to be safe, place ramdisk after that */ if(opt_ramdisk_addr == 0) initrd_base = _ALIGN(base + len * 4, getpagesize()); else initrd_base = opt_ramdisk_addr; if(!use_dtb) { if (atag_arm_load(info, base + atag_offset, command_line, command_line_len, ramdisk_buf, initrd_size, initrd_base) == -1) return -1; } else { char *dtb_img = NULL; off_t dtb_img_len = 0; int free_dtb_img = 0; int choose_res = 0; if(!mach) { fprintf(stderr, "DTB: --boardname was not specified.\n"); return -1; } if(dtb_file) { if(!load_dtb_image(dtb_file, &dtb_img, &dtb_img_len)) return -1; printf("DTB: Using DTB from file %s\n", dtb_file); free_dtb_img = 1; } else { if(!get_appended_dtb(buf, len, &dtb_img, &dtb_img_len)) return -1; printf("DTB: Using DTB appended to zImage\n"); } choose_res = (mach->choose_dtb)(dtb_img, dtb_img_len, &dtb_buf, &dtb_length); if(free_dtb_img) free(dtb_img); if(choose_res) { int ret, off; dtb_length = fdt_totalsize(dtb_buf) + DTB_PAD_SIZE; dtb_buf = xrealloc(dtb_buf, dtb_length); ret = fdt_open_into(dtb_buf, dtb_buf, dtb_length); if(ret) die("DTB: fdt_open_into failed"); ret = (mach->add_extra_regs)(dtb_buf); if (ret < 0) { fprintf(stderr, "DTB: error while adding mach-specific extra regs\n"); return -1; } if (command_line) { const char *node_name = "/chosen"; const char *prop_name = "bootargs"; /* check if a /choosen subnode already exists */ off = fdt_path_offset(dtb_buf, node_name); if (off == -FDT_ERR_NOTFOUND) off = fdt_add_subnode(dtb_buf, off, node_name); if (off < 0) { fprintf(stderr, "DTB: Error adding %s node.\n", node_name); return -1; } if (fdt_setprop(dtb_buf, off, prop_name, command_line, strlen(command_line) + 1) != 0) { fprintf(stderr, "DTB: Error setting %s/%s property.\n", node_name, prop_name); return -1; } } if(ramdisk) { const char *node_name = "/chosen"; uint32_t initrd_start, initrd_end; /* check if a /choosen subnode already exists */ off = fdt_path_offset(dtb_buf, node_name); if (off == -FDT_ERR_NOTFOUND) off = fdt_add_subnode(dtb_buf, off, node_name); if (off < 0) { fprintf(stderr, "DTB: Error adding %s node.\n", node_name); return -1; } initrd_start = cpu_to_fdt32(initrd_base); initrd_end = cpu_to_fdt32(initrd_base + initrd_size); ret = fdt_setprop(dtb_buf, off, "linux,initrd-start", &initrd_start, sizeof(initrd_start)); if (ret) die("DTB: Error setting %s/linux,initrd-start property.\n", node_name); ret = fdt_setprop(dtb_buf, off, "linux,initrd-end", &initrd_end, sizeof(initrd_end)); if (ret) die("DTB: Error setting %s/linux,initrd-end property.\n", node_name); } fdt_pack(dtb_buf); } else { /* * Extract the DTB from /proc/device-tree. */ printf("DTB: Failed to load dtb from zImage or dtb.img, using /proc/device-tree. This is unlikely to work.\n"); create_flatten_tree(&dtb_buf, &dtb_length, command_line); } if(ramdisk) { add_segment(info, ramdisk_buf, initrd_size, initrd_base, initrd_size); } if(opt_atags_addr != 0) dtb_offset = opt_atags_addr; else { dtb_offset = initrd_base + initrd_size + getpagesize(); dtb_offset = _ALIGN_DOWN(dtb_offset, getpagesize()); } printf("DTB: add dtb segment 0x%x\n", (unsigned int)dtb_offset); add_segment(info, dtb_buf, dtb_length, dtb_offset, dtb_length); } add_segment(info, buf, len, base + offset, len); info->entry = (void*)base + offset; return 0; }
int sandbox_write_state(struct sandbox_state *state, const char *fname) { struct sandbox_state_io *io; bool got_err; int size; int ret; int fd; /* Create a state FDT if we don't have one */ if (!state->state_fdt) { size = 0x4000; state->state_fdt = os_malloc(size); if (!state->state_fdt) { puts("No memory to create FDT\n"); return -ENOMEM; } ret = fdt_create_empty_tree(state->state_fdt, size); if (ret < 0) { printf("Cannot create empty state FDT: %s\n", fdt_strerror(ret)); ret = -EIO; goto err_create; } } /* Call all the state write funtcions */ got_err = false; io = ll_entry_start(struct sandbox_state_io, state_io); ret = 0; for (; io < ll_entry_end(struct sandbox_state_io, state_io); io++) { ret = sandbox_write_state_node(state, io); if (ret == -EIO) break; else if (ret) got_err = true; } if (ret == -EIO) { printf("Could not write sandbox state\n"); goto err_create; } ret = fdt_pack(state->state_fdt); if (ret < 0) { printf("Cannot pack state FDT: %s\n", fdt_strerror(ret)); ret = -EINVAL; goto err_create; } size = fdt_totalsize(state->state_fdt); fd = os_open(fname, OS_O_WRONLY | OS_O_CREAT); if (fd < 0) { printf("Cannot open sandbox state file '%s'\n", fname); ret = -EIO; goto err_create; } if (os_write(fd, state->state_fdt, size) != size) { printf("Cannot write sandbox state file '%s'\n", fname); ret = -EIO; goto err_write; } os_close(fd); debug("Wrote sandbox state to '%s'%s\n", fname, got_err ? " (with errors)" : ""); return 0; err_write: os_close(fd); err_create: os_free(state->state_fdt); return ret; }
ulong fit_get_end(const void *fit) { return map_to_sysmem((void *)(fit + fdt_totalsize(fit))); }
/** * 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; }
/** * boot_get_fdt - main fdt handling routine * @argc: command argument count * @argv: command argument list * @arch: architecture (IH_ARCH_...) * @images: pointer to the bootm images structure * @of_flat_tree: pointer to a char* variable, will hold fdt start address * @of_size: pointer to a ulong variable, will hold fdt length * * boot_get_fdt() is responsible for finding a valid flat device tree image. * Curently supported are the following ramdisk sources: * - multicomponent kernel/ramdisk image, * - commandline provided address of decicated ramdisk image. * * returns: * 0, if fdt image was found and valid, or skipped * of_flat_tree and of_size are set to fdt start address and length if * fdt image is found and valid * * 1, if fdt image is found but corrupted * of_flat_tree and of_size are set to 0 if no fdt exists */ int boot_get_fdt(int flag, int argc, char * const argv[], uint8_t arch, bootm_headers_t *images, char **of_flat_tree, ulong *of_size) { #if defined(CONFIG_IMAGE_FORMAT_LEGACY) const image_header_t *fdt_hdr; ulong load, load_end; ulong image_start, image_data, image_end; #endif ulong fdt_addr; char *fdt_blob = NULL; void *buf; #if CONFIG_IS_ENABLED(FIT) const char *fit_uname_config = images->fit_uname_cfg; const char *fit_uname_fdt = NULL; ulong default_addr; int fdt_noffset; #endif const char *select = NULL; int ok_no_fdt = 0; *of_flat_tree = NULL; *of_size = 0; if (argc > 2) select = argv[2]; if (select || genimg_has_config(images)) { #if CONFIG_IS_ENABLED(FIT) if (select) { /* * If the FDT blob comes from the FIT image and the * FIT image address is omitted in the command line * argument, try to use ramdisk or os FIT image * address or default load address. */ if (images->fit_uname_rd) default_addr = (ulong)images->fit_hdr_rd; else if (images->fit_uname_os) default_addr = (ulong)images->fit_hdr_os; else default_addr = load_addr; if (fit_parse_conf(select, default_addr, &fdt_addr, &fit_uname_config)) { debug("* fdt: config '%s' from image at 0x%08lx\n", fit_uname_config, fdt_addr); } else if (fit_parse_subimage(select, default_addr, &fdt_addr, &fit_uname_fdt)) { debug("* fdt: subimage '%s' from image at 0x%08lx\n", fit_uname_fdt, fdt_addr); } else #endif { fdt_addr = simple_strtoul(select, NULL, 16); debug("* fdt: cmdline image address = 0x%08lx\n", fdt_addr); } #if CONFIG_IS_ENABLED(FIT) } else { /* use FIT configuration provided in first bootm * command argument */ fdt_addr = map_to_sysmem(images->fit_hdr_os); fdt_noffset = fit_get_node_from_config(images, FIT_FDT_PROP, fdt_addr); if (fdt_noffset == -ENOLINK) return 0; else if (fdt_noffset < 0) return 1; } #endif debug("## Checking for 'FDT'/'FDT Image' at %08lx\n", fdt_addr); /* copy from dataflash if needed */ fdt_addr = genimg_get_image(fdt_addr); /* * Check if there is an FDT image at the * address provided in the second bootm argument * check image type, for FIT images get a FIT node. */ buf = map_sysmem(fdt_addr, 0); switch (genimg_get_format(buf)) { #if defined(CONFIG_IMAGE_FORMAT_LEGACY) case IMAGE_FORMAT_LEGACY: /* verify fdt_addr points to a valid image header */ printf("## Flattened Device Tree from Legacy Image at %08lx\n", fdt_addr); fdt_hdr = image_get_fdt(fdt_addr); if (!fdt_hdr) goto no_fdt; /* * move image data to the load address, * make sure we don't overwrite initial image */ image_start = (ulong)fdt_hdr; image_data = (ulong)image_get_data(fdt_hdr); image_end = image_get_image_end(fdt_hdr); load = image_get_load(fdt_hdr); load_end = load + image_get_data_size(fdt_hdr); if (load == image_start || load == image_data) { fdt_addr = load; break; } if ((load < image_end) && (load_end > image_start)) { fdt_error("fdt overwritten"); goto error; } debug(" Loading FDT from 0x%08lx to 0x%08lx\n", image_data, load); memmove((void *)load, (void *)image_data, image_get_data_size(fdt_hdr)); fdt_addr = load; break; #endif case IMAGE_FORMAT_FIT: /* * This case will catch both: new uImage format * (libfdt based) and raw FDT blob (also libfdt * based). */ #if CONFIG_IS_ENABLED(FIT) /* check FDT blob vs FIT blob */ if (fit_check_format(buf)) { ulong load, len; fdt_noffset = fit_image_load(images, fdt_addr, &fit_uname_fdt, &fit_uname_config, arch, IH_TYPE_FLATDT, BOOTSTAGE_ID_FIT_FDT_START, FIT_LOAD_OPTIONAL, &load, &len); images->fit_hdr_fdt = map_sysmem(fdt_addr, 0); images->fit_uname_fdt = fit_uname_fdt; images->fit_noffset_fdt = fdt_noffset; fdt_addr = load; break; } else #endif { /* * FDT blob */ debug("* fdt: raw FDT blob\n"); printf("## Flattened Device Tree blob at %08lx\n", (long)fdt_addr); } break; default: puts("ERROR: Did not find a cmdline Flattened Device Tree\n"); goto no_fdt; } printf(" Booting using the fdt blob at %#08lx\n", fdt_addr); fdt_blob = map_sysmem(fdt_addr, 0); } else if (images->legacy_hdr_valid && image_check_type(&images->legacy_hdr_os_copy, IH_TYPE_MULTI)) { ulong fdt_data, fdt_len; /* * Now check if we have a legacy multi-component image, * get second entry data start address and len. */ printf("## Flattened Device Tree from multi component Image at %08lX\n", (ulong)images->legacy_hdr_os); image_multi_getimg(images->legacy_hdr_os, 2, &fdt_data, &fdt_len); if (fdt_len) { fdt_blob = (char *)fdt_data; printf(" Booting using the fdt at 0x%p\n", fdt_blob); if (fdt_check_header(fdt_blob) != 0) { fdt_error("image is not a fdt"); goto error; } if (fdt_totalsize(fdt_blob) != fdt_len) { fdt_error("fdt size != image size"); goto error; } } else { debug("## No Flattened Device Tree\n"); goto no_fdt; } } else { debug("## No Flattened Device Tree\n"); goto no_fdt; } *of_flat_tree = fdt_blob; *of_size = fdt_totalsize(fdt_blob); debug(" of_flat_tree at 0x%08lx size 0x%08lx\n", (ulong)*of_flat_tree, *of_size); return 0; no_fdt: ok_no_fdt = 1; error: *of_flat_tree = NULL; *of_size = 0; if (!select && ok_no_fdt) { debug("Continuing to boot without FDT\n"); return 0; } return 1; }
efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt, unsigned long orig_fdt_size, void *fdt, int new_fdt_size, char *cmdline_ptr, u64 initrd_addr, u64 initrd_size, efi_memory_desc_t *memory_map, unsigned long map_size, unsigned long desc_size, u32 desc_ver) { int node, num_rsv; int status; u32 fdt_val32; u64 fdt_val64; /* Do some checks on provided FDT, if it exists*/ if (orig_fdt) { if (fdt_check_header(orig_fdt)) { pr_efi_err(sys_table, "Device Tree header not valid!\n"); return EFI_LOAD_ERROR; } /* * We don't get the size of the FDT if we get if from a * configuration table. */ if (orig_fdt_size && fdt_totalsize(orig_fdt) > orig_fdt_size) { pr_efi_err(sys_table, "Truncated device tree! foo!\n"); return EFI_LOAD_ERROR; } } if (orig_fdt) status = fdt_open_into(orig_fdt, fdt, new_fdt_size); else status = fdt_create_empty_tree(fdt, new_fdt_size); if (status != 0) goto fdt_set_fail; /* * Delete all memory reserve map entries. When booting via UEFI, * kernel will use the UEFI memory map to find reserved regions. */ num_rsv = fdt_num_mem_rsv(fdt); while (num_rsv-- > 0) fdt_del_mem_rsv(fdt, num_rsv); node = fdt_subnode_offset(fdt, 0, "chosen"); if (node < 0) { node = fdt_add_subnode(fdt, 0, "chosen"); if (node < 0) { status = node; /* node is error code when negative */ goto fdt_set_fail; } } if ((cmdline_ptr != NULL) && (strlen(cmdline_ptr) > 0)) { status = fdt_setprop(fdt, node, "bootargs", cmdline_ptr, strlen(cmdline_ptr) + 1); if (status) goto fdt_set_fail; } /* Set initrd address/end in device tree, if present */ if (initrd_size != 0) { u64 initrd_image_end; u64 initrd_image_start = cpu_to_fdt64(initrd_addr); status = fdt_setprop(fdt, node, "linux,initrd-start", &initrd_image_start, sizeof(u64)); if (status) goto fdt_set_fail; initrd_image_end = cpu_to_fdt64(initrd_addr + initrd_size); status = fdt_setprop(fdt, node, "linux,initrd-end", &initrd_image_end, sizeof(u64)); if (status) goto fdt_set_fail; } /* Add FDT entries for EFI runtime services in chosen node. */ node = fdt_subnode_offset(fdt, 0, "chosen"); fdt_val64 = cpu_to_fdt64((u64)(unsigned long)sys_table); status = fdt_setprop(fdt, node, "linux,uefi-system-table", &fdt_val64, sizeof(fdt_val64)); if (status) goto fdt_set_fail; fdt_val64 = cpu_to_fdt64((u64)(unsigned long)memory_map); status = fdt_setprop(fdt, node, "linux,uefi-mmap-start", &fdt_val64, sizeof(fdt_val64)); if (status) goto fdt_set_fail; fdt_val32 = cpu_to_fdt32(map_size); status = fdt_setprop(fdt, node, "linux,uefi-mmap-size", &fdt_val32, sizeof(fdt_val32)); if (status) goto fdt_set_fail; fdt_val32 = cpu_to_fdt32(desc_size); status = fdt_setprop(fdt, node, "linux,uefi-mmap-desc-size", &fdt_val32, sizeof(fdt_val32)); if (status) goto fdt_set_fail; fdt_val32 = cpu_to_fdt32(desc_ver); status = fdt_setprop(fdt, node, "linux,uefi-mmap-desc-ver", &fdt_val32, sizeof(fdt_val32)); if (status) goto fdt_set_fail; if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) { efi_status_t efi_status; efi_status = efi_get_random_bytes(sys_table, sizeof(fdt_val64), (u8 *)&fdt_val64); if (efi_status == EFI_SUCCESS) { status = fdt_setprop(fdt, node, "kaslr-seed", &fdt_val64, sizeof(fdt_val64)); if (status) goto fdt_set_fail; } else if (efi_status != EFI_NOT_FOUND) { return efi_status; } } return EFI_SUCCESS; fdt_set_fail: if (status == -FDT_ERR_NOSPACE) return EFI_BUFFER_TOO_SMALL; return EFI_LOAD_ERROR; }
int mc_init(bd_t *bis) { int error = 0; int timeout = 200000; struct mc_ccsr_registers __iomem *mc_ccsr_regs = MC_CCSR_BASE_ADDR; u64 mc_ram_addr; u64 mc_dpl_offset; u32 reg_gsr; u32 mc_fw_boot_status; void *dpl_fdt_hdr; int dpl_size; const void *raw_image_addr; size_t raw_image_size = 0; struct fsl_mc_io mc_io; int portal_id; struct mc_version mc_ver_info; /* * The MC private DRAM block was already carved at the end of DRAM * by board_init_f() using CONFIG_SYS_MEM_TOP_HIDE: */ if (gd->bd->bi_dram[1].start) { mc_ram_addr = gd->bd->bi_dram[1].start + gd->bd->bi_dram[1].size; } else { mc_ram_addr = gd->bd->bi_dram[0].start + gd->bd->bi_dram[0].size; } /* * Management Complex cores should be held at reset out of POR. * U-boot should be the first software to touch MC. To be safe, * we reset all cores again by setting GCR1 to 0. It doesn't do * anything if they are held at reset. After we setup the firmware * we kick off MC by deasserting the reset bit for core 0, and * deasserting the reset bits for Command Portal Managers. * The stop bits are not touched here. They are used to stop the * cores when they are active. Setting stop bits doesn't stop the * cores from fetching instructions when they are released from * reset. */ out_le32(&mc_ccsr_regs->reg_gcr1, 0); dmb(); error = parse_mc_firmware_fit_image(&raw_image_addr, &raw_image_size); if (error != 0) goto out; /* * Load the MC FW at the beginning of the MC private DRAM block: */ mc_copy_image("MC Firmware", (u64)raw_image_addr, raw_image_size, mc_ram_addr); /* * Get address and size of the DPL blob stored in flash: */ #ifdef CONFIG_SYS_LS_MC_DPL_IN_NOR dpl_fdt_hdr = (void *)CONFIG_SYS_LS_MC_DPL_ADDR; #else #error "No CONFIG_SYS_LS_MC_DPL_IN_xxx defined" #endif error = fdt_check_header(dpl_fdt_hdr); if (error != 0) { printf("fsl-mc: ERROR: Bad DPL image (bad header)\n"); goto out; } dpl_size = fdt_totalsize(dpl_fdt_hdr); if (dpl_size > CONFIG_SYS_LS_MC_DPL_MAX_LENGTH) { printf("fsl-mc: ERROR: Bad DPL image (too large: %d)\n", dpl_size); error = -EINVAL; goto out; } /* * Calculate offset in the MC private DRAM block at which the MC DPL * blob is to be placed: */ #ifdef CONFIG_SYS_LS_MC_DRAM_DPL_OFFSET BUILD_BUG_ON((CONFIG_SYS_LS_MC_DRAM_DPL_OFFSET & 0x3) != 0 || CONFIG_SYS_LS_MC_DRAM_DPL_OFFSET > 0xffffffff); mc_dpl_offset = CONFIG_SYS_LS_MC_DRAM_DPL_OFFSET; #else mc_dpl_offset = mc_get_dram_block_size() - roundup(CONFIG_SYS_LS_MC_DPL_MAX_LENGTH, 4096); if ((mc_dpl_offset & 0x3) != 0 || mc_dpl_offset > 0xffffffff) { printf("%s: Invalid MC DPL offset: %llu\n", __func__, mc_dpl_offset); error = -EINVAL; goto out; } #endif /* * Load the MC DPL blob at the far end of the MC private DRAM block: * * TODO: Should we place the DPL at a different location to match * assumptions of MC firmware about its memory layout? */ mc_copy_image("MC DPL blob", (u64)dpl_fdt_hdr, dpl_size, mc_ram_addr + mc_dpl_offset); debug("mc_ccsr_regs %p\n", mc_ccsr_regs); /* * Tell MC where the MC Firmware image was loaded in DDR: */ out_le32(&mc_ccsr_regs->reg_mcfbalr, (u32)mc_ram_addr); out_le32(&mc_ccsr_regs->reg_mcfbahr, (u32)((u64)mc_ram_addr >> 32)); out_le32(&mc_ccsr_regs->reg_mcfapr, MCFAPR_BYPASS_ICID_MASK); /* * Tell MC where the DPL blob was loaded in DDR, by indicating * its offset relative to the beginning of the DDR block * allocated to the MC firmware. The MC firmware is responsible * for checking that there is no overlap between the DPL blob * and the runtime heap and stack of the MC firmware itself. * * NOTE: bits [31:2] of this offset need to be stored in bits [29:0] of * the GSR MC CCSR register. So, this offset is assumed to be 4-byte * aligned. * Care must be taken not to write 1s into bits 31 and 30 of the GSR in * this case as the SoC COP or PIC will be signaled. */ out_le32(&mc_ccsr_regs->reg_gsr, (u32)(mc_dpl_offset >> 2)); printf("\nfsl-mc: Booting Management Complex ...\n"); /* * Deassert reset and release MC core 0 to run */ out_le32(&mc_ccsr_regs->reg_gcr1, GCR1_P1_DE_RST | GCR1_M_ALL_DE_RST); dmb(); debug("Polling mc_ccsr_regs->reg_gsr ...\n"); for (;;) { reg_gsr = in_le32(&mc_ccsr_regs->reg_gsr); mc_fw_boot_status = (reg_gsr & GSR_FS_MASK); if (mc_fw_boot_status & 0x1) break; udelay(1000); /* throttle polling */ if (timeout-- <= 0) break; } if (timeout <= 0) { printf("fsl-mc: timeout booting management complex firmware\n"); /* TODO: Get an error status from an MC CCSR register */ error = -ETIMEDOUT; goto out; } if (mc_fw_boot_status != 0x1) { /* * TODO: Identify critical errors from the GSR register's FS * field and for those errors, set error to -ENODEV or other * appropriate errno, so that the status property is set to * failure in the fsl,dprc device tree node. */ printf("fsl-mc: WARNING: Firmware booted with error (GSR: %#x)\n", reg_gsr); } /* * TODO: need to obtain the portal_id for the root container from the * DPL */ portal_id = 0; /* * Check that the MC firmware is responding portal commands: */ mc_io.mmio_regs = SOC_MC_PORTAL_ADDR(portal_id); debug("Checking access to MC portal of root DPRC container (portal_id %d, portal physical addr %p)\n", portal_id, mc_io.mmio_regs); error = mc_get_version(&mc_io, &mc_ver_info); if (error != 0) { printf("fsl-mc: ERROR: Firmware version check failed (error: %d)\n", error); goto out; } if (MC_VER_MAJOR != mc_ver_info.major) printf("fsl-mc: ERROR: Firmware major version mismatch (found: %d, expected: %d)\n", mc_ver_info.major, MC_VER_MAJOR); if (MC_VER_MINOR != mc_ver_info.minor) printf("fsl-mc: WARNING: Firmware minor version mismatch (found: %d, expected: %d)\n", mc_ver_info.minor, MC_VER_MINOR); printf("fsl-mc: Management Complex booted (version: %d.%d.%d, boot status: %#x)\n", mc_ver_info.major, mc_ver_info.minor, mc_ver_info.revision, mc_fw_boot_status); out: if (error != 0) mc_boot_status = -error; else mc_boot_status = 0; return error; }
static int hammerhead_choose_dtb(const char *dtb_img, off_t dtb_len, char **dtb_buf, off_t *dtb_length) { char *dtb = (char*)dtb_img; char *dtb_end = dtb + dtb_len; FILE *f; struct msm_id devid, dtb_id; char *bestmatch_tag = NULL; size_t id_read = 0; uint32_t bestmatch_tag_size; uint32_t bestmatch_soc_rev_id = INVALID_SOC_REV_ID; uint32_t bestmatch_board_rev_id = INVALID_SOC_REV_ID; f = fopen("/proc/device-tree/qcom,msm-id", "r"); if(!f) { fprintf(stderr, "DTB: Couldn't open /proc/device-tree/qcom,msm-id!\n"); return 0; } id_read = fread(&devid, 1, sizeof(struct msm_id), f); fclose(f); devid.platform_id = fdt32_to_cpu(devid.platform_id); devid.hardware_id = fdt32_to_cpu(devid.hardware_id); devid.soc_rev = fdt32_to_cpu(devid.soc_rev); if(id_read > 12) devid.board_rev = fdt32_to_cpu(devid.board_rev); else devid.board_rev = 0; printf("DTB: platform %u hw %u soc 0x%x board %u\n", devid.platform_id, devid.hardware_id, devid.soc_rev, devid.board_rev); while(dtb + sizeof(struct fdt_header) < dtb_end) { uint32_t dtb_soc_rev_id; struct fdt_header dtb_hdr; uint32_t dtb_size; /* the DTB could be unaligned, so extract the header, * and operate on it separately */ memcpy(&dtb_hdr, dtb, sizeof(struct fdt_header)); if (fdt_check_header((const void *)&dtb_hdr) != 0 || (dtb + fdt_totalsize((const void *)&dtb_hdr) > dtb_end)) { fprintf(stderr, "DTB: Invalid dtb header!\n"); break; } dtb_size = fdt_totalsize(&dtb_hdr); if(hammerhead_dtb_compatible(dtb, &devid, &dtb_id)) { if (dtb_id.soc_rev == devid.soc_rev && dtb_id.board_rev == devid.board_rev) { *dtb_buf = xmalloc(dtb_size); memcpy(*dtb_buf, dtb, dtb_size); *dtb_length = dtb_size; printf("DTB: match 0x%x %u, my id 0x%x %u, len %u\n", dtb_id.soc_rev, dtb_id.board_rev, devid.soc_rev, devid.board_rev, dtb_size); return 1; } else if(dtb_id.soc_rev <= devid.soc_rev && dtb_id.board_rev < devid.board_rev) { if((bestmatch_soc_rev_id == INVALID_SOC_REV_ID) || (bestmatch_soc_rev_id < dtb_id.soc_rev) || (bestmatch_soc_rev_id == dtb_id.soc_rev && bestmatch_board_rev_id < dtb_id.board_rev)) { bestmatch_tag = dtb; bestmatch_tag_size = dtb_size; bestmatch_soc_rev_id = dtb_id.soc_rev; bestmatch_board_rev_id = dtb_id.board_rev; } } } /* goto the next device tree if any */ dtb += dtb_size; // try to skip padding in standalone dtb.img files while(dtb < dtb_end && *dtb == 0) ++dtb; } if(bestmatch_tag) { printf("DTB: bestmatch 0x%x %u, my id 0x%x %u\n", bestmatch_soc_rev_id, bestmatch_board_rev_id, devid.soc_rev, devid.board_rev); *dtb_buf = xmalloc(bestmatch_tag_size); memcpy(*dtb_buf, bestmatch_tag, bestmatch_tag_size); *dtb_length = bestmatch_tag_size; return 1; } return 0; }
static vm_offset_t linux_parse_boot_param(struct arm_boot_params *abp) { struct arm_lbabi_tag *walker; uint32_t revision; uint64_t serial; int size; vm_offset_t lastaddr; #ifdef FDT struct fdt_header *dtb_ptr; uint32_t dtb_size; #endif /* * Linux boot ABI: r0 = 0, r1 is the board type (!= 0) and r2 * is atags or dtb pointer. If all of these aren't satisfied, * then punt. Unfortunately, it looks like DT enabled kernels * doesn't uses board type and U-Boot delivers 0 in r1 for them. */ if (abp->abp_r0 != 0 || abp->abp_r2 == 0) return (0); #ifdef FDT /* Test if r2 point to valid DTB. */ dtb_ptr = (struct fdt_header *)abp->abp_r2; if (fdt_check_header(dtb_ptr) == 0) { dtb_size = fdt_totalsize(dtb_ptr); return (fake_preload_metadata(abp, dtb_ptr, dtb_size)); } #endif board_id = abp->abp_r1; walker = (struct arm_lbabi_tag *)abp->abp_r2; if (ATAG_TAG(walker) != ATAG_CORE) return 0; atag_list = walker; while (ATAG_TAG(walker) != ATAG_NONE) { switch (ATAG_TAG(walker)) { case ATAG_CORE: break; case ATAG_MEM: arm_physmem_hardware_region(walker->u.tag_mem.start, walker->u.tag_mem.size); break; case ATAG_INITRD2: break; case ATAG_SERIAL: serial = walker->u.tag_sn.high; serial <<= 32; serial |= walker->u.tag_sn.low; board_set_serial(serial); break; case ATAG_REVISION: revision = walker->u.tag_rev.rev; board_set_revision(revision); break; case ATAG_CMDLINE: size = ATAG_SIZE(walker) - sizeof(struct arm_lbabi_header); size = min(size, LBABI_MAX_COMMAND_LINE); strncpy(linux_command_line, walker->u.tag_cmd.command, size); linux_command_line[size] = '\0'; break; default: break; } walker = ATAG_NEXT(walker); } /* Save a copy for later */ bcopy(atag_list, atags, (char *)walker - (char *)atag_list + ATAG_SIZE(walker)); lastaddr = fake_preload_metadata(abp, NULL, 0); cmdline_set_env(linux_command_line, CMDLINE_GUARD); return lastaddr; }
static int do_fdtoverlay(const char *input_filename, const char *output_filename, int argc, char *argv[]) { char *blob = NULL; char **ovblob = NULL; size_t blob_len, ov_len, total_len; int i, ret = -1; blob = utilfdt_read(input_filename, &blob_len); if (!blob) { fprintf(stderr, "\nFailed to read base blob %s\n", input_filename); goto out_err; } if (fdt_totalsize(blob) > blob_len) { fprintf(stderr, "\nBase blob is incomplete (%lu / %" PRIu32 " bytes read)\n", (unsigned long)blob_len, fdt_totalsize(blob)); goto out_err; } ret = 0; /* allocate blob pointer array */ ovblob = malloc(sizeof(*ovblob) * argc); memset(ovblob, 0, sizeof(*ovblob) * argc); /* read and keep track of the overlay blobs */ total_len = 0; for (i = 0; i < argc; i++) { ovblob[i] = utilfdt_read(argv[i], &ov_len); if (!ovblob[i]) { fprintf(stderr, "\nFailed to read overlay %s\n", argv[i]); goto out_err; } total_len += ov_len; } /* grow the blob to worst case */ blob_len = fdt_totalsize(blob) + total_len; blob = xrealloc(blob, blob_len); fdt_open_into(blob, blob, blob_len); /* apply the overlays in sequence */ for (i = 0; i < argc; i++) { ret = fdt_overlay_apply(blob, ovblob[i]); if (ret) { fprintf(stderr, "\nFailed to apply %s (%d)\n", argv[i], ret); goto out_err; } } fdt_pack(blob); ret = utilfdt_write(output_filename, blob); if (ret) fprintf(stderr, "\nFailed to write output blob %s\n", output_filename); out_err: if (ovblob) { for (i = 0; i < argc; i++) { if (ovblob[i]) free(ovblob[i]); } free(ovblob); } free(blob); return ret; }
//return value is the data size that actual dealed static u32 optimus_storage_write(struct ImgBurnInfo* pDownInfo, u64 addrOrOffsetInBy, unsigned dataSz, const u8* data, char* errInfo) { u32 burnSz = 0; const u32 imgType = pDownInfo->imgType; const int MediaType = pDownInfo->storageMediaType; addrOrOffsetInBy += pDownInfo->partBaseOffset; DWN_DBG("[0x]Data %p, addrOrOffsetInBy %llx, dataSzInBy %x\n", data, addrOrOffsetInBy, dataSz); if(OPTIMUS_IMG_STA_BURN_ING != pDownInfo->imgBurnSta) { sprintf(errInfo, "Error burn sta %d\n", pDownInfo->imgBurnSta); DWN_ERR(errInfo); return 0; } switch(MediaType) { case OPTIMUS_MEDIA_TYPE_NAND: case OPTIMUS_MEDIA_TYPE_SDMMC: case OPTIMUS_MEDIA_TYPE_STORE: { switch(imgType) { case IMG_TYPE_NORMAL: burnSz = optimus_download_normal_image(pDownInfo, dataSz, data); break; case IMG_TYPE_BOOTLOADER: burnSz = optimus_download_bootloader_image(pDownInfo, dataSz, data); break; case IMG_TYPE_SPARSE: burnSz = optimus_download_sparse_image(pDownInfo, dataSz, data); break; default: DWN_ERR("error image type %d\n", imgType); } } break; case OPTIMUS_MEDIA_TYPE_KEY_UNIFY: { burnSz = v2_key_burn(pDownInfo->partName, data, dataSz, errInfo); if(burnSz != dataSz){//return value is write size DWN_ERR("burn key failed\n"); return 0; } } break; case OPTIMUS_MEDIA_TYPE_MEM: { u8* buf = (u8*)(unsigned)addrOrOffsetInBy; if(buf != data){ DWN_ERR("buf(%llx) != data(%p)\n", addrOrOffsetInBy, data); return 0; } if(!strcmp("dtb", pDownInfo->partName))//as memory write back size = min[fileSz, 2G], so reach here if downloaded ok! { int rc = 0; char* dtbLoadAddr = (char*)CONFIG_DTB_LOAD_ADDR; const int DtbMaxSz = (2U<<20); unsigned fdtSz = 0; unsigned char* destDtb = (unsigned char*)data; //Make sure flash already inited before 'run aml_dt' //old tool will download dtb before 'disk_initial', but new tool will 'disk_initial' first if(is_optimus_storage_inited() || (OPTIMUS_WORK_MODE_USB_PRODUCE != optimus_work_mode_get())) { destDtb = (unsigned char*)get_multi_dt_entry((unsigned int)data); } rc = fdt_check_header(destDtb); if(rc){ sprintf(errInfo, "failed at fdt_check_header\n"); DWN_ERR(errInfo); return 0; } fdtSz = fdt_totalsize(destDtb); if(DtbMaxSz <= fdtSz){ sprintf(errInfo, "failed: fdt header ok but sz 0%x > max 0x%x\n", fdtSz, DtbMaxSz); DWN_ERR(errInfo); return 0; } DWN_MSG("load dtb to 0x%p\n", dtbLoadAddr); memcpy(dtbLoadAddr, destDtb, fdtSz); } burnSz = dataSz; } break; default: sprintf(errInfo, "Error MediaType %d\n", MediaType); DWN_ERR(errInfo); } return burnSz; }
static int do_oftree(int argc, char *argv[]) { struct fdt_header *fdt = NULL; void *fdt_free = NULL; int size; int opt; char *file = NULL; const char *node = "/"; int dump = 0; int probe = 0; int load = 0; int save = 0; int free_of = 0; int ret; while ((opt = getopt(argc, argv, "dpfn:ls")) > 0) { switch (opt) { case 'l': load = 1; break; case 'd': dump = 1; break; case 'p': if (IS_ENABLED(CONFIG_CMD_OFTREE_PROBE)) { probe = 1; } else { printf("oftree device probe support disabled\n"); return COMMAND_ERROR_USAGE; } break; case 'f': free_of = 1; break; case 'n': node = optarg; break; case 's': save = 1; break; } } if (free_of) { struct device_node *root = of_get_root_node(); if (root) of_free(root); return 0; } if (optind < argc) file = argv[optind]; if (!dump && !probe && !load && !save) return COMMAND_ERROR_USAGE; if (save) { if (!file) { printf("no file given\n"); ret = -ENOENT; goto out; } fdt = of_get_fixed_tree(NULL); if (!fdt) { printf("no devicetree available\n"); ret = -EINVAL; goto out; } ret = write_file(file, fdt, fdt_totalsize(fdt)); goto out; } if (file) { fdt = read_file(file, &size); if (!fdt) { printf("unable to read %s\n", file); return 1; } fdt_free = fdt; } if (load) { if (!fdt) { printf("no fdt given\n"); ret = -ENOENT; goto out; } ret = of_unflatten_dtb(fdt); if (ret) { printf("parse oftree: %s\n", strerror(-ret)); goto out; } } if (dump) { if (fdt) { ret = fdt_print(fdt, node); } else { struct device_node *n = of_find_node_by_path(node); if (!n) { ret = -ENOENT; goto out; } of_print_nodes(n, 0); ret = 0; } goto out; } if (probe) { ret = of_probe(); if (ret) goto out; } ret = 0; out: free(fdt_free); return ret; }
/** * of_get_flat_dt_size - Return the total size of the FDT */ int __init of_get_flat_dt_size(void) { return fdt_totalsize(initial_boot_params); }
int spl_load_simple_fit(struct spl_image_info *spl_image, struct spl_load_info *info, ulong sector, void *fit) { int sectors; ulong size; unsigned long count; struct spl_image_info image_info; int node = -1; int images, ret; int base_offset, align_len = ARCH_DMA_MINALIGN - 1; int index = 0; /* * For FIT with external data, figure out where the external images * start. This is the base for the data-offset properties in each * image. */ size = fdt_totalsize(fit); size = (size + 3) & ~3; base_offset = (size + 3) & ~3; /* * So far we only have one block of data from the FIT. Read the entire * thing, including that first block, placing it so it finishes before * where we will load the image. * * Note that we will load the image such that its first byte will be * at the load address. Since that byte may be part-way through a * block, we may load the image up to one block before the load * address. So take account of that here by subtracting an addition * block length from the FIT start position. * * In fact the FIT has its own load address, but we assume it cannot * be before CONFIG_SYS_TEXT_BASE. * * For FIT with data embedded, data is loaded as part of FIT image. * For FIT with external data, data is not loaded in this step. */ fit = (void *)((CONFIG_SYS_TEXT_BASE - size - info->bl_len - align_len) & ~align_len); sectors = get_aligned_image_size(info, size, 0); count = info->read(info, sector, sectors, fit); debug("fit read sector %lx, sectors=%d, dst=%p, count=%lu\n", sector, sectors, fit, count); if (count == 0) return -EIO; /* find the node holding the images information */ images = fdt_path_offset(fit, FIT_IMAGES_PATH); if (images < 0) { debug("%s: Cannot find /images node: %d\n", __func__, images); return -1; } /* * Find the U-Boot image using the following search order: * - start at 'firmware' (e.g. an ARM Trusted Firmware) * - fall back 'kernel' (e.g. a Falcon-mode OS boot * - fall back to using the first 'loadables' entry */ if (node < 0) node = spl_fit_get_image_node(fit, images, "firmware", 0); #ifdef CONFIG_SPL_OS_BOOT if (node < 0) node = spl_fit_get_image_node(fit, images, FIT_KERNEL_PROP, 0); #endif if (node < 0) { debug("could not find firmware image, trying loadables...\n"); node = spl_fit_get_image_node(fit, images, "loadables", 0); /* * If we pick the U-Boot image from "loadables", start at * the second image when later loading additional images. */ index = 1; } if (node < 0) { debug("%s: Cannot find u-boot image node: %d\n", __func__, node); return -1; } /* Load the image and set up the spl_image structure */ ret = spl_load_fit_image(info, sector, fit, base_offset, node, spl_image); if (ret) return ret; /* * For backward compatibility, we treat the first node that is * as a U-Boot image, if no OS-type has been declared. */ if (!spl_fit_image_get_os(fit, node, &spl_image->os)) debug("Image OS is %s\n", genimg_get_os_name(spl_image->os)); #if !defined(CONFIG_SPL_OS_BOOT) else spl_image->os = IH_OS_U_BOOT; #endif /* * Booting a next-stage U-Boot may require us to append the FDT. * We allow this to fail, as the U-Boot image might embed its FDT. */ if (spl_image->os == IH_OS_U_BOOT) spl_fit_append_fdt(spl_image, info, sector, fit, images, base_offset); /* Now check if there are more images for us to load */ for (; ; index++) { uint8_t os_type = IH_OS_INVALID; node = spl_fit_get_image_node(fit, images, "loadables", index); if (node < 0) break; ret = spl_load_fit_image(info, sector, fit, base_offset, node, &image_info); if (ret < 0) continue; if (!spl_fit_image_get_os(fit, node, &os_type)) debug("Loadable is %s\n", genimg_get_os_name(os_type)); if (os_type == IH_OS_U_BOOT) { spl_fit_append_fdt(&image_info, info, sector, fit, images, base_offset); spl_image->fdt_addr = image_info.fdt_addr; } /* * If the "firmware" image did not provide an entry point, * use the first valid entry point from the loadables. */ if (spl_image->entry_point == FDT_ERROR && image_info.entry_point != FDT_ERROR) spl_image->entry_point = image_info.entry_point; /* Record our loadables into the FDT */ if (spl_image->fdt_addr) spl_fit_record_loadable(fit, images, index, spl_image->fdt_addr, &image_info); } /* * If a platform does not provide CONFIG_SYS_UBOOT_START, U-Boot's * Makefile will set it to 0 and it will end up as the entry point * here. What it actually means is: use the load address. */ if (spl_image->entry_point == FDT_ERROR || spl_image->entry_point == 0) spl_image->entry_point = spl_image->load_addr; return 0; }
int image_setup_libfdt(bootm_headers_t *images, void *blob, int of_size, struct lmb *lmb) { ulong *initrd_start = &images->initrd_start; ulong *initrd_end = &images->initrd_end; int ret = -EPERM; int fdt_ret; if (fdt_root(blob) < 0) { printf("ERROR: root node setup failed\n"); goto err; } if (fdt_chosen(blob) < 0) { printf("ERROR: /chosen node create failed\n"); goto err; } if (arch_fixup_fdt(blob) < 0) { printf("ERROR: arch-specific fdt fixup failed\n"); goto err; } if (IMAGE_OF_BOARD_SETUP) { fdt_ret = ft_board_setup(blob, gd->bd); if (fdt_ret) { printf("ERROR: board-specific fdt fixup failed: %s\n", fdt_strerror(fdt_ret)); goto err; } } if (IMAGE_OF_SYSTEM_SETUP) { fdt_ret = ft_system_setup(blob, gd->bd); if (fdt_ret) { printf("ERROR: system-specific fdt fixup failed: %s\n", fdt_strerror(fdt_ret)); goto err; } } fdt_fixup_ethernet(blob); /* Delete the old LMB reservation */ lmb_free(lmb, (phys_addr_t)(u32)(uintptr_t)blob, (phys_size_t)fdt_totalsize(blob)); ret = fdt_shrink_to_minimum(blob); if (ret < 0) goto err; of_size = ret; if (*initrd_start && *initrd_end) { of_size += FDT_RAMDISK_OVERHEAD; fdt_set_totalsize(blob, of_size); } /* Create a new LMB reservation */ lmb_reserve(lmb, (ulong)blob, of_size); fdt_initrd(blob, *initrd_start, *initrd_end); if (!ft_verify_fdt(blob)) goto err; #if defined(CONFIG_SOC_KEYSTONE) if (IMAGE_OF_BOARD_SETUP) ft_board_setup_ex(blob, gd->bd); #endif return 0; err: printf(" - must RESET the board to recover.\n\n"); return ret; }
/* Top level function that updates the device tree. */ int update_device_tree(void *fdt, const char *cmdline, void *ramdisk, uint32_t ramdisk_size) { int ret = 0; uint32_t offset; /* Check the device tree header */ ret = fdt_check_header(fdt); if (ret) { dprintf(CRITICAL, "Invalid device tree header \n"); return ret; } /* Add padding to make space for new nodes and properties. */ ret = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + DTB_PAD_SIZE); if (ret!= 0) { dprintf(CRITICAL, "Failed to move/resize dtb buffer: %d\n", ret); return ret; } /* Get offset of the memory node */ ret = fdt_path_offset(fdt, "/memory"); if (ret < 0) { dprintf(CRITICAL, "Could not find memory node.\n"); return ret; } offset = ret; ret = target_dev_tree_mem(fdt, offset); if(ret) { dprintf(CRITICAL, "ERROR: Cannot update memory node\n"); return ret; } /* Get offset of the chosen node */ ret = fdt_path_offset(fdt, "/chosen"); if (ret < 0) { dprintf(CRITICAL, "Could not find chosen node.\n"); return ret; } offset = ret; /* Adding the cmdline to the chosen node */ ret = fdt_setprop_string(fdt, offset, (const char*)"bootargs", (const void*)cmdline); if (ret) { dprintf(CRITICAL, "ERROR: Cannot update chosen node [bootargs]\n"); return ret; } /* Adding the initrd-start to the chosen node */ ret = fdt_setprop_u32(fdt, offset, "linux,initrd-start", (uint32_t)ramdisk); if (ret) { dprintf(CRITICAL, "ERROR: Cannot update chosen node [linux,initrd-start]\n"); return ret; } /* Adding the initrd-end to the chosen node */ ret = fdt_setprop_u32(fdt, offset, "linux,initrd-end", ((uint32_t)ramdisk + ramdisk_size)); if (ret) { dprintf(CRITICAL, "ERROR: Cannot update chosen node [linux,initrd-end]\n"); return ret; } fdt_pack(fdt); return ret; }
/** * Run the main fdtgrep operation, given a filename and valid arguments * * @param disp Display information / options * @param filename Filename of blob file * @param return 0 if ok, -ve on error */ static int do_fdtgrep(struct display_info *disp, const char *filename) { struct fdt_region *region; int max_regions; int count = 100; char path[1024]; char *blob; int i, ret; blob = utilfdt_read(filename); if (!blob) return -1; ret = fdt_check_header(blob); if (ret) { fprintf(stderr, "Error: %s\n", fdt_strerror(ret)); return ret; } /* Allow old files, but they are untested */ if (fdt_version(blob) < 17 && disp->value_head) { fprintf(stderr, "Warning: fdtgrep does not fully support version %d files\n", fdt_version(blob)); } /* * We do two passes, since we don't know how many regions we need. * The first pass will count the regions, but if it is too many, * we do another pass to actually record them. */ for (i = 0; i < 3; i++) { region = malloc(count * sizeof(struct fdt_region)); if (!region) { fprintf(stderr, "Out of memory for %d regions\n", count); return -1; } max_regions = count; count = fdtgrep_find_regions(blob, h_include, disp, region, max_regions, path, sizeof(path), disp->flags); if (count < 0) { report_error("fdt_find_regions", count); if (count == -FDT_ERR_BADLAYOUT) fprintf(stderr, "/aliases node must come before all other nodes\n"); return -1; } if (count <= max_regions) break; free(region); } /* Optionally print a list of regions */ if (disp->region_list) show_region_list(region, count); /* Output either source .dts or binary .dtb */ if (disp->output == OUT_DTS) { ret = display_fdt_by_regions(disp, blob, region, count); } else { void *fdt; /* Allow reserved memory section to expand slightly */ int size = fdt_totalsize(blob) + 16; fdt = malloc(size); if (!fdt) { fprintf(stderr, "Out_of_memory\n"); ret = -1; goto err; } size = dump_fdt_regions(disp, blob, region, count, fdt); if (disp->remove_strings) { void *out; out = malloc(size); if (!out) { fprintf(stderr, "Out_of_memory\n"); ret = -1; goto err; } ret = fdt_remove_unused_strings(fdt, out); if (ret < 0) { fprintf(stderr, "Failed to remove unused strings: err=%d\n", ret); goto err; } free(fdt); fdt = out; ret = fdt_pack(fdt); if (ret < 0) { fprintf(stderr, "Failed to pack: err=%d\n", ret); goto err; } size = fdt_totalsize(fdt); } if (size != fwrite(fdt, 1, size, disp->fout)) { fprintf(stderr, "Write failure, %d bytes\n", size); free(fdt); ret = 1; goto err; } free(fdt); } err: free(blob); free(region); return ret; }
//store dtb read/write buff size static int do_store_dtb_ops(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) { int ret = 0; char _cmdBuf[128]; char* ops = argv[2]; const unsigned maxDtbSz = 256 * 1024; unsigned actualDtbSz = 0; char* devCmd = NULL; char* dtbLoadaddr = argv[3]; if (argc < 4) return CMD_RET_USAGE; const int is_write = !strcmp("write", ops); if (!is_write) { ret = !strcmp("read", ops) || !strcmp("iread", ops);//must be 0 if (!ret) return CMD_RET_USAGE; } actualDtbSz = maxDtbSz; if (argc > 4) { const unsigned bufSz = simple_strtoul(argv[4], NULL, 0); if (bufSz > maxDtbSz) { ErrP("bufSz (%s) > max 0x%x\n", argv[4], maxDtbSz); return CMD_RET_FAILURE; } } ops = is_write ? "dtb_write" : "dtb_read"; switch (device_boot_flag) { case NAND_BOOT_FLAG: case SPI_NAND_FLAG: { devCmd = "amlnf"; } break; case EMMC_BOOT_FLAG: case SPI_EMMC_FLAG: { devCmd = "emmc"; } break; default: ErrP("device_boot_flag=0x%x err\n", device_boot_flag); return CMD_RET_FAILURE; } sprintf(_cmdBuf, "%s %s %s 0x%x", devCmd, ops, dtbLoadaddr, actualDtbSz); MsgP("To run cmd[%s]\n", _cmdBuf); ret = run_command(_cmdBuf, 0); #ifdef CONFIG_MULTI_DTB if (!is_write && strcmp("iread", ops)) { extern unsigned long get_multi_dt_entry(unsigned long fdt_addr); unsigned long dtImgAddr = simple_strtoul(dtbLoadaddr, NULL, 16); unsigned long fdtAddr = get_multi_dt_entry(dtImgAddr); ret = fdt_check_header((char*)fdtAddr); if (ret) { ErrP("Fail in fdt check header\n"); return CMD_RET_FAILURE; } unsigned fdtsz = fdt_totalsize((char*)fdtAddr); memmove((char*)dtImgAddr, (char*)fdtAddr, fdtsz); } #endif// #ifdef CONFIG_MULTI_DTB return ret; }
efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt, unsigned long orig_fdt_size, void *fdt, int new_fdt_size, char *cmdline_ptr, u64 initrd_addr, u64 initrd_size, efi_memory_desc_t *memory_map, unsigned long map_size, unsigned long desc_size, u32 desc_ver) { int node, prev, num_rsv; int status; u32 fdt_val32; u64 fdt_val64; /* Do some checks on provided FDT, if it exists*/ if (orig_fdt) { if (fdt_check_header(orig_fdt)) { pr_efi_err(sys_table, "Device Tree header not valid!\n"); return EFI_LOAD_ERROR; } /* * We don't get the size of the FDT if we get if from a * configuration table. */ if (orig_fdt_size && fdt_totalsize(orig_fdt) > orig_fdt_size) { pr_efi_err(sys_table, "Truncated device tree! foo!\n"); return EFI_LOAD_ERROR; } } if (orig_fdt) status = fdt_open_into(orig_fdt, fdt, new_fdt_size); else status = fdt_create_empty_tree(fdt, new_fdt_size); if (status != 0) goto fdt_set_fail; /* * Delete any memory nodes present. We must delete nodes which * early_init_dt_scan_memory may try to use. */ prev = 0; for (;;) { const char *type; int len; node = fdt_next_node(fdt, prev, NULL); if (node < 0) break; type = fdt_getprop(fdt, node, "device_type", &len); if (type && strncmp(type, "memory", len) == 0) { fdt_del_node(fdt, node); continue; } prev = node; } /* * Delete all memory reserve map entries. When booting via UEFI, * kernel will use the UEFI memory map to find reserved regions. */ num_rsv = fdt_num_mem_rsv(fdt); while (num_rsv-- > 0) fdt_del_mem_rsv(fdt, num_rsv); node = fdt_subnode_offset(fdt, 0, "chosen"); if (node < 0) { node = fdt_add_subnode(fdt, 0, "chosen"); if (node < 0) { status = node; /* node is error code when negative */ goto fdt_set_fail; } } if ((cmdline_ptr != NULL) && (strlen(cmdline_ptr) > 0)) { status = fdt_setprop(fdt, node, "bootargs", cmdline_ptr, strlen(cmdline_ptr) + 1); if (status) goto fdt_set_fail; } /* Set initrd address/end in device tree, if present */ if (initrd_size != 0) { u64 initrd_image_end; u64 initrd_image_start = cpu_to_fdt64(initrd_addr); status = fdt_setprop(fdt, node, "linux,initrd-start", &initrd_image_start, sizeof(u64)); if (status) goto fdt_set_fail; initrd_image_end = cpu_to_fdt64(initrd_addr + initrd_size); status = fdt_setprop(fdt, node, "linux,initrd-end", &initrd_image_end, sizeof(u64)); if (status) goto fdt_set_fail; } /* Add FDT entries for EFI runtime services in chosen node. */ node = fdt_subnode_offset(fdt, 0, "chosen"); fdt_val64 = cpu_to_fdt64((u64)(unsigned long)sys_table); status = fdt_setprop(fdt, node, "linux,uefi-system-table", &fdt_val64, sizeof(fdt_val64)); if (status) goto fdt_set_fail; fdt_val64 = cpu_to_fdt64((u64)(unsigned long)memory_map); status = fdt_setprop(fdt, node, "linux,uefi-mmap-start", &fdt_val64, sizeof(fdt_val64)); if (status) goto fdt_set_fail; fdt_val32 = cpu_to_fdt32(map_size); status = fdt_setprop(fdt, node, "linux,uefi-mmap-size", &fdt_val32, sizeof(fdt_val32)); if (status) goto fdt_set_fail; fdt_val32 = cpu_to_fdt32(desc_size); status = fdt_setprop(fdt, node, "linux,uefi-mmap-desc-size", &fdt_val32, sizeof(fdt_val32)); if (status) goto fdt_set_fail; fdt_val32 = cpu_to_fdt32(desc_ver); status = fdt_setprop(fdt, node, "linux,uefi-mmap-desc-ver", &fdt_val32, sizeof(fdt_val32)); if (status) goto fdt_set_fail; /* * Add kernel version banner so stub/kernel match can be * verified. */ status = fdt_setprop_string(fdt, node, "linux,uefi-stub-kern-ver", linux_banner); if (status) goto fdt_set_fail; return EFI_SUCCESS; fdt_set_fail: if (status == -FDT_ERR_NOSPACE) return EFI_BUFFER_TOO_SMALL; return EFI_LOAD_ERROR; }
/* * 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; }
/* * Flattened Device Tree command, see the help for parameter definitions. */ int do_fdt (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) { if (argc < 2) { printf ("Usage:\n%s\n", cmdtp->usage); return 1; } /******************************************************************** * Set the address of the fdt ********************************************************************/ if (argv[1][0] == 'a') { /* * Set the address [and length] of the fdt. */ if (argc == 2) { if (!fdt_valid()) { return 1; } printf("The address of the fdt is %p\n", working_fdt); return 0; } working_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(working_fdt)) { printf ("New length %d < existing length %d, " "ignoring.\n", len, fdt_totalsize(working_fdt)); } else { /* * Open in place with a new length. */ err = fdt_open_into(working_fdt, working_fdt, len); if (err != 0) { printf ("libfdt fdt_open_into(): %s\n", fdt_strerror(err)); } } } /******************************************************************** * Move the working_fdt ********************************************************************/ } else if (strncmp(argv[1], "mo", 2) == 0) { struct fdt_header *newaddr; int len; int err; if (argc < 4) { printf ("Usage:\n%s\n", cmdtp->usage); return 1; } /* * Set the address and length of the fdt. */ working_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); /* * If the user specifies a length, use that. Otherwise use the * current length. */ if (argc <= 4) { len = fdt_totalsize(working_fdt); } else { len = simple_strtoul(argv[4], NULL, 16); if (len < fdt_totalsize(working_fdt)) { printf ("New length 0x%X < existing length " "0x%X, aborting.\n", len, fdt_totalsize(working_fdt)); return 1; } } /* * Copy to the new location. */ err = fdt_open_into(working_fdt, newaddr, len); if (err != 0) { printf ("libfdt fdt_open_into(): %s\n", fdt_strerror(err)); return 1; } working_fdt = newaddr; /******************************************************************** * Make a new node ********************************************************************/ } else if (strncmp(argv[1], "mk", 2) == 0) { char *pathp; /* path */ char *nodep; /* new node to add */ int nodeoffset; /* node offset from libfdt */ int err; /* * Parameters: Node path, new node to be appended to the path. */ if (argc < 4) { printf ("Usage:\n%s\n", cmdtp->usage); return 1; } pathp = argv[2]; nodep = argv[3]; nodeoffset = fdt_path_offset (working_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; } err = fdt_add_subnode(working_fdt, nodeoffset, nodep); if (err < 0) { printf ("libfdt fdt_add_subnode(): %s\n", fdt_strerror(err)); return 1; } /******************************************************************** * Set the value of a property in the working_fdt. ********************************************************************/ } else if (argv[1][0] == 's') { char *pathp; /* path */ char *prop; /* property */ int nodeoffset; /* node offset from libfdt */ static char data[SCRATCHPAD]; /* storage for the property */ int len; /* new length of the property */ int ret; /* return value */ /* * Parameters: Node path, property, optional value. */ if (argc < 4) { printf ("Usage:\n%s\n", cmdtp->usage); return 1; } pathp = argv[2]; prop = argv[3]; if (argc == 4) { len = 0; } else { ret = fdt_parse_prop(&argv[4], argc - 4, data, &len); if (ret != 0) return ret; } nodeoffset = fdt_path_offset (working_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; } ret = fdt_setprop(working_fdt, nodeoffset, prop, data, len); if (ret < 0) { printf ("libfdt fdt_setprop(): %s\n", fdt_strerror(ret)); return 1; } /******************************************************************** * Print (recursive) / List (single level) ********************************************************************/ } else if ((argv[1][0] == 'p') || (argv[1][0] == 'l')) { int depth = MAX_LEVEL; /* how deep to print */ char *pathp; /* path */ char *prop; /* property */ int ret; /* return value */ static char root[2] = "/"; /* * list is an alias for print, but limited to 1 level */ if (argv[1][0] == 'l') { depth = 1; } /* * Get the starting path. The root node is an oddball, * the offset is zero and has no name. */ if (argc == 2) pathp = root; else pathp = argv[2]; if (argc > 3) prop = argv[3]; else prop = NULL; ret = fdt_print(pathp, prop, depth); if (ret != 0) return ret; /******************************************************************** * Remove a property/node ********************************************************************/ } else if (strncmp(argv[1], "rm", 2) == 0) { 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. */ nodeoffset = fdt_path_offset (working_fdt, argv[2]); if (nodeoffset < 0) { /* * Not found or something else bad happened. */ printf ("libfdt fdt_path_offset() returned %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(working_fdt, nodeoffset, argv[3]); if (err < 0) { printf("libfdt fdt_delprop(): %s\n", fdt_strerror(err)); return err; } } else { err = fdt_del_node(working_fdt, nodeoffset); if (err < 0) { printf("libfdt fdt_del_node(): %s\n", fdt_strerror(err)); return err; } } /******************************************************************** * Display header info ********************************************************************/ } else if (argv[1][0] == 'h') { u32 version = fdt_version(working_fdt); printf("magic:\t\t\t0x%x\n", fdt_magic(working_fdt)); printf("totalsize:\t\t0x%x (%d)\n", fdt_totalsize(working_fdt), fdt_totalsize(working_fdt)); printf("off_dt_struct:\t\t0x%x\n", fdt_off_dt_struct(working_fdt)); printf("off_dt_strings:\t\t0x%x\n", fdt_off_dt_strings(working_fdt)); printf("off_mem_rsvmap:\t\t0x%x\n", fdt_off_mem_rsvmap(working_fdt)); printf("version:\t\t%d\n", version); printf("last_comp_version:\t%d\n", fdt_last_comp_version(working_fdt)); if (version >= 2) printf("boot_cpuid_phys:\t0x%x\n", fdt_boot_cpuid_phys(working_fdt)); if (version >= 3) printf("size_dt_strings:\t0x%x\n", fdt_size_dt_strings(working_fdt)); if (version >= 17) printf("size_dt_struct:\t\t0x%x\n", fdt_size_dt_struct(working_fdt)); printf("number mem_rsv:\t\t0x%x\n", fdt_num_mem_rsv(working_fdt)); printf("\n"); /******************************************************************** * Set boot cpu id ********************************************************************/ } else if (strncmp(argv[1], "boo", 3) == 0) { unsigned long tmp = simple_strtoul(argv[2], NULL, 16); fdt_set_boot_cpuid_phys(working_fdt, tmp); /******************************************************************** * memory command ********************************************************************/ } else if (strncmp(argv[1], "me", 2) == 0) { uint64_t addr, size; int err; #ifdef CFG_64BIT_STRTOUL addr = simple_strtoull(argv[2], NULL, 16); size = simple_strtoull(argv[3], NULL, 16); #else addr = simple_strtoul(argv[2], NULL, 16); size = simple_strtoul(argv[3], NULL, 16); #endif err = fdt_fixup_memory(working_fdt, addr, size); if (err < 0) return err; /******************************************************************** * mem reserve commands ********************************************************************/ } else if (strncmp(argv[1], "rs", 2) == 0) { if (argv[2][0] == 'p') { uint64_t addr, size; int total = fdt_num_mem_rsv(working_fdt); int j, err; printf("index\t\t start\t\t size\n"); printf("-------------------------------" "-----------------\n"); for (j = 0; j < total; j++) { err = fdt_get_mem_rsv(working_fdt, j, &addr, &size); if (err < 0) { printf("libfdt fdt_get_mem_rsv(): %s\n", fdt_strerror(err)); return err; } printf(" %x\t%08x%08x\t%08x%08x\n", j, (u32)(addr >> 32), (u32)(addr & 0xffffffff), (u32)(size >> 32), (u32)(size & 0xffffffff)); } } else if (argv[2][0] == 'a') {
static int sysctl_handle_dtb(SYSCTL_HANDLER_ARGS) { return (sysctl_handle_opaque(oidp, fdtp, fdt_totalsize(fdtp), req)); }
/* * Flattened Device Tree command, see the help for parameter definitions. */ static int do_fdt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { if (argc < 2) return CMD_RET_USAGE; /* * Set the address of the fdt */ if (strncmp(argv[1], "ad", 2) == 0) { unsigned long addr; int control = 0; struct fdt_header *blob; /* * Set the address [and length] of the fdt. */ argc -= 2; argv += 2; /* Temporary #ifdef - some archs don't have fdt_blob yet */ #ifdef CONFIG_OF_CONTROL if (argc && !strcmp(*argv, "-c")) { control = 1; argc--; argv++; } #endif if (argc == 0) { if (control) blob = (struct fdt_header *)gd->fdt_blob; else blob = working_fdt; if (!blob || !fdt_valid(&blob)) return 1; printf("The address of the fdt is %#08lx\n", control ? (ulong)map_to_sysmem(blob) : getenv_hex("fdtaddr", 0)); return 0; } addr = simple_strtoul(argv[0], NULL, 16); blob = map_sysmem(addr, 0); if (!fdt_valid(&blob)) return 1; if (control) gd->fdt_blob = blob; else set_working_fdt_addr(addr); if (argc >= 2) { int len; int err; /* * Optional new length */ len = simple_strtoul(argv[1], NULL, 16); if (len < fdt_totalsize(blob)) { printf ("New length %d < existing length %d, " "ignoring.\n", len, fdt_totalsize(blob)); } else { /* * Open in place with a new length. */ err = fdt_open_into(blob, blob, len); if (err != 0) { printf ("libfdt fdt_open_into(): %s\n", fdt_strerror(err)); } } } return CMD_RET_SUCCESS; } if (!working_fdt) { puts( "No FDT memory address configured. Please configure\n" "the FDT address via \"fdt addr <address>\" command.\n" "Aborting!\n"); return CMD_RET_FAILURE; } /* * Move the working_fdt */ if (strncmp(argv[1], "mo", 2) == 0) { struct fdt_header *newaddr; int len; int err; if (argc < 4) return CMD_RET_USAGE; /* * Set the address and length of the fdt. */ working_fdt = (struct fdt_header *)simple_strtoul(argv[2], NULL, 16); if (!fdt_valid(&working_fdt)) return 1; newaddr = (struct fdt_header *)simple_strtoul(argv[3],NULL,16); /* * If the user specifies a length, use that. Otherwise use the * current length. */ if (argc <= 4) { len = fdt_totalsize(working_fdt); } else { len = simple_strtoul(argv[4], NULL, 16); if (len < fdt_totalsize(working_fdt)) { printf ("New length 0x%X < existing length " "0x%X, aborting.\n", len, fdt_totalsize(working_fdt)); return 1; } } /* * Copy to the new location. */ err = fdt_open_into(working_fdt, newaddr, len); if (err != 0) { printf ("libfdt fdt_open_into(): %s\n", fdt_strerror(err)); return 1; } working_fdt = newaddr; /* * Make a new node */ } else if (strncmp(argv[1], "mk", 2) == 0) { char *pathp; /* path */ char *nodep; /* new node to add */ int nodeoffset; /* node offset from libfdt */ int err; /* * Parameters: Node path, new node to be appended to the path. */ if (argc < 4) return CMD_RET_USAGE; pathp = argv[2]; nodep = argv[3]; nodeoffset = fdt_path_offset (working_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; } err = fdt_add_subnode(working_fdt, nodeoffset, nodep); if (err < 0) { printf ("libfdt fdt_add_subnode(): %s\n", fdt_strerror(err)); return 1; } /* * Set the value of a property in the working_fdt. */ } else if (argv[1][0] == 's') { char *pathp; /* path */ char *prop; /* property */ int nodeoffset; /* node offset from libfdt */ static char data[SCRATCHPAD]; /* storage for the property */ int len; /* new length of the property */ int ret; /* return value */ /* * Parameters: Node path, property, optional value. */ if (argc < 4) return CMD_RET_USAGE; pathp = argv[2]; prop = argv[3]; if (argc == 4) { len = 0; } else { ret = fdt_parse_prop(&argv[4], argc - 4, data, &len); if (ret != 0) return ret; } nodeoffset = fdt_path_offset (working_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; } ret = fdt_setprop(working_fdt, nodeoffset, prop, data, len); if (ret < 0) { printf ("libfdt fdt_setprop(): %s\n", fdt_strerror(ret)); return 1; } /******************************************************************** * Get the value of a property in the working_fdt. ********************************************************************/ } else if (argv[1][0] == 'g') { char *subcmd; /* sub-command */ char *pathp; /* path */ char *prop; /* property */ char *var; /* variable to store result */ int nodeoffset; /* node offset from libfdt */ const void *nodep; /* property node pointer */ int len = 0; /* new length of the property */ /* * Parameters: Node path, property, optional value. */ if (argc < 5) return CMD_RET_USAGE; subcmd = argv[2]; if (argc < 6 && subcmd[0] != 's') return CMD_RET_USAGE; var = argv[3]; pathp = argv[4]; prop = argv[5]; nodeoffset = fdt_path_offset(working_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; } if (subcmd[0] == 'n' || (subcmd[0] == 's' && argc == 5)) { int reqIndex = -1; int startDepth = fdt_node_depth( working_fdt, nodeoffset); int curDepth = startDepth; int curIndex = -1; int nextNodeOffset = fdt_next_node( working_fdt, nodeoffset, &curDepth); if (subcmd[0] == 'n') reqIndex = simple_strtoul(argv[5], NULL, 16); while (curDepth > startDepth) { if (curDepth == startDepth + 1) curIndex++; if (subcmd[0] == 'n' && curIndex == reqIndex) { const char *nodeName = fdt_get_name( working_fdt, nextNodeOffset, NULL); setenv(var, (char *)nodeName); return 0; } nextNodeOffset = fdt_next_node( working_fdt, nextNodeOffset, &curDepth); if (nextNodeOffset < 0) break; } if (subcmd[0] == 's') { /* get the num nodes at this level */ setenv_ulong(var, curIndex + 1); } else { /* node index not found */ printf("libfdt node not found\n"); return 1; } } else { nodep = fdt_getprop( working_fdt, nodeoffset, prop, &len); if (len == 0) { /* no property value */ setenv(var, ""); return 0; } else if (len > 0) { if (subcmd[0] == 'v') { int ret; ret = fdt_value_setenv(nodep, len, var); if (ret != 0) return ret; } else if (subcmd[0] == 'a') { /* Get address */ char buf[11]; sprintf(buf, "0x%p", nodep); setenv(var, buf); } else if (subcmd[0] == 's') { /* Get size */ char buf[11]; sprintf(buf, "0x%08X", len); setenv(var, buf); } else return CMD_RET_USAGE; return 0; } else { printf("libfdt fdt_getprop(): %s\n", fdt_strerror(len)); return 1; } } /* * Print (recursive) / List (single level) */ } else if ((argv[1][0] == 'p') || (argv[1][0] == 'l')) { int depth = MAX_LEVEL; /* how deep to print */ char *pathp; /* path */ char *prop; /* property */ int ret; /* return value */ static char root[2] = "/"; /* * list is an alias for print, but limited to 1 level */ if (argv[1][0] == 'l') { depth = 1; } /* * Get the starting path. The root node is an oddball, * the offset is zero and has no name. */ if (argc == 2) pathp = root; else pathp = argv[2]; if (argc > 3) prop = argv[3]; else prop = NULL; ret = fdt_print(pathp, prop, depth); if (ret != 0) return ret; /* * Remove a property/node */ } else if (strncmp(argv[1], "rm", 2) == 0) { 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. */ nodeoffset = fdt_path_offset (working_fdt, argv[2]); if (nodeoffset < 0) { /* * Not found or something else bad happened. */ printf ("libfdt fdt_path_offset() returned %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(working_fdt, nodeoffset, argv[3]); if (err < 0) { printf("libfdt fdt_delprop(): %s\n", fdt_strerror(err)); return err; } } else { err = fdt_del_node(working_fdt, nodeoffset); if (err < 0) { printf("libfdt fdt_del_node(): %s\n", fdt_strerror(err)); return err; } } /* * Display header info */ } else if (argv[1][0] == 'h') { u32 version = fdt_version(working_fdt); printf("magic:\t\t\t0x%x\n", fdt_magic(working_fdt)); printf("totalsize:\t\t0x%x (%d)\n", fdt_totalsize(working_fdt), fdt_totalsize(working_fdt)); printf("off_dt_struct:\t\t0x%x\n", fdt_off_dt_struct(working_fdt)); printf("off_dt_strings:\t\t0x%x\n", fdt_off_dt_strings(working_fdt)); printf("off_mem_rsvmap:\t\t0x%x\n", fdt_off_mem_rsvmap(working_fdt)); printf("version:\t\t%d\n", version); printf("last_comp_version:\t%d\n", fdt_last_comp_version(working_fdt)); if (version >= 2) printf("boot_cpuid_phys:\t0x%x\n", fdt_boot_cpuid_phys(working_fdt)); if (version >= 3) printf("size_dt_strings:\t0x%x\n", fdt_size_dt_strings(working_fdt)); if (version >= 17) printf("size_dt_struct:\t\t0x%x\n", fdt_size_dt_struct(working_fdt)); printf("number mem_rsv:\t\t0x%x\n", fdt_num_mem_rsv(working_fdt)); printf("\n"); /* * Set boot cpu id */ } else if (strncmp(argv[1], "boo", 3) == 0) { unsigned long tmp = simple_strtoul(argv[2], NULL, 16); fdt_set_boot_cpuid_phys(working_fdt, tmp); /* * memory command */ } else if (strncmp(argv[1], "me", 2) == 0) { uint64_t addr, size; int err; addr = simple_strtoull(argv[2], NULL, 16); size = simple_strtoull(argv[3], NULL, 16); err = fdt_fixup_memory(working_fdt, addr, size); if (err < 0) return err; /* * mem reserve commands */ } else if (strncmp(argv[1], "rs", 2) == 0) { if (argv[2][0] == 'p') { uint64_t addr, size; int total = fdt_num_mem_rsv(working_fdt); int j, err; printf("index\t\t start\t\t size\n"); printf("-------------------------------" "-----------------\n"); for (j = 0; j < total; j++) { err = fdt_get_mem_rsv(working_fdt, j, &addr, &size); if (err < 0) { printf("libfdt fdt_get_mem_rsv(): %s\n", fdt_strerror(err)); return err; } printf(" %x\t%08x%08x\t%08x%08x\n", j, (u32)(addr >> 32), (u32)(addr & 0xffffffff), (u32)(size >> 32), (u32)(size & 0xffffffff)); } } else if (argv[2][0] == 'a') {
int spl_load_simple_fit(struct spl_load_info *info, ulong sector, void *fit) { int sectors; ulong size, load; unsigned long count; int node, images; void *load_ptr; int fdt_offset, fdt_len; int data_offset, data_size; int base_offset; int src_sector; void *dst; /* * Figure out where the external images start. This is the base for the * data-offset properties in each image. */ size = fdt_totalsize(fit); size = (size + 3) & ~3; base_offset = (size + 3) & ~3; /* * So far we only have one block of data from the FIT. Read the entire * thing, including that first block, placing it so it finishes before * where we will load the image. * * Note that we will load the image such that its first byte will be * at the load address. Since that byte may be part-way through a * block, we may load the image up to one block before the load * address. So take account of that here by subtracting an addition * block length from the FIT start position. * * In fact the FIT has its own load address, but we assume it cannot * be before CONFIG_SYS_TEXT_BASE. */ fit = (void *)(CONFIG_SYS_TEXT_BASE - size - info->bl_len); sectors = (size + info->bl_len - 1) / info->bl_len; count = info->read(info, sector, sectors, fit); debug("fit read sector %lx, sectors=%d, dst=%p, count=%lu\n", sector, sectors, fit, count); if (count == 0) return -EIO; /* find the firmware image to load */ images = fdt_path_offset(fit, FIT_IMAGES_PATH); if (images < 0) { debug("%s: Cannot find /images node: %d\n", __func__, images); return -1; } node = fdt_first_subnode(fit, images); if (node < 0) { debug("%s: Cannot find first image node: %d\n", __func__, node); return -1; } /* Get its information and set up the spl_image structure */ data_offset = fdt_getprop_u32(fit, node, "data-offset"); data_size = fdt_getprop_u32(fit, node, "data-size"); load = fdt_getprop_u32(fit, node, "load"); debug("data_offset=%x, data_size=%x\n", data_offset, data_size); spl_image.load_addr = load; spl_image.entry_point = load; spl_image.os = IH_OS_U_BOOT; /* * Work out where to place the image. We read it so that the first * byte will be at 'load'. This may mean we need to load it starting * before then, since we can only read whole blocks. */ sectors = (data_size + info->bl_len - 1) / info->bl_len; data_offset += base_offset; load_ptr = (void *)load; debug("U-Boot size %x, data %p\n", data_size, load_ptr); dst = load_ptr - (data_offset % info->bl_len); /* Read the image */ src_sector = sector + data_offset / info->bl_len; debug("image: data_offset=%x, dst=%p, src_sector=%x, sectors=%x\n", data_offset, dst, src_sector, sectors); count = info->read(info, src_sector, sectors, dst); if (count != sectors) return -EIO; /* Figure out which device tree the board wants to use */ fdt_len = spl_fit_select_fdt(fit, images, &fdt_offset); if (fdt_len < 0) return fdt_len; /* * Read the device tree and place it after the image. There may be * some extra data before it since we can only read entire blocks. */ dst = load_ptr + data_size; fdt_offset += base_offset; count = info->read(info, sector + fdt_offset / info->bl_len, sectors, dst); debug("fit read %x sectors to %x, dst %p, data_offset %x\n", sectors, spl_image.load_addr, dst, fdt_offset); if (count != sectors) return -EIO; /* * Copy the device tree so that it starts immediately after the image. * After this we will have the U-Boot image and its device tree ready * for us to start. */ memcpy(dst, dst + fdt_offset % info->bl_len, fdt_len); return 0; }
void board_init_f(ulong bootflag) { bd_t *bd; init_fnc_t **init_fnc_ptr; gd_t *id; ulong addr, addr_sp; #ifdef CONFIG_PRAM ulong reg; #endif void *new_fdt = NULL; size_t fdt_size = 0; memset((void *)gd, 0, sizeof(gd_t)); gd->mon_len = (ulong)&__bss_end - (ulong)_start; #ifdef CONFIG_OF_EMBED /* Get a pointer to the FDT */ gd->fdt_blob = __dtb_db_begin; #elif defined CONFIG_OF_SEPARATE /* FDT is at end of image */ gd->fdt_blob = &_end; #endif /* Allow the early environment to override the fdt address */ gd->fdt_blob = (void *)getenv_ulong("fdtcontroladdr", 16, (uintptr_t)gd->fdt_blob); for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { if ((*init_fnc_ptr)() != 0) { hang (); } } #ifdef CONFIG_OF_CONTROL /* For now, put this check after the console is ready */ if (fdtdec_prepare_fdt()) { panic("** CONFIG_OF_CONTROL defined but no FDT - please see " "doc/README.fdt-control"); } #endif debug("monitor len: %08lX\n", gd->mon_len); /* * Ram is setup, size stored in gd !! */ debug("ramsize: %08lX\n", gd->ram_size); #if defined(CONFIG_SYS_MEM_TOP_HIDE) /* * Subtract specified amount of memory to hide so that it won't * get "touched" at all by U-Boot. By fixing up gd->ram_size * the Linux kernel should now get passed the now "corrected" * memory size and won't touch it either. This should work * for arch/ppc and arch/powerpc. Only Linux board ports in * arch/powerpc with bootwrapper support, that recalculate the * memory size from the SDRAM controller setup will have to * get fixed. */ gd->ram_size -= CONFIG_SYS_MEM_TOP_HIDE; #endif addr = CONFIG_SYS_SDRAM_BASE + get_effective_memsize(); #ifdef CONFIG_LOGBUFFER #ifndef CONFIG_ALT_LB_ADDR /* reserve kernel log buffer */ addr -= (LOGBUFF_RESERVE); debug("Reserving %dk for kernel logbuffer at %08lx\n", LOGBUFF_LEN, addr); #endif #endif #ifdef CONFIG_PRAM /* * reserve protected RAM */ reg = getenv_ulong("pram", 10, CONFIG_PRAM); addr -= (reg << 10); /* size is in kB */ debug("Reserving %ldk for protected RAM at %08lx\n", reg, addr); #endif /* CONFIG_PRAM */ #if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF)) /* reserve TLB table */ gd->arch.tlb_size = PGTABLE_SIZE; addr -= gd->arch.tlb_size; /* round down to next 64 kB limit */ addr &= ~(0x10000 - 1); gd->arch.tlb_addr = addr; debug("TLB table from %08lx to %08lx\n", addr, addr + gd->arch.tlb_size); #endif /* round down to next 4 kB limit */ addr &= ~(4096 - 1); debug("Top of RAM usable for U-Boot at: %08lx\n", addr); #ifdef CONFIG_LCD #ifdef CONFIG_FB_ADDR gd->fb_base = CONFIG_FB_ADDR; #else /* reserve memory for LCD display (always full pages) */ addr = lcd_setmem(addr); gd->fb_base = addr; #endif /* CONFIG_FB_ADDR */ #endif /* CONFIG_LCD */ /* * reserve memory for U-Boot code, data & bss * round down to next 4 kB limit */ addr -= gd->mon_len; addr &= ~(4096 - 1); debug("Reserving %ldk for U-Boot at: %08lx\n", gd->mon_len >> 10, addr); #ifndef CONFIG_SPL_BUILD /* * reserve memory for malloc() arena */ addr_sp = addr - TOTAL_MALLOC_LEN; debug("Reserving %dk for malloc() at: %08lx\n", TOTAL_MALLOC_LEN >> 10, addr_sp); /* * (permanently) allocate a Board Info struct * and a permanent copy of the "global" data */ addr_sp -= sizeof (bd_t); bd = (bd_t *) addr_sp; gd->bd = bd; debug("Reserving %zu Bytes for Board Info at: %08lx\n", sizeof (bd_t), addr_sp); #ifdef CONFIG_MACH_TYPE gd->bd->bi_arch_number = CONFIG_MACH_TYPE; /* board id for Linux */ #endif addr_sp -= sizeof (gd_t); id = (gd_t *) addr_sp; debug("Reserving %zu Bytes for Global Data at: %08lx\n", sizeof (gd_t), addr_sp); #if defined(CONFIG_OF_SEPARATE) && defined(CONFIG_OF_CONTROL) /* * If the device tree is sitting immediate above our image then we * must relocate it. If it is embedded in the data section, then it * will be relocated with other data. */ if (gd->fdt_blob) { fdt_size = ALIGN(fdt_totalsize(gd->fdt_blob) + 0x1000, 32); addr_sp -= fdt_size; new_fdt = (void *)addr_sp; debug("Reserving %zu Bytes for FDT at: %08lx\n", fdt_size, addr_sp); } #endif #ifndef CONFIG_ARM64 /* setup stackpointer for exeptions */ gd->irq_sp = addr_sp; #ifdef CONFIG_USE_IRQ addr_sp -= (CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ); debug("Reserving %zu Bytes for IRQ stack at: %08lx\n", CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ, addr_sp); #endif /* leave 3 words for abort-stack */ addr_sp -= 12; /* 8-byte alignment for ABI compliance */ addr_sp &= ~0x07; #else /* CONFIG_ARM64 */ /* 16-byte alignment for ABI compliance */ addr_sp &= ~0x0f; #endif /* CONFIG_ARM64 */ #else addr_sp += 128; /* leave 32 words for abort-stack */ gd->irq_sp = addr_sp; #endif debug("New Stack Pointer is: %08lx\n", addr_sp); #ifdef CONFIG_POST post_bootmode_init(); post_run(NULL, POST_ROM | post_bootmode_get(0)); #endif gd->bd->bi_baudrate = gd->baudrate; /* Ram ist board specific, so move it to board code ... */ dram_init_banksize(); display_dram_config(); /* and display it */ gd->relocaddr = addr; gd->start_addr_sp = addr_sp; gd->reloc_off = addr - (ulong)&_start; debug("relocation Offset is: %08lx\n", gd->reloc_off); if (new_fdt) { memcpy(new_fdt, gd->fdt_blob, fdt_size); gd->fdt_blob = new_fdt; } memcpy(id, (void *)gd, sizeof(gd_t)); }
extern "C" int start_raw(int argc, const char **argv) { stage2_args args; clear_bss(); // call C++ constructors before doing anything else call_ctors(); args.heap_size = HEAP_SIZE; args.arguments = NULL; args.platform.boot_tgz_data = NULL; args.platform.boot_tgz_size = 0; args.platform.fdt_data = NULL; args.platform.fdt_size = 0; // if we get passed a uimage, try to find the third blob only if we do not have FDT data yet if (gUImage != NULL && !gFDT && image_multi_getimg(gUImage, 2, (uint32*)&args.platform.fdt_data, &args.platform.fdt_size)) { // found a blob, assume it is FDT data, when working on a platform // which does not have an FDT enabled U-Boot gFDT = args.platform.fdt_data; } serial_init(gFDT); console_init(); cpu_init(); if (args.platform.fdt_data) { dprintf("Found FDT from uimage @ %p, %" B_PRIu32 " bytes\n", args.platform.fdt_data, args.platform.fdt_size); } else if (gFDT) { /* Fixup args so we can pass the gFDT on to the kernel */ args.platform.fdt_data = gFDT; args.platform.fdt_size = fdt_totalsize(gFDT); } // if we get passed an FDT, check /chosen for initrd if (gFDT != NULL) { int node = fdt_path_offset(gFDT, "/chosen"); const void *prop; int len; phys_addr_t initrd_start = 0, initrd_end = 0; if (node >= 0) { prop = fdt_getprop(gFDT, node, "linux,initrd-start", &len); if (prop && len == 4) initrd_start = fdt32_to_cpu(*(uint32_t *)prop); prop = fdt_getprop(gFDT, node, "linux,initrd-end", &len); if (prop && len == 4) initrd_end = fdt32_to_cpu(*(uint32_t *)prop); if (initrd_end > initrd_start) { args.platform.boot_tgz_data = (void *)initrd_start; args.platform.boot_tgz_size = initrd_end - initrd_start; dprintf("Found boot tgz from FDT @ %p, %" B_PRIu32 " bytes\n", args.platform.boot_tgz_data, args.platform.boot_tgz_size); } } } // if we get passed a uimage, try to find the second blob if (gUImage != NULL && image_multi_getimg(gUImage, 1, (uint32*)&args.platform.boot_tgz_data, &args.platform.boot_tgz_size)) { dprintf("Found boot tgz from uimage @ %p, %" B_PRIu32 " bytes\n", args.platform.boot_tgz_data, args.platform.boot_tgz_size); } { //DEBUG: int i; dprintf("argc = %d\n", argc); for (i = 0; i < argc; i++) dprintf("argv[%d] @%lx = '%s'\n", i, (uint32)argv[i], argv[i]); dprintf("os: %d\n", (int)gUBootOS); dprintf("gd @ %p\n", gUBootGlobalData); if (gUBootGlobalData) dprintf("gd->bd @ %p\n", gUBootGlobalData->bd); //dprintf("fb_base %p\n", (void*)gUBootGlobalData->fb_base); if (gUImage) dump_uimage(gUImage); if (gFDT) dump_fdt(gFDT); } mmu_init(); // wait a bit to give the user the opportunity to press a key // spin(750000); // reading the keyboard doesn't seem to work in graphics mode // (maybe a bochs problem) // sBootOptions = check_for_boot_keys(); //if (sBootOptions & BOOT_OPTION_DEBUG_OUTPUT) serial_enable(); main(&args); return 0; }