Exemple #1
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");
}
Exemple #2
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();
}
Exemple #3
0
int fdt_initrd(void *fdt, ulong initrd_start, ulong initrd_end)
{
	int   nodeoffset;
	int   err, j, total;
	int is_u64;
	uint64_t addr, size;

	/* just return if the size of initrd is zero */
	if (initrd_start == initrd_end)
		return 0;

	/* find or create "/chosen" node. */
	nodeoffset = fdt_find_or_add_subnode(fdt, 0, "chosen");
	if (nodeoffset < 0)
		return nodeoffset;

	total = fdt_num_mem_rsv(fdt);

	/*
	 * Look for an existing entry and update it.  If we don't find
	 * the entry, we will j be the next available slot.
	 */
	for (j = 0; j < total; j++) {
		err = fdt_get_mem_rsv(fdt, j, &addr, &size);
		if (addr == initrd_start) {
			fdt_del_mem_rsv(fdt, j);
			break;
		}
	}

	err = fdt_add_mem_rsv(fdt, initrd_start, initrd_end - initrd_start);
	if (err < 0) {
		printf("fdt_initrd: %s\n", fdt_strerror(err));
		return err;
	}

	is_u64 = (fdt_address_cells(fdt, 0) == 2);

	err = fdt_setprop_uxx(fdt, nodeoffset, "linux,initrd-start",
			      (uint64_t)initrd_start, is_u64);

	if (err < 0) {
		printf("WARNING: could not set linux,initrd-start %s.\n",
		       fdt_strerror(err));
		return err;
	}

	err = fdt_setprop_uxx(fdt, nodeoffset, "linux,initrd-end",
			      (uint64_t)initrd_end, is_u64);

	if (err < 0) {
		printf("WARNING: could not set linux,initrd-end %s.\n",
		       fdt_strerror(err));

		return err;
	}

	return 0;
}
Exemple #4
0
int spapr_rtas_device_tree_setup(void *fdt, hwaddr rtas_addr,
                                 hwaddr rtas_size)
{
    int ret;
    int i;

    ret = fdt_add_mem_rsv(fdt, rtas_addr, rtas_size);
    if (ret < 0) {
        fprintf(stderr, "Couldn't add RTAS reserve entry: %s\n",
                fdt_strerror(ret));
        return ret;
    }

    ret = qemu_fdt_setprop_cell(fdt, "/rtas", "linux,rtas-base",
                                rtas_addr);
    if (ret < 0) {
        fprintf(stderr, "Couldn't add linux,rtas-base property: %s\n",
                fdt_strerror(ret));
        return ret;
    }

    ret = qemu_fdt_setprop_cell(fdt, "/rtas", "linux,rtas-entry",
                                rtas_addr);
    if (ret < 0) {
        fprintf(stderr, "Couldn't add linux,rtas-entry property: %s\n",
                fdt_strerror(ret));
        return ret;
    }

    ret = qemu_fdt_setprop_cell(fdt, "/rtas", "rtas-size",
                                rtas_size);
    if (ret < 0) {
        fprintf(stderr, "Couldn't add rtas-size property: %s\n",
                fdt_strerror(ret));
        return ret;
    }

    for (i = 0; i < TOKEN_MAX; i++) {
        struct rtas_call *call = &rtas_table[i];

        if (!call->name) {
            continue;
        }

        ret = qemu_fdt_setprop_cell(fdt, "/rtas", call->name,
                                    i + TOKEN_BASE);
        if (ret < 0) {
            fprintf(stderr, "Couldn't add rtas token for %s: %s\n",
                    call->name, fdt_strerror(ret));
            return ret;
        }

    }
    return 0;
}
Exemple #5
0
int psci_update_dt(void *fdt)
{
#ifdef CONFIG_ARMV7_NONSEC
    if (!armv7_boot_nonsec())
        return 0;
#endif
#ifndef CONFIG_ARMV7_SECURE_BASE
    /* secure code lives in RAM, keep it alive */
    fdt_add_mem_rsv(fdt, (unsigned long)__secure_start,
                    __secure_end - __secure_start);
#endif

    return fdt_psci(fdt);
}
Exemple #6
0
void ft_cpu_setup(void *blob, bd_t *bd)
{
#ifdef CONFIG_MP
	int off;
	u32 bootpg = determine_mp_bootpg(NULL);
#endif

	do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
			     "timebase-frequency", bd->bi_busfreq / 4, 1);
	do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
			     "bus-frequency", bd->bi_busfreq, 1);
	do_fixup_by_prop_u32(blob, "device_type", "cpu", 4,
			     "clock-frequency", bd->bi_intfreq, 1);
	do_fixup_by_prop_u32(blob, "device_type", "soc", 4,
			     "bus-frequency", bd->bi_busfreq, 1);

#if defined(CONFIG_MPC8641)
	do_fixup_by_compat_u32(blob, "fsl,mpc8641-localbus",
			       "bus-frequency", gd->arch.lbc_clk, 1);
#endif
	do_fixup_by_compat_u32(blob, "fsl,elbc",
			       "bus-frequency", gd->arch.lbc_clk, 1);

	fdt_fixup_memory(blob, (u64)bd->bi_memstart, (u64)bd->bi_memsize);

#if defined(CONFIG_HAS_ETH0) || defined(CONFIG_HAS_ETH1) \
    || defined(CONFIG_HAS_ETH2) || defined(CONFIG_HAS_ETH3)
	fdt_fixup_ethernet(blob);
#endif

#ifdef CONFIG_SYS_NS16550
	do_fixup_by_compat_u32(blob, "ns16550",
			       "clock-frequency", CONFIG_SYS_NS16550_CLK, 1);
#endif

#ifdef CONFIG_MP
	/* Reserve the boot page so OSes dont use it */
	off = fdt_add_mem_rsv(blob, bootpg, (u64)4096);
	if (off < 0)
		printf("%s: %s\n", __FUNCTION__, fdt_strerror(off));

	ft_fixup_num_cores(blob);
#endif

#ifdef CONFIG_SYS_SRIO
	ft_srio_setup(blob);
#endif
}
Exemple #7
0
void ft_fixup_cpu(void *blob)
{
	int off;
	__maybe_unused u64 spin_tbl_addr = (u64)get_spin_tbl_addr();
	fdt32_t *reg;
	int addr_cells;
	u64 val, core_id;
	size_t *boot_code_size = &(__secondary_boot_code_size);

	off = fdt_path_offset(blob, "/cpus");
	if (off < 0) {
		puts("couldn't find /cpus node\n");
		return;
	}
	of_bus_default_count_cells(blob, off, &addr_cells, NULL);

	off = fdt_node_offset_by_prop_value(blob, -1, "device_type", "cpu", 4);
	while (off != -FDT_ERR_NOTFOUND) {
		reg = (fdt32_t *)fdt_getprop(blob, off, "reg", 0);
		core_id = of_read_number(reg, addr_cells);
		if (reg) {
			if (core_id  == 0 || (is_core_online(core_id))) {
				val = spin_tbl_addr;
				val += id_to_core(core_id) *
				       SPIN_TABLE_ELEM_SIZE;
				val = cpu_to_fdt64(val);
				fdt_setprop_string(blob, off, "enable-method",
						   "spin-table");
				fdt_setprop(blob, off, "cpu-release-addr",
					    &val, sizeof(val));
			} else {
				debug("skipping offline core\n");
			}
		} else {
			puts("Warning: found cpu node without reg property\n");
		}
		off = fdt_node_offset_by_prop_value(blob, off, "device_type",
						    "cpu", 4);
	}

	fdt_add_mem_rsv(blob, (uintptr_t)&secondary_boot_code,
			*boot_code_size);
}
Exemple #8
0
/* Resize the fdt to its actual size + a bit of padding */
int fdt_shrink_to_minimum(void *blob, uint extrasize)
{
	int i;
	uint64_t addr, size;
	int total, ret;
	uint actualsize;

	if (!blob)
		return 0;

	total = fdt_num_mem_rsv(blob);
	for (i = 0; i < total; i++) {
		fdt_get_mem_rsv(blob, i, &addr, &size);
		if (addr == (uintptr_t)blob) {
			fdt_del_mem_rsv(blob, i);
			break;
		}
	}

	/*
	 * Calculate the actual size of the fdt
	 * plus the size needed for 5 fdt_add_mem_rsv, one
	 * for the fdt itself and 4 for a possible initrd
	 * ((initrd-start + initrd-end) * 2 (name & value))
	 */
	actualsize = fdt_off_dt_strings(blob) +
		fdt_size_dt_strings(blob) + 5 * sizeof(struct fdt_reserve_entry);

	actualsize += extrasize;
	/* Make it so the fdt ends on a page boundary */
	actualsize = ALIGN(actualsize + ((uintptr_t)blob & 0xfff), 0x1000);
	actualsize = actualsize - ((uintptr_t)blob & 0xfff);

	/* Change the fdt header to reflect the correct size */
	fdt_set_totalsize(blob, actualsize);

	/* Add the new reservation */
	ret = fdt_add_mem_rsv(blob, (uintptr_t)blob, actualsize);
	if (ret < 0)
		return ret;

	return actualsize;
}
Exemple #9
0
int psci_update_dt(void *fdt)
{
	/*
	 * If the PSCI in SEC Firmware didn't work, avoid to update the
	 * device node of PSCI. But still return 0 instead of an error
	 * number to support detecting PSCI dynamically and then switching
	 * the SMP boot method between PSCI and spin-table.
	 */
	if (sec_firmware_support_psci_version() == PSCI_INVALID_VER)
		return 0;
	fdt_psci(fdt);

#if defined(CONFIG_ARMV8_PSCI) && !defined(CONFIG_ARMV8_SECURE_BASE)
	/* secure code lives in RAM, keep it alive */
	fdt_add_mem_rsv(fdt, (unsigned long)__secure_start,
			__secure_end - __secure_start);
#endif

	return 0;
}
Exemple #10
0
void spapr_load_rtas(sPAPRMachineState *spapr, void *fdt, hwaddr addr)
{
    int rtas_node;
    int ret;

    /* Copy RTAS blob into guest RAM */
    cpu_physical_memory_write(addr, spapr->rtas_blob, spapr->rtas_size);

    ret = fdt_add_mem_rsv(fdt, addr, spapr->rtas_size);
    if (ret < 0) {
        error_report("Couldn't add RTAS reserve entry: %s",
                     fdt_strerror(ret));
        exit(1);
    }

    /* Update the device tree with the blob's location */
    rtas_node = fdt_path_offset(fdt, "/rtas");
    assert(rtas_node >= 0);

    ret = fdt_setprop_cell(fdt, rtas_node, "linux,rtas-base", addr);
    if (ret < 0) {
        error_report("Couldn't add linux,rtas-base property: %s",
                     fdt_strerror(ret));
        exit(1);
    }

    ret = fdt_setprop_cell(fdt, rtas_node, "linux,rtas-entry", addr);
    if (ret < 0) {
        error_report("Couldn't add linux,rtas-entry property: %s",
                     fdt_strerror(ret));
        exit(1);
    }

    ret = fdt_setprop_cell(fdt, rtas_node, "rtas-size", spapr->rtas_size);
    if (ret < 0) {
        error_report("Couldn't add rtas-size property: %s",
                     fdt_strerror(ret));
        exit(1);
    }
}
Exemple #11
0
void ft_fixup_cpu(void *blob)
{
	int off;
	__maybe_unused u64 spin_tbl_addr = (u64)get_spin_tbl_addr();
	fdt32_t *reg;
	int addr_cells;
	u64 val, core_id;
	size_t *boot_code_size = &(__secondary_boot_code_size);
	u32 mask = cpu_pos_mask();
	int off_prev = -1;

	off = fdt_path_offset(blob, "/cpus");
	if (off < 0) {
		puts("couldn't find /cpus node\n");
		return;
	}

	fdt_support_default_count_cells(blob, off, &addr_cells, NULL);

	off = fdt_node_offset_by_prop_value(blob, off_prev, "device_type",
					    "cpu", 4);
	while (off != -FDT_ERR_NOTFOUND) {
		reg = (fdt32_t *)fdt_getprop(blob, off, "reg", 0);
		if (reg) {
			core_id = fdt_read_number(reg, addr_cells);
			if (!test_bit(id_to_core(core_id), &mask)) {
				fdt_del_node(blob, off);
				off = off_prev;
			}
		}
		off_prev = off;
		off = fdt_node_offset_by_prop_value(blob, off_prev,
						    "device_type", "cpu", 4);
	}

#if defined(CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT) && \
	defined(CONFIG_SEC_FIRMWARE_ARMV8_PSCI)
	int node;
	u32 psci_ver;

	/* Check the psci version to determine if the psci is supported */
	psci_ver = sec_firmware_support_psci_version();
	if (psci_ver == 0xffffffff) {
		/* remove psci DT node */
		node = fdt_path_offset(blob, "/psci");
		if (node >= 0)
			goto remove_psci_node;

		node = fdt_node_offset_by_compatible(blob, -1, "arm,psci");
		if (node >= 0)
			goto remove_psci_node;

		node = fdt_node_offset_by_compatible(blob, -1, "arm,psci-0.2");
		if (node >= 0)
			goto remove_psci_node;

		node = fdt_node_offset_by_compatible(blob, -1, "arm,psci-1.0");
		if (node >= 0)
			goto remove_psci_node;

remove_psci_node:
		if (node >= 0)
			fdt_del_node(blob, node);
	} else {
		return;
	}
#endif
	off = fdt_path_offset(blob, "/cpus");
	if (off < 0) {
		puts("couldn't find /cpus node\n");
		return;
	}
	fdt_support_default_count_cells(blob, off, &addr_cells, NULL);

	off = fdt_node_offset_by_prop_value(blob, -1, "device_type", "cpu", 4);
	while (off != -FDT_ERR_NOTFOUND) {
		reg = (fdt32_t *)fdt_getprop(blob, off, "reg", 0);
		if (reg) {
			core_id = fdt_read_number(reg, addr_cells);
			if (core_id  == 0 || (is_core_online(core_id))) {
				val = spin_tbl_addr;
				val += id_to_core(core_id) *
				       SPIN_TABLE_ELEM_SIZE;
				val = cpu_to_fdt64(val);
				fdt_setprop_string(blob, off, "enable-method",
						   "spin-table");
				fdt_setprop(blob, off, "cpu-release-addr",
					    &val, sizeof(val));
			} else {
				debug("skipping offline core\n");
			}
		} else {
			puts("Warning: found cpu node without reg property\n");
		}
		off = fdt_node_offset_by_prop_value(blob, off, "device_type",
						    "cpu", 4);
	}

	fdt_add_mem_rsv(blob, (uintptr_t)&secondary_boot_code,
			*boot_code_size);
#if defined(CONFIG_EFI_LOADER) && !defined(CONFIG_SPL_BUILD)
	efi_add_memory_map((uintptr_t)&secondary_boot_code,
			   ALIGN(*boot_code_size, EFI_PAGE_SIZE) >> EFI_PAGE_SHIFT,
			   EFI_RESERVED_MEMORY_TYPE, false);
#endif
}
Exemple #12
0
					printf("libfdt fdt_get_mem_rsv():  %s\n",
							fdt_strerror(err));
					return err;
				}
				printf("    %x\t%08x%08x\t%08x%08x\n", j,
					(u32)(addr >> 32),
					(u32)(addr & 0xffffffff),
					(u32)(size >> 32),
					(u32)(size & 0xffffffff));
			}
		} else if (argv[2][0] == 'a') {
			uint64_t addr, size;
			int err;
			addr = simple_strtoull(argv[3], NULL, 16);
			size = simple_strtoull(argv[4], NULL, 16);
			err = fdt_add_mem_rsv(working_fdt, addr, size);

			if (err < 0) {
				printf("libfdt fdt_add_mem_rsv():  %s\n",
					fdt_strerror(err));
				return err;
			}
		} else if (argv[2][0] == 'd') {
			unsigned long idx = simple_strtoul(argv[3], NULL, 16);
			int err = fdt_del_mem_rsv(working_fdt, idx);

			if (err < 0) {
				printf("libfdt fdt_del_mem_rsv():  %s\n",
					fdt_strerror(err));
				return err;
			}
Exemple #13
0
void ft_cpu_setup(void *blob, bd_t *bd)
{
	int off;
	int val;
	const char *sysclk_path;
	struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
	unsigned int svr;
	svr = in_be32(&gur->svr);

	unsigned long busclk = get_bus_freq(0);

	/* delete crypto node if not on an E-processor */
	if (!IS_E_PROCESSOR(svr))
		fdt_fixup_crypto_node(blob, 0);
#if CONFIG_SYS_FSL_SEC_COMPAT >= 4
	else {
		ccsr_sec_t __iomem *sec;

		sec = (void __iomem *)CONFIG_SYS_FSL_SEC_ADDR;
		fdt_fixup_crypto_node(blob, sec_in32(&sec->secvid_ms));
	}
#endif

	off = fdt_node_offset_by_prop_value(blob, -1, "device_type", "cpu", 4);
	while (off != -FDT_ERR_NOTFOUND) {
		val = gd->cpu_clk;
		fdt_setprop(blob, off, "clock-frequency", &val, 4);
		off = fdt_node_offset_by_prop_value(blob, off,
						    "device_type", "cpu", 4);
	}

	do_fixup_by_prop_u32(blob, "device_type", "soc",
			     4, "bus-frequency", busclk, 1);

	ft_fixup_enet_phy_connect_type(blob);

#ifdef CONFIG_SYS_NS16550
	do_fixup_by_compat_u32(blob, "fsl,16550-FIFO64",
			       "clock-frequency", CONFIG_SYS_NS16550_CLK, 1);
#endif

	sysclk_path = fdt_get_alias(blob, "sysclk");
	if (sysclk_path)
		do_fixup_by_path_u32(blob, sysclk_path, "clock-frequency",
				     CONFIG_SYS_CLK_FREQ, 1);
	do_fixup_by_compat_u32(blob, "fsl,qoriq-sysclk-2.0",
			       "clock-frequency", CONFIG_SYS_CLK_FREQ, 1);

#if defined(CONFIG_DEEP_SLEEP) && defined(CONFIG_SD_BOOT)
#define UBOOT_HEAD_LEN	0x1000
	/*
	 * Reserved memory in SD boot deep sleep case.
	 * Second stage uboot binary and malloc space should be reserved.
	 * If the memory they occupied has not been reserved, then this
	 * space would be used by kernel and overwritten in uboot when
	 * deep sleep resume, which cause deep sleep failed.
	 * Since second uboot binary has a head, that space need to be
	 * reserved either(assuming its size is less than 0x1000).
	 */
	off = fdt_add_mem_rsv(blob, CONFIG_SYS_TEXT_BASE - UBOOT_HEAD_LEN,
			CONFIG_SYS_MONITOR_LEN + CONFIG_SYS_SPL_MALLOC_SIZE +
			UBOOT_HEAD_LEN);
	if (off < 0)
		printf("Failed to reserve memory for SD boot deep sleep: %s\n",
		       fdt_strerror(off));
#endif

#if defined(CONFIG_FSL_ESDHC)
	fdt_fixup_esdhc(blob, bd);
#endif

	/*
	 * platform bus clock = system bus clock/2
	 * Here busclk = system bus clock
	 * We are using the platform bus clock as 1588 Timer reference
	 * clock source select
	 */
	do_fixup_by_compat_u32(blob, "fsl, gianfar-ptp-timer",
			       "timer-frequency", busclk / 2, 1);

	/*
	 * clock-freq should change to clock-frequency and
	 * flexcan-v1.0 should change to p1010-flexcan respectively
	 * in the future.
	 */
	do_fixup_by_compat_u32(blob, "fsl, flexcan-v1.0",
			       "clock_freq", busclk / 2, 1);

	do_fixup_by_compat_u32(blob, "fsl, flexcan-v1.0",
			       "clock-frequency", busclk / 2, 1);

	do_fixup_by_compat_u32(blob, "fsl, ls1021a-flexcan",
			       "clock-frequency", busclk / 2, 1);

#if defined(CONFIG_QSPI_BOOT) || defined(CONFIG_SD_BOOT_QSPI)
	off = fdt_node_offset_by_compat_reg(blob, FSL_IFC_COMPAT,
					    CONFIG_SYS_IFC_ADDR);
	fdt_set_node_status(blob, off, FDT_STATUS_DISABLED, 0);
#else
	off = fdt_node_offset_by_compat_reg(blob, FSL_QSPI_COMPAT,
					    QSPI0_BASE_ADDR);
	fdt_set_node_status(blob, off, FDT_STATUS_DISABLED, 0);
	off = fdt_node_offset_by_compat_reg(blob, FSL_DSPI_COMPAT,
					    DSPI1_BASE_ADDR);
	fdt_set_node_status(blob, off, FDT_STATUS_DISABLED, 0);
#endif
}
					(u32)(addr >> 32),
					(u32)(addr & 0xffffffff),
					(u32)(size >> 32),
					(u32)(size & 0xffffffff));
			}
		} else if (argv[2][0] == 'a') {
			uint64_t addr, size;
			int err;
#ifdef CFG_64BIT_STRTOUL
			addr = simple_strtoull(argv[3], NULL, 16);
			size = simple_strtoull(argv[4], NULL, 16);
#else
			addr = simple_strtoul(argv[3], NULL, 16);
			size = simple_strtoul(argv[4], NULL, 16);
#endif
			err = fdt_add_mem_rsv(fdt, addr, size);

			if (err < 0) {
				printf("libfdt fdt_add_mem_rsv():  %s\n",
					fdt_strerror(err));
				return err;
			}
		} else if (argv[2][0] == 'd') {
			unsigned long idx = simple_strtoul(argv[3], NULL, 16);
			int err = fdt_del_mem_rsv(fdt, idx);

			if (err < 0) {
				printf("libfdt fdt_del_mem_rsv():  %s\n",
					fdt_strerror(err));
				return err;
			}
Exemple #15
0
int fdt_initrd(void *fdt, ulong initrd_start, ulong initrd_end, int force)
{
	int   nodeoffset;
	int   err, j, total;
	u32   tmp;
	const char *path;
	uint64_t addr, size;

	/* Find the "chosen" node.  */
	nodeoffset = fdt_path_offset (fdt, "/chosen");

	/* If there is no "chosen" node in the blob return */
	if (nodeoffset < 0) {
		printf("fdt_initrd: %s\n", fdt_strerror(nodeoffset));
		return nodeoffset;
	}

	/* just return if initrd_start/end aren't valid */
	if ((initrd_start == 0) || (initrd_end == 0))
		return 0;

	total = fdt_num_mem_rsv(fdt);

	/*
	 * Look for an existing entry and update it.  If we don't find
	 * the entry, we will j be the next available slot.
	 */
	for (j = 0; j < total; j++) {
		err = fdt_get_mem_rsv(fdt, j, &addr, &size);
		if (addr == initrd_start) {
			fdt_del_mem_rsv(fdt, j);
			break;
		}
	}

	err = fdt_add_mem_rsv(fdt, initrd_start, initrd_end - initrd_start + 1);
	if (err < 0) {
		printf("fdt_initrd: %s\n", fdt_strerror(err));
		return err;
	}

	path = fdt_getprop(fdt, nodeoffset, "linux,initrd-start", NULL);
	if ((path == NULL) || force) {
		tmp = __cpu_to_be32(initrd_start);
		err = fdt_setprop(fdt, nodeoffset,
			"linux,initrd-start", &tmp, sizeof(tmp));
		if (err < 0) {
			printf("WARNING: "
				"could not set linux,initrd-start %s.\n",
				fdt_strerror(err));
			return err;
		}
		tmp = __cpu_to_be32(initrd_end);
		err = fdt_setprop(fdt, nodeoffset,
			"linux,initrd-end", &tmp, sizeof(tmp));
		if (err < 0) {
			printf("WARNING: could not set linux,initrd-end %s.\n",
				fdt_strerror(err));

			return err;
		}
	}

	return 0;
}
Exemple #16
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;
}
int fdt_chosen(void *fdt, ulong initrd_start, ulong initrd_end, int force)
{
	int   nodeoffset;
	int   err;
	u32   tmp;		/* used to set 32 bit integer properties */
	char  *str;		/* used to set string properties */

	err = fdt_check_header(fdt);
	if (err < 0) {
		printf("fdt_chosen: %s\n", fdt_strerror(err));
		return err;
	}

	if (initrd_start && initrd_end) {
		uint64_t addr, size;
		int  total = fdt_num_mem_rsv(fdt);
		int  j;

		/*
		 * Look for an existing entry and update it.  If we don't find
		 * the entry, we will j be the next available slot.
		 */
		for (j = 0; j < total; j++) {
			err = fdt_get_mem_rsv(fdt, j, &addr, &size);
			if (addr == initrd_start) {
				fdt_del_mem_rsv(fdt, j);
				break;
			}
		}

		err = fdt_add_mem_rsv(fdt, initrd_start, initrd_end - initrd_start + 1);
		if (err < 0) {
			printf("fdt_chosen: %s\n", fdt_strerror(err));
			return err;
		}
	}

	/*
	 * Find the "chosen" node.
	 */
	nodeoffset = fdt_path_offset (fdt, "/chosen");

	/*
	 * If we have a "chosen" node already the "force the writing"
	 * is not set, our job is done.
	 */
	if ((nodeoffset >= 0) && !force)
		return 0;

	/*
	 * No "chosen" node in the blob: create it.
	 */
	if (nodeoffset < 0) {
		/*
		 * Create a new node "/chosen" (offset 0 is root level)
		 */
		nodeoffset = fdt_add_subnode(fdt, 0, "chosen");
		if (nodeoffset < 0) {
			printf("WARNING: could not create /chosen %s.\n",
				fdt_strerror(nodeoffset));
			return nodeoffset;
		}
	}

	/*
	 * Update pre-existing properties, create them if non-existant.
	 */
	str = getenv("bootargs");
	if (str != NULL) {
		err = fdt_setprop(fdt, nodeoffset,
			"bootargs", str, strlen(str)+1);
		if (err < 0)
			printf("WARNING: could not set bootargs %s.\n",
				fdt_strerror(err));
	}
	if (initrd_start && initrd_end) {
		tmp = __cpu_to_be32(initrd_start);
		err = fdt_setprop(fdt, nodeoffset,
			 "linux,initrd-start", &tmp, sizeof(tmp));
		if (err < 0)
			printf("WARNING: "
				"could not set linux,initrd-start %s.\n",
				fdt_strerror(err));
		tmp = __cpu_to_be32(initrd_end);
		err = fdt_setprop(fdt, nodeoffset,
			"linux,initrd-end", &tmp, sizeof(tmp));
		if (err < 0)
			printf("WARNING: could not set linux,initrd-end %s.\n",
				fdt_strerror(err));
	}
#ifdef OF_STDOUT_PATH
	err = fdt_setprop(fdt, nodeoffset,
		"linux,stdout-path", OF_STDOUT_PATH, strlen(OF_STDOUT_PATH)+1);
	if (err < 0)
		printf("WARNING: could not set linux,stdout-path %s.\n",
			fdt_strerror(err));
#endif

	return err;
}
Exemple #18
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,
};
static int new_style_reservation(void *fdt, int reserve_initrd)
{
	int nodeoffset;
	const void *p;
	fdt64_t *ranges, *range;
	char *names, *name;
	int ranges_len, names_len;

	nodeoffset = fdt_path_offset(fdt, "/");
	if (nodeoffset < 0) {
		fprintf(stderr, "Device tree has no root node\n");
		exit(1);
	}

	p = fdt_getprop(fdt, nodeoffset, "reserved-ranges", &ranges_len);
	if (!p && ranges_len == -FDT_ERR_NOTFOUND)
		return 0;

	if (!p) {
		fprintf(stderr, "getprop reserved-ranges returned %d\n",
			ranges_len);
		exit(1);
	}

	ranges = malloc(ranges_len);
	if (!ranges) {
		perror("malloc");
		exit(1);
	}
	memcpy(ranges, p, ranges_len);

	p = fdt_getprop(fdt, nodeoffset, "reserved-names", &names_len);
	if (!p && names_len == -FDT_ERR_NOTFOUND)
		return 0;

	if (!p) {
		fprintf(stderr, "getprop reserved-names returned %d\n",
			names_len);
		exit(1);
	}

	names = malloc(names_len);
	if (!names) {
		perror("malloc");
		exit(1);
	}
	memcpy(names, p, names_len);

	name = names;
	range = ranges;
	while (ranges_len > 0 && names_len > 0) {
		uint64_t start, size;

		start = fdt64_to_cpu(*range++);
		size = fdt64_to_cpu(*range++);

#ifdef DEBUG
		printf("%s %lx %lx\n", name, start, size);
#endif

		if (!reserve_initrd && !strcmp(name, "linux,initramfs"))
			continue;

		simple_alloc_at(kexec_map, start, size);

		if (fdt_add_mem_rsv(fdt, start, size))
			perror("fdt_add_mem_rsv");

		ranges_len -= 2 * sizeof(uint64_t);
		names_len -= strlen(name) + 1;
		name += strlen(name) + 1;
	}

	free(ranges);
	free(names);

	return 1;
}
void kexec_memory_map(void *fdt, int reserve_initrd)
{
	uint64_t start, size, end;
	int nodeoffset;
	int lpar = 0;

	kexec_map = simple_init();

	/* Work out if we are in LPAR mode */
	nodeoffset = fdt_path_offset(fdt, "/rtas");
	if (nodeoffset >= 0) {
		if (fdt_getprop(fdt, nodeoffset, "ibm,hypertas-functions", NULL))
			lpar = 1;
	}

	/* First find our memory */
	nodeoffset = fdt_path_offset(fdt, "/");
	if (nodeoffset < 0) {
		fprintf(stderr, "Device tree has no root node\n");
		exit(1);
	}

	while (1) {
		const char *type;
		int len;
		const fdt64_t *reg;

		nodeoffset = fdt_next_node(fdt, nodeoffset, NULL);
		if (nodeoffset < 0)
			break;

		type = fdt_getprop(fdt, nodeoffset, "device_type", NULL);

		if (!type || strcmp(type, "memory"))
			continue;

		reg = fdt_getprop(fdt, nodeoffset, "reg", &len);

		while (len) {
			start = fdt64_to_cpu(*reg++);
			size = fdt64_to_cpu(*reg++);
			len -= 2 * sizeof(uint64_t);

			if (lpar == 1) {
				/* Only use the RMA region for LPAR */
				if (start == 0) {
					if (size > MEMORY_CAP)
						size = MEMORY_CAP;
					simple_free(kexec_map, 0, size);
					mem_top = size;
				}
			} else {
				if (start >= MEMORY_CAP)
					continue;

				if ((start + size) > MEMORY_CAP)
					size = MEMORY_CAP - start;

				simple_free(kexec_map, start, size);

				if ((start + size) > mem_top)
					mem_top = start + size;
			}
		}
	}

	/* Reserve the kernel */
	nodeoffset = fdt_path_offset(fdt, "/chosen");
	if (nodeoffset < 0) {
		fprintf(stderr, "Device tree has no chosen node\n");
		exit(1);
	}

	/*
	 * XXX FIXME: Need to add linux,kernel-start property to the
	 * kernel to handle relocatable kernels.
	 */
	start = 0;
	if (getprop_u64(fdt, nodeoffset, "linux,kernel-end", &end)) {
		fprintf(stderr, "getprop linux,kernel-end failed\n");
		exit(1);
	}

	simple_alloc_at(kexec_map, start, end - start);

	/* Reserve the MMU hashtable in non LPAR mode */
	if (lpar == 0) {
		if (getprop_u64(fdt, nodeoffset, "linux,htab-base", &start) ||
		    getprop_u64(fdt, nodeoffset, "linux,htab-size", &size)) {
			fprintf(stderr, "Could not find linux,htab-base or "
				"linux,htab-size properties\n");
			exit(1);
		}

		if (start < mem_top)
			simple_alloc_at(kexec_map, start, size);
	}

	/* XXX FIXME: Reserve TCEs in kexec_map */

	if (new_style_reservation(fdt, reserve_initrd))
		return;

	/* Reserve the initrd if requested */
	if (reserve_initrd &&
            !getprop_u64(fdt, nodeoffset, "linux,initrd-start", &start) &&
	    !getprop_u64(fdt, nodeoffset, "linux,initrd-end", &end)) {

		if (start < mem_top)
			simple_alloc_at(kexec_map, start, end - start);
	}

	/* Reserve RTAS */
	nodeoffset = fdt_path_offset(fdt, "/rtas");
	if (nodeoffset > 0) {
		uint32_t rtas_start, rtas_size;

		if (getprop_u32(fdt, nodeoffset, "linux,rtas-base", &rtas_start)) {
			fprintf(stderr, "getprop linux,rtas-base failed\n");
			exit(1);
		}

		if (getprop_u32(fdt, nodeoffset, "rtas-size", &rtas_size)) {
			fprintf(stderr, "getprop rtas-size failed\n");
			exit(1);
		}

		simple_alloc_at(kexec_map, rtas_start, rtas_size);

		if (fdt_add_mem_rsv(fdt, rtas_start, rtas_size))
			perror("fdt_add_mem_rsv");
	}

	nodeoffset = fdt_path_offset(fdt, "/ibm,opal");
	if (nodeoffset > 0) {
		uint64_t opal_start, opal_size;

		if (getprop_u64(fdt, nodeoffset, "opal-base-address",
				&opal_start)) {
			fprintf(stderr, "getprop opal-base-address failed\n");
			exit(1);
		}

		if (getprop_u64(fdt, nodeoffset, "opal-runtime-size",
				&opal_size)) {
			fprintf(stderr, "getprop opal-runtime-size failed\n");
			exit(1);
		}

		simple_alloc_at(kexec_map, opal_start, opal_size);

		if (fdt_add_mem_rsv(fdt, opal_start, opal_size))
			perror("fdt_add_mem_rsv");
	}
}