static void spapr_finalize_fdt(sPAPREnvironment *spapr, target_phys_addr_t fdt_addr, target_phys_addr_t rtas_addr, target_phys_addr_t rtas_size) { int ret; void *fdt; fdt = qemu_malloc(FDT_MAX_SIZE); /* open out the base tree into a temp buffer for the final tweaks */ _FDT((fdt_open_into(spapr->fdt_skel, fdt, FDT_MAX_SIZE))); ret = spapr_populate_vdevice(spapr->vio_bus, fdt); if (ret < 0) { fprintf(stderr, "couldn't setup vio devices in fdt\n"); exit(1); } /* RTAS */ ret = spapr_rtas_device_tree_setup(fdt, rtas_addr, rtas_size); if (ret < 0) { fprintf(stderr, "Couldn't set up RTAS device tree properties\n"); } _FDT((fdt_pack(fdt))); cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt)); qemu_free(fdt); }
int main(int argc, char *argv[]) { void *fdt; const uint32_t *intp; const char *strp; int err, lenerr; int oldsize, delsize, newsize; test_init(argc, argv); fdt = load_blob_arg(argc, argv); fdt = open_blob_rw(fdt); oldsize = fdt_totalsize(fdt); intp = check_getprop_cell(fdt, 0, "prop-int", TEST_VALUE_1); verbose_printf("int value was 0x%08x\n", *intp); err = fdt_delprop(fdt, 0, "prop-int"); if (err) FAIL("Failed to delete \"prop-int\": %s", fdt_strerror(err)); intp = fdt_getprop(fdt, 0, "prop-int", &lenerr); if (intp) FAIL("prop-int still present after deletion"); if (lenerr != -FDT_ERR_NOTFOUND) FAIL("Unexpected error on second getprop: %s", fdt_strerror(lenerr)); strp = check_getprop(fdt, 0, "prop-str", strlen(TEST_STRING_1)+1, TEST_STRING_1); verbose_printf("string value was \"%s\"\n", strp); err = fdt_delprop(fdt, 0, "prop-str"); if (err) FAIL("Failed to delete \"prop-str\": %s", fdt_strerror(err)); strp = fdt_getprop(fdt, 0, "prop-str", &lenerr); if (strp) FAIL("prop-str still present after deletion"); if (lenerr != -FDT_ERR_NOTFOUND) FAIL("Unexpected error on second getprop: %s", fdt_strerror(lenerr)); delsize = fdt_totalsize(fdt); err = fdt_pack(fdt); if (err) FAIL("fdt_pack(): %s\n", fdt_strerror(err)); newsize = fdt_totalsize(fdt); verbose_printf("oldsize = %d, delsize = %d, newsize = %d\n", oldsize, delsize, newsize); if (newsize >= oldsize) FAIL("Tree failed to shrink after deletions"); PASS(); }
static void devtree_prepare(void) { int res, node; u64 memreg1[] = {0, mm_bootmem_size}; u64 memreg2[] = {mm_highmem_addr, mm_highmem_size}; res = fdt_open_into(dt_blob_start, __devtree, DT_BUFSIZE); if (res < 0) fatal("fdt_open_into() failed"); node = fdt_path_offset(__devtree, "/chosen"); if (node < 0) fatal("/chosen node not found in devtree"); res = fdt_setprop(__devtree, node, "bootargs", bootargs, strlen(bootargs)+1); if (res < 0) fatal("couldn't set chosen.bootargs property"); if (initrd_start && initrd_size) { u64 start, end; start = mm_addr_to_kernel(initrd_start); res = fdt_setprop(__devtree, node, "linux,initrd-start", &start, sizeof(start)); if (res < 0) fatal("couldn't set chosen.linux,initrd-start property"); end = mm_addr_to_kernel(initrd_start + initrd_size); res = fdt_setprop(__devtree, node, "linux,initrd-end", &end, sizeof(end)); if (res < 0) fatal("couldn't set chosen.linux,initrd-end property"); res = fdt_add_mem_rsv(__devtree, start, initrd_size); if (res < 0) fatal("couldn't add reservation for the initrd"); } node = fdt_path_offset(__devtree, "/memory"); if (node < 0) fatal("/memory node not found in devtree"); res = fdt_setprop(__devtree, node, "reg", memreg1, sizeof(memreg1)); if (res < 0) fatal("couldn't set memory.reg property"); res = fdt_setprop(__devtree, node, "sony,lv1-highmem", memreg2, sizeof(memreg2)); if (res < 0) fatal("couldn't set memory.sony,lv1-highmem property"); res = fdt_add_mem_rsv(__devtree, (u64)__devtree, DT_BUFSIZE); if (res < 0) fatal("couldn't add reservation for the devtree"); res = fdt_pack(__devtree); if (res < 0) fatal("fdt_pack() failed"); printf("Device tree prepared\n"); }
int main(int argc, char *argv[]) { void *fdt; int err; int offset, s1, s2; test_init(argc, argv); fdt = xmalloc(SPACE); /* First create empty tree with SW */ CHECK(fdt_create(fdt, SPACE)); CHECK(fdt_finish_reservemap(fdt)); CHECK(fdt_begin_node(fdt, "")); CHECK(fdt_end_node(fdt)); CHECK(fdt_finish(fdt)); verbose_printf("Built empty tree, totalsize = %d\n", fdt_totalsize(fdt)); CHECK(fdt_open_into(fdt, fdt, SPACE)); CHECK(fdt_add_mem_rsv(fdt, TEST_ADDR_1, TEST_SIZE_1)); CHECK(fdt_add_mem_rsv(fdt, TEST_ADDR_2, TEST_SIZE_2)); CHECK(fdt_setprop_string(fdt, 0, "compatible", "test_tree1")); CHECK(fdt_setprop_cell(fdt, 0, "prop-int", TEST_VALUE_1)); CHECK(fdt_setprop_string(fdt, 0, "prop-str", TEST_STRING_1)); OFF_CHECK(offset, fdt_add_subnode(fdt, 0, "subnode@1")); s1 = offset; CHECK(fdt_setprop_string(fdt, s1, "compatible", "subnode1")); CHECK(fdt_setprop_cell(fdt, s1, "prop-int", TEST_VALUE_1)); OFF_CHECK(offset, fdt_add_subnode(fdt, s1, "subsubnode")); CHECK(fdt_setprop(fdt, offset, "compatible", "subsubnode1\0subsubnode", 23)); CHECK(fdt_setprop_cell(fdt, offset, "prop-int", TEST_VALUE_1)); OFF_CHECK(offset, fdt_add_subnode(fdt, s1, "ss1")); OFF_CHECK(offset, fdt_add_subnode(fdt, 0, "subnode@2")); s2 = offset; CHECK(fdt_setprop_cell(fdt, s2, "linux,phandle", PHANDLE_1)); CHECK(fdt_setprop_cell(fdt, s2, "prop-int", TEST_VALUE_2)); OFF_CHECK(offset, fdt_add_subnode(fdt, s2, "subsubnode@0")); CHECK(fdt_setprop_cell(fdt, offset, "linux,phandle", PHANDLE_2)); CHECK(fdt_setprop(fdt, offset, "compatible", "subsubnode2\0subsubnode", 23)); CHECK(fdt_setprop_cell(fdt, offset, "prop-int", TEST_VALUE_2)); OFF_CHECK(offset, fdt_add_subnode(fdt, s2, "ss2")); CHECK(fdt_pack(fdt)); save_blob("rw_tree1.test.dtb", fdt); PASS(); }
static unsigned long fdt_wrapper_finalize(void) { int rc; rc = fdt_pack(fdt); if (rc != 0) fatal("Couldn't pack flat tree: %s\n\r", fdt_strerror(rc)); return (unsigned long)fdt; }
/* Top level function that updates the device tree. */ int modem_pintrl_dts_parse(int mode, PINTRL_STRU **iocfg_table, unsigned int *length) { int ret; int len; int offset; unsigned int fdt = DDR_DTS_ADDR; int total_space = 0x40000; int *data = NULL; char pintrl_name[20]={0}; const struct fdt_property *pro = NULL; /* let's give it all the room it could need */ ret = fdt_open_into((void*)fdt, (void*)fdt, total_space); if (ret < 0){ ios_print_error("Could not open modem dts, fdt=0x%x ret=0x%x.\n", fdt, ret); return ret; } /* Get offset of the chosen node */ ret = fdt_path_offset((void*)fdt, "/modem_pintrl"); if (ret < 0) { ios_print_error("Could not find modem_pintrl node, fdt=0x%x ret=0x%x.\n", fdt, ret); return ret; } offset = ret; /* Get property of the chosen node */ pro = fdt_get_property((void*)fdt, offset, (const char*)"pinctrl-num",&len); if((int)pro < 0){ ios_print_error("Could not get property, pro=0x%x fdt=0x%x offset=0x%x len=0x%x.\n", pro, fdt, offset, len); return -1; } data = (int*)pro->data; *length = data[mode]; snprintf(pintrl_name,20,"pinctrl-%d",mode); /* Adding the cmdline to the chosen node */ pro = fdt_get_property((void*)fdt, offset, pintrl_name,&len); if((int)pro < 0){ ios_print_error("Could not get property, pro=0x%x fdt=0x%x offset=0x%x len=0x%x.\n", pro, fdt, offset, len); return -1; } *iocfg_table = (PINTRL_STRU*)pro->data; fdt_pack((void*)fdt); return 0; }
/* * Convert and fold provided ATAGs into the provided FDT. * * REturn values: * = 0 -> pretend success * = 1 -> bad ATAG (may retry with another possible ATAG pointer) * < 0 -> error from libfdt */ int atags_to_fdt(void *atag_list, void *fdt, int total_space) { struct tag *atag = atag_list; uint32_t mem_reg_property[16]; int memcount = 0; int ret; /* make sure we've got an aligned pointer */ if ((u32)atag_list & 0x3) return 1; /* if we get a DTB here we're done already */ if (*(u32 *)atag_list == fdt32_to_cpu(FDT_MAGIC)) return 0; /* validate the ATAG */ if (atag->hdr.tag != ATAG_CORE || (atag->hdr.size != tag_size(tag_core) && atag->hdr.size != 2)) return 1; /* let's give it all the room it could need */ ret = fdt_open_into(fdt, fdt, total_space); if (ret < 0) return ret; for_each_tag(atag, atag_list) { if (atag->hdr.tag == ATAG_CMDLINE) { setprop_string(fdt, "/chosen", "bootargs", atag->u.cmdline.cmdline); } else if (atag->hdr.tag == ATAG_MEM) { if (memcount >= sizeof(mem_reg_property)/sizeof(uint32_t)) continue; mem_reg_property[memcount++] = cpu_to_fdt32(atag->u.mem.start); mem_reg_property[memcount++] = cpu_to_fdt32(atag->u.mem.size); } else if (atag->hdr.tag == ATAG_INITRD2) { uint32_t initrd_start, initrd_size; initrd_start = atag->u.initrd.start; initrd_size = atag->u.initrd.size; setprop_cell(fdt, "/chosen", "linux,initrd-start", initrd_start); setprop_cell(fdt, "/chosen", "linux,initrd-end", initrd_start + initrd_size); } } if (memcount) setprop(fdt, "/memory", "reg", mem_reg_property, 4*memcount); return fdt_pack(fdt); }
/* * Make a test fdt * * @param fdt Device tree pointer * @param size Size of device tree blob * @param aliases Specifies alias assignments. Format is a list of items * separated by space. Items are #a where * # is the alias number * a is the node to point to * @param nodes Specifies nodes to generate (a=0, b=1), upper case * means to create a disabled node */ static int make_fdt(void *fdt, int size, const char *aliases, const char *nodes) { char name[20], value[20]; const char *s; int fd; CHECK(fdt_create(fdt, size)); CHECK(fdt_finish_reservemap(fdt)); CHECK(fdt_begin_node(fdt, "")); CHECK(fdt_begin_node(fdt, "aliases")); for (s = aliases; *s;) { sprintf(name, "i2c%c", *s); sprintf(value, "/i2c%d@0", s[1] - 'a'); CHECK(fdt_property_string(fdt, name, value)); s += 2 + (s[2] != '\0'); } CHECK(fdt_end_node(fdt)); for (s = nodes; *s; s++) { sprintf(value, "i2c%d@0", (*s & 0xdf) - 'A'); CHECK(fdt_begin_node(fdt, value)); CHECK(fdt_property_string(fdt, "compatible", fdtdec_get_compatible(COMPAT_UNKNOWN))); if (*s <= 'Z') CHECK(fdt_property_string(fdt, "status", "disabled")); CHECK(fdt_end_node(fdt)); } CHECK(fdt_end_node(fdt)); CHECK(fdt_finish(fdt)); CHECK(fdt_pack(fdt)); #if defined(DEBUG) && defined(CONFIG_SANDBOX) fd = os_open("/tmp/fdtdec-text.dtb", OS_O_CREAT | OS_O_WRONLY); if (fd == -1) { printf("Could not open .dtb file to write\n"); return -1; } os_write(fd, fdt, size); os_close(fd); #endif return 0; }
int main(int argc, char *argv[]) { void *fdt, *fdt1; void *buf; int oldsize, bufsize, packsize; int err; const char *inname; char outname[PATH_MAX]; test_init(argc, argv); fdt = load_blob_arg(argc, argv); inname = argv[1]; oldsize = fdt_totalsize(fdt); bufsize = oldsize * 2; buf = xmalloc(bufsize); /* don't leak uninitialized memory into our output */ memset(buf, 0, bufsize); fdt1 = buf; err = fdt_open_into(fdt, fdt1, bufsize); if (err) FAIL("fdt_open_into(): %s", fdt_strerror(err)); sprintf(outname, "opened.%s", inname); save_blob(outname, fdt1); err = fdt_pack(fdt1); if (err) FAIL("fdt_pack(): %s", fdt_strerror(err)); sprintf(outname, "repacked.%s", inname); save_blob(outname, fdt1); packsize = fdt_totalsize(fdt1); verbose_printf("oldsize = %d, bufsize = %d, packsize = %d\n", oldsize, bufsize, packsize); PASS(); }
int main(int argc, char *argv[]) { void *fdt, *buf; int err; uint8_t bytes[] = {0x00, 0x01, 0x02, 0x03, 0x04}; test_init(argc, argv); fdt = load_blob_arg(argc, argv); buf = xmalloc(SPACE); CHECK(fdt_open_into(fdt, buf, SPACE)); fdt = buf; CHECK(fdt_appendprop(fdt, 0, "prop-bytes", bytes, sizeof(bytes))); CHECK(fdt_appendprop_cell(fdt, 0, "prop-int", TEST_VALUE_2)); CHECK(fdt_appendprop_u64(fdt, 0, "prop-int64", TEST_VALUE64_1)); CHECK(fdt_appendprop_string(fdt, 0, "prop-str", TEST_STRING_2)); CHECK(fdt_pack(fdt)); save_blob("appendprop2.test.dtb", fdt); PASS(); }
EFI_STATUS PrepareFdt ( IN CONST CHAR8* CommandLineArguments, IN EFI_PHYSICAL_ADDRESS InitrdImage, IN UINTN InitrdImageSize, IN OUT EFI_PHYSICAL_ADDRESS *FdtBlobBase, IN OUT UINTN *FdtBlobSize ) { EFI_STATUS Status; EFI_PHYSICAL_ADDRESS NewFdtBlobBase; EFI_PHYSICAL_ADDRESS NewFdtBlobAllocation; UINTN NewFdtBlobSize; VOID* fdt; INTN err; INTN node; INT32 lenp; CONST VOID* BootArg; EFI_PHYSICAL_ADDRESS InitrdImageStart; EFI_PHYSICAL_ADDRESS InitrdImageEnd; UINTN Index; UINTN MemoryMapSize; EFI_MEMORY_DESCRIPTOR *MemoryMap; EFI_MEMORY_DESCRIPTOR *MemoryMapPtr; UINTN MapKey; UINTN DescriptorSize; UINT32 DescriptorVersion; UINTN Pages; UINTN OriginalFdtSize; NewFdtBlobAllocation = 0; // // Sanity checks on the original FDT blob. // err = fdt_check_header ((VOID*)(UINTN)(*FdtBlobBase)); if (err != 0) { Print (L"ERROR: Device Tree header not valid (err:%d)\n", err); return EFI_INVALID_PARAMETER; } // The original FDT blob might have been loaded partially. // Check that it is not the case. OriginalFdtSize = (UINTN)fdt_totalsize ((VOID*)(UINTN)(*FdtBlobBase)); if (OriginalFdtSize > *FdtBlobSize) { Print (L"ERROR: Incomplete FDT. Only %d/%d bytes have been loaded.\n", *FdtBlobSize, OriginalFdtSize); return EFI_INVALID_PARAMETER; } // // Relocate the FDT to its final location. // Status = RelocateFdt (*FdtBlobBase, OriginalFdtSize, &NewFdtBlobBase, &NewFdtBlobSize, &NewFdtBlobAllocation); if (EFI_ERROR (Status)) { goto FAIL_RELOCATE_FDT; } fdt = (VOID*)(UINTN)NewFdtBlobBase; node = fdt_subnode_offset (fdt, 0, "chosen"); if (node < 0) { // The 'chosen' node does not exist, create it node = fdt_add_subnode (fdt, 0, "chosen"); if (node < 0) { DEBUG ((EFI_D_ERROR, "Error on finding 'chosen' node\n")); Status = EFI_INVALID_PARAMETER; goto FAIL_COMPLETE_FDT; } } DEBUG_CODE_BEGIN (); BootArg = fdt_getprop (fdt, node, "bootargs", &lenp); if (BootArg != NULL) { DEBUG ((EFI_D_ERROR, "BootArg: %a\n", BootArg)); } DEBUG_CODE_END (); // // Set Linux CmdLine // if ((CommandLineArguments != NULL) && (AsciiStrLen (CommandLineArguments) > 0)) { err = fdt_setprop (fdt, node, "bootargs", CommandLineArguments, AsciiStrSize (CommandLineArguments)); if (err) { DEBUG ((EFI_D_ERROR, "Fail to set new 'bootarg' (err:%d)\n", err)); } } // // Set Linux Initrd // if (InitrdImageSize != 0) { InitrdImageStart = cpu_to_fdt64 (InitrdImage); err = fdt_setprop (fdt, node, "linux,initrd-start", &InitrdImageStart, sizeof (EFI_PHYSICAL_ADDRESS)); if (err) { DEBUG ((EFI_D_ERROR, "Fail to set new 'linux,initrd-start' (err:%d)\n", err)); } InitrdImageEnd = cpu_to_fdt64 (InitrdImage + InitrdImageSize); err = fdt_setprop (fdt, node, "linux,initrd-end", &InitrdImageEnd, sizeof (EFI_PHYSICAL_ADDRESS)); if (err) { DEBUG ((EFI_D_ERROR, "Fail to set new 'linux,initrd-start' (err:%d)\n", err)); } } // // Add the memory regions reserved by the UEFI Firmware // // Retrieve the UEFI Memory Map MemoryMap = NULL; MemoryMapSize = 0; Status = gBS->GetMemoryMap (&MemoryMapSize, MemoryMap, &MapKey, &DescriptorSize, &DescriptorVersion); if (Status == EFI_BUFFER_TOO_SMALL) { // The UEFI specification advises to allocate more memory for the MemoryMap buffer between successive // calls to GetMemoryMap(), since allocation of the new buffer may potentially increase memory map size. Pages = EFI_SIZE_TO_PAGES (MemoryMapSize) + 1; MemoryMap = AllocatePages (Pages); if (MemoryMap == NULL) { Status = EFI_OUT_OF_RESOURCES; goto FAIL_COMPLETE_FDT; } Status = gBS->GetMemoryMap (&MemoryMapSize, MemoryMap, &MapKey, &DescriptorSize, &DescriptorVersion); } // Go through the list and add the reserved region to the Device Tree if (!EFI_ERROR (Status)) { MemoryMapPtr = MemoryMap; for (Index = 0; Index < (MemoryMapSize / DescriptorSize); Index++) { if (IsLinuxReservedRegion ((EFI_MEMORY_TYPE)MemoryMapPtr->Type)) { DEBUG ((DEBUG_VERBOSE, "Reserved region of type %d [0x%lX, 0x%lX]\n", MemoryMapPtr->Type, (UINTN)MemoryMapPtr->PhysicalStart, (UINTN)(MemoryMapPtr->PhysicalStart + MemoryMapPtr->NumberOfPages * EFI_PAGE_SIZE))); err = fdt_add_mem_rsv (fdt, MemoryMapPtr->PhysicalStart, MemoryMapPtr->NumberOfPages * EFI_PAGE_SIZE); if (err != 0) { Print (L"Warning: Fail to add 'memreserve' (err:%d)\n", err); } } MemoryMapPtr = (EFI_MEMORY_DESCRIPTOR*)((UINTN)MemoryMapPtr + DescriptorSize); } } // Update the real size of the Device Tree fdt_pack ((VOID*)(UINTN)(NewFdtBlobBase)); *FdtBlobBase = NewFdtBlobBase; *FdtBlobSize = (UINTN)fdt_totalsize ((VOID*)(UINTN)(NewFdtBlobBase)); return EFI_SUCCESS; FAIL_COMPLETE_FDT: gBS->FreePages (NewFdtBlobAllocation, EFI_SIZE_TO_PAGES (NewFdtBlobSize)); FAIL_RELOCATE_FDT: *FdtBlobSize = (UINTN)fdt_totalsize ((VOID*)(UINTN)(*FdtBlobBase)); // Return success even if we failed to update the FDT blob. // The original one is still valid. return EFI_SUCCESS; }
/** * 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; }
STATIC EFI_STATUS PrepareFdt ( IN OUT VOID *Fdt, IN UINTN FdtSize ) { EFI_STATUS Status; INT32 Node; INT32 CpuNode; UINTN Index; ARM_CORE_INFO *ArmCoreInfoTable; UINTN ArmCoreCount; INT32 MapNode; INT32 ClusterNode; INT32 PmuNode; PMU_INTERRUPT PmuInt; INT32 Phandle[NUM_CORES]; UINT32 ClusterIndex; UINT32 CoreIndex; UINT32 ClusterCount; UINT32 CoresInCluster; UINT32 ClusterId; UINTN MpId; CHAR8 Name[10]; AMD_MP_CORE_INFO_PROTOCOL *AmdMpCoreInfoProtocol; // // Setup Arm Mpcore Info if it is a multi-core or multi-cluster platforms. // // For 'cpus' and 'cpu' device tree nodes bindings, refer to this file // in the kernel documentation: // Documentation/devicetree/bindings/arm/cpus.txt // Status = gBS->LocateProtocol ( &gAmdMpCoreInfoProtocolGuid, NULL, (VOID **)&AmdMpCoreInfoProtocol ); ASSERT_EFI_ERROR (Status); // Get pointer to ARM core info table ArmCoreInfoTable = AmdMpCoreInfoProtocol->GetArmCoreInfoTable (&ArmCoreCount); ASSERT (ArmCoreInfoTable != NULL); ASSERT (ArmCoreCount <= NUM_CORES); // Get Id from primary CPU MpId = (UINTN)ArmReadMpidr (); // Create /pmu node PmuNode = fdt_add_subnode(Fdt, 0, "pmu"); if (PmuNode >= 0) { fdt_setprop_string (Fdt, PmuNode, "compatible", "arm,armv8-pmuv3"); // append PMU interrupts for (Index = 0; Index < ArmCoreCount; Index++) { MpId = (UINTN)GET_MPID (ArmCoreInfoTable[Index].ClusterId, ArmCoreInfoTable[Index].CoreId); Status = AmdMpCoreInfoProtocol->GetPmuSpiFromMpId (MpId, &PmuInt.IntId); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "FDT: Error getting PMU interrupt for MpId '0x%x'\n", MpId)); return Status; } PmuInt.Flag = cpu_to_fdt32 (PMU_INT_FLAG_SPI); PmuInt.IntId = cpu_to_fdt32 (PmuInt.IntId); PmuInt.Type = cpu_to_fdt32 (PMU_INT_TYPE_HIGH_LEVEL); fdt_appendprop (Fdt, PmuNode, "interrupts", &PmuInt, sizeof(PmuInt)); } } else { DEBUG ((DEBUG_ERROR, "FDT: Error creating 'pmu' node\n")); return EFI_INVALID_PARAMETER; } // Create /cpus noide Node = fdt_add_subnode (Fdt, 0, "cpus"); if (Node >= 0) { // Configure the 'cpus' node fdt_setprop_string (Fdt, Node, "name", "cpus"); fdt_setprop_cell (Fdt, Node, "#address-cells", sizeof (UINTN) / 4); fdt_setprop_cell (Fdt, Node, "#size-cells", 0); } else { DEBUG ((DEBUG_ERROR, "FDT: Error creating 'cpus' node\n")); return EFI_INVALID_PARAMETER; } // // Walk the processor table in reverse order for proper listing in FDT // Index = ArmCoreCount; while (Index--) { // Create 'cpu' node AsciiSPrint (Name, sizeof (Name), "CPU%d", Index); CpuNode = fdt_add_subnode (Fdt, Node, Name); if (CpuNode < 0) { DEBUG ((DEBUG_ERROR, "FDT: Error on creating '%a' node\n", Name)); return EFI_INVALID_PARAMETER; } Phandle[Index] = fdt_alloc_phandle (Fdt); fdt_setprop_cell (Fdt, CpuNode, "phandle", Phandle[Index]); fdt_setprop_cell (Fdt, CpuNode, "linux,phandle", Phandle[Index]); fdt_setprop_string (Fdt, CpuNode, "enable-method", "psci"); MpId = (UINTN)GET_MPID (ArmCoreInfoTable[Index].ClusterId, ArmCoreInfoTable[Index].CoreId); MpId = cpu_to_fdt64 (MpId); fdt_setprop (Fdt, CpuNode, "reg", &MpId, sizeof (MpId)); fdt_setprop_string (Fdt, CpuNode, "compatible", "arm,armv8"); fdt_setprop_string (Fdt, CpuNode, "device_type", "cpu"); } // Create /cpu-map node MapNode = fdt_add_subnode (Fdt, Node, "cpu-map"); if (MapNode >= 0) { ClusterIndex = ArmCoreCount - 1; ClusterCount = NumberOfClustersInTable (ArmCoreInfoTable, ArmCoreCount); while (ClusterCount--) { // Create 'cluster' node AsciiSPrint (Name, sizeof (Name), "cluster%d", ClusterCount); ClusterNode = fdt_add_subnode (Fdt, MapNode, Name); if (ClusterNode < 0) { DEBUG ((DEBUG_ERROR, "FDT: Error creating '%a' node\n", Name)); return EFI_INVALID_PARAMETER; } ClusterId = ArmCoreInfoTable[ClusterIndex].ClusterId; CoreIndex = ClusterIndex; CoresInCluster = NumberOfCoresInCluster (ArmCoreInfoTable, ArmCoreCount, ClusterId); while (CoresInCluster--) { // Create 'core' node AsciiSPrint (Name, sizeof (Name), "core%d", CoresInCluster); CpuNode = fdt_add_subnode (Fdt, ClusterNode, Name); if (CpuNode < 0) { DEBUG ((DEBUG_ERROR, "FDT: Error creating '%a' node\n", Name)); return EFI_INVALID_PARAMETER; } fdt_setprop_cell (Fdt, CpuNode, "cpu", Phandle[CoreIndex]); // iterate to next core in cluster if (CoresInCluster) { do { --CoreIndex; } while (ClusterId != ArmCoreInfoTable[CoreIndex].ClusterId); } } // iterate to next cluster if (ClusterCount) { do { --ClusterIndex; } while (ClusterInRange (ArmCoreInfoTable, ArmCoreInfoTable[ClusterIndex].ClusterId, ClusterIndex + 1, ArmCoreCount - 1)); } } } else { DEBUG ((DEBUG_ERROR,"FDT: Error creating 'cpu-map' node\n")); return EFI_INVALID_PARAMETER; } SetSocIdStatus (Fdt); SetXgbeStatus (Fdt); // Update the real size of the Device Tree fdt_pack (Fdt); return EFI_SUCCESS; }
/* 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; } /* 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; }
/* * Convert and fold provided ATAGs into the provided FDT. * * REturn values: * = 0 -> pretend success * = 1 -> bad ATAG (may retry with another possible ATAG pointer) * < 0 -> error from libfdt */ int atags_to_fdt(void *atag_list, void *fdt, int total_space) { struct tag *atag = atag_list; /* In the case of 64 bits memory size, need to reserve 2 cells for * address and size for each bank */ uint32_t mem_reg_property[2 * 2 * NR_BANKS]; int memcount = 0; int ret, memsize; /* make sure we've got an aligned pointer */ if ((u32)atag_list & 0x3) return 1; /* if we get a DTB here we're done already */ if (*(u32 *)atag_list == fdt32_to_cpu(FDT_MAGIC)) return 0; /* validate the ATAG */ if (atag->hdr.tag != ATAG_CORE || (atag->hdr.size != tag_size(tag_core) && atag->hdr.size != 2)) return 1; /* let's give it all the room it could need */ ret = fdt_open_into(fdt, fdt, total_space); if (ret < 0) return ret; for_each_tag(atag, atag_list) { if (atag->hdr.tag == ATAG_CMDLINE) { /* Append the ATAGS command line to the device tree * command line. * NB: This means that if the same parameter is set in * the device tree and in the tags, the one from the * tags will be chosen. */ if (do_extend_cmdline) merge_fdt_bootargs(fdt, atag->u.cmdline.cmdline); else setprop_string(fdt, "/chosen", "bootargs", atag->u.cmdline.cmdline); } else if (atag->hdr.tag == ATAG_MEM) { if (memcount >= sizeof(mem_reg_property)/4) continue; if (!atag->u.mem.size) continue; memsize = get_cell_size(fdt); if (memsize == 2) { /* if memsize is 2, that means that * each data needs 2 cells of 32 bits, * so the data are 64 bits */ uint64_t *mem_reg_prop64 = (uint64_t *)mem_reg_property; mem_reg_prop64[memcount++] = cpu_to_fdt64(atag->u.mem.start); mem_reg_prop64[memcount++] = cpu_to_fdt64(atag->u.mem.size); } else { mem_reg_property[memcount++] = cpu_to_fdt32(atag->u.mem.start); mem_reg_property[memcount++] = cpu_to_fdt32(atag->u.mem.size); } } else if (atag->hdr.tag == ATAG_INITRD2) { uint32_t initrd_start, initrd_size; initrd_start = atag->u.initrd.start; initrd_size = atag->u.initrd.size; setprop_cell(fdt, "/chosen", "linux,initrd-start", initrd_start); setprop_cell(fdt, "/chosen", "linux,initrd-end", initrd_start + initrd_size); } else if (atag->hdr.tag == ATAG_BLUETOOTH) { setprop_values(fdt, "/chosen", "linux,bt_mac", (unsigned char *)(&atag->u), (atag->hdr.size-2)*sizeof(__u32)); } else if (atag->hdr.tag == ATAG_MSM_WIFI) { #define NVS_MAX_SIZE 0x800U #define NVS_LEN_OFFSET 0x0C #define NVS_DATA_OFFSET 0x40 char append[] = "\nsd_oobonly=1\nbtc_params80=0\nbtc_params6=30\n"; __u32 len = 0; __u32 full_len = (atag->hdr.size-2)*sizeof(__u32); // check that we have enought space for get len if (full_len > NVS_LEN_OFFSET) memcpy(&len, (unsigned char *)(&atag->u) + NVS_LEN_OFFSET, sizeof(len)); // len is less than full block size if (len > (NVS_MAX_SIZE - NVS_DATA_OFFSET)) len = (NVS_MAX_SIZE - NVS_DATA_OFFSET); // len is less than atag block size if (len > full_len) len = full_len; // we have enought space for add additional params if ((len + strlen(append) + 1) <= full_len) { // block is finished by zero if (((unsigned char *)(&atag->u))[NVS_DATA_OFFSET + len] == 0) len --; //copy additional params memcpy( (unsigned char *)(&atag->u) + NVS_DATA_OFFSET + len, append, strlen(append) + 1 ); len += strlen(append); len ++; } // finaly save new wifi calibration setprop_values(fdt, "/chosen", "linux,wifi-calibration", (unsigned char *)(&atag->u) + NVS_DATA_OFFSET, len); } else if (atag->hdr.tag == ATAG_MSM_AWB_CAL) { setprop_values(fdt, "/chosen", "linux,awb_cal", (unsigned char *)(&atag->u), (atag->hdr.size-2)*sizeof(__u32)); } else if (atag->hdr.tag == ATAG_MFG_GPIO_TABLE) { setprop_values(fdt, "/chosen", "linux,gpio_table", (unsigned char *)(&atag->u), (atag->hdr.size-2)*sizeof(__u32)); } else if (atag->hdr.tag == ATAG_MSM_PARTITION) { setprop_values(fdt, "/chosen", "linux,msm_partitions", (unsigned char *)(&atag->u), (atag->hdr.size-2)*sizeof(__u32)); } else if (atag->hdr.tag == ATAG_MEMSIZE) { setprop_cell(fdt, "/chosen", "linux,memsize", atag->u.revision.rev); } else if (atag->hdr.tag == ATAG_ALS) { setprop_cell(fdt, "/chosen", "linux,als_calibration", atag->u.als_kadc.kadc); } else if (atag->hdr.tag == ATAG_ENGINEERID) { setprop_cell(fdt, "/chosen", "linux,engineerid", atag->u.revision.rev); } else if (atag->hdr.tag == ATAG_SMI) { setprop_cell(fdt, "/chosen", "linux,smi", atag->u.mem.size); } else if (atag->hdr.tag == ATAG_HWID) { setprop_cell(fdt, "/chosen", "linux,hwid", atag->u.revision.rev); } else if (atag->hdr.tag == ATAG_SKUID) { setprop_cell(fdt, "/chosen", "linux,skuid", atag->u.revision.rev); } else if (atag->hdr.tag == ATAG_HERO_PANEL_TYPE) { setprop_cell(fdt, "/chosen", "linux,panel_type", atag->u.revision.rev); } else if (atag->hdr.tag == ATAG_GS) { setprop_cell(fdt, "/chosen", "linux,gs_calibration", atag->u.revision.rev); } else if (atag->hdr.tag == ATAG_REVISION) { __u32 revision[2]; revision[0] = cpu_to_fdt32(atag->u.revision.rev); revision[1] = cpu_to_fdt32(atag->u.revision.rev); if (atag->hdr.size > 3) { revision[1] = cpu_to_fdt32(atag->u.revision.rev2); } setprop_values(fdt, "/chosen", "linux,revision", revision, sizeof(revision)); } else if (atag->hdr.tag == ATAG_PS) { __u32 ps_settings[2]; ps_settings[0] = cpu_to_fdt32(atag->u.serialnr.low); ps_settings[1] = cpu_to_fdt32(atag->u.serialnr.high); setprop_values(fdt, "/chosen", "linux,ps_calibration", ps_settings, sizeof(ps_settings)); } else if (atag->hdr.tag == ATAG_PS_TYPE) { setprop_cell(fdt, "/chosen", "linux,ps_type", atag->u.revision.rev); } } if (memcount) { setprop(fdt, "/memory", "reg", mem_reg_property, 4 * memcount * memsize); } return fdt_pack(fdt); }
void update_partial_goods_dtb_nodes(void *fdt) { int i; int tbl_sz = sizeof(table) / sizeof(struct partial_goods); int parent_offset = 0; int subnode_offset = 0; int ret = 0; int prop_len = 0; uint32_t reg = readl(QFPROM_PTE_PART_ADDR); uint32_t prop_type = 0; struct subnode_list *subnode_lst = NULL; const struct fdt_property *prop = NULL; const char *replace_str = NULL; /* * The PTE register bits 23 to 27 have the partial goods * info, extract the partial goods value before using */ reg = (reg & 0x0f800000) >> 23; /* If none of the DTB needs update */ if (!reg) return; ret = fdt_open_into(fdt, fdt, fdt_totalsize(fdt)); if (ret != 0) { dprintf(CRITICAL, "Failed to move/resize dtb buffer: %d\n", ret); ASSERT(0); } for (i = 0; i < tbl_sz; i++) { if (reg == table[i].val) { /* Find the Parent node */ ret = fdt_path_offset(fdt, table[i].parent_node); if (ret < 0) { dprintf(CRITICAL, "Failed to get parent node: %s\terrno:%d\n", table[i].parent_node, ret); ASSERT(0); } parent_offset = ret; /* Find the subnode */ subnode_lst = table[i].subnode; while (subnode_lst->subnode) { ret = fdt_subnode_offset(fdt, parent_offset, subnode_lst->subnode); if (ret < 0) { dprintf(CRITICAL, "Failed to get subnode: %s\terrno:%d\n", subnode_lst->subnode, ret); ASSERT(0); } subnode_offset = ret; /* Find the property node and its length */ prop = fdt_get_property(fdt, subnode_offset, subnode_lst->property, &prop_len); if (!prop) { dprintf(CRITICAL, "Failed to get property: %s\terrno: %d\n", subnode_lst->property, prop_len); ASSERT(0); } /* * Replace the property value based on the property * length and type */ if (!(strncmp(subnode_lst->property, "device_type", sizeof(subnode_lst->property)))) prop_type = DEVICE_TYPE; else if ((!strncmp(subnode_lst->property, "status", sizeof(subnode_lst->property)))) prop_type = STATUS_TYPE; else { dprintf(CRITICAL, "%s: Property type is not supported\n", subnode_lst->property); ASSERT(0); } switch (prop_type) { case DEVICE_TYPE: replace_str = "nak"; break; case STATUS_TYPE: if (prop_len == sizeof("ok")) replace_str = "no"; else if (prop_len == sizeof("okay")) replace_str = "dsbl"; else { dprintf(CRITICAL, "Property value length: %u is invalid for property: %s\n", prop_len, subnode_lst->property); ASSERT(0); } break; default: /* Control would not come here, as this gets taken care while setting property type */ break; }; /* Replace the property with new value */ ret = fdt_setprop_inplace(fdt, subnode_offset, subnode_lst->property, (const void *)replace_str, prop_len); if (!ret) dprintf(INFO, "Updated device tree property: %s @ %s node\n", subnode_lst->property, subnode_lst->subnode); else { dprintf(CRITICAL, "Failed to update property: %s: error no: %d\n", subnode_lst->property, ret); ASSERT(0); } subnode_lst++; } } } fdt_pack(fdt); }
/** * elf_exec_load - load ELF executable image * @lowest_load_addr: On return, will be the address where the first PT_LOAD * section will be loaded in memory. * * Return: * 0 on success, negative value on failure. */ static int elf_exec_load(struct kimage *image, struct elfhdr *ehdr, struct elf_info *elf_info, unsigned long *lowest_load_addr) { unsigned long base = 0, lowest_addr = UINT_MAX; int ret; size_t i; struct kexec_buf kbuf = { .image = image, .buf_max = ppc64_rma_size, .top_down = false }; /* Read in the PT_LOAD segments. */ for (i = 0; i < ehdr->e_phnum; i++) { unsigned long load_addr; size_t size; const struct elf_phdr *phdr; phdr = &elf_info->proghdrs[i]; if (phdr->p_type != PT_LOAD) continue; size = phdr->p_filesz; if (size > phdr->p_memsz) size = phdr->p_memsz; kbuf.buffer = (void *) elf_info->buffer + phdr->p_offset; kbuf.bufsz = size; kbuf.memsz = phdr->p_memsz; kbuf.buf_align = phdr->p_align; kbuf.buf_min = phdr->p_paddr + base; ret = kexec_add_buffer(&kbuf); if (ret) goto out; load_addr = kbuf.mem; if (load_addr < lowest_addr) lowest_addr = load_addr; } /* Update entry point to reflect new load address. */ ehdr->e_entry += base; *lowest_load_addr = lowest_addr; ret = 0; out: return ret; } static void *elf64_load(struct kimage *image, char *kernel_buf, unsigned long kernel_len, char *initrd, unsigned long initrd_len, char *cmdline, unsigned long cmdline_len) { int ret; unsigned int fdt_size; unsigned long kernel_load_addr, purgatory_load_addr; unsigned long initrd_load_addr = 0, fdt_load_addr; void *fdt; const void *slave_code; struct elfhdr ehdr; struct elf_info elf_info; struct kexec_buf kbuf = { .image = image, .buf_min = 0, .buf_max = ppc64_rma_size }; ret = build_elf_exec_info(kernel_buf, kernel_len, &ehdr, &elf_info); if (ret) goto out; ret = elf_exec_load(image, &ehdr, &elf_info, &kernel_load_addr); if (ret) goto out; pr_debug("Loaded the kernel at 0x%lx\n", kernel_load_addr); ret = kexec_load_purgatory(image, 0, ppc64_rma_size, true, &purgatory_load_addr); if (ret) { pr_err("Loading purgatory failed.\n"); goto out; } pr_debug("Loaded purgatory at 0x%lx\n", purgatory_load_addr); if (initrd != NULL) { kbuf.buffer = initrd; kbuf.bufsz = kbuf.memsz = initrd_len; kbuf.buf_align = PAGE_SIZE; kbuf.top_down = false; ret = kexec_add_buffer(&kbuf); if (ret) goto out; initrd_load_addr = kbuf.mem; pr_debug("Loaded initrd at 0x%lx\n", initrd_load_addr); } fdt_size = fdt_totalsize(initial_boot_params) * 2; fdt = kmalloc(fdt_size, GFP_KERNEL); if (!fdt) { pr_err("Not enough memory for the device tree.\n"); ret = -ENOMEM; goto out; } ret = fdt_open_into(initial_boot_params, fdt, fdt_size); if (ret < 0) { pr_err("Error setting up the new device tree.\n"); ret = -EINVAL; goto out; } ret = setup_new_fdt(fdt, initrd_load_addr, initrd_len, cmdline); if (ret) goto out; fdt_pack(fdt); kbuf.buffer = fdt; kbuf.bufsz = kbuf.memsz = fdt_size; kbuf.buf_align = PAGE_SIZE; kbuf.top_down = true; ret = kexec_add_buffer(&kbuf); if (ret) goto out; fdt_load_addr = kbuf.mem; pr_debug("Loaded device tree at 0x%lx\n", fdt_load_addr); slave_code = elf_info.buffer + elf_info.proghdrs[0].p_offset; ret = setup_purgatory(image, slave_code, fdt, kernel_load_addr, fdt_load_addr); if (ret) pr_err("Error setting up the purgatory.\n"); out: elf_free_info(&elf_info); /* Make kimage_file_post_load_cleanup free the fdt buffer for us. */ return ret ? ERR_PTR(ret) : fdt; } struct kexec_file_ops kexec_elf64_ops = { .probe = elf64_probe, .load = elf64_load, };
static int setup_fdt(struct kvm *kvm) { struct device_header *dev_hdr; u8 staging_fdt[FDT_MAX_SIZE]; u32 gic_phandle = fdt__alloc_phandle(); u64 mem_reg_prop[] = { cpu_to_fdt64(kvm->arch.memory_guest_start), cpu_to_fdt64(kvm->ram_size), }; void *fdt = staging_fdt; void *fdt_dest = guest_flat_to_host(kvm, kvm->arch.dtb_guest_start); void (*generate_mmio_fdt_nodes)(void *, struct device_header *, void (*)(void *, u8)); void (*generate_cpu_peripheral_fdt_nodes)(void *, struct kvm *, u32) = kvm->cpus[0]->generate_fdt_nodes; /* Create new tree without a reserve map */ _FDT(fdt_create(fdt, FDT_MAX_SIZE)); _FDT(fdt_finish_reservemap(fdt)); /* Header */ _FDT(fdt_begin_node(fdt, "")); _FDT(fdt_property_cell(fdt, "interrupt-parent", gic_phandle)); _FDT(fdt_property_string(fdt, "compatible", "linux,dummy-virt")); _FDT(fdt_property_cell(fdt, "#address-cells", 0x2)); _FDT(fdt_property_cell(fdt, "#size-cells", 0x2)); /* /chosen */ _FDT(fdt_begin_node(fdt, "chosen")); _FDT(fdt_property_cell(fdt, "linux,pci-probe-only", 1)); _FDT(fdt_property_string(fdt, "bootargs", kern_cmdline)); /* Initrd */ if (kvm->arch.initrd_size != 0) { u32 ird_st_prop = cpu_to_fdt64(kvm->arch.initrd_guest_start); u32 ird_end_prop = cpu_to_fdt64(kvm->arch.initrd_guest_start + kvm->arch.initrd_size); _FDT(fdt_property(fdt, "linux,initrd-start", &ird_st_prop, sizeof(ird_st_prop))); _FDT(fdt_property(fdt, "linux,initrd-end", &ird_end_prop, sizeof(ird_end_prop))); } _FDT(fdt_end_node(fdt)); /* Memory */ _FDT(fdt_begin_node(fdt, "memory")); _FDT(fdt_property_string(fdt, "device_type", "memory")); _FDT(fdt_property(fdt, "reg", mem_reg_prop, sizeof(mem_reg_prop))); _FDT(fdt_end_node(fdt)); /* CPU and peripherals (interrupt controller, timers, etc) */ generate_cpu_nodes(fdt, kvm); if (generate_cpu_peripheral_fdt_nodes) generate_cpu_peripheral_fdt_nodes(fdt, kvm, gic_phandle); /* Virtio MMIO devices */ dev_hdr = device__first_dev(DEVICE_BUS_MMIO); while (dev_hdr) { generate_mmio_fdt_nodes = dev_hdr->data; generate_mmio_fdt_nodes(fdt, dev_hdr, generate_irq_prop); dev_hdr = device__next_dev(dev_hdr); } /* IOPORT devices (!) */ dev_hdr = device__first_dev(DEVICE_BUS_IOPORT); while (dev_hdr) { generate_mmio_fdt_nodes = dev_hdr->data; generate_mmio_fdt_nodes(fdt, dev_hdr, generate_irq_prop); dev_hdr = device__next_dev(dev_hdr); } /* PCI host controller */ pci__generate_fdt_nodes(fdt, gic_phandle); /* PSCI firmware */ _FDT(fdt_begin_node(fdt, "psci")); _FDT(fdt_property_string(fdt, "compatible", "arm,psci")); _FDT(fdt_property_string(fdt, "method", "hvc")); _FDT(fdt_property_cell(fdt, "cpu_suspend", KVM_PSCI_FN_CPU_SUSPEND)); _FDT(fdt_property_cell(fdt, "cpu_off", KVM_PSCI_FN_CPU_OFF)); _FDT(fdt_property_cell(fdt, "cpu_on", KVM_PSCI_FN_CPU_ON)); _FDT(fdt_property_cell(fdt, "migrate", KVM_PSCI_FN_MIGRATE)); _FDT(fdt_end_node(fdt)); /* Finalise. */ _FDT(fdt_end_node(fdt)); _FDT(fdt_finish(fdt)); _FDT(fdt_open_into(fdt, fdt_dest, FDT_MAX_SIZE)); _FDT(fdt_pack(fdt_dest)); if (kvm->cfg.arch.dump_dtb_filename) dump_fdt(kvm->cfg.arch.dump_dtb_filename, fdt_dest); return 0; }
/** * elf_exec_load - load ELF executable image * @lowest_load_addr: On return, will be the address where the first PT_LOAD * section will be loaded in memory. * * Return: * 0 on success, negative value on failure. */ static int elf_exec_load(struct kimage *image, struct elfhdr *ehdr, struct elf_info *elf_info, unsigned long *lowest_load_addr) { unsigned long base = 0, lowest_addr = UINT_MAX; int ret; size_t i; struct kexec_buf kbuf = { .image = image, .buf_max = ppc64_rma_size, .top_down = false }; /* Read in the PT_LOAD segments. */ for (i = 0; i < ehdr->e_phnum; i++) { unsigned long load_addr; size_t size; const struct elf_phdr *phdr; phdr = &elf_info->proghdrs[i]; if (phdr->p_type != PT_LOAD) continue; size = phdr->p_filesz; if (size > phdr->p_memsz) size = phdr->p_memsz; kbuf.buffer = (void *) elf_info->buffer + phdr->p_offset; kbuf.bufsz = size; kbuf.memsz = phdr->p_memsz; kbuf.buf_align = phdr->p_align; kbuf.buf_min = phdr->p_paddr + base; ret = kexec_add_buffer(&kbuf); if (ret) goto out; load_addr = kbuf.mem; if (load_addr < lowest_addr) lowest_addr = load_addr; } /* Update entry point to reflect new load address. */ ehdr->e_entry += base; *lowest_load_addr = lowest_addr; ret = 0; out: return ret; } void *elf64_load(struct kimage *image, char *kernel_buf, unsigned long kernel_len, char *initrd, unsigned long initrd_len, char *cmdline, unsigned long cmdline_len) { int i, ret; unsigned int fdt_size; unsigned long kernel_load_addr, purgatory_load_addr; unsigned long initrd_load_addr, fdt_load_addr, stack_top; void *fdt; const void *slave_code; struct elfhdr ehdr; struct elf_info elf_info; struct fdt_reserve_entry *rsvmap; struct kexec_buf kbuf = { .image = image, .buf_min = 0, .buf_max = ppc64_rma_size }; ret = build_elf_exec_info(kernel_buf, kernel_len, &ehdr, &elf_info); if (ret) goto out; ret = elf_exec_load(image, &ehdr, &elf_info, &kernel_load_addr); if (ret) goto out; pr_debug("Loaded the kernel at 0x%lx\n", kernel_load_addr); ret = kexec_load_purgatory(image, 0, ppc64_rma_size, true, &purgatory_load_addr); if (ret) { pr_err("Loading purgatory failed.\n"); goto out; } pr_debug("Loaded purgatory at 0x%lx\n", purgatory_load_addr); if (initrd != NULL) { kbuf.buffer = initrd; kbuf.bufsz = kbuf.memsz = initrd_len; kbuf.buf_align = PAGE_SIZE; kbuf.top_down = false; ret = kexec_add_buffer(&kbuf); if (ret) goto out; initrd_load_addr = kbuf.mem; pr_debug("Loaded initrd at 0x%lx\n", initrd_load_addr); } fdt_size = fdt_totalsize(initial_boot_params) * 2; fdt = kmalloc(fdt_size, GFP_KERNEL); if (!fdt) { pr_err("Not enough memory for the device tree.\n"); ret = -ENOMEM; goto out; } ret = fdt_open_into(initial_boot_params, fdt, fdt_size); if (ret < 0) { pr_err("Error setting up the new device tree.\n"); ret = -EINVAL; goto out; } ret = setup_new_fdt(image, fdt, initrd_load_addr, initrd_len, cmdline); if (ret) goto out; /* * Documentation/devicetree/booting-without-of.txt says we need to * add a reservation entry for the device tree block, but * early_init_fdt_reserve_self reserves the memory even if there's no * such entry. We'll add a reservation entry anyway, to be safe and * compliant. * * Use dummy values, we will correct them in a moment. */ ret = fdt_add_mem_rsv(fdt, 1, 1); if (ret) { pr_err("Error reserving device tree memory: %s\n", fdt_strerror(ret)); ret = -EINVAL; goto out; } fdt_pack(fdt); kbuf.buffer = fdt; kbuf.bufsz = kbuf.memsz = fdt_size; kbuf.buf_align = PAGE_SIZE; kbuf.top_down = true; ret = kexec_add_buffer(&kbuf); if (ret) goto out; fdt_load_addr = kbuf.mem; /* * Fix fdt reservation, now that we now where it will be loaded * and how big it is. */ rsvmap = fdt + fdt_off_mem_rsvmap(fdt); i = fdt_num_mem_rsv(fdt) - 1; rsvmap[i].address = cpu_to_fdt64(fdt_load_addr); rsvmap[i].size = cpu_to_fdt64(fdt_totalsize(fdt)); pr_debug("Loaded device tree at 0x%lx\n", fdt_load_addr); kbuf.memsz = PURGATORY_STACK_SIZE; kbuf.buf_align = PAGE_SIZE; kbuf.top_down = true; ret = kexec_locate_mem_hole(&kbuf); if (ret) { pr_err("Couldn't find free memory for the purgatory stack.\n"); ret = -ENOMEM; goto out; } stack_top = kbuf.mem + PURGATORY_STACK_SIZE - 1; pr_debug("Purgatory stack is at 0x%lx\n", stack_top); slave_code = elf_info.buffer + elf_info.proghdrs[0].p_offset; ret = setup_purgatory(image, slave_code, fdt, kernel_load_addr, fdt_load_addr, stack_top, find_debug_console(fdt)); if (ret) pr_err("Error setting up the purgatory.\n"); out: elf_free_info(&elf_info); /* Make kimage_file_post_load_cleanup free the fdt buffer for us. */ return ret ? ERR_PTR(ret) : fdt; } struct kexec_file_ops kexec_elf64_ops = { .probe = elf64_probe, .load = elf64_load, };
/* 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; }
int atags_to_fdt(void *atag_list, void *fdt, int total_space) { struct tag *atag = atag_list; /* In the case of 64 bits memory size, need to reserve 2 cells for * address and size for each bank */ /* IAMROOT-12A: * ------------ * 64비트 시스템의 경우 한 개 뱅크당 주소와 사이즈((2 + 2) x sizeof(int32)) */ uint32_t mem_reg_property[2 * 2 * NR_BANKS]; int memcount = 0; int ret, memsize; /* make sure we've got an aligned pointer */ if ((u32)atag_list & 0x3) return 1; /* IAMROOT-12A: * ------------ * atag/DTB 포인터에서 DTB 매직넘버를 발견하면 이미 DTB가 존재하는 것으로 파악이되어 * ATAG를 컨버전할 필요 없으므로 성공으로 리턴 */ /* if we get a DTB here we're done already */ if (*(u32 *)atag_list == fdt32_to_cpu(FDT_MAGIC)) return 0; /* IAMROOT-12A: * ------------ * 처음에 오는 태크가 ATAG_CORE가 아니거나 사이즈가 맞지않으면 실패(1)로 리턴 */ /* validate the ATAG */ if (atag->hdr.tag != ATAG_CORE || (atag->hdr.size != tag_size(tag_core) && atag->hdr.size != 2)) return 1; /* let's give it all the room it could need */ ret = fdt_open_into(fdt, fdt, total_space); if (ret < 0) return ret; /* IAMROOT-12A: * ------------ * atag_list는 atag 개채의 묶음. * for_each_tag()를 수행 시 atag에 하나의 ATAG를 가리키는 포인터가 담김 * 태그는 3개(ATAG_CMDLINE, ATAG_MEM, ATAG_INITRD2)만 디바이스트리로 컨버전 * - ATAG_CMDLINE(cmdline) ---> DTB:/chosen 노드 -> bootargs 프로퍼티 * - ATAG_MEM(u.mem.start & u.mem.size x N뱅크) ---> DTB:/memory 노드 -> reg 프로퍼티 * - ATAG_INITRD2(u.initrd.start & u.initrd.size) ---> DTB:/chosen 노드 -> linux,initrd-start * ---> DTB:/chosen 노드 -> linux,initrd-end */ for_each_tag(atag, atag_list) { if (atag->hdr.tag == ATAG_CMDLINE) { /* Append the ATAGS command line to the device tree * command line. * NB: This means that if the same parameter is set in * the device tree and in the tags, the one from the * tags will be chosen. */ if (do_extend_cmdline) merge_fdt_bootargs(fdt, atag->u.cmdline.cmdline); else setprop_string(fdt, "/chosen", "bootargs", atag->u.cmdline.cmdline); } else if (atag->hdr.tag == ATAG_MEM) { if (memcount >= sizeof(mem_reg_property)/4) continue; if (!atag->u.mem.size) continue; memsize = get_cell_size(fdt); /* IAMROOT-12A: * ------------ * memsize=2인 경우 64비트 * ATAG_MEM은 여러 개가 존재할 수 있다. */ if (memsize == 2) { /* if memsize is 2, that means that * each data needs 2 cells of 32 bits, * so the data are 64 bits */ uint64_t *mem_reg_prop64 = (uint64_t *)mem_reg_property; mem_reg_prop64[memcount++] = cpu_to_fdt64(atag->u.mem.start); mem_reg_prop64[memcount++] = cpu_to_fdt64(atag->u.mem.size); } else { mem_reg_property[memcount++] = cpu_to_fdt32(atag->u.mem.start); mem_reg_property[memcount++] = cpu_to_fdt32(atag->u.mem.size); } } else if (atag->hdr.tag == ATAG_INITRD2) { uint32_t initrd_start, initrd_size; initrd_start = atag->u.initrd.start; initrd_size = atag->u.initrd.size; setprop_cell(fdt, "/chosen", "linux,initrd-start", initrd_start); setprop_cell(fdt, "/chosen", "linux,initrd-end", initrd_start + initrd_size); } } if (memcount) { setprop(fdt, "/memory", "reg", mem_reg_property, 4 * memcount * memsize); } return fdt_pack(fdt); }
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; }
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; }
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; }
/* * Convert and fold provided ATAGs into the provided FDT. * * REturn values: * = 0 -> pretend success * = 1 -> bad ATAG (may retry with another possible ATAG pointer) * < 0 -> error from libfdt */ int atags_to_fdt(void *atag_list, void *fdt, int total_space) { struct tag *atag = atag_list; /* In the case of 64 bits memory size, need to reserve 2 cells for * address and size for each bank */ uint32_t mem_reg_property[2 * 2 * NR_BANKS]; int memcount = 0; int ret, memsize; /* make sure we've got an aligned pointer */ if ((u32)atag_list & 0x3) return 1; /* if we get a DTB here we're done already */ if (*(u32 *)atag_list == fdt32_to_cpu(FDT_MAGIC)) return 0; /* validate the ATAG */ if (atag->hdr.tag != ATAG_CORE || (atag->hdr.size != tag_size(tag_core) && atag->hdr.size != 2)) return 1; /* let's give it all the room it could need */ ret = fdt_open_into(fdt, fdt, total_space); if (ret < 0) return ret; for_each_tag(atag, atag_list) { if (atag->hdr.tag == ATAG_CMDLINE) { /* Append the ATAGS command line to the device tree * command line. * NB: This means that if the same parameter is set in * the device tree and in the tags, the one from the * tags will be chosen. */ if (do_extend_cmdline) merge_fdt_bootargs(fdt, atag->u.cmdline.cmdline); else setprop_string(fdt, "/chosen", "bootargs", atag->u.cmdline.cmdline); } else if (atag->hdr.tag == ATAG_MEM) { if (memcount >= sizeof(mem_reg_property)/4) continue; if (!atag->u.mem.size) continue; memsize = get_cell_size(fdt); if (memsize == 2) { /* if memsize is 2, that means that * each data needs 2 cells of 32 bits, * so the data are 64 bits */ uint64_t *mem_reg_prop64 = (uint64_t *)mem_reg_property; mem_reg_prop64[memcount++] = cpu_to_fdt64(atag->u.mem.start); mem_reg_prop64[memcount++] = cpu_to_fdt64(atag->u.mem.size); } else { mem_reg_property[memcount++] = cpu_to_fdt32(atag->u.mem.start); mem_reg_property[memcount++] = cpu_to_fdt32(atag->u.mem.size); } } else if (atag->hdr.tag == ATAG_INITRD2) { uint32_t initrd_start, initrd_size; initrd_start = atag->u.initrd.start; initrd_size = atag->u.initrd.size; setprop_cell(fdt, "/chosen", "linux,initrd-start", initrd_start); setprop_cell(fdt, "/chosen", "linux,initrd-end", initrd_start + initrd_size); } } if (memcount) { setprop(fdt, "/memory", "reg", mem_reg_property, 4 * memcount * memsize); } return fdt_pack(fdt); }