Example #1
0
static int
fdt_nextprop(int offset, char *buf, size_t size)
{
	const struct fdt_property *prop;
	const char *name;
	uint32_t tag;
	int nextoffset, depth;

	depth = 0;
	tag = fdt_next_tag(fdtp, offset, &nextoffset);

	/* Find the next prop */
	do {
		offset = nextoffset;
		tag = fdt_next_tag(fdtp, offset, &nextoffset);

		if (tag == FDT_BEGIN_NODE)
			depth++;
		else if (tag == FDT_END_NODE)
			depth--;
		else if ((tag == FDT_PROP) && (depth == 0)) {
			prop =
			    (const struct fdt_property *)fdt_offset_ptr(fdtp,
			    offset, sizeof(*prop));
			name = fdt_string(fdtp,
			    fdt32_to_cpu(prop->nameoff));
			strncpy(buf, name, size);
			return (strlen(name));
		} else
			depth = -1;
	} while (depth >= 0);

	return (-1);
}
Example #2
0
int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
				  const char *propname,
				  const void *propval, int proplen)
{
	uint32_t tag;
	int offset, nextoffset;
	const void *val;
	int len;

	CHECK_HEADER(fdt);

	if (startoffset >= 0) {
		tag = fdt_next_tag(fdt, startoffset, &nextoffset);
		if (tag != FDT_BEGIN_NODE)
			return -FDT_ERR_BADOFFSET;
	} else {
		nextoffset = 0;
	}

	/* FIXME: The algorithm here is pretty horrible: we scan each
	 * property of a node in fdt_getprop(), then if that didn't
	 * find what we want, we scan over them again making our way
	 * to the next node.  Still it's the easiest to implement
	 * approach; performance can come later. */
	do {
		offset = nextoffset;
		tag = fdt_next_tag(fdt, offset, &nextoffset);

		switch (tag) {
		case FDT_BEGIN_NODE:
			val = fdt_getprop(fdt, offset, propname, &len);
			if (val
			    && (len == proplen)
			    && (memcmp(val, propval, len) == 0))
				return offset;
			break;

		case FDT_PROP:
		case FDT_END:
		case FDT_END_NODE:
		case FDT_NOP:
			break;

		default:
			return -FDT_ERR_BADSTRUCTURE;
		}
	} while (tag != FDT_END);

	return -FDT_ERR_NOTFOUND;
}
Example #3
0
int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
				  const char *compatible)
{
	uint32_t tag;
	int offset, nextoffset;
	int err;

	CHECK_HEADER(fdt);

	if (startoffset >= 0) {
		tag = fdt_next_tag(fdt, startoffset, &nextoffset);
		if (tag != FDT_BEGIN_NODE)
			return -FDT_ERR_BADOFFSET;
	} else {
		nextoffset = 0;
	}

	/* FIXME: The algorithm here is pretty horrible: we scan each
	 * property of a node in fdt_node_check_compatible(), then if
	 * that didn't find what we want, we scan over them again
	 * making our way to the next node.  Still it's the easiest to
	 * implement approach; performance can come later. */
	do {
		offset = nextoffset;
		tag = fdt_next_tag(fdt, offset, &nextoffset);

		switch (tag) {
		case FDT_BEGIN_NODE:
			err = fdt_node_check_compatible(fdt, offset,
							compatible);
			if ((err < 0)
			    && (err != -FDT_ERR_NOTFOUND))
				return err;
			else if (err == 0)
				return offset;
			break;

		case FDT_PROP:
		case FDT_END:
		case FDT_END_NODE:
		case FDT_NOP:
			break;

		default:
			return -FDT_ERR_BADSTRUCTURE;
		}
	} while (tag != FDT_END);

	return -FDT_ERR_NOTFOUND;
}
Example #4
0
/*
 * 다음 property를 찾아서 해당 offset을 리턴
*/
static int _nextprop(const void *fdt, int offset)
{
	uint32_t tag;
	int nextoffset;

	do {
		/*
		 * offset: property의 offset
		 * nextoffset: property offset의 다음 offset
		*/
		tag = fdt_next_tag(fdt, offset, &nextoffset);

		switch (tag) {
		case FDT_END:
			/*
			 * 이미 FDT_END인데 nextoffset이 있다면 에러
			 * (FDT_END인데 다음 offset이 있다가 말이 안됨)
			 * nextoffset<0 라면 에러값이 들어가 있음
			*/
			if (nextoffset >= 0)
				return -FDT_ERR_BADSTRUCTURE;
			else
				return nextoffset;

		// property라면 해당 offset 리턴
		case FDT_PROP:
			return offset;
		}
		// property를 찾을때까지 다음 offset으로 이동
		offset = nextoffset;
	} while (tag == FDT_NOP);

	return -FDT_ERR_NOTFOUND;
}
Example #5
0
int _fdt_check_prop_offset(const void *fdt, int offset)
{
	if ((offset < 0) || (offset % FDT_TAGSIZE)
	    || (fdt_next_tag(fdt, offset, &offset) != FDT_PROP))
		return -FDT_ERR_BADOFFSET;

	return offset;
}
Example #6
0
int _fdt_check_node_offset(const void *fdt, int offset)
{
	if ((offset < 0) || (offset % FDT_TAGSIZE)
	    || (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE))
		return -FDT_ERR_BADOFFSET;

	return offset;
}
Example #7
0
int fdt_subnode_offset_namelen(const void *fdt, int parentoffset,
			       const char *name, int namelen)
{
	int level = 0;
	uint32_t tag;
	int offset, nextoffset;

	CHECK_HEADER(fdt);

	tag = fdt_next_tag(fdt, parentoffset, &nextoffset);
	if (tag != FDT_BEGIN_NODE)
		return -FDT_ERR_BADOFFSET;

	do {
		offset = nextoffset;
		tag = fdt_next_tag(fdt, offset, &nextoffset);

		switch (tag) {
		case FDT_END:
			return -FDT_ERR_TRUNCATED;

		case FDT_BEGIN_NODE:
			level++;
			if (level != 1)
				continue;
			if (nodename_eq(fdt, offset+FDT_TAGSIZE, name, namelen))
				/* Found it! */
				return offset;
			break;

		case FDT_END_NODE:
			level--;
			break;

		case FDT_PROP:
		case FDT_NOP:
			break;

		default:
			return -FDT_ERR_BADSTRUCTURE;
		}
	} while (level >= 0);

	return -FDT_ERR_NOTFOUND;
}
Example #8
0
File: fdt.c Project: 95strat/linux
/*
 * offset을 기준으로 다음 노드를 가져옴
 * 현재 탐색중인 node의 depth를 저장
*/
int fdt_next_node(const void *fdt, int offset, int *depth)
{
	int nextoffset = 0;
	uint32_t tag;

	// "chosen" 맨 처음에는 offset는 0
	if (offset >= 0)
		/*
		 * offset의 유효성 체크
		 * 참고:http://iamroot.org/wiki/lib/exe/fetch.php?media=%EC%8A%A4%ED%84%B0%EB%94%94:dtb_structure.png
		*/
		if ((nextoffset = _fdt_check_node_offset(fdt, offset)) < 0)
			return nextoffset;

	/*
	 * FDT_BEGIN_NODE
	 * - 현재 노드의 tag값을 찾는데 만약에 새로운 노드가 시작되면 depth++
	 * FDT_END_NODE
	 * - 탐색중인 노드가 끝난 경우 depth를 --
	 * depth를 감소했을때 음수가 아닌경우
	 * - childNode가 더이상 없는 경우 nextoffset(0) 리턴

	 * childNode안에 또 childNode가 있을수 있으니 depth로 판별?
	*/
	do {
		offset = nextoffset;
		tag = fdt_next_tag(fdt, offset, &nextoffset);

		switch (tag) {
		case FDT_PROP:
		case FDT_NOP:
			break;

		case FDT_BEGIN_NODE:
			if (depth)
				(*depth)++;
			break;

		case FDT_END_NODE:
			if (depth && ((--(*depth)) < 0))
				return nextoffset;
			break;

		case FDT_END:
			if ((nextoffset >= 0)
			    || ((nextoffset == -FDT_ERR_TRUNCATED) && !depth))
				return -FDT_ERR_NOTFOUND;
			else
				return nextoffset;
		}
	} while (tag != FDT_BEGIN_NODE);

	return offset;
}
Example #9
0
static void prop_get_fdt(Object *obj, Visitor *v, void *opaque,
                        const char *name, Error **errp)
{
    sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(obj);
    int fdt_offset_next, fdt_offset, fdt_depth;
    void *fdt;

    if (!drc->fdt) {
        return;
    }

    fdt = drc->fdt;
    fdt_offset = drc->fdt_start_offset;
    fdt_depth = 0;

    do {
        const char *name = NULL;
        const struct fdt_property *prop = NULL;
        int prop_len = 0, name_len = 0;
        uint32_t tag;

        tag = fdt_next_tag(fdt, fdt_offset, &fdt_offset_next);
        switch (tag) {
        case FDT_BEGIN_NODE:
            fdt_depth++;
            name = fdt_get_name(fdt, fdt_offset, &name_len);
            visit_start_struct(v, NULL, NULL, name, 0, NULL);
            break;
        case FDT_END_NODE:
            /* shouldn't ever see an FDT_END_NODE before FDT_BEGIN_NODE */
            g_assert(fdt_depth > 0);
            visit_end_struct(v, NULL);
            fdt_depth--;
            break;
        case FDT_PROP: {
            int i;
            prop = fdt_get_property_by_offset(fdt, fdt_offset, &prop_len);
            name = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
            visit_start_list(v, name, NULL);
            for (i = 0; i < prop_len; i++) {
                visit_type_uint8(v, (uint8_t *)&prop->data[i], NULL, NULL);

            }
            visit_end_list(v, NULL);
            break;
        }
        default:
            error_setg(&error_abort, "device FDT in unexpected state: %d", tag);
        }
        fdt_offset = fdt_offset_next;
    } while (fdt_depth != 0);
}
Example #10
0
int _fdt_node_end_offset(void *fdt, int nodeoffset)
{
	int level = 0;
	uint32_t tag;
	int offset, nextoffset;

	tag = fdt_next_tag(fdt, nodeoffset, &nextoffset, NULL);
	if (tag != FDT_BEGIN_NODE)
		return -FDT_ERR_BADOFFSET;
	do {
		offset = nextoffset;
		tag = fdt_next_tag(fdt, offset, &nextoffset, NULL);

		switch (tag) {
		case FDT_END:
			return offset;

		case FDT_BEGIN_NODE:
			level++;
			break;

		case FDT_END_NODE:
			level--;
			break;

		case FDT_PROP:
		case FDT_NOP:
			break;

		default:
			return -FDT_ERR_BADSTRUCTURE;
		}
	} while (level >= 0);

	return nextoffset;
}
Example #11
0
const struct fdt_property *fdt_get_property_namelen(const void *fdt,
						    int nodeoffset,
						    const char *name,
						    int namelen, int *lenp)
{
	uint32_t tag;
	const struct fdt_property *prop;
	int offset, nextoffset;
	int err;

	if (((err = fdt_check_header(fdt)) != 0)
	    || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0))
			goto fail;

	nextoffset = err;
	do {
		offset = nextoffset;

		tag = fdt_next_tag(fdt, offset, &nextoffset);
		switch (tag) {
		case FDT_END:
			if (nextoffset < 0)
				err = nextoffset;
			else
				/* FDT_END tag with unclosed nodes */
				err = -FDT_ERR_BADSTRUCTURE;
			goto fail;

		case FDT_PROP:
			prop = _fdt_offset_ptr(fdt, offset);
			if (_fdt_string_eq(fdt, fdt32_to_cpu(prop->nameoff),
					   name, namelen)) {
				/* Found it! */
				if (lenp)
					*lenp = fdt32_to_cpu(prop->len);

				return prop;
			}
			break;
		}
	} while ((tag != FDT_BEGIN_NODE) && (tag != FDT_END_NODE));

	err = -FDT_ERR_NOTFOUND;
 fail:
	if (lenp)
		*lenp = err;
	return NULL;
}
Example #12
0
File: fdt_sw.c Project: 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;
}
Example #13
0
int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
				 int supernodedepth, int *nodedepth)
{
	int level = -1;
	uint32_t tag;
	int offset, nextoffset = 0;
	int supernodeoffset = -FDT_ERR_INTERNAL;

	CHECK_HEADER(fdt);

	if (supernodedepth < 0)
		return -FDT_ERR_NOTFOUND;

	do {
		offset = nextoffset;
		tag = fdt_next_tag(fdt, offset, &nextoffset);
		switch (tag) {
		case FDT_END:
			return -FDT_ERR_BADOFFSET;

		case FDT_BEGIN_NODE:
			level++;
			if (level == supernodedepth)
				supernodeoffset = offset;
			break;

		case FDT_END_NODE:
			level--;
			break;

		case FDT_PROP:
		case FDT_NOP:
			break;

		default:
			return -FDT_ERR_BADSTRUCTURE;
		}
	} while (offset < nodeoffset);

	if (nodedepth)
		*nodedepth = level;

	if (supernodedepth > level)
		return -FDT_ERR_NOTFOUND;
	return supernodeoffset;
}
Example #14
0
static int list_subnodes(const void *blob, int node)
{
	int nextoffset;		/*                              */
	uint32_t tag;		/*             */
	int level = 0;		/*                             */
	const char *pathp;
	int depth = 1;		/*                                */

	while (level >= 0) {
		tag = fdt_next_tag(blob, node, &nextoffset);
		switch (tag) {
		case FDT_BEGIN_NODE:
			pathp = fdt_get_name(blob, node, NULL);
			if (level <= depth) {
				if (pathp == NULL)
					pathp = "/* NULL pointer error */";
				if (*pathp == '\0')
					pathp = "/";	/*                  */
				if (level == 1)
					puts(pathp);
			}
			level++;
			if (level >= MAX_LEVEL) {
				printf("Nested too deep, aborting.\n");
				return 1;
			}
			break;
		case FDT_END_NODE:
			level--;
			if (level == 0)
				level = -1;		/*               */
			break;
		case FDT_END:
			return 1;
		case FDT_PROP:
			break;
		default:
			if (level <= depth)
				printf("Unknown tag 0x%08X\n", tag);
			return 1;
		}
		node = nextoffset;
	}
	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;
}
Example #16
0
int fdt_next_node(const void *fdt, int offset, int *depth)
{
	int nextoffset = 0;
	uint32_t tag;

	if (offset >= 0)
		if ((nextoffset = _fdt_check_node_offset(fdt, offset)) < 0)
			return nextoffset;

	do {
		offset = nextoffset;
		tag = fdt_next_tag(fdt, offset, &nextoffset);

		switch (tag) {
		case FDT_PROP:
		case FDT_NOP:
			break;

		case FDT_BEGIN_NODE:
			if (depth)
				(*depth)++;
			break;

		case FDT_END_NODE:
			if (depth && ((--(*depth)) < 0))
				return nextoffset;
			break;

		case FDT_END:
			if ((nextoffset >= 0)
			    || ((nextoffset == -FDT_ERR_TRUNCATED) && !depth))
				return -FDT_ERR_NOTFOUND;
			else
				return nextoffset;
		}
	} while (tag != FDT_BEGIN_NODE);

	return offset;
}
Example #17
0
int fdt_next_node(const void *fdt, int offset, int *depth)
{
	int nextoffset = 0;
	uint32_t tag;

	if (offset >= 0)
		if ((nextoffset = _fdt_check_node_offset(fdt, offset)) < 0)
			return nextoffset;

	do {
		offset = nextoffset;
		tag = fdt_next_tag(fdt, offset, &nextoffset);

		switch (tag) {
		case FDT_PROP:
		case FDT_NOP:
			break;

		case FDT_BEGIN_NODE:
			if (depth)
				(*depth)++;
			break;

		case FDT_END_NODE:
			if (depth)
				(*depth)--;
			break;

		case FDT_END:
			return -FDT_ERR_NOTFOUND;

		default:
			return -FDT_ERR_BADSTRUCTURE;
		}
	} while (tag != FDT_BEGIN_NODE);

	return offset;
}
Example #18
0
static int _nextprop(const void *fdt, int offset)
{
	uint32_t tag;
	int nextoffset;

	do {
		tag = fdt_next_tag(fdt, offset, &nextoffset);

		switch (tag) {
		case FDT_END:
			if (nextoffset >= 0)
				return -FDT_ERR_BADSTRUCTURE;
			else
				return nextoffset;

		case FDT_PROP:
			return offset;
		}
		offset = nextoffset;
	} while (tag == FDT_NOP);

	return -FDT_ERR_NOTFOUND;
}
/*
 * Recursively print (a portion of) the fdt.  The depth parameter
 * determines how deeply nested the fdt is printed.
 */
static int fdt_print(const char *pathp, char *prop, int depth)
{
	static char tabs[MAX_LEVEL+1] =
		"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"
		"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
	const void *nodep;	/* property node pointer */
	int  nodeoffset;	/* node offset from libfdt */
	int  nextoffset;	/* next node offset from libfdt */
	uint32_t tag;		/* tag */
	int  len;		/* length of the property */
	int  level = 0;		/* keep track of nesting level */
	const struct fdt_property *fdt_prop;

	nodeoffset = fdt_path_offset (fdt, pathp);
	if (nodeoffset < 0) {
		/*
		 * Not found or something else bad happened.
		 */
		printf ("libfdt fdt_path_offset() returned %s\n",
			fdt_strerror(nodeoffset));
		return 1;
	}
	/*
	 * The user passed in a property as well as node path.
	 * Print only the given property and then return.
	 */
	if (prop) {
		nodep = fdt_getprop (fdt, nodeoffset, prop, &len);
		if (len == 0) {
			/* no property value */
			printf("%s %s\n", pathp, prop);
			return 0;
		} else if (len > 0) {
			printf("%s=", prop);
			print_data (nodep, len);
			printf("\n");
			return 0;
		} else {
			printf ("libfdt fdt_getprop(): %s\n",
				fdt_strerror(len));
			return 1;
		}
	}

	/*
	 * The user passed in a node path and no property,
	 * print the node and all subnodes.
	 */
	while(level >= 0) {
		tag = fdt_next_tag(fdt, nodeoffset, &nextoffset);
		switch(tag) {
		case FDT_BEGIN_NODE:
			pathp = fdt_get_name(fdt, nodeoffset, NULL);
			if (level <= depth) {
				if (pathp == NULL)
					pathp = "/* NULL pointer error */";
				if (*pathp == '\0')
					pathp = "/";	/* root is nameless */
				printf("%s%s {\n",
					&tabs[MAX_LEVEL - level], pathp);
			}
			level++;
			if (level >= MAX_LEVEL) {
				printf("Nested too deep, aborting.\n");
				return 1;
			}
			break;
		case FDT_END_NODE:
			level--;
			if (level <= depth)
				printf("%s};\n", &tabs[MAX_LEVEL - level]);
			if (level == 0) {
				level = -1;		/* exit the loop */
			}
			break;
		case FDT_PROP:
			fdt_prop = fdt_offset_ptr(fdt, nodeoffset,
					sizeof(*fdt_prop));
			pathp    = fdt_string(fdt,
					fdt32_to_cpu(fdt_prop->nameoff));
			len      = fdt32_to_cpu(fdt_prop->len);
			nodep    = fdt_prop->data;
			if (len < 0) {
				printf ("libfdt fdt_getprop(): %s\n",
					fdt_strerror(len));
				return 1;
			} else if (len == 0) {
				/* the property has no value */
				if (level <= depth)
					printf("%s%s;\n",
						&tabs[MAX_LEVEL - level],
						pathp);
			} else {
				if (level <= depth) {
					printf("%s%s=",
						&tabs[MAX_LEVEL - level],
						pathp);
					print_data (nodep, len);
					printf(";\n");
				}
			}
			break;
		case FDT_NOP:
			printf("/* NOP */\n", &tabs[MAX_LEVEL - level]);
			break;
		case FDT_END:
			return 1;
		default:
			if (level <= depth)
				printf("Unknown tag 0x%08X\n", tag);
			return 1;
		}
		nodeoffset = nextoffset;
	}
	return 0;
}
Example #20
0
int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
{
	uint32_t tag;
	int p = 0, overflow = 0;
	int offset, nextoffset, namelen;
	const char *name;

	CHECK_HEADER(fdt);

	tag = fdt_next_tag(fdt, 0, &nextoffset);
	if (tag != FDT_BEGIN_NODE)
		return -FDT_ERR_BADSTRUCTURE;

	if (buflen < 2)
		return -FDT_ERR_NOSPACE;
	buf[0] = '/';
	p = 1;

	while (nextoffset <= nodeoffset) {
		offset = nextoffset;
		tag = fdt_next_tag(fdt, offset, &nextoffset);
		switch (tag) {
		case FDT_END:
			return -FDT_ERR_BADOFFSET;

		case FDT_BEGIN_NODE:
			name = fdt_get_name(fdt, offset, &namelen);
			if (!name)
				return namelen;
			if (overflow || ((p + namelen + 1) > buflen)) {
				overflow++;
				break;
			}
			memcpy(buf + p, name, namelen);
			p += namelen;
			buf[p++] = '/';
			break;

		case FDT_END_NODE:
			if (overflow) {
				overflow--;
				break;
			}
			do {
				p--;
			} while  (buf[p-1] != '/');
			break;

		case FDT_PROP:
		case FDT_NOP:
			break;

		default:
			return -FDT_ERR_BADSTRUCTURE;
		}
	}

	if (overflow)
		return -FDT_ERR_NOSPACE;

	if (p > 1) /* special case so that root path is "/", not "" */
		p--;
	buf[p] = '\0';
	return p;
}
Example #21
0
const struct fdt_property *fdt_get_property(const void *fdt,
					    int nodeoffset,
					    const char *name, int *lenp)
{
	uint32_t tag;
	const struct fdt_property *prop;
	int namestroff;
	int offset, nextoffset;
	int err;

	if ((err = fdt_check_header(fdt)) != 0)
		goto fail;

	err = -FDT_ERR_BADOFFSET;
	if (nodeoffset % FDT_TAGSIZE)
		goto fail;

	tag = fdt_next_tag(fdt, nodeoffset, &nextoffset);
	if (tag != FDT_BEGIN_NODE)
		goto fail;

	do {
		offset = nextoffset;

		tag = fdt_next_tag(fdt, offset, &nextoffset);
		switch (tag) {
		case FDT_END:
			err = -FDT_ERR_TRUNCATED;
			goto fail;

		case FDT_BEGIN_NODE:
		case FDT_END_NODE:
		case FDT_NOP:
			break;

		case FDT_PROP:
			err = -FDT_ERR_BADSTRUCTURE;
			prop = fdt_offset_ptr(fdt, offset, sizeof(*prop));
			if (! prop)
				goto fail;
			namestroff = fdt32_to_cpu(prop->nameoff);
			if (streq(fdt_string(fdt, namestroff), name)) {
				/* Found it! */
				int len = fdt32_to_cpu(prop->len);
				prop = fdt_offset_ptr(fdt, offset,
						      sizeof(*prop)+len);
				if (! prop)
					goto fail;

				if (lenp)
					*lenp = len;

				return prop;
			}
			break;

		default:
			err = -FDT_ERR_BADSTRUCTURE;
			goto fail;
		}
	} while ((tag != FDT_BEGIN_NODE) && (tag != FDT_END_NODE));

	err = -FDT_ERR_NOTFOUND;
 fail:
	if (lenp)
		*lenp = err;
	return NULL;
}
Example #22
0
int fdt_find_regions(const void *fdt, char * const inc[], int inc_count,
		     char * const exc_prop[], int exc_prop_count,
		     struct fdt_region region[], int max_regions,
		     char *path, int path_len, int add_string_tab)
{
	int stack[FDT_MAX_DEPTH];
	char *end;
	int nextoffset = 0;
	uint32_t tag;
	int count = 0;
	int start = -1;
	int depth = -1;
	int want = 0;
	int base = fdt_off_dt_struct(fdt);

	end = path;
	*end = '\0';
	do {
		const struct fdt_property *prop;
		const char *name;
		const char *str;
		int include = 0;
		int stop_at = 0;
		int offset;
		int len;

		offset = nextoffset;
		tag = fdt_next_tag(fdt, offset, &nextoffset);
		stop_at = nextoffset;

		switch (tag) {
		case FDT_PROP:
			include = want >= 2;
			stop_at = offset;
			prop = fdt_get_property_by_offset(fdt, offset, NULL);
			str = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
			if (str_in_list(str, exc_prop, exc_prop_count))
				include = 0;
			break;

		case FDT_NOP:
			include = want >= 2;
			stop_at = offset;
			break;

		case FDT_BEGIN_NODE:
			depth++;
			if (depth == FDT_MAX_DEPTH)
				return -FDT_ERR_BADSTRUCTURE;
			name = fdt_get_name(fdt, offset, &len);
			if (end - path + 2 + len >= path_len)
				return -FDT_ERR_NOSPACE;
			if (end != path + 1)
				*end++ = '/';
			strcpy(end, name);
			end += len;
			stack[depth] = want;
			if (want == 1)
				stop_at = offset;
			if (str_in_list(path, inc, inc_count))
				want = 2;
			else if (want)
				want--;
			else
				stop_at = offset;
			include = want;
			break;

		case FDT_END_NODE:
			include = want;
			want = stack[depth--];
			while (end > path && *--end != '/')
				;
			*end = '\0';
			break;

		case FDT_END:
			include = 1;
			break;
		}

		if (include && start == -1) {
			/* Should we merge with previous? */
			if (count && count <= max_regions &&
			    offset == region[count - 1].offset +
					region[count - 1].size - base)
				start = region[--count].offset - base;
			else
				start = offset;
		}

		if (!include && start != -1) {
			if (count < max_regions) {
				region[count].offset = base + start;
				region[count].size = stop_at - start;
			}
			count++;
			start = -1;
		}
	} while (tag != FDT_END);

	if (nextoffset != fdt_size_dt_struct(fdt))
		return -FDT_ERR_BADLAYOUT;

	/* Add a region for the END tag and the string table */
	if (count < max_regions) {
		region[count].offset = base + start;
		region[count].size = nextoffset - start;
		if (add_string_tab)
			region[count].size += fdt_size_dt_strings(fdt);
	}
	count++;

	return count;
}
Example #23
0
static void compare_structure(const void *fdt1, const void *fdt2)
{
	int nextoffset1 = 0, nextoffset2 = 0;
	int offset1, offset2;
	uint32_t tag1, tag2;
	const char *name1, *name2;
	int err;
	const struct fdt_property *prop1, *prop2;
	int len1, len2;

	while (1) {
		do {
			offset1 = nextoffset1;
			tag1 = fdt_next_tag(fdt1, offset1, &nextoffset1);
		} while (tag1 == FDT_NOP);
		do {
			offset2 = nextoffset2;
			tag2 = fdt_next_tag(fdt2, offset2, &nextoffset2);
		} while (tag2 == FDT_NOP);

		if (tag1 != tag2)
			MISMATCH("Tag mismatch (%d != %d) at (%d, %d)",
			     tag1, tag2, offset1, offset2);

		switch (tag1) {
		case FDT_BEGIN_NODE:
			name1 = fdt_get_name(fdt1, offset1, &err);
			if (!name1)
				FAIL("fdt_get_name(fdt1, %d, ..): %s",
				     offset1, fdt_strerror(err));
			name2 = fdt_get_name(fdt2, offset2, NULL);
			if (!name2)
				FAIL("fdt_get_name(fdt2, %d, ..): %s",
				     offset2, fdt_strerror(err));

			if (!streq(name1, name2))
			    MISMATCH("Name mismatch (\"%s\" != \"%s\") at (%d, %d)",
				     name1, name2, offset1, offset2);
			break;

		case FDT_PROP:
			prop1 = fdt_offset_ptr(fdt1, offset1, sizeof(*prop1));
			if (!prop1)
				FAIL("Could get fdt1 property at %d", offset1);
			prop2 = fdt_offset_ptr(fdt2, offset2, sizeof(*prop2));
			if (!prop2)
				FAIL("Could get fdt2 property at %d", offset2);

			name1 = fdt_string(fdt1, fdt32_to_cpu(prop1->nameoff));
			name2 = fdt_string(fdt2, fdt32_to_cpu(prop2->nameoff));
			if (!streq(name1, name2))
				MISMATCH("Property name mismatch \"%s\" != \"%s\" "
					 "at (%d, %d)", name1, name2, offset1, offset2);
			len1 = fdt32_to_cpu(prop1->len);
			len2 = fdt32_to_cpu(prop2->len);
			if (len1 != len2)
				MISMATCH("Property length mismatch %u != %u "
					 "at (%d, %d)", len1, len2, offset1, offset2);

			if (memcmp(prop1->data, prop2->data, len1) != 0)
				MISMATCH("Property value mismatch at (%d, %d)",
					 offset1, offset2);
			break;

		case FDT_END:
			return;
		}
	}
}
static int nlm_fdt_read(char *page, char **start, off_t off,
			     int count, int *eof, void *data)
{
	static char tabs[MAX_LEVEL+1] =
		"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"
		"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
	const void *nodep;	/* property node pointer */
	int  nodeoffset;	/* node offset from libfdt */
	int  nextoffset;	/* next node offset from libfdt */
	uint32_t tag;		/* tag */
	int  len;		/* length of the property */
	int  level = 0;		/* keep track of nesting level */
	const struct fdt_property *fdt_prop;
	int plen = 0;
	const char *pathp = "/";
	int depth = MAX_LEVEL;
	off_t begin = 0;

	working_fdt = (struct fdt_header *)fdt;

	nodeoffset = fdt_path_offset (working_fdt, pathp);
	if (nodeoffset < 0) {
		/*
		 * Not found or something else bad happened.
		 */
		plen += sprintf(page + plen, 
			"libfdt fdt_path_offset() returned %s\n",
			fdt_strerror(nodeoffset));
		goto out;
	}

	/*
	 * The user passed in a node path and no property,
	 * print the node and all subnodes.
	 */
	while(level >= 0) {
		if (!proc_pos_check(&begin, &plen, off, count)) goto out;
		tag = fdt_next_tag(working_fdt, nodeoffset, &nextoffset);
		switch(tag) {
		case FDT_BEGIN_NODE:
			pathp = fdt_get_name(working_fdt, nodeoffset, NULL);
			if (level <= depth) {
				if (pathp == NULL)
					pathp = "/* NULL pointer error */";
				if (*pathp == '\0')
					pathp = "/";	/* root is nameless */
				plen += sprintf(page + plen, "%s%s {\n",
					&tabs[MAX_LEVEL - level], pathp);
			}
			level++;
			if (level >= MAX_LEVEL) {
				plen += sprintf(page + plen, "Nested too deep, aborting.\n");
				goto out;
			}
			break;
		case FDT_END_NODE:
			level--;
			if (level <= depth)
				plen += sprintf(page + plen, "%s};\n", &tabs[MAX_LEVEL - level]);
			if (level == 0) {
				level = -1;		/* exit the loop */
			}
			break;
		case FDT_PROP:
			fdt_prop = fdt_offset_ptr(working_fdt, nodeoffset,
					sizeof(*fdt_prop));
			pathp    = fdt_string(working_fdt,
					fdt32_to_cpu(fdt_prop->nameoff));
			len      = fdt32_to_cpu(fdt_prop->len);
			nodep    = fdt_prop->data;
			if (len < 0) {
				plen += sprintf (page + plen, "libfdt fdt_getprop(): %s\n",
					fdt_strerror(len));
				goto out;
			} else if (len == 0) {
				/* the property has no value */
				if (level <= depth)
					plen += sprintf(page + plen, "%s%s;\n",
						&tabs[MAX_LEVEL - level],
						pathp);
			} else {
				if (level <= depth) {
					plen += sprintf(page + plen, "%s%s = ",
						&tabs[MAX_LEVEL - level],
						pathp);
					plen += print_data (page + plen, nodep, len);
					plen += sprintf(page + plen, ";\n");
				}
			}
			break;
		case FDT_NOP:
			plen += sprintf(page + plen, "%s/* NOP */\n", &tabs[MAX_LEVEL - level]);
			break;
		case FDT_END:
			goto good_out;
		default:
			if (level <= depth)
				plen += sprintf(page + plen, "Unknown tag 0x%08X\n", tag);
			goto out;
		}
		nodeoffset = nextoffset;
	}

	good_out:
	*eof = 1;

	out:
	*start = page + (off - begin);
	plen -= (off - begin);
	if (plen > count)
		plen = count;
	if (plen < 0)
		plen = 0;

	return plen;
}
Example #25
0
/**
 * display_fdt_by_regions() - Display regions of an FDT source
 *
 * This dumps an FDT as source, but only certain regions of it. This is the
 * final stage of the grep - we have a list of regions we want to display,
 * and this function displays them.
 *
 * @disp:	Display structure, holding info about our options
 * @blob:	FDT blob to display
 * @region:	List of regions to display
 * @count:	Number of regions
 */
static int display_fdt_by_regions(struct display_info *disp, const void *blob,
		struct fdt_region region[], int count)
{
	struct fdt_region *reg = region, *reg_end = region + count;
	uint32_t off_mem_rsvmap = fdt_off_mem_rsvmap(blob);
	int base = fdt_off_dt_struct(blob);
	int version = fdt_version(blob);
	int offset, nextoffset;
	int tag, depth, shift;
	FILE *f = disp->fout;
	uint64_t addr, size;
	int in_region;
	int file_ofs;
	int i;

	if (disp->show_dts_version)
		fprintf(f, "/dts-v1/;\n");

	if (disp->header) {
		fprintf(f, "// magic:\t\t0x%x\n", fdt_magic(blob));
		fprintf(f, "// totalsize:\t\t0x%x (%d)\n", fdt_totalsize(blob),
			fdt_totalsize(blob));
		fprintf(f, "// off_dt_struct:\t0x%x\n",
			fdt_off_dt_struct(blob));
		fprintf(f, "// off_dt_strings:\t0x%x\n",
			fdt_off_dt_strings(blob));
		fprintf(f, "// off_mem_rsvmap:\t0x%x\n", off_mem_rsvmap);
		fprintf(f, "// version:\t\t%d\n", version);
		fprintf(f, "// last_comp_version:\t%d\n",
			fdt_last_comp_version(blob));
		if (version >= 2) {
			fprintf(f, "// boot_cpuid_phys:\t0x%x\n",
				fdt_boot_cpuid_phys(blob));
		}
		if (version >= 3) {
			fprintf(f, "// size_dt_strings:\t0x%x\n",
				fdt_size_dt_strings(blob));
		}
		if (version >= 17) {
			fprintf(f, "// size_dt_struct:\t0x%x\n",
				fdt_size_dt_struct(blob));
		}
		fprintf(f, "\n");
	}

	if (disp->flags & FDT_REG_ADD_MEM_RSVMAP) {
		const struct fdt_reserve_entry *p_rsvmap;

		p_rsvmap = (const struct fdt_reserve_entry *)
				((const char *)blob + off_mem_rsvmap);
		for (i = 0; ; i++) {
			addr = fdt64_to_cpu(p_rsvmap[i].address);
			size = fdt64_to_cpu(p_rsvmap[i].size);
			if (addr == 0 && size == 0)
				break;

			fprintf(f, "/memreserve/ %llx %llx;\n",
				(unsigned long long)addr,
				(unsigned long long)size);
		}
	}

	depth = 0;
	nextoffset = 0;
	shift = 4;	/* 4 spaces per indent */
	do {
		const struct fdt_property *prop;
		const char *name;
		int show;
		int len;

		offset = nextoffset;

		/*
		 * Work out the file offset of this offset, and decide
		 * whether it is in the region list or not
		 */
		file_ofs = base + offset;
		if (reg < reg_end && file_ofs >= reg->offset + reg->size)
			reg++;
		in_region = reg < reg_end && file_ofs >= reg->offset &&
				file_ofs < reg->offset + reg->size;
		tag = fdt_next_tag(blob, offset, &nextoffset);

		if (tag == FDT_END)
			break;
		show = in_region || disp->all;
		if (show && disp->diff)
			fprintf(f, "%c", in_region ? '+' : '-');

		if (!show) {
			/* Do this here to avoid 'if (show)' in every 'case' */
			if (tag == FDT_BEGIN_NODE)
				depth++;
			else if (tag == FDT_END_NODE)
				depth--;
			continue;
		}
		if (tag != FDT_END) {
			if (disp->show_addr)
				fprintf(f, "%4x: ", file_ofs);
			if (disp->show_offset)
				fprintf(f, "%4x: ", file_ofs - base);
		}

		/* Green means included, red means excluded */
		if (disp->colour)
			print_ansi_colour(f, in_region ? COL_GREEN : COL_RED);

		switch (tag) {
		case FDT_PROP:
			prop = fdt_get_property_by_offset(blob, offset, NULL);
			name = fdt_string(blob, fdt32_to_cpu(prop->nameoff));
			fprintf(f, "%*s%s", depth * shift, "", name);
			utilfdt_print_data(prop->data,
					   fdt32_to_cpu(prop->len));
			fprintf(f, ";");
			break;

		case FDT_NOP:
			fprintf(f, "%*s// [NOP]", depth * shift, "");
			break;

		case FDT_BEGIN_NODE:
			name = fdt_get_name(blob, offset, &len);
			fprintf(f, "%*s%s {", depth++ * shift, "",
				*name ? name : "/");
			break;

		case FDT_END_NODE:
			fprintf(f, "%*s};", --depth * shift, "");
			break;
		}

		/* Reset colour back to normal before end of line */
		if (disp->colour)
			print_ansi_colour(f, COL_NONE);
		fprintf(f, "\n");
	} while (1);

	/* Print a list of strings if requested */
	if (disp->list_strings) {
		const char *str;
		int str_base = fdt_off_dt_strings(blob);

		for (offset = 0; offset < fdt_size_dt_strings(blob);
				offset += strlen(str) + 1) {
			str = fdt_string(blob, offset);
			int len = strlen(str) + 1;
			int show;

			/* Only print strings that are in the region */
			file_ofs = str_base + offset;
			in_region = reg < reg_end &&
					file_ofs >= reg->offset &&
					file_ofs + len < reg->offset +
						reg->size;
			show = in_region || disp->all;
			if (show && disp->diff)
				printf("%c", in_region ? '+' : '-');
			if (disp->show_addr)
				printf("%4x: ", file_ofs);
			if (disp->show_offset)
				printf("%4x: ", offset);
			printf("%s\n", str);
		}
	}

	return 0;
}
Example #26
0
/*
 * Flattened Device Tree command, see the help for parameter definitions.
 */
int do_fdt (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
{
	char		op;

	if (argc < 2) {
		printf ("Usage:\n%s\n", cmdtp->usage);
		return 1;
	}

	/*
	 * Figure out which subcommand was given
	 */
	op = argv[1][0];
	/********************************************************************
	 * Set the address of the fdt
	 ********************************************************************/
	if (op == 'a') {
		/*
		 * Set the address [and length] of the fdt.
		 */
		fdt = (struct fdt_header *)simple_strtoul(argv[2], NULL, 16);

		if (!fdt_valid()) {
			return 1;
		}

		if (argc >= 4) {
			int  len;
			int  err;
			/*
			 * Optional new length
			 */
			len =  simple_strtoul(argv[3], NULL, 16);
			if (len < fdt_totalsize(fdt)) {
				printf ("New length %d < existing length %d, ignoring.\n",
					len, fdt_totalsize(fdt));
			} else {
				/*
				 * Open in place with a new length.
				 */
				err = fdt_open_into(fdt, fdt, len);
				if (err != 0) {
					printf ("libfdt: %s\n", fdt_strerror(err));
				}
			}
		}

	/********************************************************************
	 * Move the fdt
	 ********************************************************************/
	} else if (op == 'm' && argv[1][1] == 'o') {
		struct fdt_header *newaddr;
		int  len;
		int  err;

		if (argc != 5) {
			printf ("Usage:\n%s\n", cmdtp->usage);
			return 1;
		}

		/*
		 * Set the address and length of the fdt.
		 */
		fdt = (struct fdt_header *)simple_strtoul(argv[2], NULL, 16);
		if (!fdt_valid()) {
			return 1;
		}

		newaddr = (struct fdt_header *)simple_strtoul(argv[3], NULL, 16);
		len     =  simple_strtoul(argv[4], NULL, 16);
		if (len < fdt_totalsize(fdt)) {
			printf ("New length %d < existing length %d, aborting.\n",
				len, fdt_totalsize(fdt));
			return 1;
		}

		/*
		 * Copy to the new location.
		 */
		err = fdt_open_into(fdt, newaddr, len);
		if (err != 0) {
			printf ("libfdt: %s\n", fdt_strerror(err));
			return 1;
		}
		fdt = newaddr;

	/********************************************************************
	 * mknode 
	 ********************************************************************/
	} else if (op == 'm' && argv[1][1] == 'k') {
		char *pathp = argv[2];
		char *node = argv[3];
		int nodeoffset;

		if (argc != 4) {
			printf ("Usage:\n%s\n", cmdtp->usage);
			return 1;
		}
			
		/*
		 * See if the node already exists
		 */
		if (strcmp(pathp, "/") == 0)
			nodeoffset = 0;
		else
			nodeoffset = fdt_path_offset (fdt, pathp);

		if (nodeoffset < 0) {
			printf("parent node %s doesn't exist\n", pathp);
			return 1;
		}

		/*
		 * Create the new node
		 */
		nodeoffset = fdt_add_subnode(fdt, nodeoffset, node);
		if (nodeoffset < 0) {
			printf("libfdt: %s\n", fdt_strerror(nodeoffset));
			return 1;
		}

	/********************************************************************
	 * Set the value of a node in the fdt.
	 ********************************************************************/
	} else if (op == 's') {
		char *pathp;		/* path */
		char *prop;			/* property */
		struct fdt_property *nodep;	/* node struct pointer */
		char *newval;		/* value from the user (as a string) */
		char *vp;			/* temporary value pointer */
		char *cp;			/* temporary char pointer */
		int  nodeoffset;	/* node offset from libfdt */
		int  len;			/* new length of the property */
		int  oldlen;		/* original length of the property */
		unsigned long tmp;	/* holds converted values */
		int  ret;			/* return value */

		/*
		 * Parameters: Node path, property, value.
		 */
		if (argc < 5) {
			printf ("Usage:\n%s\n", cmdtp->usage);
			return 1;
		}

		pathp  = argv[2];
		prop   = argv[3];
		newval = argv[4];

		if (strcmp(pathp, "/") == 0) {
			nodeoffset = 0;
		} else {
			nodeoffset = fdt_path_offset (fdt, pathp);
			if (nodeoffset < 0) {
				/*
			 	 * Not found or something else bad happened.
			 	 */
				printf ("libfdt: %s\n", fdt_strerror(nodeoffset));
				return 1;
			}
		}
		nodep = fdt_getprop (fdt, nodeoffset, prop, &oldlen);
		if (oldlen == 0) {
			/*
			 * The specified property has no value
			 */
			printf("%s has no value, cannot set one (yet).\n", prop);
			return 1;
		} else {
			/*
			 * Convert the new property
			 */
			vp = data;
			if (*newval == '<') {
				/*
				 * Bigger values than bytes.
				 */
				len = 0;
				newval++;
				while ((*newval != '>') && (*newval != '\0')) {
					cp = newval;
					tmp = simple_strtoul(cp, &newval, 16);
					if ((newval - cp) <= 2) {
						*vp = tmp & 0xFF;
						vp  += 1;
						len += 1;
					} else if ((newval - cp) <= 4) {
						*(uint16_t *)vp = __cpu_to_be16(tmp);
						vp  += 2;
						len += 2;
					} else if ((newval - cp) <= 8) {
						*(uint32_t *)vp = __cpu_to_be32(tmp);
						vp  += 4;
						len += 4;
					} else {
						printf("Sorry, I could not convert \"%s\"\n", cp);
						return 1;
					}
					while (*newval == ' ')
						newval++;
				}
				if (*newval != '>') {
					printf("Unexpected character '%c'\n", *newval);
					return 1;
				}
			} else if (*newval == '[') {
				/*
				 * Byte stream.  Convert the values.
				 */
				len = 0;
				newval++;
				while ((*newval != ']') && (*newval != '\0')) {
					tmp = simple_strtoul(newval, &newval, 16);
					*vp++ = tmp & 0xFF;
					len++;
					while (*newval == ' ')
						newval++;
				}
				if (*newval != ']') {
					printf("Unexpected character '%c'\n", *newval);
					return 1;
				}
			} else {
				/*
				 * Assume it is a string.  Copy it into our data area for
				 * convenience (including the terminating '\0').
				 */
				len = strlen(newval) + 1;
				strcpy(data, newval);
			}

			ret = fdt_setprop(fdt, nodeoffset, prop, data, len);
			if (ret < 0) {
				printf ("libfdt %s\n", fdt_strerror(ret));
				return 1;
			}
		}

	/********************************************************************
	 * Print (recursive) / List (single level)
	 ********************************************************************/
	} else if ((op == 'p') || (op == 'l')) {
		/*
		 * Recursively print (a portion of) the fdt.
		 */
		static int offstack[MAX_LEVEL];
		static char tabs[MAX_LEVEL+1] = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
		int depth = MAX_LEVEL;	/* how deep to print */
		char *pathp;		/* path */
		char *prop;			/* property */
		void *nodep;		/* property node pointer */
		int  nodeoffset;	/* node offset from libfdt */
		int  nextoffset;	/* next node offset from libfdt */
		uint32_t tag;		/* tag */
		int  len;			/* length of the property */
		int  level = 0;		/* keep track of nesting level */

		/*
		 * list is an alias for print, but limited to 1 level
		 */
		if (op == 'l') {
			depth = 1;
		}

		/*
		 * Get the starting path.  The root node is an oddball,
		 * the offset is zero and has no name.
		 */
		pathp = argv[2];
		if (argc > 3)
			prop = argv[3];
		else
			prop = NULL;

		if (strcmp(pathp, "/") == 0) {
			nodeoffset = 0;
			printf("/");
		} else {
			nodeoffset = fdt_path_offset (fdt, pathp);
			if (nodeoffset < 0) {
				/*
				 * Not found or something else bad happened.
				 */
				printf ("libfdt %s\n", fdt_strerror(nodeoffset));
				return 1;
			}
		}
		/*
		 * The user passed in a property as well as node path.  Print only
		 * the given property and then return.
		 */
		if (prop) {
			nodep = fdt_getprop (fdt, nodeoffset, prop, &len);
			if (len == 0) {
				printf("%s %s\n", pathp, prop);	/* no property value */
				return 0;
			} else if (len > 0) {
				printf("%s=", prop);
				print_data (nodep, len);
				printf("\n");
				return 0;
			} else {
				printf ("libfdt %s\n", fdt_strerror(len));
				return 1;
			}
		}

		/*
		 * The user passed in a node path and no property, print the node
		 * and all subnodes.
		 */
		offstack[0] = nodeoffset;

		while(level >= 0) {
			tag = fdt_next_tag(fdt, nodeoffset, &nextoffset, &pathp);
			switch(tag) {
			case FDT_BEGIN_NODE:
				if(level <= depth)
					printf("%s%s {\n", &tabs[MAX_LEVEL - level], pathp);
				level++;
				offstack[level] = nodeoffset;
				if (level >= MAX_LEVEL) {
					printf("Aaaiii <splat> nested too deep.\n");
					return 1;
				}
				break;
			case FDT_END_NODE:
				level--;
				if(level <= depth)
					printf("%s};\n", &tabs[MAX_LEVEL - level]);
				if (level == 0) {
					level = -1;		/* exit the loop */
				}
				break;
			case FDT_PROP:
				nodep = fdt_getprop (fdt, offstack[level], pathp, &len);
				if (len < 0) {
					printf ("libfdt %s\n", fdt_strerror(len));
					return 1;
				} else if (len == 0) {
					/* the property has no value */
					if(level <= depth)
						printf("%s%s;\n", &tabs[MAX_LEVEL - level], pathp);
				} else {
					if(level <= depth) {
						printf("%s%s=", &tabs[MAX_LEVEL - level], pathp);
						print_data (nodep, len);
						printf(";\n");
					}
				}
				break;
			case FDT_NOP:
				break;
			case FDT_END:
				return 1;
			default:
				if(level <= depth)
					printf("Unknown tag 0x%08X\n", tag);
				return 1;
			}
			nodeoffset = nextoffset;
		}

	/********************************************************************
	 * Remove a property/node
	 ********************************************************************/
	} else if (op == 'r') {
		int  nodeoffset;	/* node offset from libfdt */
		int  err;

		/*
		 * Get the path.  The root node is an oddball, the offset
		 * is zero and has no name.
		 */
		if (strcmp(argv[2], "/") == 0) {
			nodeoffset = 0;
		} else {
			nodeoffset = fdt_path_offset (fdt, argv[2]);
			if (nodeoffset < 0) {
				/*
				 * Not found or something else bad happened.
				 */
				printf ("libfdt %s\n", fdt_strerror(nodeoffset));
				return 1;
			}
		}
		/*
		 * Do the delete.  A fourth parameter means delete a property,
		 * otherwise delete the node.
		 */
		if (argc > 3) {
			err = fdt_delprop(fdt, nodeoffset, argv[3]);
			if (err < 0) {
				printf("fdt_delprop libfdt: %s\n", fdt_strerror(err));
				return err;
			}
		} else {
			err = fdt_del_node(fdt, nodeoffset);
			if (err < 0) {
				printf("fdt_del_node libfdt: %s\n", fdt_strerror(err));
				return err;
			}
		}

	/********************************************************************
	 * Create a chosen node
	 ********************************************************************/
	} else if (op == 'c') {
		fdt_chosen(fdt, 0, 0, 1);

#ifdef CONFIG_OF_HAS_UBOOT_ENV
	/********************************************************************
	 * Create a u-boot-env node
	 ********************************************************************/
	} else if (op == 'e') {
		fdt_env(fdt);
#endif 
#ifdef CONFIG_OF_HAS_BD_T
	/********************************************************************
	 * Create a bd_t node
	 ********************************************************************/
	} else if (op == 'b') {
		fdt_bd_t(fdt);
#endif
	/********************************************************************
	 * Unrecognized command
	 ********************************************************************/
	} else {
		printf ("Usage:\n%s\n", cmdtp->usage);
		return 1;
	}

	return 0;
}