199767f8919635c4928607450d9e0abb932109ceToomas Soome * Copyright (c) 2009-2010 The FreeBSD Foundation
199767f8919635c4928607450d9e0abb932109ceToomas Soome * All rights reserved.
199767f8919635c4928607450d9e0abb932109ceToomas Soome * This software was developed by Semihalf under sponsorship from
199767f8919635c4928607450d9e0abb932109ceToomas Soome * the FreeBSD Foundation.
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Redistribution and use in source and binary forms, with or without
199767f8919635c4928607450d9e0abb932109ceToomas Soome * modification, are permitted provided that the following conditions
199767f8919635c4928607450d9e0abb932109ceToomas Soome * 1. Redistributions of source code must retain the above copyright
199767f8919635c4928607450d9e0abb932109ceToomas Soome * notice, this list of conditions and the following disclaimer.
199767f8919635c4928607450d9e0abb932109ceToomas Soome * 2. Redistributions in binary form must reproduce the above copyright
199767f8919635c4928607450d9e0abb932109ceToomas Soome * notice, this list of conditions and the following disclaimer in the
199767f8919635c4928607450d9e0abb932109ceToomas Soome * documentation and/or other materials provided with the distribution.
199767f8919635c4928607450d9e0abb932109ceToomas Soome * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
199767f8919635c4928607450d9e0abb932109ceToomas Soome * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
199767f8919635c4928607450d9e0abb932109ceToomas Soome * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
199767f8919635c4928607450d9e0abb932109ceToomas Soome * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
199767f8919635c4928607450d9e0abb932109ceToomas Soome * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
199767f8919635c4928607450d9e0abb932109ceToomas Soome * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
199767f8919635c4928607450d9e0abb932109ceToomas Soome * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
199767f8919635c4928607450d9e0abb932109ceToomas Soome * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
199767f8919635c4928607450d9e0abb932109ceToomas Soome * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
199767f8919635c4928607450d9e0abb932109ceToomas Soome * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
199767f8919635c4928607450d9e0abb932109ceToomas Soome * SUCH DAMAGE.
199767f8919635c4928607450d9e0abb932109ceToomas Soome#define debugf(fmt, args...) do { printf("%s(): ", __func__); \
199767f8919635c4928607450d9e0abb932109ceToomas Soome#define COPYOUT(s,d,l) archsw.arch_copyout(s, d, l)
199767f8919635c4928607450d9e0abb932109ceToomas Soome#define COPYIN(s,d,l) archsw.arch_copyin(s, d, l)
199767f8919635c4928607450d9e0abb932109ceToomas Soome/* Location of FDT yet to be loaded. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome/* This may be in read-only memory, so can't be manipulated directly. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome/* Location of FDT on heap. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome/* This is the copy we actually manipulate. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome/* Size of FDT blob */
199767f8919635c4928607450d9e0abb932109ceToomas Soome/* Location of FDT in kernel or module. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome/* This won't be set if FDT is loaded from disk or memory. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome/* If it is set, we'll update it when fdt_copy() gets called. */
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int fdt_cmd_addr(int argc, char *argv[]);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int fdt_cmd_mkprop(int argc, char *argv[]);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int fdt_cmd_prop(int argc, char *argv[]);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int fdt_cmd_mknode(int argc, char *argv[]);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int fdt_cmd_mres(int argc, char *argv[]);
199767f8919635c4928607450d9e0abb932109ceToomas Soome { "mknode", &fdt_cmd_mknode, CMD_REQUIRES_BLOB },
199767f8919635c4928607450d9e0abb932109ceToomas Soome { "mkprop", &fdt_cmd_mkprop, CMD_REQUIRES_BLOB },
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Locate the dynamic symbols and strtab. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (shdr[i].sh_type == SHT_DYNSYM && symtab == 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome } else if (shdr[i].sh_type == SHT_STRTAB && strtab == 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome * The most efficent way to find a symbol would be to calculate a
199767f8919635c4928607450d9e0abb932109ceToomas Soome * hash, find proper bucket and chain, and thus find a symbol.
199767f8919635c4928607450d9e0abb932109ceToomas Soome * However, that would involve code duplication (e.g. for hash
199767f8919635c4928607450d9e0abb932109ceToomas Soome * function). So we're using simpler and a bit slower way: we're
199767f8919635c4928607450d9e0abb932109ceToomas Soome * iterating through symbols, searching for the one which name is
199767f8919635c4928607450d9e0abb932109ceToomas Soome * 'equal' to 'fdt_static_dtb'. To speed up the process a little bit,
199767f8919635c4928607450d9e0abb932109ceToomas Soome * we are eliminating symbols type of which is not STT_NOTYPE, or(and)
199767f8919635c4928607450d9e0abb932109ceToomas Soome * those which binding attribute is not STB_GLOBAL.
199767f8919635c4928607450d9e0abb932109ceToomas Soome debugf("fdt_load_dtb(0x%08jx)\n", (uintmax_t)va);
199767f8919635c4928607450d9e0abb932109ceToomas Soome snprintf(command_errbuf, sizeof (command_errbuf),
199767f8919635c4928607450d9e0abb932109ceToomas Soome "incompatible blob version: %d, should be: %d",
199767f8919635c4928607450d9e0abb932109ceToomas Soome fdt_version(fdtp), FDT_LAST_SUPPORTED_VERSION);
199767f8919635c4928607450d9e0abb932109ceToomas Soome snprintf(command_errbuf, sizeof (command_errbuf),
199767f8919635c4928607450d9e0abb932109ceToomas Soome "error validating blob: %s", fdt_strerror(err));
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Release previous blob
199767f8919635c4928607450d9e0abb932109ceToomas Soome command_errmsg = "can't allocate memory for device tree copy";
199767f8919635c4928607450d9e0abb932109ceToomas Soome debugf("DTB blob found at 0x%jx, size: 0x%jx\n", (uintmax_t)va, (uintmax_t)fdtp_size);
199767f8919635c4928607450d9e0abb932109ceToomas Soome snprintf(command_errbuf, sizeof (command_errbuf),
199767f8919635c4928607450d9e0abb932109ceToomas Soome "error validating blob: %s", fdt_strerror(err));
199767f8919635c4928607450d9e0abb932109ceToomas Soome command_errmsg = "can't allocate memory for device tree copy";
199767f8919635c4928607450d9e0abb932109ceToomas Soome fdtp_va = 0; // Don't write this back into module or kernel.
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Attempt to load and validate a new dtb from a file. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if ((bfp = file_loadraw(filename, "dtb", 1)) == NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome snprintf(command_errbuf, sizeof (command_errbuf),
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* A new dtb was validated, discard any previous file. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* If we already loaded a file, use it. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if ((bfp = file_findfile(NULL, "dtb")) != NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* If we were given the address of a valid blob in memory, use it. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome printf("Using DTB from memory address 0x%p.\n",
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* If there is a dtb compiled into the kernel, use it. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome command_errmsg = "No device tree blob found!\n";
199767f8919635c4928607450d9e0abb932109ceToomas Soome#define fdt_strtovect(str, cellbuf, lim, cellsize) _fdt_strtovect((str), \
199767f8919635c4928607450d9e0abb932109ceToomas Soome/* Force using base 16 */
199767f8919635c4928607450d9e0abb932109ceToomas Soome#define fdt_strtovectx(str, cellbuf, lim, cellsize) _fdt_strtovect((str), \
199767f8919635c4928607450d9e0abb932109ceToomas Soome_fdt_strtovect(const char *str, void *cellbuf, int lim, unsigned char cellsize,
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Skip white whitespace(s)/separators */
199767f8919635c4928607450d9e0abb932109ceToomas Soome cpu_to_fdt32((uint32_t)strtol(buf, NULL, base));
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Find another number */
199767f8919635c4928607450d9e0abb932109ceToomas Soome while ((isxdigit(*buf) || *buf == 'x') && buf < end)
199767f8919635c4928607450d9e0abb932109ceToomas Soomefdt_fixup_ethernet(const char *str, char *ethstr, int len)
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Convert macaddr string into a vector of uints */
199767f8919635c4928607450d9e0abb932109ceToomas Soome fdt_strtovectx(str, &tmp_addr, 6, sizeof(uint8_t));
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Set actual property to a value from vect */
199767f8919635c4928607450d9e0abb932109ceToomas Soome fdt_setprop(fdtp, fdt_path_offset(fdtp, ethstr),
199767f8919635c4928607450d9e0abb932109ceToomas Soome "local-mac-address", &tmp_addr, 6 * sizeof(uint8_t));
199767f8919635c4928607450d9e0abb932109ceToomas Soomefdt_fixup_cpubusfreqs(unsigned long cpufreq, unsigned long busfreq)
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* We want to modify every subnode of /cpus */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* maxo should contain offset of node next to /cpus */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Find CPU frequency properties */
199767f8919635c4928607450d9e0abb932109ceToomas Soome o = fdt_node_offset_by_prop_value(fdtp, o, "clock-frequency",
199767f8919635c4928607450d9e0abb932109ceToomas Soome o2 = fdt_node_offset_by_prop_value(fdtp, o, "bus-frequency", &zero,
199767f8919635c4928607450d9e0abb932109ceToomas Soome while (o != -FDT_ERR_NOTFOUND && o2 != -FDT_ERR_NOTFOUND) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome o2 = fdt_node_offset_by_prop_value(fdtp, lo, "bus-frequency",
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* We're only interested in /cpus subnode(s) */
199767f8919635c4928607450d9e0abb932109ceToomas Soome fdt_setprop_inplace_cell(fdtp, lo, "clock-frequency",
199767f8919635c4928607450d9e0abb932109ceToomas Soome fdt_setprop_inplace_cell(fdtp, lo, "bus-frequency",
199767f8919635c4928607450d9e0abb932109ceToomas Soomefdt_reg_valid(uint32_t *reg, int len, int addr_cells, int size_cells)
199767f8919635c4928607450d9e0abb932109ceToomas Soome tuple_size = cells_in_tuple * sizeof(uint32_t);
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (i = 0; i < tuples; i++) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome cur_start = fdt64_to_cpu(reg[i * cells_in_tuple]);
199767f8919635c4928607450d9e0abb932109ceToomas Soome cur_start = fdt32_to_cpu(reg[i * cells_in_tuple]);
199767f8919635c4928607450d9e0abb932109ceToomas Soome cur_size = fdt64_to_cpu(reg[i * cells_in_tuple + 2]);
199767f8919635c4928607450d9e0abb932109ceToomas Soome cur_size = fdt32_to_cpu(reg[i * cells_in_tuple + 1]);
199767f8919635c4928607450d9e0abb932109ceToomas Soome debugf(" reg#%d (start: 0x%0x size: 0x%0x) valid!\n",
199767f8919635c4928607450d9e0abb932109ceToomas Soomefdt_fixup_memory(struct fdt_mem_region *region, size_t num)
199767f8919635c4928607450d9e0abb932109ceToomas Soome sprintf(command_errbuf, "Could not find root node !");
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Create proper '/memory' node. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome memory = fdt_add_subnode(fdtp, root, "memory");
199767f8919635c4928607450d9e0abb932109ceToomas Soome snprintf(command_errbuf, sizeof (command_errbuf),
199767f8919635c4928607450d9e0abb932109ceToomas Soome "Could not fixup '/memory' "
199767f8919635c4928607450d9e0abb932109ceToomas Soome err = fdt_setprop(fdtp, memory, "device_type", "memory",
199767f8919635c4928607450d9e0abb932109ceToomas Soome sizeof("memory"));
199767f8919635c4928607450d9e0abb932109ceToomas Soome addr_cellsp = (uint32_t *)fdt_getprop(fdtp, root, "#address-cells",
199767f8919635c4928607450d9e0abb932109ceToomas Soome size_cellsp = (uint32_t *)fdt_getprop(fdtp, root, "#size-cells", NULL);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (addr_cellsp == NULL || size_cellsp == NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome snprintf(command_errbuf, sizeof (command_errbuf),
199767f8919635c4928607450d9e0abb932109ceToomas Soome "Could not fixup '/memory' node : "
199767f8919635c4928607450d9e0abb932109ceToomas Soome "%s %s property not found in root node!\n",
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Convert memreserve data to memreserve property
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Check if property already exists
199767f8919635c4928607450d9e0abb932109ceToomas Soome (fdt_getprop(fdtp, root, "memreserve", NULL) == NULL)) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome len = (addr_cells + size_cells) * reserved * sizeof(uint32_t);
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (i = 0; i < reserved; i++) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Ensure endianess, and put cells into a buffer */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Set property */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if ((err = fdt_setprop(fdtp, root, "memreserve", sb, len)) < 0)
199767f8919635c4928607450d9e0abb932109ceToomas Soome printf("Could not fixup 'memreserve' property.\n");
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Count valid memory regions entries in sysinfo. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (i = 0; i < num; i++)
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (region[i].start == 0 && region[i].size == 0)
199767f8919635c4928607450d9e0abb932109ceToomas Soome snprintf(command_errbuf, sizeof (command_errbuf),
199767f8919635c4928607450d9e0abb932109ceToomas Soome "Could not fixup '/memory' node : "
199767f8919635c4928607450d9e0abb932109ceToomas Soome "sysinfo doesn't contain valid memory regions info!\n");
199767f8919635c4928607450d9e0abb932109ceToomas Soome len = (addr_cells + size_cells) * realmrno * sizeof(uint32_t);
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (i = 0; i < num; i++) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Ensure endianess, and put cells into a buffer */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Set property */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if ((err = fdt_setprop(fdtp, memory, "reg", sb, len)) < 0)
199767f8919635c4928607450d9e0abb932109ceToomas Soome sprintf(command_errbuf, "Could not fixup '/memory' node.\n");
199767f8919635c4928607450d9e0abb932109ceToomas Soome prop = fdt_get_property(fdtp, no, "stdout", &len);
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* If /chosen/stdout does not extist, create it */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (prop == NULL || (prop != NULL && len == 0)) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Serial number too long */
199767f8919635c4928607450d9e0abb932109ceToomas Soome sero = fdt_path_offset(fdtp, (const char *)tmp);
199767f8919635c4928607450d9e0abb932109ceToomas Soome * If serial device we're trying to assign
199767f8919635c4928607450d9e0abb932109ceToomas Soome * stdout to doesn't exist in DT -- return.
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Locate the blob, fix it up and return its location.
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Create /chosen node (if not exists) */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if ((chosen = fdt_subnode_offset(fdtp, 0, "chosen")) ==
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Value assigned to fixup-applied does not matter. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (fdt_getprop(fdtp, chosen, "fixup-applied", NULL))
199767f8919635c4928607450d9e0abb932109ceToomas Soome fdt_setprop(fdtp, chosen, "fixup-applied", NULL, 0);
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Copy DTB blob to specified location and return size
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Overwrite the FDT with the fixed version. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* XXX Is this really appropriate? */
199767f8919635c4928607450d9e0abb932109ceToomas Soome command_errmsg = "usage is 'fdt <command> [<args>]";
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Validate fdt <command>.
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* found it */
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Check if uboot env vars were parsed already. If not, do it now.
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Call command handler.
199767f8919635c4928607450d9e0abb932109ceToomas Soome sprintf(command_errbuf, "no address specified");
199767f8919635c4928607450d9e0abb932109ceToomas Soome hdr = (struct fdt_header *)strtoul(addr, &cp, 16);
199767f8919635c4928607450d9e0abb932109ceToomas Soome snprintf(command_errbuf, sizeof (command_errbuf),
199767f8919635c4928607450d9e0abb932109ceToomas Soome while ((fp = file_findfile(NULL, "dtb")) != NULL) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Handle path specification relative to cwd */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (o < 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome snprintf(command_errbuf, sizeof (command_errbuf),
199767f8919635c4928607450d9e0abb932109ceToomas Soome snprintf(command_errbuf, sizeof (command_errbuf),
199767f8919635c4928607450d9e0abb932109ceToomas Soome "path too long: %d, max allowed: %d", len, FDT_CWD_LEN - 1);
199767f8919635c4928607450d9e0abb932109ceToomas Soomefdt_cmd_hdr(int argc __unused, char *argv[] __unused)
199767f8919635c4928607450d9e0abb932109ceToomas Soome command_errmsg = "no device tree blob pointer?!";
199767f8919635c4928607450d9e0abb932109ceToomas Soome sprintf(line, "\nFlattened device tree header (%p):\n", fdtp);
199767f8919635c4928607450d9e0abb932109ceToomas Soome sprintf(line, " magic = 0x%08x\n", fdt_magic(fdtp));
199767f8919635c4928607450d9e0abb932109ceToomas Soome sprintf(line, " size = %d\n", fdt_totalsize(fdtp));
199767f8919635c4928607450d9e0abb932109ceToomas Soome sprintf(line, " last compatible version = %d\n",
199767f8919635c4928607450d9e0abb932109ceToomas Soome const char *prevname[FDT_MAX_DEPTH] = { NULL };
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (o < 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome snprintf(command_errbuf, sizeof (command_errbuf),
199767f8919635c4928607450d9e0abb932109ceToomas Soome (o >= 0) && (depth >= 0);
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Skip root (i = 1) when printing devices */
199767f8919635c4928607450d9e0abb932109ceToomas Soomefdt_isprint(const void *data, int len, int *count)
199767f8919635c4928607450d9e0abb932109ceToomas Soome const char *d;
199767f8919635c4928607450d9e0abb932109ceToomas Soome d = (const char *)data;
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (i = 0; i < len; i++) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Count strings */
199767f8919635c4928607450d9e0abb932109ceToomas Soomefdt_data_str(const void *data, int len, int count, char **buf)
199767f8919635c4928607450d9e0abb932109ceToomas Soome const char *d;
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Calculate the length for the string and allocate memory.
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Note that 'len' already includes at least one terminator.
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Each token had already a terminator buried in 'len', but we
199767f8919635c4928607450d9e0abb932109ceToomas Soome * only need one eventually, don't count space for these.
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Each consecutive token requires a ", " separator. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Add some space for surrounding double quotes. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Note that string being put in 'tmp' may be as big as 'buf_len'. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome b[0] = '\0';
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Now that we have space, format the string.
199767f8919635c4928607450d9e0abb932109ceToomas Soome d = (const char *)data + i;
199767f8919635c4928607450d9e0abb932109ceToomas Soome } while (i < len);
199767f8919635c4928607450d9e0abb932109ceToomas Soomefdt_data_cell(const void *data, int len, char **buf)
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Number of cells */
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Calculate the length for the string and allocate memory.
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Each byte translates to 2 output characters */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Each consecutive cell requires a " " separator. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Each cell will have a "0x" prefix */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Space for surrounding <> and terminator */
199767f8919635c4928607450d9e0abb932109ceToomas Soome b = (char *)malloc(l);
199767f8919635c4928607450d9e0abb932109ceToomas Soome b[0] = '\0';
199767f8919635c4928607450d9e0abb932109ceToomas Soome c = (const uint32_t *)((const uint8_t *)data + i);
199767f8919635c4928607450d9e0abb932109ceToomas Soomefdt_data_bytes(const void *data, int len, char **buf)
199767f8919635c4928607450d9e0abb932109ceToomas Soome const char *d;
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Calculate the length for the string and allocate memory.
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Each byte translates to 2 output characters */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Each consecutive byte requires a " " separator. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Each byte will have a "0x" prefix */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Space for surrounding [] and terminator. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome b = (char *)malloc(l);
199767f8919635c4928607450d9e0abb932109ceToomas Soome b[0] = '\0';
199767f8919635c4928607450d9e0abb932109ceToomas Soome sprintf(tmp, "0x%02x%s", d[i], i < len - 1 ? " " : "");
199767f8919635c4928607450d9e0abb932109ceToomas Soomefdt_data_fmt(const void *data, int len, char **buf)
199767f8919635c4928607450d9e0abb932109ceToomas Soome prop = fdt_offset_ptr(fdtp, offset, sizeof(*prop));
199767f8919635c4928607450d9e0abb932109ceToomas Soome name = fdt_string(fdtp, fdt32_to_cpu(prop->nameoff));
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Property without value */
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Process property with value
199767f8919635c4928607450d9e0abb932109ceToomas Soome line = (char *)malloc(strlen(name) + strlen(FDT_PROP_SEP) +
199767f8919635c4928607450d9e0abb932109ceToomas Soome sprintf(command_errbuf, "could not allocate space for string");
199767f8919635c4928607450d9e0abb932109ceToomas Soome sprintf(line, "%s" FDT_PROP_SEP "%s\n", name, buf);
199767f8919635c4928607450d9e0abb932109ceToomas Soomefdt_modprop(int nodeoff, char *propname, void *value, char mode)
199767f8919635c4928607450d9e0abb932109ceToomas Soome const struct fdt_property *p;
199767f8919635c4928607450d9e0abb932109ceToomas Soome p = fdt_get_property(fdtp, nodeoff, propname, NULL);
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Adding inexistant value in mode 1 is forbidden */
199767f8919635c4928607450d9e0abb932109ceToomas Soome sprintf(command_errbuf, "property already exists!");
199767f8919635c4928607450d9e0abb932109ceToomas Soome } else if (mode == 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome sprintf(command_errbuf, "property does not exist!");
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* phandles */
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Data cells */
199767f8919635c4928607450d9e0abb932109ceToomas Soome rv = fdt_setprop(fdtp, nodeoff, propname, &cells,
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Data bytes */
199767f8919635c4928607450d9e0abb932109ceToomas Soome rv = fdt_setprop(fdtp, nodeoff, propname, &cells,
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Default -- string */
199767f8919635c4928607450d9e0abb932109ceToomas Soome rv = fdt_setprop_string(fdtp, nodeoff, propname, value);
199767f8919635c4928607450d9e0abb932109ceToomas Soome "Device tree blob is too small!\n");
199767f8919635c4928607450d9e0abb932109ceToomas Soome "Could not add/modify property!\n");
199767f8919635c4928607450d9e0abb932109ceToomas Soome/* Merge strings from argv into a single string */
199767f8919635c4928607450d9e0abb932109ceToomas Soomefdt_merge_strings(int argc, char *argv[], int start, char **buffer)
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Additional bytes for whitespaces between args */
199767f8919635c4928607450d9e0abb932109ceToomas Soome sprintf(command_errbuf, "could not allocate space "
199767f8919635c4928607450d9e0abb932109ceToomas Soome "for string");
199767f8919635c4928607450d9e0abb932109ceToomas Soome/* Extract offset and name of node/property from a given path */
199767f8919635c4928607450d9e0abb932109ceToomas Soomefdt_extract_nameloc(char **pathp, char **namep, int *nodeoff)
199767f8919635c4928607450d9e0abb932109ceToomas Soome char *path = *pathp, *name = NULL, *subpath = NULL;
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (o < 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome snprintf(command_errbuf, sizeof (command_errbuf),
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Merge property value strings into one */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (fdt_merge_strings(argc, argv, 3, &value) != 0)
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* If value is specified -- try to modify prop. */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (fdt_extract_nameloc(&path, &propname, &o) != 0)
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* User wants to display properties */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (o < 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome snprintf(command_errbuf, sizeof (command_errbuf),
199767f8919635c4928607450d9e0abb932109ceToomas Soome while (depth >= 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Don't process properties of nested nodes */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (fdt_prop(o) != 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome "property");
199767f8919635c4928607450d9e0abb932109ceToomas Soome * This is the end of our starting node, force
199767f8919635c4928607450d9e0abb932109ceToomas Soome * the loop finish.
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Merge property value strings into one */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (fdt_merge_strings(argc, argv, 3, &value) != 0)
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (fdt_extract_nameloc(&path, &propname, &o) != 0)
199767f8919635c4928607450d9e0abb932109ceToomas Soome sprintf(command_errbuf, "no node/property name specified");
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (o < 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* If node not found -- try to find & delete property */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (fdt_extract_nameloc(&path, &propname, &o) != 0)
199767f8919635c4928607450d9e0abb932109ceToomas Soome if ((rv = fdt_delprop(fdtp, o, propname)) != 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome snprintf(command_errbuf, sizeof (command_errbuf),
199767f8919635c4928607450d9e0abb932109ceToomas Soome "could not delete %s\n",
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* If node exists -- remove node */
199767f8919635c4928607450d9e0abb932109ceToomas Soome sprintf(command_errbuf, "could not delete node");
199767f8919635c4928607450d9e0abb932109ceToomas Soome sprintf(command_errbuf, "no node name specified");
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (fdt_extract_nameloc(&path, &nodename, &o) != 0)
199767f8919635c4928607450d9e0abb932109ceToomas Soome "Device tree blob is too small!\n");
199767f8919635c4928607450d9e0abb932109ceToomas Soome "Could not add node!\n");
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (i = 0; i < total; i++) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome sprintf(line, "reg#%d: (start: 0x%jx, size: 0x%jx)\n",