Esempio n. 1
0
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);
}
Esempio n. 2
0
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();
}
Esempio n. 3
0
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");
}
Esempio n. 4
0
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;
}
Esempio n. 6
0
/* 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;
}
Esempio n. 7
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);
}
Esempio n. 8
0
/*
 * 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;
}
Esempio n. 9
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();
}
Esempio n. 10
0
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();
}
Esempio n. 11
0
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;
}
Esempio n. 12
0
/**
 * 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;
}
Esempio n. 13
0
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;
}
Esempio n. 14
0
/* 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);
}
Esempio n. 16
0
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);
}
Esempio n. 17
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;
}

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,
};
Esempio n. 18
0
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;
}
Esempio n. 19
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;
}
Esempio n. 21
0
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);
}
Esempio n. 22
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;
}
Esempio n. 23
0
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;
}
Esempio n. 25
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);
}