示例#1
0
static int setup_dtb_prop(char **bufp, off_t *sizep, const char *node_name,
		const char *prop_name, const void *val, int len)
{
	char *dtb_buf;
	off_t dtb_size;
	int off;
	int prop_len = 0;
	const struct fdt_property *prop;

	if ((bufp == NULL) || (sizep == NULL) || (*bufp == NULL))
		die("Internal error\n");

	dtb_buf = *bufp;
	dtb_size = *sizep;

	/* check if the subnode has already exist */
	off = fdt_path_offset(dtb_buf, node_name);
	if (off == -FDT_ERR_NOTFOUND) {
		dtb_size += fdt_node_len(node_name);
		fdt_set_totalsize(dtb_buf, dtb_size);
		dtb_buf = xrealloc(dtb_buf, dtb_size);
		if (dtb_buf == NULL)
			die("xrealloc failed\n");
		off = fdt_add_subnode(dtb_buf, off, node_name);
	}

	if (off < 0) {
		fprintf(stderr, "FDT: Error adding %s node.\n", node_name);
		return -1;
	}

	prop = fdt_get_property(dtb_buf, off, prop_name, &prop_len);
	if ((prop == NULL) && (prop_len != -FDT_ERR_NOTFOUND)) {
		die("FDT: fdt_get_property");
	} else if (prop == NULL) {
		/* prop_len == -FDT_ERR_NOTFOUND */
		/* prop doesn't exist */
		dtb_size += fdt_prop_len(prop_name, len);
	} else {
		if (prop_len < len)
			dtb_size += len - prop_len;
	}

	if (fdt_totalsize(dtb_buf) < dtb_size) {
		fdt_set_totalsize(dtb_buf, dtb_size);
		dtb_buf = xrealloc(dtb_buf, dtb_size);
		if (dtb_buf == NULL)
			die("xrealloc failed\n");
	}

	if (fdt_setprop(dtb_buf, off, prop_name,
				val, len) != 0) {
		fprintf(stderr, "FDT: Error setting %s/%s property.\n",
				node_name, prop_name);
		return -1;
	}
	*bufp = dtb_buf;
	*sizep = dtb_size;
	return 0;
}
示例#2
0
int fdt_resize(void *fdt, void *buf, int bufsize)
{
	size_t headsize, tailsize;
	char *oldtail, *newtail;

	FDT_SW_CHECK_HEADER(fdt);

	headsize = fdt_off_dt_struct(fdt);
	tailsize = fdt_size_dt_strings(fdt);

	if ((headsize + tailsize) > bufsize)
		return -FDT_ERR_NOSPACE;

	oldtail = (char *)fdt + fdt_totalsize(fdt) - tailsize;
	newtail = (char *)buf + bufsize - tailsize;

	/* Two cases to avoid clobbering data if the old and new
	 * buffers partially overlap */
	if (buf <= fdt) {
		memmove(buf, fdt, headsize);
		memmove(newtail, oldtail, tailsize);
	} else {
		memmove(newtail, oldtail, tailsize);
		memmove(buf, fdt, headsize);
	}

	fdt_set_off_dt_strings(buf, bufsize);
	fdt_set_totalsize(buf, bufsize);

	return 0;
}
示例#3
0
文件: fdt_sw.c 项目: 274914765/C
int fdt_finish(void *fdt)
{
    int err = check_header_sw(fdt);
    char *p = (char *)fdt;
    uint32_t *end;
    int oldstroffset, newstroffset;
    uint32_t tag;
    int offset, nextoffset;

    if (err)
        return err;

    /* Add terminator */
    end = grab_space(fdt, sizeof(*end));
    if (! end)
        return -FDT_ERR_NOSPACE;
    *end = cpu_to_fdt32(FDT_END);

    /* Relocate the string table */
    oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt);
    newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
    memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt));
    fdt_set_off_dt_strings(fdt, newstroffset);

    /* Walk the structure, correcting string offsets */
    offset = 0;
    while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) {
        if (tag == FDT_PROP) {
            struct fdt_property *prop =
                fdt_offset_ptr_w(fdt, offset, sizeof(*prop));
            int nameoff;

            if (! prop)
                return -FDT_ERR_BADSTRUCTURE;

            nameoff = fdt32_to_cpu(prop->nameoff);
            nameoff += fdt_size_dt_strings(fdt);
            prop->nameoff = cpu_to_fdt32(nameoff);
        }
        offset = nextoffset;
    }

    /* Finally, adjust the header */
    fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt));
    fdt_set_magic(fdt, FDT_MAGIC);
    return 0;
}
int fdt_finish(void *fdt)
{
	char *p = (char *)fdt;
	uint32_t *end;
	int oldstroffset, newstroffset;
	uint32_t tag;
	int offset, nextoffset;

	FDT_SW_CHECK_HEADER(fdt);

	
	end = _fdt_grab_space(fdt, sizeof(*end));
	if (! end)
		return -FDT_ERR_NOSPACE;
	*end = cpu_to_fdt32(FDT_END);

	
	oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt);
	newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
	memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt));
	fdt_set_off_dt_strings(fdt, newstroffset);

	
	offset = 0;
	while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) {
		if (tag == FDT_PROP) {
			struct fdt_property *prop =
				_fdt_offset_ptr_w(fdt, offset);
			int nameoff;

			nameoff = fdt32_to_cpu(prop->nameoff);
			nameoff += fdt_size_dt_strings(fdt);
			prop->nameoff = cpu_to_fdt32(nameoff);
		}
		offset = nextoffset;
	}
	if (nextoffset < 0)
		return nextoffset;

	
	fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt));
	fdt_set_magic(fdt, FDT_MAGIC);
	return 0;
}
示例#5
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;
}
示例#6
0
int fdt_create(void *buf, int bufsize)
{
	void *fdt = buf;

	if (bufsize < (int)sizeof(struct fdt_header))
		return -FDT_ERR_NOSPACE;

	memset(buf, 0, bufsize);

	fdt_set_magic(fdt, FDT_SW_MAGIC);
	fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION);
	fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION);
	fdt_set_totalsize(fdt,  bufsize);

	fdt_set_off_mem_rsvmap(fdt, FDT_ALIGN(sizeof(struct fdt_header),
					      sizeof(struct fdt_reserve_entry)));
	fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt));
	fdt_set_off_dt_strings(fdt, bufsize);

	return 0;
}
示例#7
0
int image_setup_libfdt(bootm_headers_t *images, void *blob,
		       int of_size, struct lmb *lmb)
{
	ulong *initrd_start = &images->initrd_start;
	ulong *initrd_end = &images->initrd_end;
	int ret;

	if (fdt_chosen(blob, 1) < 0) {
		puts("ERROR: /chosen node create failed");
		puts(" - must RESET the board to recover.\n");
		return -1;
	}
	arch_fixup_memory_node(blob);
	if (IMAGE_OF_BOARD_SETUP)
		ft_board_setup(blob, gd->bd);
	fdt_fixup_ethernet(blob);

	/* Delete the old LMB reservation */
	lmb_free(lmb, (phys_addr_t)(u32)(uintptr_t)blob,
		 (phys_size_t)fdt_totalsize(blob));

	ret = fdt_resize(blob);
	if (ret < 0)
		return ret;
	of_size = ret;

	if (*initrd_start && *initrd_end) {
		of_size += FDT_RAMDISK_OVERHEAD;
		fdt_set_totalsize(blob, of_size);
	}
	/* Create a new LMB reservation */
	lmb_reserve(lmb, (ulong)blob, of_size);

	fdt_initrd(blob, *initrd_start, *initrd_end, 1);
	if (!ft_verify_fdt(blob))
		return -1;

	return 0;
}
示例#8
0
static void *copy_fdt(void *fdt)
{
	u64 fdt_size = fdt_totalsize(fdt);
	unsigned long fdt_ram_start = -1L, fdt_pages;
	u64 new_fdt_addr;
	void *new_fdt;
	int i;

        for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
                u64 ram_start = gd->bd->bi_dram[i].start;
                u64 ram_size = gd->bd->bi_dram[i].size;

		if (!ram_size)
			continue;

		if (ram_start < fdt_ram_start)
			fdt_ram_start = ram_start;
	}

	/* Give us at least 4kb breathing room */
	fdt_size = ALIGN(fdt_size + 4096, 4096);
	fdt_pages = fdt_size >> EFI_PAGE_SHIFT;

	/* Safe fdt location is at 128MB */
	new_fdt_addr = fdt_ram_start + (128 * 1024 * 1024) + fdt_size;
	if (efi_allocate_pages(1, EFI_BOOT_SERVICES_DATA, fdt_pages,
			       &new_fdt_addr) != EFI_SUCCESS) {
		/* If we can't put it there, put it somewhere */
		new_fdt_addr = (ulong)memalign(4096, fdt_size);
	}
	new_fdt = (void*)(ulong)new_fdt_addr;
	memcpy(new_fdt, fdt, fdt_totalsize(fdt));
	fdt_set_totalsize(new_fdt, fdt_size);

	return new_fdt;
}
示例#9
0
/**
 * dump_fdt_regions() - Dump regions of an FDT as binary data
 *
 * This dumps an FDT as binary, but only certain regions of it. This is the
 * final stage of the grep - we have a list of regions we want to dump,
 * and this function dumps them.
 *
 * The output of this function may or may not be a valid FDT. To ensure it
 * is, these disp->flags must be set:
 *
 *   FDT_REG_SUPERNODES: ensures that subnodes are preceeded by their
 *		parents. Without this option, fragments of subnode data may be
 *		output without the supernodes above them. This is useful for
 *		hashing but cannot produce a valid FDT.
 *   FDT_REG_ADD_STRING_TAB: Adds a string table to the end of the FDT.
 *		Without this none of the properties will have names
 *   FDT_REG_ADD_MEM_RSVMAP: Adds a mem_rsvmap table - an FDT is invalid
 *		without this.
 *
 * @disp:	Display structure, holding info about our options
 * @blob:	FDT blob to display
 * @region:	List of regions to display
 * @count:	Number of regions
 * @out:	Output destination
 */
static int dump_fdt_regions(struct display_info *disp, const void *blob,
		struct fdt_region region[], int count, char *out)
{
	struct fdt_header *fdt;
	int size, struct_start;
	int ptr;
	int i;

	/* Set up a basic header (even if we don't actually write it) */
	fdt = (struct fdt_header *)out;
	memset(fdt, '\0', sizeof(*fdt));
	fdt_set_magic(fdt, FDT_MAGIC);
	struct_start = FDT_ALIGN(sizeof(struct fdt_header),
					sizeof(struct fdt_reserve_entry));
	fdt_set_off_mem_rsvmap(fdt, struct_start);
	fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION);
	fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION);

	/*
	 * Calculate the total size of the regions we are writing out. The
	 * first will be the mem_rsvmap if the FDT_REG_ADD_MEM_RSVMAP flag
	 * is set. The last will be the string table if FDT_REG_ADD_STRING_TAB
	 * is set.
	 */
	for (i = size = 0; i < count; i++)
		size += region[i].size;

	/* Bring in the mem_rsvmap section from the old file if requested */
	if (count > 0 && (disp->flags & FDT_REG_ADD_MEM_RSVMAP)) {
		struct_start += region[0].size;
		size -= region[0].size;
	}
	fdt_set_off_dt_struct(fdt, struct_start);

	/* Update the header to have the correct offsets/sizes */
	if (count >= 2 && (disp->flags & FDT_REG_ADD_STRING_TAB)) {
		int str_size;

		str_size = region[count - 1].size;
		fdt_set_size_dt_struct(fdt, size - str_size);
		fdt_set_off_dt_strings(fdt, struct_start + size - str_size);
		fdt_set_size_dt_strings(fdt, str_size);
		fdt_set_totalsize(fdt, struct_start + size);
	}

	/* Write the header if required */
	ptr = 0;
	if (disp->header) {
		ptr = sizeof(*fdt);
		while (ptr < fdt_off_mem_rsvmap(fdt))
			out[ptr++] = '\0';
	}

	/* Output all the nodes including any mem_rsvmap/string table */
	for (i = 0; i < count; i++) {
		struct fdt_region *reg = &region[i];

		memcpy(out + ptr, (const char *)blob + reg->offset, reg->size);
		ptr += reg->size;
	}

	return ptr;
}
示例#10
0
int image_setup_libfdt(bootm_headers_t *images, void *blob,
		       int of_size, struct lmb *lmb)
{
	ulong *initrd_start = &images->initrd_start;
	ulong *initrd_end = &images->initrd_end;
	int ret = -EPERM;
	int fdt_ret;

	if (fdt_root(blob) < 0) {
		printf("ERROR: root node setup failed\n");
		goto err;
	}
	if (fdt_chosen(blob) < 0) {
		printf("ERROR: /chosen node create failed\n");
		goto err;
	}
	if (arch_fixup_fdt(blob) < 0) {
		printf("ERROR: arch-specific fdt fixup failed\n");
		goto err;
	}
	if (IMAGE_OF_BOARD_SETUP) {
		fdt_ret = ft_board_setup(blob, gd->bd);
		if (fdt_ret) {
			printf("ERROR: board-specific fdt fixup failed: %s\n",
			       fdt_strerror(fdt_ret));
			goto err;
		}
	}
	if (IMAGE_OF_SYSTEM_SETUP) {
		fdt_ret = ft_system_setup(blob, gd->bd);
		if (fdt_ret) {
			printf("ERROR: system-specific fdt fixup failed: %s\n",
			       fdt_strerror(fdt_ret));
			goto err;
		}
	}
	fdt_fixup_ethernet(blob);

	/* Delete the old LMB reservation */
	lmb_free(lmb, (phys_addr_t)(u32)(uintptr_t)blob,
		 (phys_size_t)fdt_totalsize(blob));

	ret = fdt_shrink_to_minimum(blob);
	if (ret < 0)
		goto err;
	of_size = ret;

	if (*initrd_start && *initrd_end) {
		of_size += FDT_RAMDISK_OVERHEAD;
		fdt_set_totalsize(blob, of_size);
	}
	/* Create a new LMB reservation */
	lmb_reserve(lmb, (ulong)blob, of_size);

	fdt_initrd(blob, *initrd_start, *initrd_end);
	if (!ft_verify_fdt(blob))
		goto err;

#if defined(CONFIG_SOC_KEYSTONE)
	if (IMAGE_OF_BOARD_SETUP)
		ft_board_setup_ex(blob, gd->bd);
#endif

	return 0;
err:
	printf(" - must RESET the board to recover.\n\n");

	return ret;
}
示例#11
0
/**
 * boot_relocate_fdt - relocate flat device tree
 * @lmb: pointer to lmb handle, will be used for memory mgmt
 * @of_flat_tree: pointer to a char* variable, will hold fdt start address
 * @of_size: pointer to a ulong variable, will hold fdt length
 *
 * boot_relocate_fdt() allocates a region of memory within the bootmap and
 * relocates the of_flat_tree into that region, even if the fdt is already in
 * the bootmap.  It also expands the size of the fdt by CONFIG_SYS_FDT_PAD
 * bytes.
 *
 * of_flat_tree and of_size are set to final (after relocation) values
 *
 * returns:
 *      0 - success
 *      1 - failure
 */
int boot_relocate_fdt(struct lmb *lmb, char **of_flat_tree, ulong *of_size)
{
	void	*fdt_blob = *of_flat_tree;
	void	*of_start = NULL;
	char	*fdt_high;
	ulong	of_len = 0;
	int	err;
	int	disable_relocation = 0;

	/* nothing to do */
	if (*of_size == 0)
		return 0;

	if (fdt_check_header(fdt_blob) != 0) {
		fdt_error("image is not a fdt");
		goto error;
	}

	/* position on a 4K boundary before the alloc_current */
	/* Pad the FDT by a specified amount */
	of_len = *of_size + CONFIG_SYS_FDT_PAD;

	/* If fdt_high is set use it to select the relocation address */
	fdt_high = getenv("fdt_high");
	if (fdt_high) {
		void *desired_addr = (void *)simple_strtoul(fdt_high, NULL, 16);

		if (((ulong) desired_addr) == ~0UL) {
			/* All ones means use fdt in place */
			of_start = fdt_blob;
			lmb_reserve(lmb, (ulong)of_start, of_len);
			disable_relocation = 1;
		} else if (desired_addr) {
			of_start =
			    (void *)(ulong) lmb_alloc_base(lmb, of_len, 0x1000,
							   (ulong)desired_addr);
			if (of_start == NULL) {
				puts("Failed using fdt_high value for Device Tree");
				goto error;
			}
		} else {
			of_start =
			    (void *)(ulong) lmb_alloc(lmb, of_len, 0x1000);
		}
	} else {
		of_start =
		    (void *)(ulong) lmb_alloc_base(lmb, of_len, 0x1000,
						   getenv_bootm_mapsize()
						   + getenv_bootm_low());
	}

	if (of_start == NULL) {
		puts("device tree - allocation error\n");
		goto error;
	}

	if (disable_relocation) {
		/*
		 * We assume there is space after the existing fdt to use
		 * for padding
		 */
		fdt_set_totalsize(of_start, of_len);
		printf("   Using Device Tree in place at %p, end %p\n",
		       of_start, of_start + of_len - 1);
	} else {
		debug("## device tree at %p ... %p (len=%ld [0x%lX])\n",
		      fdt_blob, fdt_blob + *of_size - 1, of_len, of_len);

		printf("   Loading Device Tree to %p, end %p ... ",
		       of_start, of_start + of_len - 1);

		err = fdt_open_into(fdt_blob, of_start, of_len);
		if (err != 0) {
			fdt_error("fdt move failed");
			goto error;
		}
		puts("OK\n");
	}

	*of_flat_tree = of_start;
	*of_size = of_len;

	set_working_fdt_addr((ulong)*of_flat_tree);
	return 0;

error:
	return 1;
}