diff options
| author | Thomas Gleixner <tglx@linutronix.de> | 2009-05-20 09:02:28 +0200 | 
|---|---|---|
| committer | Thomas Gleixner <tglx@linutronix.de> | 2009-05-20 09:02:28 +0200 | 
| commit | 521c180874dae86f675d23c4eade4dba8b1f2cc8 (patch) | |
| tree | 7509303da3a9a1b40a26f6811f321c89cd31737b /scripts/dtc | |
| parent | f1a11e0576c7a73d759d05d776692b2b2d37172b (diff) | |
| parent | 64d1304a64477629cb16b75491a77bafe6f86963 (diff) | |
Merge branch 'core/urgent' into core/futexes
Merge reason: this branch was on an pre -rc1 base, merge it up to -rc6+
              to get the latest upstream fixes.
Conflicts:
	kernel/futex.c
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'scripts/dtc')
29 files changed, 11161 insertions, 0 deletions
| diff --git a/scripts/dtc/Makefile b/scripts/dtc/Makefile new file mode 100644 index 00000000000..01cdb36fc58 --- /dev/null +++ b/scripts/dtc/Makefile @@ -0,0 +1,54 @@ +# scripts/dtc makefile + +hostprogs-y	:= dtc +always		:= $(hostprogs-y) + +dtc-objs	:= dtc.o flattree.o fstree.o data.o livetree.o treesource.o \ +		   srcpos.o checks.o +dtc-objs	+= dtc-lexer.lex.o dtc-parser.tab.o + +# Source files need to get at the userspace version of libfdt_env.h to compile + +HOSTCFLAGS_DTC := -I$(src) -I$(src)/libfdt + +HOSTCFLAGS_checks.o := $(HOSTCFLAGS_DTC) +HOSTCFLAGS_data.o := $(HOSTCFLAGS_DTC) +HOSTCFLAGS_dtc.o := $(HOSTCFLAGS_DTC) +HOSTCFLAGS_flattree.o := $(HOSTCFLAGS_DTC) +HOSTCFLAGS_fstree.o := $(HOSTCFLAGS_DTC) +HOSTCFLAGS_livetree.o := $(HOSTCFLAGS_DTC) +HOSTCFLAGS_srcpos.o := $(HOSTCFLAGS_DTC) +HOSTCFLAGS_treesource.o := $(HOSTCFLAGS_DTC) + +HOSTCFLAGS_dtc-lexer.lex.o := $(HOSTCFLAGS_DTC) +HOSTCFLAGS_dtc-parser.tab.o := $(HOSTCFLAGS_DTC) + +# dependencies on generated files need to be listed explicitly +$(obj)/dtc-parser.tab.o: $(obj)/dtc-parser.tab.c $(obj)/dtc-parser.tab.h +$(obj)/dtc-lexer.lex.o:  $(obj)/dtc-lexer.lex.c $(obj)/dtc-parser.tab.h + +targets += dtc-parser.tab.c dtc-lexer.lex.c + +clean-files += dtc-parser.tab.h + +# GENERATE_PARSER := 1		# Uncomment to rebuild flex/bison output + +ifdef GENERATE_PARSER + +BISON = bison +FLEX = flex + +quiet_cmd_bison = BISON   $@ +      cmd_bison = $(BISON) -o$@ -d $<; cp $@ $@_shipped +quiet_cmd_flex = FLEX    $@ +      cmd_flex = $(FLEX) -o$@ $<; cp $@ $@_shipped + +$(obj)/dtc-parser.tab.c: $(src)/dtc-parser.y FORCE +        $(call if_changed,bison) + +$(obj)/dtc-parser.tab.h: $(obj)/dtc-parser.tab.c + +$(obj)/dtc-lexer.lex.c: $(src)/dtc-lexer.l FORCE +        $(call if_changed,flex) + +endif diff --git a/scripts/dtc/Makefile.dtc b/scripts/dtc/Makefile.dtc new file mode 100644 index 00000000000..6ddf9ecac66 --- /dev/null +++ b/scripts/dtc/Makefile.dtc @@ -0,0 +1,9 @@ +# Makefile.dtc +# +# This is not a complete Makefile of itself.  Instead, it is designed to +# be easily embeddable into other systems of Makefiles. +# +DTC_SRCS = dtc.c flattree.c fstree.c data.c livetree.c treesource.c srcpos.c \ +	checks.c +DTC_GEN_SRCS = dtc-lexer.lex.c dtc-parser.tab.c +DTC_OBJS = $(DTC_SRCS:%.c=%.o) $(DTC_GEN_SRCS:%.c=%.o) diff --git a/scripts/dtc/checks.c b/scripts/dtc/checks.c new file mode 100644 index 00000000000..95485796f25 --- /dev/null +++ b/scripts/dtc/checks.c @@ -0,0 +1,587 @@ +/* + * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2007. + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + *  General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 + *                                                                   USA + */ + +#include "dtc.h" + +#ifdef TRACE_CHECKS +#define TRACE(c, ...) \ +	do { \ +		fprintf(stderr, "=== %s: ", (c)->name); \ +		fprintf(stderr, __VA_ARGS__); \ +		fprintf(stderr, "\n"); \ +	} while (0) +#else +#define TRACE(c, fmt, ...)	do { } while (0) +#endif + +enum checklevel { +	IGNORE = 0, +	WARN = 1, +	ERROR = 2, +}; + +enum checkstatus { +	UNCHECKED = 0, +	PREREQ, +	PASSED, +	FAILED, +}; + +struct check; + +typedef void (*tree_check_fn)(struct check *c, struct node *dt); +typedef void (*node_check_fn)(struct check *c, struct node *dt, struct node *node); +typedef void (*prop_check_fn)(struct check *c, struct node *dt, +			      struct node *node, struct property *prop); + +struct check { +	const char *name; +	tree_check_fn tree_fn; +	node_check_fn node_fn; +	prop_check_fn prop_fn; +	void *data; +	enum checklevel level; +	enum checkstatus status; +	int inprogress; +	int num_prereqs; +	struct check **prereq; +}; + +#define CHECK(nm, tfn, nfn, pfn, d, lvl, ...) \ +	static struct check *nm##_prereqs[] = { __VA_ARGS__ }; \ +	static struct check nm = { \ +		.name = #nm, \ +		.tree_fn = (tfn), \ +		.node_fn = (nfn), \ +		.prop_fn = (pfn), \ +		.data = (d), \ +		.level = (lvl), \ +		.status = UNCHECKED, \ +		.num_prereqs = ARRAY_SIZE(nm##_prereqs), \ +		.prereq = nm##_prereqs, \ +	}; + +#define TREE_CHECK(nm, d, lvl, ...) \ +	CHECK(nm, check_##nm, NULL, NULL, d, lvl, __VA_ARGS__) +#define NODE_CHECK(nm, d, lvl, ...) \ +	CHECK(nm, NULL, check_##nm, NULL, d, lvl, __VA_ARGS__) +#define PROP_CHECK(nm, d, lvl, ...) \ +	CHECK(nm, NULL, NULL, check_##nm, d, lvl, __VA_ARGS__) +#define BATCH_CHECK(nm, lvl, ...) \ +	CHECK(nm, NULL, NULL, NULL, NULL, lvl, __VA_ARGS__) + +#ifdef __GNUC__ +static inline void check_msg(struct check *c, const char *fmt, ...) __attribute__((format (printf, 2, 3))); +#endif +static inline void check_msg(struct check *c, const char *fmt, ...) +{ +	va_list ap; +	va_start(ap, fmt); + +	if ((c->level < WARN) || (c->level <= quiet)) +		return; /* Suppress message */ + +	fprintf(stderr, "%s (%s): ", +		(c->level == ERROR) ? "ERROR" : "Warning", c->name); +	vfprintf(stderr, fmt, ap); +	fprintf(stderr, "\n"); +} + +#define FAIL(c, ...) \ +	do { \ +		TRACE((c), "\t\tFAILED at %s:%d", __FILE__, __LINE__); \ +		(c)->status = FAILED; \ +		check_msg((c), __VA_ARGS__); \ +	} while (0) + +static void check_nodes_props(struct check *c, struct node *dt, struct node *node) +{ +	struct node *child; +	struct property *prop; + +	TRACE(c, "%s", node->fullpath); +	if (c->node_fn) +		c->node_fn(c, dt, node); + +	if (c->prop_fn) +		for_each_property(node, prop) { +			TRACE(c, "%s\t'%s'", node->fullpath, prop->name); +			c->prop_fn(c, dt, node, prop); +		} + +	for_each_child(node, child) +		check_nodes_props(c, dt, child); +} + +static int run_check(struct check *c, struct node *dt) +{ +	int error = 0; +	int i; + +	assert(!c->inprogress); + +	if (c->status != UNCHECKED) +		goto out; + +	c->inprogress = 1; + +	for (i = 0; i < c->num_prereqs; i++) { +		struct check *prq = c->prereq[i]; +		error |= run_check(prq, dt); +		if (prq->status != PASSED) { +			c->status = PREREQ; +			check_msg(c, "Failed prerequisite '%s'", +				  c->prereq[i]->name); +		} +	} + +	if (c->status != UNCHECKED) +		goto out; + +	if (c->node_fn || c->prop_fn) +		check_nodes_props(c, dt, dt); + +	if (c->tree_fn) +		c->tree_fn(c, dt); +	if (c->status == UNCHECKED) +		c->status = PASSED; + +	TRACE(c, "\tCompleted, status %d", c->status); + +out: +	c->inprogress = 0; +	if ((c->status != PASSED) && (c->level == ERROR)) +		error = 1; +	return error; +} + +/* + * Utility check functions + */ + +static void check_is_string(struct check *c, struct node *root, +			    struct node *node) +{ +	struct property *prop; +	char *propname = c->data; + +	prop = get_property(node, propname); +	if (!prop) +		return; /* Not present, assumed ok */ + +	if (!data_is_one_string(prop->val)) +		FAIL(c, "\"%s\" property in %s is not a string", +		     propname, node->fullpath); +} +#define CHECK_IS_STRING(nm, propname, lvl) \ +	CHECK(nm, NULL, check_is_string, NULL, (propname), (lvl)) + +static void check_is_cell(struct check *c, struct node *root, +			  struct node *node) +{ +	struct property *prop; +	char *propname = c->data; + +	prop = get_property(node, propname); +	if (!prop) +		return; /* Not present, assumed ok */ + +	if (prop->val.len != sizeof(cell_t)) +		FAIL(c, "\"%s\" property in %s is not a single cell", +		     propname, node->fullpath); +} +#define CHECK_IS_CELL(nm, propname, lvl) \ +	CHECK(nm, NULL, check_is_cell, NULL, (propname), (lvl)) + +/* + * Structural check functions + */ + +static void check_duplicate_node_names(struct check *c, struct node *dt, +				       struct node *node) +{ +	struct node *child, *child2; + +	for_each_child(node, child) +		for (child2 = child->next_sibling; +		     child2; +		     child2 = child2->next_sibling) +			if (streq(child->name, child2->name)) +				FAIL(c, "Duplicate node name %s", +				     child->fullpath); +} +NODE_CHECK(duplicate_node_names, NULL, ERROR); + +static void check_duplicate_property_names(struct check *c, struct node *dt, +					   struct node *node) +{ +	struct property *prop, *prop2; + +	for_each_property(node, prop) +		for (prop2 = prop->next; prop2; prop2 = prop2->next) +			if (streq(prop->name, prop2->name)) +				FAIL(c, "Duplicate property name %s in %s", +				     prop->name, node->fullpath); +} +NODE_CHECK(duplicate_property_names, NULL, ERROR); + +#define LOWERCASE	"abcdefghijklmnopqrstuvwxyz" +#define UPPERCASE	"ABCDEFGHIJKLMNOPQRSTUVWXYZ" +#define DIGITS		"0123456789" +#define PROPNODECHARS	LOWERCASE UPPERCASE DIGITS ",._+*#?-" + +static void check_node_name_chars(struct check *c, struct node *dt, +				  struct node *node) +{ +	int n = strspn(node->name, c->data); + +	if (n < strlen(node->name)) +		FAIL(c, "Bad character '%c' in node %s", +		     node->name[n], node->fullpath); +} +NODE_CHECK(node_name_chars, PROPNODECHARS "@", ERROR); + +static void check_node_name_format(struct check *c, struct node *dt, +				   struct node *node) +{ +	if (strchr(get_unitname(node), '@')) +		FAIL(c, "Node %s has multiple '@' characters in name", +		     node->fullpath); +} +NODE_CHECK(node_name_format, NULL, ERROR, &node_name_chars); + +static void check_property_name_chars(struct check *c, struct node *dt, +				      struct node *node, struct property *prop) +{ +	int n = strspn(prop->name, c->data); + +	if (n < strlen(prop->name)) +		FAIL(c, "Bad character '%c' in property name \"%s\", node %s", +		     prop->name[n], prop->name, node->fullpath); +} +PROP_CHECK(property_name_chars, PROPNODECHARS, ERROR); + +static void check_explicit_phandles(struct check *c, struct node *root, +					  struct node *node) +{ +	struct property *prop; +	struct node *other; +	cell_t phandle; + +	prop = get_property(node, "linux,phandle"); +	if (! prop) +		return; /* No phandle, that's fine */ + +	if (prop->val.len != sizeof(cell_t)) { +		FAIL(c, "%s has bad length (%d) linux,phandle property", +		     node->fullpath, prop->val.len); +		return; +	} + +	phandle = propval_cell(prop); +	if ((phandle == 0) || (phandle == -1)) { +		FAIL(c, "%s has invalid linux,phandle value 0x%x", +		     node->fullpath, phandle); +		return; +	} + +	other = get_node_by_phandle(root, phandle); +	if (other) { +		FAIL(c, "%s has duplicated phandle 0x%x (seen before at %s)", +		     node->fullpath, phandle, other->fullpath); +		return; +	} + +	node->phandle = phandle; +} +NODE_CHECK(explicit_phandles, NULL, ERROR); + +static void check_name_properties(struct check *c, struct node *root, +				  struct node *node) +{ +	struct property **pp, *prop = NULL; + +	for (pp = &node->proplist; *pp; pp = &((*pp)->next)) +		if (streq((*pp)->name, "name")) { +			prop = *pp; +			break; +		} + +	if (!prop) +		return; /* No name property, that's fine */ + +	if ((prop->val.len != node->basenamelen+1) +	    || (memcmp(prop->val.val, node->name, node->basenamelen) != 0)) { +		FAIL(c, "\"name\" property in %s is incorrect (\"%s\" instead" +		     " of base node name)", node->fullpath, prop->val.val); +	} else { +		/* The name property is correct, and therefore redundant. +		 * Delete it */ +		*pp = prop->next; +		free(prop->name); +		data_free(prop->val); +		free(prop); +	} +} +CHECK_IS_STRING(name_is_string, "name", ERROR); +NODE_CHECK(name_properties, NULL, ERROR, &name_is_string); + +/* + * Reference fixup functions + */ + +static void fixup_phandle_references(struct check *c, struct node *dt, +				     struct node *node, struct property *prop) +{ +	struct marker *m = prop->val.markers; +	struct node *refnode; +	cell_t phandle; + +	for_each_marker_of_type(m, REF_PHANDLE) { +		assert(m->offset + sizeof(cell_t) <= prop->val.len); + +		refnode = get_node_by_ref(dt, m->ref); +		if (! refnode) { +			FAIL(c, "Reference to non-existent node or label \"%s\"\n", +			     m->ref); +			continue; +		} + +		phandle = get_node_phandle(dt, refnode); +		*((cell_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle); +	} +} +CHECK(phandle_references, NULL, NULL, fixup_phandle_references, NULL, ERROR, +      &duplicate_node_names, &explicit_phandles); + +static void fixup_path_references(struct check *c, struct node *dt, +				  struct node *node, struct property *prop) +{ +	struct marker *m = prop->val.markers; +	struct node *refnode; +	char *path; + +	for_each_marker_of_type(m, REF_PATH) { +		assert(m->offset <= prop->val.len); + +		refnode = get_node_by_ref(dt, m->ref); +		if (!refnode) { +			FAIL(c, "Reference to non-existent node or label \"%s\"\n", +			     m->ref); +			continue; +		} + +		path = refnode->fullpath; +		prop->val = data_insert_at_marker(prop->val, m, path, +						  strlen(path) + 1); +	} +} +CHECK(path_references, NULL, NULL, fixup_path_references, NULL, ERROR, +      &duplicate_node_names); + +/* + * Semantic checks + */ +CHECK_IS_CELL(address_cells_is_cell, "#address-cells", WARN); +CHECK_IS_CELL(size_cells_is_cell, "#size-cells", WARN); +CHECK_IS_CELL(interrupt_cells_is_cell, "#interrupt-cells", WARN); + +CHECK_IS_STRING(device_type_is_string, "device_type", WARN); +CHECK_IS_STRING(model_is_string, "model", WARN); +CHECK_IS_STRING(status_is_string, "status", WARN); + +static void fixup_addr_size_cells(struct check *c, struct node *dt, +				  struct node *node) +{ +	struct property *prop; + +	node->addr_cells = -1; +	node->size_cells = -1; + +	prop = get_property(node, "#address-cells"); +	if (prop) +		node->addr_cells = propval_cell(prop); + +	prop = get_property(node, "#size-cells"); +	if (prop) +		node->size_cells = propval_cell(prop); +} +CHECK(addr_size_cells, NULL, fixup_addr_size_cells, NULL, NULL, WARN, +      &address_cells_is_cell, &size_cells_is_cell); + +#define node_addr_cells(n) \ +	(((n)->addr_cells == -1) ? 2 : (n)->addr_cells) +#define node_size_cells(n) \ +	(((n)->size_cells == -1) ? 1 : (n)->size_cells) + +static void check_reg_format(struct check *c, struct node *dt, +			     struct node *node) +{ +	struct property *prop; +	int addr_cells, size_cells, entrylen; + +	prop = get_property(node, "reg"); +	if (!prop) +		return; /* No "reg", that's fine */ + +	if (!node->parent) { +		FAIL(c, "Root node has a \"reg\" property"); +		return; +	} + +	if (prop->val.len == 0) +		FAIL(c, "\"reg\" property in %s is empty", node->fullpath); + +	addr_cells = node_addr_cells(node->parent); +	size_cells = node_size_cells(node->parent); +	entrylen = (addr_cells + size_cells) * sizeof(cell_t); + +	if ((prop->val.len % entrylen) != 0) +		FAIL(c, "\"reg\" property in %s has invalid length (%d bytes) " +		     "(#address-cells == %d, #size-cells == %d)", +		     node->fullpath, prop->val.len, addr_cells, size_cells); +} +NODE_CHECK(reg_format, NULL, WARN, &addr_size_cells); + +static void check_ranges_format(struct check *c, struct node *dt, +				struct node *node) +{ +	struct property *prop; +	int c_addr_cells, p_addr_cells, c_size_cells, p_size_cells, entrylen; + +	prop = get_property(node, "ranges"); +	if (!prop) +		return; + +	if (!node->parent) { +		FAIL(c, "Root node has a \"ranges\" property"); +		return; +	} + +	p_addr_cells = node_addr_cells(node->parent); +	p_size_cells = node_size_cells(node->parent); +	c_addr_cells = node_addr_cells(node); +	c_size_cells = node_size_cells(node); +	entrylen = (p_addr_cells + c_addr_cells + c_size_cells) * sizeof(cell_t); + +	if (prop->val.len == 0) { +		if (p_addr_cells != c_addr_cells) +			FAIL(c, "%s has empty \"ranges\" property but its " +			     "#address-cells (%d) differs from %s (%d)", +			     node->fullpath, c_addr_cells, node->parent->fullpath, +			     p_addr_cells); +		if (p_size_cells != c_size_cells) +			FAIL(c, "%s has empty \"ranges\" property but its " +			     "#size-cells (%d) differs from %s (%d)", +			     node->fullpath, c_size_cells, node->parent->fullpath, +			     p_size_cells); +	} else if ((prop->val.len % entrylen) != 0) { +		FAIL(c, "\"ranges\" property in %s has invalid length (%d bytes) " +		     "(parent #address-cells == %d, child #address-cells == %d, " +		     "#size-cells == %d)", node->fullpath, prop->val.len, +		     p_addr_cells, c_addr_cells, c_size_cells); +	} +} +NODE_CHECK(ranges_format, NULL, WARN, &addr_size_cells); + +/* + * Style checks + */ +static void check_avoid_default_addr_size(struct check *c, struct node *dt, +					  struct node *node) +{ +	struct property *reg, *ranges; + +	if (!node->parent) +		return; /* Ignore root node */ + +	reg = get_property(node, "reg"); +	ranges = get_property(node, "ranges"); + +	if (!reg && !ranges) +		return; + +	if ((node->parent->addr_cells == -1)) +		FAIL(c, "Relying on default #address-cells value for %s", +		     node->fullpath); + +	if ((node->parent->size_cells == -1)) +		FAIL(c, "Relying on default #size-cells value for %s", +		     node->fullpath); +} +NODE_CHECK(avoid_default_addr_size, NULL, WARN, &addr_size_cells); + +static void check_obsolete_chosen_interrupt_controller(struct check *c, +						       struct node *dt) +{ +	struct node *chosen; +	struct property *prop; + +	chosen = get_node_by_path(dt, "/chosen"); +	if (!chosen) +		return; + +	prop = get_property(chosen, "interrupt-controller"); +	if (prop) +		FAIL(c, "/chosen has obsolete \"interrupt-controller\" " +		     "property"); +} +TREE_CHECK(obsolete_chosen_interrupt_controller, NULL, WARN); + +static struct check *check_table[] = { +	&duplicate_node_names, &duplicate_property_names, +	&node_name_chars, &node_name_format, &property_name_chars, +	&name_is_string, &name_properties, +	&explicit_phandles, +	&phandle_references, &path_references, + +	&address_cells_is_cell, &size_cells_is_cell, &interrupt_cells_is_cell, +	&device_type_is_string, &model_is_string, &status_is_string, + +	&addr_size_cells, ®_format, &ranges_format, + +	&avoid_default_addr_size, +	&obsolete_chosen_interrupt_controller, +}; + +void process_checks(int force, struct boot_info *bi) +{ +	struct node *dt = bi->dt; +	int i; +	int error = 0; + +	for (i = 0; i < ARRAY_SIZE(check_table); i++) { +		struct check *c = check_table[i]; + +		if (c->level != IGNORE) +			error = error || run_check(c, dt); +	} + +	if (error) { +		if (!force) { +			fprintf(stderr, "ERROR: Input tree has errors, aborting " +				"(use -f to force output)\n"); +			exit(2); +		} else if (quiet < 3) { +			fprintf(stderr, "Warning: Input tree has errors, " +				"output forced\n"); +		} +	} +} diff --git a/scripts/dtc/data.c b/scripts/dtc/data.c new file mode 100644 index 00000000000..dd2e3d39d4c --- /dev/null +++ b/scripts/dtc/data.c @@ -0,0 +1,321 @@ +/* + * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005. + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + *  General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 + *                                                                   USA + */ + +#include "dtc.h" + +void data_free(struct data d) +{ +	struct marker *m, *nm; + +	m = d.markers; +	while (m) { +		nm = m->next; +		free(m->ref); +		free(m); +		m = nm; +	} + +	if (d.val) +		free(d.val); +} + +struct data data_grow_for(struct data d, int xlen) +{ +	struct data nd; +	int newsize; + +	if (xlen == 0) +		return d; + +	nd = d; + +	newsize = xlen; + +	while ((d.len + xlen) > newsize) +		newsize *= 2; + +	nd.val = xrealloc(d.val, newsize); + +	return nd; +} + +struct data data_copy_mem(const char *mem, int len) +{ +	struct data d; + +	d = data_grow_for(empty_data, len); + +	d.len = len; +	memcpy(d.val, mem, len); + +	return d; +} + +static char get_oct_char(const char *s, int *i) +{ +	char x[4]; +	char *endx; +	long val; + +	x[3] = '\0'; +	strncpy(x, s + *i, 3); + +	val = strtol(x, &endx, 8); + +	assert(endx > x); + +	(*i) += endx - x; +	return val; +} + +static char get_hex_char(const char *s, int *i) +{ +	char x[3]; +	char *endx; +	long val; + +	x[2] = '\0'; +	strncpy(x, s + *i, 2); + +	val = strtol(x, &endx, 16); +	if (!(endx  > x)) +		die("\\x used with no following hex digits\n"); + +	(*i) += endx - x; +	return val; +} + +struct data data_copy_escape_string(const char *s, int len) +{ +	int i = 0; +	struct data d; +	char *q; + +	d = data_grow_for(empty_data, strlen(s)+1); + +	q = d.val; +	while (i < len) { +		char c = s[i++]; + +		if (c != '\\') { +			q[d.len++] = c; +			continue; +		} + +		c = s[i++]; +		assert(c); +		switch (c) { +		case 'a': +			q[d.len++] = '\a'; +			break; +		case 'b': +			q[d.len++] = '\b'; +			break; +		case 't': +			q[d.len++] = '\t'; +			break; +		case 'n': +			q[d.len++] = '\n'; +			break; +		case 'v': +			q[d.len++] = '\v'; +			break; +		case 'f': +			q[d.len++] = '\f'; +			break; +		case 'r': +			q[d.len++] = '\r'; +			break; +		case '0': +		case '1': +		case '2': +		case '3': +		case '4': +		case '5': +		case '6': +		case '7': +			i--; /* need to re-read the first digit as +			      * part of the octal value */ +			q[d.len++] = get_oct_char(s, &i); +			break; +		case 'x': +			q[d.len++] = get_hex_char(s, &i); +			break; +		default: +			q[d.len++] = c; +		} +	} + +	q[d.len++] = '\0'; +	return d; +} + +struct data data_copy_file(FILE *f, size_t maxlen) +{ +	struct data d = empty_data; + +	while (!feof(f) && (d.len < maxlen)) { +		size_t chunksize, ret; + +		if (maxlen == -1) +			chunksize = 4096; +		else +			chunksize = maxlen - d.len; + +		d = data_grow_for(d, chunksize); +		ret = fread(d.val + d.len, 1, chunksize, f); + +		if (ferror(f)) +			die("Error reading file into data: %s", strerror(errno)); + +		if (d.len + ret < d.len) +			die("Overflow reading file into data\n"); + +		d.len += ret; +	} + +	return d; +} + +struct data data_append_data(struct data d, const void *p, int len) +{ +	d = data_grow_for(d, len); +	memcpy(d.val + d.len, p, len); +	d.len += len; +	return d; +} + +struct data data_insert_at_marker(struct data d, struct marker *m, +				  const void *p, int len) +{ +	d = data_grow_for(d, len); +	memmove(d.val + m->offset + len, d.val + m->offset, d.len - m->offset); +	memcpy(d.val + m->offset, p, len); +	d.len += len; + +	/* Adjust all markers after the one we're inserting at */ +	m = m->next; +	for_each_marker(m) +		m->offset += len; +	return d; +} + +struct data data_append_markers(struct data d, struct marker *m) +{ +	struct marker **mp = &d.markers; + +	/* Find the end of the markerlist */ +	while (*mp) +		mp = &((*mp)->next); +	*mp = m; +	return d; +} + +struct data data_merge(struct data d1, struct data d2) +{ +	struct data d; +	struct marker *m2 = d2.markers; + +	d = data_append_markers(data_append_data(d1, d2.val, d2.len), m2); + +	/* Adjust for the length of d1 */ +	for_each_marker(m2) +		m2->offset += d1.len; + +	d2.markers = NULL; /* So data_free() doesn't clobber them */ +	data_free(d2); + +	return d; +} + +struct data data_append_cell(struct data d, cell_t word) +{ +	cell_t beword = cpu_to_fdt32(word); + +	return data_append_data(d, &beword, sizeof(beword)); +} + +struct data data_append_re(struct data d, const struct fdt_reserve_entry *re) +{ +	struct fdt_reserve_entry bere; + +	bere.address = cpu_to_fdt64(re->address); +	bere.size = cpu_to_fdt64(re->size); + +	return data_append_data(d, &bere, sizeof(bere)); +} + +struct data data_append_addr(struct data d, uint64_t addr) +{ +	uint64_t beaddr = cpu_to_fdt64(addr); + +	return data_append_data(d, &beaddr, sizeof(beaddr)); +} + +struct data data_append_byte(struct data d, uint8_t byte) +{ +	return data_append_data(d, &byte, 1); +} + +struct data data_append_zeroes(struct data d, int len) +{ +	d = data_grow_for(d, len); + +	memset(d.val + d.len, 0, len); +	d.len += len; +	return d; +} + +struct data data_append_align(struct data d, int align) +{ +	int newlen = ALIGN(d.len, align); +	return data_append_zeroes(d, newlen - d.len); +} + +struct data data_add_marker(struct data d, enum markertype type, char *ref) +{ +	struct marker *m; + +	m = xmalloc(sizeof(*m)); +	m->offset = d.len; +	m->type = type; +	m->ref = ref; +	m->next = NULL; + +	return data_append_markers(d, m); +} + +int data_is_one_string(struct data d) +{ +	int i; +	int len = d.len; + +	if (len == 0) +		return 0; + +	for (i = 0; i < len-1; i++) +		if (d.val[i] == '\0') +			return 0; + +	if (d.val[len-1] != '\0') +		return 0; + +	return 1; +} diff --git a/scripts/dtc/dtc-lexer.l b/scripts/dtc/dtc-lexer.l new file mode 100644 index 00000000000..44dbfd3f097 --- /dev/null +++ b/scripts/dtc/dtc-lexer.l @@ -0,0 +1,320 @@ +/* + * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005. + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + *  General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 + *                                                                   USA + */ + +%option noyywrap nounput yylineno + +%x INCLUDE +%x BYTESTRING +%x PROPNODENAME +%s V1 + +PROPNODECHAR	[a-zA-Z0-9,._+*#?@-] +PATHCHAR	({PROPNODECHAR}|[/]) +LABEL		[a-zA-Z_][a-zA-Z0-9_]* +STRING		\"([^\\"]|\\.)*\" +WS		[[:space:]] +COMMENT		"/*"([^*]|\*+[^*/])*\*+"/" +LINECOMMENT	"//".*\n + +%{ +#include "dtc.h" +#include "srcpos.h" +#include "dtc-parser.tab.h" + + +/*#define LEXDEBUG	1*/ + +#ifdef LEXDEBUG +#define DPRINT(fmt, ...)	fprintf(stderr, fmt, ##__VA_ARGS__) +#else +#define DPRINT(fmt, ...)	do { } while (0) +#endif + +static int dts_version; /* = 0 */ + +#define BEGIN_DEFAULT()	if (dts_version == 0) { \ +				DPRINT("<INITIAL>\n"); \ +				BEGIN(INITIAL); \ +			} else { \ +				DPRINT("<V1>\n"); \ +				BEGIN(V1); \ +			} + +static void push_input_file(const char *filename); +static int pop_input_file(void); +%} + +%% +<*>"/include/"{WS}*{STRING} { +			char *name = strchr(yytext, '\"') + 1; +			yytext[yyleng-1] = '\0'; +			push_input_file(name); +		} + +<*><<EOF>>		{ +			if (!pop_input_file()) { +				yyterminate(); +			} +		} + +<*>{STRING}	{ +			yylloc.file = srcpos_file; +			yylloc.first_line = yylineno; +			DPRINT("String: %s\n", yytext); +			yylval.data = data_copy_escape_string(yytext+1, +					yyleng-2); +			yylloc.first_line = yylineno; +			return DT_STRING; +		} + +<*>"/dts-v1/"	{ +			yylloc.file = srcpos_file; +			yylloc.first_line = yylineno; +			DPRINT("Keyword: /dts-v1/\n"); +			dts_version = 1; +			BEGIN_DEFAULT(); +			return DT_V1; +		} + +<*>"/memreserve/"	{ +			yylloc.file = srcpos_file; +			yylloc.first_line = yylineno; +			DPRINT("Keyword: /memreserve/\n"); +			BEGIN_DEFAULT(); +			return DT_MEMRESERVE; +		} + +<*>{LABEL}:	{ +			yylloc.file = srcpos_file; +			yylloc.first_line = yylineno; +			DPRINT("Label: %s\n", yytext); +			yylval.labelref = strdup(yytext); +			yylval.labelref[yyleng-1] = '\0'; +			return DT_LABEL; +		} + +<INITIAL>[bodh]# { +			yylloc.file = srcpos_file; +			yylloc.first_line = yylineno; +			if (*yytext == 'b') +				yylval.cbase = 2; +			else if (*yytext == 'o') +				yylval.cbase = 8; +			else if (*yytext == 'd') +				yylval.cbase = 10; +			else +				yylval.cbase = 16; +			DPRINT("Base: %d\n", yylval.cbase); +			return DT_BASE; +		} + +<INITIAL>[0-9a-fA-F]+	{ +			yylloc.file = srcpos_file; +			yylloc.first_line = yylineno; +			yylval.literal = strdup(yytext); +			DPRINT("Literal: '%s'\n", yylval.literal); +			return DT_LEGACYLITERAL; +		} + +<V1>[0-9]+|0[xX][0-9a-fA-F]+      { +			yylloc.file = srcpos_file; +			yylloc.first_line = yylineno; +			yylval.literal = strdup(yytext); +			DPRINT("Literal: '%s'\n", yylval.literal); +			return DT_LITERAL; +		} + +\&{LABEL}	{	/* label reference */ +			yylloc.file = srcpos_file; +			yylloc.first_line = yylineno; +			DPRINT("Ref: %s\n", yytext+1); +			yylval.labelref = strdup(yytext+1); +			return DT_REF; +		} + +"&{/"{PATHCHAR}+\}	{	/* new-style path reference */ +			yylloc.file = srcpos_file; +			yylloc.first_line = yylineno; +			yytext[yyleng-1] = '\0'; +			DPRINT("Ref: %s\n", yytext+2); +			yylval.labelref = strdup(yytext+2); +			return DT_REF; +		} + +<INITIAL>"&/"{PATHCHAR}+ {	/* old-style path reference */ +			yylloc.file = srcpos_file; +			yylloc.first_line = yylineno; +			DPRINT("Ref: %s\n", yytext+1); +			yylval.labelref = strdup(yytext+1); +			return DT_REF; +		} + +<BYTESTRING>[0-9a-fA-F]{2} { +			yylloc.file = srcpos_file; +			yylloc.first_line = yylineno; +			yylval.byte = strtol(yytext, NULL, 16); +			DPRINT("Byte: %02x\n", (int)yylval.byte); +			return DT_BYTE; +		} + +<BYTESTRING>"]"	{ +			yylloc.file = srcpos_file; +			yylloc.first_line = yylineno; +			DPRINT("/BYTESTRING\n"); +			BEGIN_DEFAULT(); +			return ']'; +		} + +<PROPNODENAME>{PROPNODECHAR}+ { +			yylloc.file = srcpos_file; +			yylloc.first_line = yylineno; +			DPRINT("PropNodeName: %s\n", yytext); +			yylval.propnodename = strdup(yytext); +			BEGIN_DEFAULT(); +			return DT_PROPNODENAME; +		} + +"/incbin/"	{ +			yylloc.file = srcpos_file; +			yylloc.first_line = yylineno; +			DPRINT("Binary Include\n"); +			return DT_INCBIN; +		} + +<*>{WS}+	/* eat whitespace */ +<*>{COMMENT}+	/* eat C-style comments */ +<*>{LINECOMMENT}+ /* eat C++-style comments */ + +<*>.		{ +			yylloc.file = srcpos_file; +			yylloc.first_line = yylineno; +			DPRINT("Char: %c (\\x%02x)\n", yytext[0], +				(unsigned)yytext[0]); +			if (yytext[0] == '[') { +				DPRINT("<BYTESTRING>\n"); +				BEGIN(BYTESTRING); +			} +			if ((yytext[0] == '{') +			    || (yytext[0] == ';')) { +				DPRINT("<PROPNODENAME>\n"); +				BEGIN(PROPNODENAME); +			} +			return yytext[0]; +		} + +%% + + +/* + * Stack of nested include file contexts. + */ + +struct incl_file { +	struct dtc_file *file; +	YY_BUFFER_STATE yy_prev_buf; +	int yy_prev_lineno; +	struct incl_file *prev; +}; + +static struct incl_file *incl_file_stack; + + +/* + * Detect infinite include recursion. + */ +#define MAX_INCLUDE_DEPTH	(100) + +static int incl_depth = 0; + + +static void push_input_file(const char *filename) +{ +	struct incl_file *incl_file; +	struct dtc_file *newfile; +	struct search_path search, *searchptr = NULL; + +	assert(filename); + +	if (incl_depth++ >= MAX_INCLUDE_DEPTH) +		die("Includes nested too deeply"); + +	if (srcpos_file) { +		search.dir = srcpos_file->dir; +		search.next = NULL; +		search.prev = NULL; +		searchptr = &search; +	} + +	newfile = dtc_open_file(filename, searchptr); + +	incl_file = xmalloc(sizeof(struct incl_file)); + +	/* +	 * Save current context. +	 */ +	incl_file->yy_prev_buf = YY_CURRENT_BUFFER; +	incl_file->yy_prev_lineno = yylineno; +	incl_file->file = srcpos_file; +	incl_file->prev = incl_file_stack; + +	incl_file_stack = incl_file; + +	/* +	 * Establish new context. +	 */ +	srcpos_file = newfile; +	yylineno = 1; +	yyin = newfile->file; +	yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE)); +} + + +static int pop_input_file(void) +{ +	struct incl_file *incl_file; + +	if (incl_file_stack == 0) +		return 0; + +	dtc_close_file(srcpos_file); + +	/* +	 * Pop. +	 */ +	--incl_depth; +	incl_file = incl_file_stack; +	incl_file_stack = incl_file->prev; + +	/* +	 * Recover old context. +	 */ +	yy_delete_buffer(YY_CURRENT_BUFFER); +	yy_switch_to_buffer(incl_file->yy_prev_buf); +	yylineno = incl_file->yy_prev_lineno; +	srcpos_file = incl_file->file; +	yyin = incl_file->file ? incl_file->file->file : NULL; + +	/* +	 * Free old state. +	 */ +	free(incl_file); + +	return 1; +} diff --git a/scripts/dtc/dtc-lexer.lex.c_shipped b/scripts/dtc/dtc-lexer.lex.c_shipped new file mode 100644 index 00000000000..ac392cb040f --- /dev/null +++ b/scripts/dtc/dtc-lexer.lex.c_shipped @@ -0,0 +1,2187 @@ +#line 2 "dtc-lexer.lex.c" + +#line 4 "dtc-lexer.lex.c" + +#define  YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 +#define YY_FLEX_SUBMINOR_VERSION 34 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* First, we deal with  platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <stdlib.h> + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types.  + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include <inttypes.h> +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t;  +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; +#endif /* ! C99 */ + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN               (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN              (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN              (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX               (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX              (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX              (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX              (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX             (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX             (4294967295U) +#endif + +#endif /* ! FLEXINT_H */ + +#ifdef __cplusplus + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else	/* ! __cplusplus */ + +/* C99 requires __STDC__ to be defined as 1. */ +#if defined (__STDC__) + +#define YY_USE_CONST + +#endif	/* defined (__STDC__) */ +#endif	/* ! __cplusplus */ + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index.  If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* Enter a start condition.  This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN (yy_start) = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state.  The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START (((yy_start) - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart(yyin  ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#define YY_BUF_SIZE 16384 +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE   ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +extern int yyleng; + +extern FILE *yyin, *yyout; + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + +    /* Note: We specifically omit the test for yy_rule_can_match_eol because it requires +     *       access to the local variable yy_act. Since yyless() is a macro, it would break +     *       existing scanners that call yyless() from OUTSIDE yylex.  +     *       One obvious solution it to make yy_act a global. I tried that, and saw +     *       a 5% performance hit in a non-yylineno scanner, because yy_act is +     *       normally declared as a register variable-- so it is not worth it. +     */ +    #define  YY_LESS_LINENO(n) \ +            do { \ +                int yyl;\ +                for ( yyl = n; yyl < yyleng; ++yyl )\ +                    if ( yytext[yyl] == '\n' )\ +                        --yylineno;\ +            }while(0) +     +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ +	do \ +		{ \ +		/* Undo effects of setting up yytext. */ \ +        int yyless_macro_arg = (n); \ +        YY_LESS_LINENO(yyless_macro_arg);\ +		*yy_cp = (yy_hold_char); \ +		YY_RESTORE_YY_MORE_OFFSET \ +		(yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ +		YY_DO_BEFORE_ACTION; /* set up yytext again */ \ +		} \ +	while ( 0 ) + +#define unput(c) yyunput( c, (yytext_ptr)  ) + +/* The following is because we cannot portably get our hands on size_t + * (without autoconf's help, which isn't available because we want + * flex-generated scanners to compile on their own). + * Given that the standard has decreed that size_t exists since 1989, + * I guess we can afford to depend on it. Manoj. + */ + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state +	{ +	FILE *yy_input_file; + +	char *yy_ch_buf;		/* input buffer */ +	char *yy_buf_pos;		/* current position in input buffer */ + +	/* Size of input buffer in bytes, not including room for EOB +	 * characters. +	 */ +	yy_size_t yy_buf_size; + +	/* Number of characters read into yy_ch_buf, not including EOB +	 * characters. +	 */ +	int yy_n_chars; + +	/* Whether we "own" the buffer - i.e., we know we created it, +	 * and can realloc() it to grow it, and should free() it to +	 * delete it. +	 */ +	int yy_is_our_buffer; + +	/* Whether this is an "interactive" input source; if so, and +	 * if we're using stdio for input, then we want to use getc() +	 * instead of fread(), to make sure we stop fetching input after +	 * each newline. +	 */ +	int yy_is_interactive; + +	/* Whether we're considered to be at the beginning of a line. +	 * If so, '^' rules will be active on the next match, otherwise +	 * not. +	 */ +	int yy_at_bol; + +    int yy_bs_lineno; /**< The line count. */ +    int yy_bs_column; /**< The column count. */ +     +	/* Whether to try to fill the input buffer when we reach the +	 * end of it. +	 */ +	int yy_fill_buffer; + +	int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 +	/* When an EOF's been seen but there's still some text to process +	 * then we mark the buffer as YY_EOF_PENDING, to indicate that we +	 * shouldn't try reading from the input source any more.  We might +	 * still have a bunch of tokens to match, though, because of +	 * possible backing-up. +	 * +	 * When we actually see the EOF, we change the status to "new" +	 * (via yyrestart()), so that the user can continue scanning by +	 * just pointing yyin at a new input file. +	 */ +#define YY_BUFFER_EOF_PENDING 2 + +	}; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* Stack of input buffers. */ +static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ +static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ +static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ +                          ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ +                          : NULL) + +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] + +/* yy_hold_char holds the character lost when yytext is formed. */ +static char yy_hold_char; +static int yy_n_chars;		/* number of characters read into yy_ch_buf */ +int yyleng; + +/* Points to current character in buffer. */ +static char *yy_c_buf_p = (char *) 0; +static int yy_init = 0;		/* whether we need to initialize */ +static int yy_start = 0;	/* start state number */ + +/* Flag which is used to allow yywrap()'s to do buffer switches + * instead of setting up a fresh yyin.  A bit of a hack ... + */ +static int yy_did_buffer_switch_on_eof; + +void yyrestart (FILE *input_file  ); +void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer  ); +YY_BUFFER_STATE yy_create_buffer (FILE *file,int size  ); +void yy_delete_buffer (YY_BUFFER_STATE b  ); +void yy_flush_buffer (YY_BUFFER_STATE b  ); +void yypush_buffer_state (YY_BUFFER_STATE new_buffer  ); +void yypop_buffer_state (void ); + +static void yyensure_buffer_stack (void ); +static void yy_load_buffer_state (void ); +static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file  ); + +#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ) + +YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size  ); +YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str  ); +YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len  ); + +void *yyalloc (yy_size_t  ); +void *yyrealloc (void *,yy_size_t  ); +void yyfree (void *  ); + +#define yy_new_buffer yy_create_buffer + +#define yy_set_interactive(is_interactive) \ +	{ \ +	if ( ! YY_CURRENT_BUFFER ){ \ +        yyensure_buffer_stack (); \ +		YY_CURRENT_BUFFER_LVALUE =    \ +            yy_create_buffer(yyin,YY_BUF_SIZE ); \ +	} \ +	YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ +	} + +#define yy_set_bol(at_bol) \ +	{ \ +	if ( ! YY_CURRENT_BUFFER ){\ +        yyensure_buffer_stack (); \ +		YY_CURRENT_BUFFER_LVALUE =    \ +            yy_create_buffer(yyin,YY_BUF_SIZE ); \ +	} \ +	YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ +	} + +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +/* Begin user sect3 */ + +#define yywrap(n) 1 +#define YY_SKIP_YYWRAP + +typedef unsigned char YY_CHAR; + +FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; + +typedef int yy_state_type; + +extern int yylineno; + +int yylineno = 1; + +extern char *yytext; +#define yytext_ptr yytext + +static yy_state_type yy_get_previous_state (void ); +static yy_state_type yy_try_NUL_trans (yy_state_type current_state  ); +static int yy_get_next_buffer (void ); +static void yy_fatal_error (yyconst char msg[]  ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ +	(yytext_ptr) = yy_bp; \ +	yyleng = (size_t) (yy_cp - yy_bp); \ +	(yy_hold_char) = *yy_cp; \ +	*yy_cp = '\0'; \ +	(yy_c_buf_p) = yy_cp; + +#define YY_NUM_RULES 20 +#define YY_END_OF_BUFFER 21 +/* This struct is not used in this scanner, +   but its presence is necessary. */ +struct yy_trans_info +	{ +	flex_int32_t yy_verify; +	flex_int32_t yy_nxt; +	}; +static yyconst flex_int16_t yy_accept[104] = +    {   0, +        0,    0,    0,    0,    0,    0,    0,    0,    0,    0, +       21,   19,   16,   16,   19,   19,   19,    7,    7,   19, +        7,   19,   19,   19,   19,   13,   14,   14,   19,    8, +        8,   16,    0,    2,    0,    0,    9,    0,    0,    0, +        0,    0,    0,    7,    7,    5,    0,    6,    0,   12, +       12,   14,   14,    8,    0,   11,    9,    0,    0,    0, +        0,   18,    0,    0,    0,    0,    8,    0,   17,    0, +        0,    0,    0,    0,   10,    0,    0,    0,    0,    0, +        0,    0,    0,    0,    0,    0,    0,    0,    3,   15, +        0,    0,    0,    0,    0,    0,    0,    0,    1,    0, + +        0,    4,    0 +    } ; + +static yyconst flex_int32_t yy_ec[256] = +    {   0, +        1,    1,    1,    1,    1,    1,    1,    1,    2,    3, +        2,    2,    2,    1,    1,    1,    1,    1,    1,    1, +        1,    1,    1,    1,    1,    1,    1,    1,    1,    1, +        1,    2,    1,    4,    5,    1,    1,    6,    1,    1, +        1,    7,    8,    8,    9,    8,   10,   11,   12,   13, +       13,   13,   13,   13,   13,   13,   13,   14,    1,    1, +        1,    1,    8,    8,   15,   15,   15,   15,   15,   15, +       16,   16,   16,   16,   16,   16,   16,   16,   16,   16, +       16,   16,   16,   16,   16,   16,   16,   17,   16,   16, +        1,   18,   19,    1,   16,    1,   15,   20,   21,   22, + +       23,   15,   16,   24,   25,   16,   16,   26,   27,   28, +       24,   16,   16,   29,   30,   31,   32,   33,   16,   17, +       16,   16,   34,    1,   35,    1,    1,    1,    1,    1, +        1,    1,    1,    1,    1,    1,    1,    1,    1,    1, +        1,    1,    1,    1,    1,    1,    1,    1,    1,    1, +        1,    1,    1,    1,    1,    1,    1,    1,    1,    1, +        1,    1,    1,    1,    1,    1,    1,    1,    1,    1, +        1,    1,    1,    1,    1,    1,    1,    1,    1,    1, +        1,    1,    1,    1,    1,    1,    1,    1,    1,    1, +        1,    1,    1,    1,    1,    1,    1,    1,    1,    1, + +        1,    1,    1,    1,    1,    1,    1,    1,    1,    1, +        1,    1,    1,    1,    1,    1,    1,    1,    1,    1, +        1,    1,    1,    1,    1,    1,    1,    1,    1,    1, +        1,    1,    1,    1,    1,    1,    1,    1,    1,    1, +        1,    1,    1,    1,    1,    1,    1,    1,    1,    1, +        1,    1,    1,    1,    1 +    } ; + +static yyconst flex_int32_t yy_meta[36] = +    {   0, +        1,    1,    1,    1,    2,    1,    2,    2,    2,    3, +        4,    4,    4,    5,    6,    7,    7,    1,    1,    6, +        6,    6,    6,    7,    7,    7,    7,    7,    7,    7, +        7,    7,    7,    8,    1 +    } ; + +static yyconst flex_int16_t yy_base[117] = +    {   0, +        0,    0,   30,    0,   44,    0,   67,    0,   97,  105, +      302,  303,   35,   44,   40,   94,  112,    0,  129,  152, +      296,  295,  159,    0,  176,  303,    0,  116,   95,  165, +       49,   46,  102,  303,  296,    0,    0,  288,  290,  293, +      264,  266,  270,    0,    0,  303,    0,  303,  264,  303, +        0,    0,  195,  101,    0,    0,    0,    0,  284,  125, +      277,  265,  225,  230,  216,  218,    0,  202,  224,  221, +      217,  107,  196,  188,  303,  206,  179,  186,  178,  185, +      183,  162,  161,  150,  169,  160,  145,  125,  303,  303, +      137,  109,  190,  103,  203,  167,  108,  197,  303,  123, + +       29,  303,  303,  215,  221,  226,  229,  234,  240,  246, +      250,  257,  265,  270,  275,  282 +    } ; + +static yyconst flex_int16_t yy_def[117] = +    {   0, +      103,    1,    1,    3,    3,    5,  103,    7,    3,    3, +      103,  103,  103,  103,  104,  105,  103,  106,  103,   19, +       19,   20,  103,  107,   20,  103,  108,  109,  105,  103, +      103,  103,  104,  103,  104,  110,  111,  103,  112,  113, +      103,  103,  103,  106,   19,  103,   20,  103,  103,  103, +       20,  108,  109,  103,  114,  110,  111,  115,  112,  112, +      113,  103,  103,  103,  103,  103,  114,  115,  103,  103, +      103,  103,  103,  103,  103,  103,  103,  103,  103,  103, +      103,  103,  103,  103,  103,  103,  103,  103,  103,  103, +      103,  103,  103,  103,  103,  116,  103,  116,  103,  116, + +      103,  103,    0,  103,  103,  103,  103,  103,  103,  103, +      103,  103,  103,  103,  103,  103 +    } ; + +static yyconst flex_int16_t yy_nxt[339] = +    {   0, +       12,   13,   14,   15,   12,   16,   12,   12,   12,   17, +       18,   18,   18,   12,   19,   20,   20,   12,   12,   21, +       19,   21,   19,   22,   20,   20,   20,   20,   20,   20, +       20,   20,   20,   12,   12,   12,   32,   32,  102,   23, +       12,   12,   12,   34,   20,   32,   32,   32,   32,   20, +       20,   20,   20,   20,   24,   24,   24,   35,   25,   54, +       54,   54,   26,   25,   25,   25,   25,   12,   13,   14, +       15,   27,   12,   27,   27,   27,   23,   27,   27,   27, +       12,   28,   28,   28,   12,   12,   28,   28,   28,   28, +       28,   28,   28,   28,   28,   28,   28,   28,   28,   28, + +       12,   12,   29,   36,  103,   34,   17,   30,   31,   31, +       29,   54,   54,   54,   17,   30,   31,   31,   39,   35, +       52,   40,   52,   52,   52,  103,   78,   38,   38,   46, +      101,   60,   79,   41,   69,   97,   42,   94,   43,   45, +       45,   45,   46,   45,   47,   47,   93,   92,   45,   45, +       45,   45,   47,   47,   47,   47,   47,   47,   47,   47, +       47,   47,   47,   47,   47,   39,   47,   91,   40,   90, +       99,   47,   47,   47,   47,   54,   54,   54,   89,   88, +       41,   55,   87,   49,  100,   43,   51,   51,   51,   86, +       51,   95,   95,   96,   85,   51,   51,   51,   51,   52, + +       99,   52,   52,   52,   95,   95,   96,   84,   46,   83, +       82,   81,   39,   79,  100,   33,   33,   33,   33,   33, +       33,   33,   33,   37,   80,   77,   37,   37,   37,   44, +       40,   44,   50,   76,   50,   52,   75,   52,   74,   52, +       52,   53,   73,   53,   53,   53,   53,   56,   56,   56, +       72,   56,   56,   57,   71,   57,   57,   59,   59,   59, +       59,   59,   59,   59,   59,   61,   61,   61,   61,   61, +       61,   61,   61,   67,   70,   67,   68,   68,   68,   62, +       68,   68,   98,   98,   98,   98,   98,   98,   98,   98, +       60,   66,   65,   64,   63,   62,   60,   58,  103,   48, + +       48,  103,   11,  103,  103,  103,  103,  103,  103,  103, +      103,  103,  103,  103,  103,  103,  103,  103,  103,  103, +      103,  103,  103,  103,  103,  103,  103,  103,  103,  103, +      103,  103,  103,  103,  103,  103,  103,  103 +    } ; + +static yyconst flex_int16_t yy_chk[339] = +    {   0, +        1,    1,    1,    1,    1,    1,    1,    1,    1,    1, +        1,    1,    1,    1,    1,    1,    1,    1,    1,    1, +        1,    1,    1,    1,    1,    1,    1,    1,    1,    1, +        1,    1,    1,    1,    1,    3,   13,   13,  101,    3, +        3,    3,    3,   15,    3,   14,   14,   32,   32,    3, +        3,    3,    3,    3,    5,    5,    5,   15,    5,   31, +       31,   31,    5,    5,    5,    5,    5,    7,    7,    7, +        7,    7,    7,    7,    7,    7,    7,    7,    7,    7, +        7,    7,    7,    7,    7,    7,    7,    7,    7,    7, +        7,    7,    7,    7,    7,    7,    7,    7,    7,    7, + +        7,    7,    9,   16,   29,   33,    9,    9,    9,    9, +       10,   54,   54,   54,   10,   10,   10,   10,   17,   33, +       28,   17,   28,   28,   28,  100,   72,   16,   29,   28, +       97,   60,   72,   17,   60,   94,   17,   92,   17,   19, +       19,   19,   19,   19,   19,   19,   91,   88,   19,   19, +       19,   19,   19,   19,   19,   19,   19,   19,   19,   19, +       19,   19,   20,   20,   20,   23,   20,   87,   23,   86, +       96,   20,   20,   20,   20,   30,   30,   30,   85,   84, +       23,   30,   83,   23,   96,   23,   25,   25,   25,   82, +       25,   93,   93,   93,   81,   25,   25,   25,   25,   53, + +       98,   53,   53,   53,   95,   95,   95,   80,   53,   79, +       78,   77,   76,   74,   98,  104,  104,  104,  104,  104, +      104,  104,  104,  105,   73,   71,  105,  105,  105,  106, +       70,  106,  107,   69,  107,  108,   68,  108,   66,  108, +      108,  109,   65,  109,  109,  109,  109,  110,  110,  110, +       64,  110,  110,  111,   63,  111,  111,  112,  112,  112, +      112,  112,  112,  112,  112,  113,  113,  113,  113,  113, +      113,  113,  113,  114,   62,  114,  115,  115,  115,   61, +      115,  115,  116,  116,  116,  116,  116,  116,  116,  116, +       59,   49,   43,   42,   41,   40,   39,   38,   35,   22, + +       21,   11,  103,  103,  103,  103,  103,  103,  103,  103, +      103,  103,  103,  103,  103,  103,  103,  103,  103,  103, +      103,  103,  103,  103,  103,  103,  103,  103,  103,  103, +      103,  103,  103,  103,  103,  103,  103,  103 +    } ; + +/* Table of booleans, true if rule could match eol. */ +static yyconst flex_int32_t yy_rule_can_match_eol[21] = +    {   0, +1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0,  +    0,     }; + +static yy_state_type yy_last_accepting_state; +static char *yy_last_accepting_cpos; + +extern int yy_flex_debug; +int yy_flex_debug = 0; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +char *yytext; +#line 1 "dtc-lexer.l" +/* + * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005. + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + *  General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 + *                                                                   USA + */ + + + + +#line 37 "dtc-lexer.l" +#include "dtc.h" +#include "srcpos.h" +#include "dtc-parser.tab.h" + + +/*#define LEXDEBUG	1*/ + +#ifdef LEXDEBUG +#define DPRINT(fmt, ...)	fprintf(stderr, fmt, ##__VA_ARGS__) +#else +#define DPRINT(fmt, ...)	do { } while (0) +#endif + +static int dts_version; /* = 0 */ + +#define BEGIN_DEFAULT()	if (dts_version == 0) { \ +				DPRINT("<INITIAL>\n"); \ +				BEGIN(INITIAL); \ +			} else { \ +				DPRINT("<V1>\n"); \ +				BEGIN(V1); \ +			} + +static void push_input_file(const char *filename); +static int pop_input_file(void); +#line 638 "dtc-lexer.lex.c" + +#define INITIAL 0 +#define INCLUDE 1 +#define BYTESTRING 2 +#define PROPNODENAME 3 +#define V1 4 + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include <unistd.h> +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +static int yy_init_globals (void ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap (void ); +#else +extern int yywrap (void ); +#endif +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy (char *,yyconst char *,int ); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * ); +#endif + +#ifndef YY_NO_INPUT + +#ifdef __cplusplus +static int yyinput (void ); +#else +static int input (void ); +#endif + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 8192 +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO fwrite( yytext, yyleng, 1, yyout ) +#endif + +/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ +	if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ +		{ \ +		int c = '*'; \ +		int n; \ +		for ( n = 0; n < max_size && \ +			     (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ +			buf[n] = (char) c; \ +		if ( c == '\n' ) \ +			buf[n++] = (char) c; \ +		if ( c == EOF && ferror( yyin ) ) \ +			YY_FATAL_ERROR( "input in flex scanner failed" ); \ +		result = n; \ +		} \ +	else \ +		{ \ +		errno=0; \ +		while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ +			{ \ +			if( errno != EINTR) \ +				{ \ +				YY_FATAL_ERROR( "input in flex scanner failed" ); \ +				break; \ +				} \ +			errno=0; \ +			clearerr(yyin); \ +			} \ +		}\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int yylex (void); + +#define YY_DECL int yylex (void) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ +	YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ +	register yy_state_type yy_current_state; +	register char *yy_cp, *yy_bp; +	register int yy_act; +     +#line 64 "dtc-lexer.l" + +#line 795 "dtc-lexer.lex.c" + +	if ( !(yy_init) ) +		{ +		(yy_init) = 1; + +#ifdef YY_USER_INIT +		YY_USER_INIT; +#endif + +		if ( ! (yy_start) ) +			(yy_start) = 1;	/* first start state */ + +		if ( ! yyin ) +			yyin = stdin; + +		if ( ! yyout ) +			yyout = stdout; + +		if ( ! YY_CURRENT_BUFFER ) { +			yyensure_buffer_stack (); +			YY_CURRENT_BUFFER_LVALUE = +				yy_create_buffer(yyin,YY_BUF_SIZE ); +		} + +		yy_load_buffer_state( ); +		} + +	while ( 1 )		/* loops until end-of-file is reached */ +		{ +		yy_cp = (yy_c_buf_p); + +		/* Support of yytext. */ +		*yy_cp = (yy_hold_char); + +		/* yy_bp points to the position in yy_ch_buf of the start of +		 * the current run. +		 */ +		yy_bp = yy_cp; + +		yy_current_state = (yy_start); +yy_match: +		do +			{ +			register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; +			if ( yy_accept[yy_current_state] ) +				{ +				(yy_last_accepting_state) = yy_current_state; +				(yy_last_accepting_cpos) = yy_cp; +				} +			while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) +				{ +				yy_current_state = (int) yy_def[yy_current_state]; +				if ( yy_current_state >= 104 ) +					yy_c = yy_meta[(unsigned int) yy_c]; +				} +			yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; +			++yy_cp; +			} +		while ( yy_base[yy_current_state] != 303 ); + +yy_find_action: +		yy_act = yy_accept[yy_current_state]; +		if ( yy_act == 0 ) +			{ /* have to back up */ +			yy_cp = (yy_last_accepting_cpos); +			yy_current_state = (yy_last_accepting_state); +			yy_act = yy_accept[yy_current_state]; +			} + +		YY_DO_BEFORE_ACTION; + +		if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] ) +			{ +			int yyl; +			for ( yyl = 0; yyl < yyleng; ++yyl ) +				if ( yytext[yyl] == '\n' ) +					    +    yylineno++; +; +			} + +do_action:	/* This label is used only to access EOF actions. */ + +		switch ( yy_act ) +	{ /* beginning of action switch */ +			case 0: /* must back up */ +			/* undo the effects of YY_DO_BEFORE_ACTION */ +			*yy_cp = (yy_hold_char); +			yy_cp = (yy_last_accepting_cpos); +			yy_current_state = (yy_last_accepting_state); +			goto yy_find_action; + +case 1: +/* rule 1 can match eol */ +YY_RULE_SETUP +#line 65 "dtc-lexer.l" +{ +			char *name = strchr(yytext, '\"') + 1; +			yytext[yyleng-1] = '\0'; +			push_input_file(name); +		} +	YY_BREAK +case YY_STATE_EOF(INITIAL): +case YY_STATE_EOF(INCLUDE): +case YY_STATE_EOF(BYTESTRING): +case YY_STATE_EOF(PROPNODENAME): +case YY_STATE_EOF(V1): +#line 71 "dtc-lexer.l" +{ +			if (!pop_input_file()) { +				yyterminate(); +			} +		} +	YY_BREAK +case 2: +/* rule 2 can match eol */ +YY_RULE_SETUP +#line 77 "dtc-lexer.l" +{ +			yylloc.file = srcpos_file; +			yylloc.first_line = yylineno; +			DPRINT("String: %s\n", yytext); +			yylval.data = data_copy_escape_string(yytext+1, +					yyleng-2); +			yylloc.first_line = yylineno; +			return DT_STRING; +		} +	YY_BREAK +case 3: +YY_RULE_SETUP +#line 87 "dtc-lexer.l" +{ +			yylloc.file = srcpos_file; +			yylloc.first_line = yylineno; +			DPRINT("Keyword: /dts-v1/\n"); +			dts_version = 1; +			BEGIN_DEFAULT(); +			return DT_V1; +		} +	YY_BREAK +case 4: +YY_RULE_SETUP +#line 96 "dtc-lexer.l" +{ +			yylloc.file = srcpos_file; +			yylloc.first_line = yylineno; +			DPRINT("Keyword: /memreserve/\n"); +			BEGIN_DEFAULT(); +			return DT_MEMRESERVE; +		} +	YY_BREAK +case 5: +YY_RULE_SETUP +#line 104 "dtc-lexer.l" +{ +			yylloc.file = srcpos_file; +			yylloc.first_line = yylineno; +			DPRINT("Label: %s\n", yytext); +			yylval.labelref = strdup(yytext); +			yylval.labelref[yyleng-1] = '\0'; +			return DT_LABEL; +		} +	YY_BREAK +case 6: +YY_RULE_SETUP +#line 113 "dtc-lexer.l" +{ +			yylloc.file = srcpos_file; +			yylloc.first_line = yylineno; +			if (*yytext == 'b') +				yylval.cbase = 2; +			else if (*yytext == 'o') +				yylval.cbase = 8; +			else if (*yytext == 'd') +				yylval.cbase = 10; +			else +				yylval.cbase = 16; +			DPRINT("Base: %d\n", yylval.cbase); +			return DT_BASE; +		} +	YY_BREAK +case 7: +YY_RULE_SETUP +#line 128 "dtc-lexer.l" +{ +			yylloc.file = srcpos_file; +			yylloc.first_line = yylineno; +			yylval.literal = strdup(yytext); +			DPRINT("Literal: '%s'\n", yylval.literal); +			return DT_LEGACYLITERAL; +		} +	YY_BREAK +case 8: +YY_RULE_SETUP +#line 136 "dtc-lexer.l" +{ +			yylloc.file = srcpos_file; +			yylloc.first_line = yylineno; +			yylval.literal = strdup(yytext); +			DPRINT("Literal: '%s'\n", yylval.literal); +			return DT_LITERAL; +		} +	YY_BREAK +case 9: +YY_RULE_SETUP +#line 144 "dtc-lexer.l" +{	/* label reference */ +			yylloc.file = srcpos_file; +			yylloc.first_line = yylineno; +			DPRINT("Ref: %s\n", yytext+1); +			yylval.labelref = strdup(yytext+1); +			return DT_REF; +		} +	YY_BREAK +case 10: +YY_RULE_SETUP +#line 152 "dtc-lexer.l" +{	/* new-style path reference */ +			yylloc.file = srcpos_file; +			yylloc.first_line = yylineno; +			yytext[yyleng-1] = '\0'; +			DPRINT("Ref: %s\n", yytext+2); +			yylval.labelref = strdup(yytext+2); +			return DT_REF; +		} +	YY_BREAK +case 11: +YY_RULE_SETUP +#line 161 "dtc-lexer.l" +{	/* old-style path reference */ +			yylloc.file = srcpos_file; +			yylloc.first_line = yylineno; +			DPRINT("Ref: %s\n", yytext+1); +			yylval.labelref = strdup(yytext+1); +			return DT_REF; +		} +	YY_BREAK +case 12: +YY_RULE_SETUP +#line 169 "dtc-lexer.l" +{ +			yylloc.file = srcpos_file; +			yylloc.first_line = yylineno; +			yylval.byte = strtol(yytext, NULL, 16); +			DPRINT("Byte: %02x\n", (int)yylval.byte); +			return DT_BYTE; +		} +	YY_BREAK +case 13: +YY_RULE_SETUP +#line 177 "dtc-lexer.l" +{ +			yylloc.file = srcpos_file; +			yylloc.first_line = yylineno; +			DPRINT("/BYTESTRING\n"); +			BEGIN_DEFAULT(); +			return ']'; +		} +	YY_BREAK +case 14: +YY_RULE_SETUP +#line 185 "dtc-lexer.l" +{ +			yylloc.file = srcpos_file; +			yylloc.first_line = yylineno; +			DPRINT("PropNodeName: %s\n", yytext); +			yylval.propnodename = strdup(yytext); +			BEGIN_DEFAULT(); +			return DT_PROPNODENAME; +		} +	YY_BREAK +case 15: +YY_RULE_SETUP +#line 194 "dtc-lexer.l" +{ +			yylloc.file = srcpos_file; +			yylloc.first_line = yylineno; +			DPRINT("Binary Include\n"); +			return DT_INCBIN; +		} +	YY_BREAK +case 16: +/* rule 16 can match eol */ +YY_RULE_SETUP +#line 201 "dtc-lexer.l" +/* eat whitespace */ +	YY_BREAK +case 17: +/* rule 17 can match eol */ +YY_RULE_SETUP +#line 202 "dtc-lexer.l" +/* eat C-style comments */ +	YY_BREAK +case 18: +/* rule 18 can match eol */ +YY_RULE_SETUP +#line 203 "dtc-lexer.l" +/* eat C++-style comments */ +	YY_BREAK +case 19: +YY_RULE_SETUP +#line 205 "dtc-lexer.l" +{ +			yylloc.file = srcpos_file; +			yylloc.first_line = yylineno; +			DPRINT("Char: %c (\\x%02x)\n", yytext[0], +				(unsigned)yytext[0]); +			if (yytext[0] == '[') { +				DPRINT("<BYTESTRING>\n"); +				BEGIN(BYTESTRING); +			} +			if ((yytext[0] == '{') +			    || (yytext[0] == ';')) { +				DPRINT("<PROPNODENAME>\n"); +				BEGIN(PROPNODENAME); +			} +			return yytext[0]; +		} +	YY_BREAK +case 20: +YY_RULE_SETUP +#line 222 "dtc-lexer.l" +ECHO; +	YY_BREAK +#line 1120 "dtc-lexer.lex.c" + +	case YY_END_OF_BUFFER: +		{ +		/* Amount of text matched not including the EOB char. */ +		int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; + +		/* Undo the effects of YY_DO_BEFORE_ACTION. */ +		*yy_cp = (yy_hold_char); +		YY_RESTORE_YY_MORE_OFFSET + +		if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) +			{ +			/* We're scanning a new file or input source.  It's +			 * possible that this happened because the user +			 * just pointed yyin at a new source and called +			 * yylex().  If so, then we have to assure +			 * consistency between YY_CURRENT_BUFFER and our +			 * globals.  Here is the right place to do so, because +			 * this is the first action (other than possibly a +			 * back-up) that will match for the new input source. +			 */ +			(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; +			YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; +			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; +			} + +		/* Note that here we test for yy_c_buf_p "<=" to the position +		 * of the first EOB in the buffer, since yy_c_buf_p will +		 * already have been incremented past the NUL character +		 * (since all states make transitions on EOB to the +		 * end-of-buffer state).  Contrast this with the test +		 * in input(). +		 */ +		if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) +			{ /* This was really a NUL. */ +			yy_state_type yy_next_state; + +			(yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; + +			yy_current_state = yy_get_previous_state(  ); + +			/* Okay, we're now positioned to make the NUL +			 * transition.  We couldn't have +			 * yy_get_previous_state() go ahead and do it +			 * for us because it doesn't know how to deal +			 * with the possibility of jamming (and we don't +			 * want to build jamming into it because then it +			 * will run more slowly). +			 */ + +			yy_next_state = yy_try_NUL_trans( yy_current_state ); + +			yy_bp = (yytext_ptr) + YY_MORE_ADJ; + +			if ( yy_next_state ) +				{ +				/* Consume the NUL. */ +				yy_cp = ++(yy_c_buf_p); +				yy_current_state = yy_next_state; +				goto yy_match; +				} + +			else +				{ +				yy_cp = (yy_c_buf_p); +				goto yy_find_action; +				} +			} + +		else switch ( yy_get_next_buffer(  ) ) +			{ +			case EOB_ACT_END_OF_FILE: +				{ +				(yy_did_buffer_switch_on_eof) = 0; + +				if ( yywrap( ) ) +					{ +					/* Note: because we've taken care in +					 * yy_get_next_buffer() to have set up +					 * yytext, we can now set up +					 * yy_c_buf_p so that if some total +					 * hoser (like flex itself) wants to +					 * call the scanner after we return the +					 * YY_NULL, it'll still work - another +					 * YY_NULL will get returned. +					 */ +					(yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; + +					yy_act = YY_STATE_EOF(YY_START); +					goto do_action; +					} + +				else +					{ +					if ( ! (yy_did_buffer_switch_on_eof) ) +						YY_NEW_FILE; +					} +				break; +				} + +			case EOB_ACT_CONTINUE_SCAN: +				(yy_c_buf_p) = +					(yytext_ptr) + yy_amount_of_matched_text; + +				yy_current_state = yy_get_previous_state(  ); + +				yy_cp = (yy_c_buf_p); +				yy_bp = (yytext_ptr) + YY_MORE_ADJ; +				goto yy_match; + +			case EOB_ACT_LAST_MATCH: +				(yy_c_buf_p) = +				&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; + +				yy_current_state = yy_get_previous_state(  ); + +				yy_cp = (yy_c_buf_p); +				yy_bp = (yytext_ptr) + YY_MORE_ADJ; +				goto yy_find_action; +			} +		break; +		} + +	default: +		YY_FATAL_ERROR( +			"fatal flex scanner internal error--no action found" ); +	} /* end of action switch */ +		} /* end of scanning one token */ +} /* end of yylex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + *	EOB_ACT_LAST_MATCH - + *	EOB_ACT_CONTINUE_SCAN - continue scanning from current position + *	EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (void) +{ +    	register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; +	register char *source = (yytext_ptr); +	register int number_to_move, i; +	int ret_val; + +	if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) +		YY_FATAL_ERROR( +		"fatal flex scanner internal error--end of buffer missed" ); + +	if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) +		{ /* Don't try to fill the buffer, so this is an EOF. */ +		if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) +			{ +			/* We matched a single character, the EOB, so +			 * treat this as a final EOF. +			 */ +			return EOB_ACT_END_OF_FILE; +			} + +		else +			{ +			/* We matched some text prior to the EOB, first +			 * process it. +			 */ +			return EOB_ACT_LAST_MATCH; +			} +		} + +	/* Try to read more data. */ + +	/* First move last chars to start of buffer. */ +	number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1; + +	for ( i = 0; i < number_to_move; ++i ) +		*(dest++) = *(source++); + +	if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) +		/* don't do the read, it's not guaranteed to return an EOF, +		 * just force an EOF +		 */ +		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; + +	else +		{ +			int num_to_read = +			YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + +		while ( num_to_read <= 0 ) +			{ /* Not enough room in the buffer - grow it. */ + +			/* just a shorter name for the current buffer */ +			YY_BUFFER_STATE b = YY_CURRENT_BUFFER; + +			int yy_c_buf_p_offset = +				(int) ((yy_c_buf_p) - b->yy_ch_buf); + +			if ( b->yy_is_our_buffer ) +				{ +				int new_size = b->yy_buf_size * 2; + +				if ( new_size <= 0 ) +					b->yy_buf_size += b->yy_buf_size / 8; +				else +					b->yy_buf_size *= 2; + +				b->yy_ch_buf = (char *) +					/* Include room in for 2 EOB chars. */ +					yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2  ); +				} +			else +				/* Can't grow it, we don't own it. */ +				b->yy_ch_buf = 0; + +			if ( ! b->yy_ch_buf ) +				YY_FATAL_ERROR( +				"fatal error - scanner input buffer overflow" ); + +			(yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; + +			num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - +						number_to_move - 1; + +			} + +		if ( num_to_read > YY_READ_BUF_SIZE ) +			num_to_read = YY_READ_BUF_SIZE; + +		/* Read in more data. */ +		YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), +			(yy_n_chars), (size_t) num_to_read ); + +		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); +		} + +	if ( (yy_n_chars) == 0 ) +		{ +		if ( number_to_move == YY_MORE_ADJ ) +			{ +			ret_val = EOB_ACT_END_OF_FILE; +			yyrestart(yyin  ); +			} + +		else +			{ +			ret_val = EOB_ACT_LAST_MATCH; +			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = +				YY_BUFFER_EOF_PENDING; +			} +		} + +	else +		ret_val = EOB_ACT_CONTINUE_SCAN; + +	if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { +		/* Extend the array by 50%, plus the number we really need. */ +		yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); +		YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size  ); +		if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) +			YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); +	} + +	(yy_n_chars) += number_to_move; +	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; +	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; + +	(yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + +	return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + +    static yy_state_type yy_get_previous_state (void) +{ +	register yy_state_type yy_current_state; +	register char *yy_cp; +     +	yy_current_state = (yy_start); + +	for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) +		{ +		register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); +		if ( yy_accept[yy_current_state] ) +			{ +			(yy_last_accepting_state) = yy_current_state; +			(yy_last_accepting_cpos) = yy_cp; +			} +		while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) +			{ +			yy_current_state = (int) yy_def[yy_current_state]; +			if ( yy_current_state >= 104 ) +				yy_c = yy_meta[(unsigned int) yy_c]; +			} +		yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; +		} + +	return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + *	next_state = yy_try_NUL_trans( current_state ); + */ +    static yy_state_type yy_try_NUL_trans  (yy_state_type yy_current_state ) +{ +	register int yy_is_jam; +    	register char *yy_cp = (yy_c_buf_p); + +	register YY_CHAR yy_c = 1; +	if ( yy_accept[yy_current_state] ) +		{ +		(yy_last_accepting_state) = yy_current_state; +		(yy_last_accepting_cpos) = yy_cp; +		} +	while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) +		{ +		yy_current_state = (int) yy_def[yy_current_state]; +		if ( yy_current_state >= 104 ) +			yy_c = yy_meta[(unsigned int) yy_c]; +		} +	yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; +	yy_is_jam = (yy_current_state == 103); + +	return yy_is_jam ? 0 : yy_current_state; +} + +#ifndef YY_NO_INPUT +#ifdef __cplusplus +    static int yyinput (void) +#else +    static int input  (void) +#endif + +{ +	int c; +     +	*(yy_c_buf_p) = (yy_hold_char); + +	if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) +		{ +		/* yy_c_buf_p now points to the character we want to return. +		 * If this occurs *before* the EOB characters, then it's a +		 * valid NUL; if not, then we've hit the end of the buffer. +		 */ +		if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) +			/* This was really a NUL. */ +			*(yy_c_buf_p) = '\0'; + +		else +			{ /* need more input */ +			int offset = (yy_c_buf_p) - (yytext_ptr); +			++(yy_c_buf_p); + +			switch ( yy_get_next_buffer(  ) ) +				{ +				case EOB_ACT_LAST_MATCH: +					/* This happens because yy_g_n_b() +					 * sees that we've accumulated a +					 * token and flags that we need to +					 * try matching the token before +					 * proceeding.  But for input(), +					 * there's no matching to consider. +					 * So convert the EOB_ACT_LAST_MATCH +					 * to EOB_ACT_END_OF_FILE. +					 */ + +					/* Reset buffer status. */ +					yyrestart(yyin ); + +					/*FALLTHROUGH*/ + +				case EOB_ACT_END_OF_FILE: +					{ +					if ( yywrap( ) ) +						return EOF; + +					if ( ! (yy_did_buffer_switch_on_eof) ) +						YY_NEW_FILE; +#ifdef __cplusplus +					return yyinput(); +#else +					return input(); +#endif +					} + +				case EOB_ACT_CONTINUE_SCAN: +					(yy_c_buf_p) = (yytext_ptr) + offset; +					break; +				} +			} +		} + +	c = *(unsigned char *) (yy_c_buf_p);	/* cast for 8-bit char's */ +	*(yy_c_buf_p) = '\0';	/* preserve yytext */ +	(yy_hold_char) = *++(yy_c_buf_p); + +	if ( c == '\n' ) +		    +    yylineno++; +; + +	return c; +} +#endif	/* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + *  + * @note This function does not reset the start condition to @c INITIAL . + */ +    void yyrestart  (FILE * input_file ) +{ +     +	if ( ! YY_CURRENT_BUFFER ){ +        yyensure_buffer_stack (); +		YY_CURRENT_BUFFER_LVALUE = +            yy_create_buffer(yyin,YY_BUF_SIZE ); +	} + +	yy_init_buffer(YY_CURRENT_BUFFER,input_file ); +	yy_load_buffer_state( ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + *  + */ +    void yy_switch_to_buffer  (YY_BUFFER_STATE  new_buffer ) +{ +     +	/* TODO. We should be able to replace this entire function body +	 * with +	 *		yypop_buffer_state(); +	 *		yypush_buffer_state(new_buffer); +     */ +	yyensure_buffer_stack (); +	if ( YY_CURRENT_BUFFER == new_buffer ) +		return; + +	if ( YY_CURRENT_BUFFER ) +		{ +		/* Flush out information for old buffer. */ +		*(yy_c_buf_p) = (yy_hold_char); +		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); +		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); +		} + +	YY_CURRENT_BUFFER_LVALUE = new_buffer; +	yy_load_buffer_state( ); + +	/* We don't actually know whether we did this switch during +	 * EOF (yywrap()) processing, but the only time this flag +	 * is looked at is after yywrap() is called, so it's safe +	 * to go ahead and always set it. +	 */ +	(yy_did_buffer_switch_on_eof) = 1; +} + +static void yy_load_buffer_state  (void) +{ +    	(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; +	(yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; +	yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; +	(yy_hold_char) = *(yy_c_buf_p); +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + *  + * @return the allocated buffer state. + */ +    YY_BUFFER_STATE yy_create_buffer  (FILE * file, int  size ) +{ +	YY_BUFFER_STATE b; +     +	b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state )  ); +	if ( ! b ) +		YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + +	b->yy_buf_size = size; + +	/* yy_ch_buf has to be 2 characters longer than the size given because +	 * we need to put in 2 end-of-buffer characters. +	 */ +	b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2  ); +	if ( ! b->yy_ch_buf ) +		YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + +	b->yy_is_our_buffer = 1; + +	yy_init_buffer(b,file ); + +	return b; +} + +/** Destroy the buffer. + * @param b a buffer created with yy_create_buffer() + *  + */ +    void yy_delete_buffer (YY_BUFFER_STATE  b ) +{ +     +	if ( ! b ) +		return; + +	if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ +		YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + +	if ( b->yy_is_our_buffer ) +		yyfree((void *) b->yy_ch_buf  ); + +	yyfree((void *) b  ); +} + +#ifndef __cplusplus +extern int isatty (int ); +#endif /* __cplusplus */ +     +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a yyrestart() or at EOF. + */ +    static void yy_init_buffer  (YY_BUFFER_STATE  b, FILE * file ) + +{ +	int oerrno = errno; +     +	yy_flush_buffer(b ); + +	b->yy_input_file = file; +	b->yy_fill_buffer = 1; + +    /* If b is the current buffer, then yy_init_buffer was _probably_ +     * called from yyrestart() or through yy_get_next_buffer. +     * In that case, we don't want to reset the lineno or column. +     */ +    if (b != YY_CURRENT_BUFFER){ +        b->yy_bs_lineno = 1; +        b->yy_bs_column = 0; +    } + +        b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; +     +	errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + *  + */ +    void yy_flush_buffer (YY_BUFFER_STATE  b ) +{ +    	if ( ! b ) +		return; + +	b->yy_n_chars = 0; + +	/* We always need two end-of-buffer characters.  The first causes +	 * a transition to the end-of-buffer state.  The second causes +	 * a jam in that state. +	 */ +	b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; +	b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + +	b->yy_buf_pos = &b->yy_ch_buf[0]; + +	b->yy_at_bol = 1; +	b->yy_buffer_status = YY_BUFFER_NEW; + +	if ( b == YY_CURRENT_BUFFER ) +		yy_load_buffer_state( ); +} + +/** Pushes the new state onto the stack. The new state becomes + *  the current state. This function will allocate the stack + *  if necessary. + *  @param new_buffer The new state. + *   + */ +void yypush_buffer_state (YY_BUFFER_STATE new_buffer ) +{ +    	if (new_buffer == NULL) +		return; + +	yyensure_buffer_stack(); + +	/* This block is copied from yy_switch_to_buffer. */ +	if ( YY_CURRENT_BUFFER ) +		{ +		/* Flush out information for old buffer. */ +		*(yy_c_buf_p) = (yy_hold_char); +		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); +		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); +		} + +	/* Only push if top exists. Otherwise, replace top. */ +	if (YY_CURRENT_BUFFER) +		(yy_buffer_stack_top)++; +	YY_CURRENT_BUFFER_LVALUE = new_buffer; + +	/* copied from yy_switch_to_buffer. */ +	yy_load_buffer_state( ); +	(yy_did_buffer_switch_on_eof) = 1; +} + +/** Removes and deletes the top of the stack, if present. + *  The next element becomes the new top. + *   + */ +void yypop_buffer_state (void) +{ +    	if (!YY_CURRENT_BUFFER) +		return; + +	yy_delete_buffer(YY_CURRENT_BUFFER ); +	YY_CURRENT_BUFFER_LVALUE = NULL; +	if ((yy_buffer_stack_top) > 0) +		--(yy_buffer_stack_top); + +	if (YY_CURRENT_BUFFER) { +		yy_load_buffer_state( ); +		(yy_did_buffer_switch_on_eof) = 1; +	} +} + +/* Allocates the stack if it does not exist. + *  Guarantees space for at least one push. + */ +static void yyensure_buffer_stack (void) +{ +	int num_to_alloc; +     +	if (!(yy_buffer_stack)) { + +		/* First allocation is just for 2 elements, since we don't know if this +		 * scanner will even need a stack. We use 2 instead of 1 to avoid an +		 * immediate realloc on the next call. +         */ +		num_to_alloc = 1; +		(yy_buffer_stack) = (struct yy_buffer_state**)yyalloc +								(num_to_alloc * sizeof(struct yy_buffer_state*) +								); +		if ( ! (yy_buffer_stack) ) +			YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); +								   +		memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); +				 +		(yy_buffer_stack_max) = num_to_alloc; +		(yy_buffer_stack_top) = 0; +		return; +	} + +	if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ + +		/* Increase the buffer to prepare for a possible push. */ +		int grow_size = 8 /* arbitrary grow size */; + +		num_to_alloc = (yy_buffer_stack_max) + grow_size; +		(yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc +								((yy_buffer_stack), +								num_to_alloc * sizeof(struct yy_buffer_state*) +								); +		if ( ! (yy_buffer_stack) ) +			YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + +		/* zero only the new slots.*/ +		memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); +		(yy_buffer_stack_max) = num_to_alloc; +	} +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + *  + * @return the newly allocated buffer state object.  + */ +YY_BUFFER_STATE yy_scan_buffer  (char * base, yy_size_t  size ) +{ +	YY_BUFFER_STATE b; +     +	if ( size < 2 || +	     base[size-2] != YY_END_OF_BUFFER_CHAR || +	     base[size-1] != YY_END_OF_BUFFER_CHAR ) +		/* They forgot to leave room for the EOB's. */ +		return 0; + +	b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state )  ); +	if ( ! b ) +		YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + +	b->yy_buf_size = size - 2;	/* "- 2" to take care of EOB's */ +	b->yy_buf_pos = b->yy_ch_buf = base; +	b->yy_is_our_buffer = 0; +	b->yy_input_file = 0; +	b->yy_n_chars = b->yy_buf_size; +	b->yy_is_interactive = 0; +	b->yy_at_bol = 1; +	b->yy_fill_buffer = 0; +	b->yy_buffer_status = YY_BUFFER_NEW; + +	yy_switch_to_buffer(b  ); + +	return b; +} + +/** Setup the input buffer state to scan a string. The next call to yylex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + *  + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + *       yy_scan_bytes() instead. + */ +YY_BUFFER_STATE yy_scan_string (yyconst char * yystr ) +{ +     +	return yy_scan_bytes(yystr,strlen(yystr) ); +} + +/** Setup the input buffer state to scan the given bytes. The next call to yylex() will + * scan from a @e copy of @a bytes. + * @param bytes the byte buffer to scan + * @param len the number of bytes in the buffer pointed to by @a bytes. + *  + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_bytes  (yyconst char * yybytes, int  _yybytes_len ) +{ +	YY_BUFFER_STATE b; +	char *buf; +	yy_size_t n; +	int i; +     +	/* Get memory for full buffer, including space for trailing EOB's. */ +	n = _yybytes_len + 2; +	buf = (char *) yyalloc(n  ); +	if ( ! buf ) +		YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + +	for ( i = 0; i < _yybytes_len; ++i ) +		buf[i] = yybytes[i]; + +	buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + +	b = yy_scan_buffer(buf,n ); +	if ( ! b ) +		YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + +	/* It's okay to grow etc. this buffer, and we should throw it +	 * away when we're done. +	 */ +	b->yy_is_our_buffer = 1; + +	return b; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yy_fatal_error (yyconst char* msg ) +{ +    	(void) fprintf( stderr, "%s\n", msg ); +	exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ +	do \ +		{ \ +		/* Undo effects of setting up yytext. */ \ +        int yyless_macro_arg = (n); \ +        YY_LESS_LINENO(yyless_macro_arg);\ +		yytext[yyleng] = (yy_hold_char); \ +		(yy_c_buf_p) = yytext + yyless_macro_arg; \ +		(yy_hold_char) = *(yy_c_buf_p); \ +		*(yy_c_buf_p) = '\0'; \ +		yyleng = yyless_macro_arg; \ +		} \ +	while ( 0 ) + +/* Accessor  methods (get/set functions) to struct members. */ + +/** Get the current line number. + *  + */ +int yyget_lineno  (void) +{ +         +    return yylineno; +} + +/** Get the input stream. + *  + */ +FILE *yyget_in  (void) +{ +        return yyin; +} + +/** Get the output stream. + *  + */ +FILE *yyget_out  (void) +{ +        return yyout; +} + +/** Get the length of the current token. + *  + */ +int yyget_leng  (void) +{ +        return yyleng; +} + +/** Get the current token. + *  + */ + +char *yyget_text  (void) +{ +        return yytext; +} + +/** Set the current line number. + * @param line_number + *  + */ +void yyset_lineno (int  line_number ) +{ +     +    yylineno = line_number; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param in_str A readable stream. + *  + * @see yy_switch_to_buffer + */ +void yyset_in (FILE *  in_str ) +{ +        yyin = in_str ; +} + +void yyset_out (FILE *  out_str ) +{ +        yyout = out_str ; +} + +int yyget_debug  (void) +{ +        return yy_flex_debug; +} + +void yyset_debug (int  bdebug ) +{ +        yy_flex_debug = bdebug ; +} + +static int yy_init_globals (void) +{ +        /* Initialization is the same as for the non-reentrant scanner. +     * This function is called from yylex_destroy(), so don't allocate here. +     */ + +    /* We do not touch yylineno unless the option is enabled. */ +    yylineno =  1; +     +    (yy_buffer_stack) = 0; +    (yy_buffer_stack_top) = 0; +    (yy_buffer_stack_max) = 0; +    (yy_c_buf_p) = (char *) 0; +    (yy_init) = 0; +    (yy_start) = 0; + +/* Defined in main.c */ +#ifdef YY_STDINIT +    yyin = stdin; +    yyout = stdout; +#else +    yyin = (FILE *) 0; +    yyout = (FILE *) 0; +#endif + +    /* For future reference: Set errno on error, since we are called by +     * yylex_init() +     */ +    return 0; +} + +/* yylex_destroy is for both reentrant and non-reentrant scanners. */ +int yylex_destroy  (void) +{ +     +    /* Pop the buffer stack, destroying each element. */ +	while(YY_CURRENT_BUFFER){ +		yy_delete_buffer(YY_CURRENT_BUFFER  ); +		YY_CURRENT_BUFFER_LVALUE = NULL; +		yypop_buffer_state(); +	} + +	/* Destroy the stack itself. */ +	yyfree((yy_buffer_stack) ); +	(yy_buffer_stack) = NULL; + +    /* Reset the globals. This is important in a non-reentrant scanner so the next time +     * yylex() is called, initialization will occur. */ +    yy_init_globals( ); + +    return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) +{ +	register int i; +	for ( i = 0; i < n; ++i ) +		s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * s ) +{ +	register int n; +	for ( n = 0; s[n]; ++n ) +		; + +	return n; +} +#endif + +void *yyalloc (yy_size_t  size ) +{ +	return (void *) malloc( size ); +} + +void *yyrealloc  (void * ptr, yy_size_t  size ) +{ +	/* The cast to (char *) in the following accommodates both +	 * implementations that use char* generic pointers, and those +	 * that use void* generic pointers.  It works with the latter +	 * because both ANSI C and C++ allow castless assignment from +	 * any pointer type to void*, and deal with argument conversions +	 * as though doing an assignment. +	 */ +	return (void *) realloc( (char *) ptr, size ); +} + +void yyfree (void * ptr ) +{ +	free( (char *) ptr );	/* see yyrealloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +#line 222 "dtc-lexer.l" + + + + +/* + * Stack of nested include file contexts. + */ + +struct incl_file { +	struct dtc_file *file; +	YY_BUFFER_STATE yy_prev_buf; +	int yy_prev_lineno; +	struct incl_file *prev; +}; + +static struct incl_file *incl_file_stack; + + +/* + * Detect infinite include recursion. + */ +#define MAX_INCLUDE_DEPTH	(100) + +static int incl_depth = 0; + + +static void push_input_file(const char *filename) +{ +	struct incl_file *incl_file; +	struct dtc_file *newfile; +	struct search_path search, *searchptr = NULL; + +	assert(filename); + +	if (incl_depth++ >= MAX_INCLUDE_DEPTH) +		die("Includes nested too deeply"); + +	if (srcpos_file) { +		search.dir = srcpos_file->dir; +		search.next = NULL; +		search.prev = NULL; +		searchptr = &search; +	} + +	newfile = dtc_open_file(filename, searchptr); + +	incl_file = xmalloc(sizeof(struct incl_file)); + +	/* +	 * Save current context. +	 */ +	incl_file->yy_prev_buf = YY_CURRENT_BUFFER; +	incl_file->yy_prev_lineno = yylineno; +	incl_file->file = srcpos_file; +	incl_file->prev = incl_file_stack; + +	incl_file_stack = incl_file; + +	/* +	 * Establish new context. +	 */ +	srcpos_file = newfile; +	yylineno = 1; +	yyin = newfile->file; +	yy_switch_to_buffer(yy_create_buffer(yyin,YY_BUF_SIZE)); +} + + +static int pop_input_file(void) +{ +	struct incl_file *incl_file; + +	if (incl_file_stack == 0) +		return 0; + +	dtc_close_file(srcpos_file); + +	/* +	 * Pop. +	 */ +	--incl_depth; +	incl_file = incl_file_stack; +	incl_file_stack = incl_file->prev; + +	/* +	 * Recover old context. +	 */ +	yy_delete_buffer(YY_CURRENT_BUFFER); +	yy_switch_to_buffer(incl_file->yy_prev_buf); +	yylineno = incl_file->yy_prev_lineno; +	srcpos_file = incl_file->file; +	yyin = incl_file->file ? incl_file->file->file : NULL; + +	/* +	 * Free old state. +	 */ +	free(incl_file); + +	return 1; +} + diff --git a/scripts/dtc/dtc-parser.tab.c_shipped b/scripts/dtc/dtc-parser.tab.c_shipped new file mode 100644 index 00000000000..27129377e5d --- /dev/null +++ b/scripts/dtc/dtc-parser.tab.c_shipped @@ -0,0 +1,2040 @@ +/* A Bison parser, made by GNU Bison 2.3.  */ + +/* Skeleton implementation for Bison's Yacc-like parsers in C + +   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 +   Free Software Foundation, Inc. + +   This program is free software; you can redistribute it and/or modify +   it under the terms of the GNU General Public License as published by +   the Free Software Foundation; either version 2, or (at your option) +   any later version. + +   This program is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +   GNU General Public License for more details. + +   You should have received a copy of the GNU General Public License +   along with this program; if not, write to the Free Software +   Foundation, Inc., 51 Franklin Street, Fifth Floor, +   Boston, MA 02110-1301, USA.  */ + +/* As a special exception, you may create a larger work that contains +   part or all of the Bison parser skeleton and distribute that work +   under terms of your choice, so long as that work isn't itself a +   parser generator using the skeleton or a modified version thereof +   as a parser skeleton.  Alternatively, if you modify or redistribute +   the parser skeleton itself, you may (at your option) remove this +   special exception, which will cause the skeleton and the resulting +   Bison output files to be licensed under the GNU General Public +   License without this special exception. + +   This special exception was added by the Free Software Foundation in +   version 2.2 of Bison.  */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by +   simplifying the original so-called "semantic" parser.  */ + +/* All symbols defined below should begin with yy or YY, to avoid +   infringing on user name space.  This should be done even for local +   variables, as they might otherwise be expanded by user macros. +   There are some unavoidable exceptions within include files to +   define necessary library symbols; they are noted "INFRINGES ON +   USER NAME SPACE" below.  */ + +/* Identify Bison output.  */ +#define YYBISON 1 + +/* Bison version.  */ +#define YYBISON_VERSION "2.3" + +/* Skeleton name.  */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers.  */ +#define YYPURE 0 + +/* Using locations.  */ +#define YYLSP_NEEDED 1 + + + +/* Tokens.  */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE +   /* Put the tokens into the symbol table, so that GDB and other debuggers +      know about them.  */ +   enum yytokentype { +     DT_V1 = 258, +     DT_MEMRESERVE = 259, +     DT_PROPNODENAME = 260, +     DT_LITERAL = 261, +     DT_LEGACYLITERAL = 262, +     DT_BASE = 263, +     DT_BYTE = 264, +     DT_STRING = 265, +     DT_LABEL = 266, +     DT_REF = 267, +     DT_INCBIN = 268 +   }; +#endif +/* Tokens.  */ +#define DT_V1 258 +#define DT_MEMRESERVE 259 +#define DT_PROPNODENAME 260 +#define DT_LITERAL 261 +#define DT_LEGACYLITERAL 262 +#define DT_BASE 263 +#define DT_BYTE 264 +#define DT_STRING 265 +#define DT_LABEL 266 +#define DT_REF 267 +#define DT_INCBIN 268 + + + + +/* Copy the first part of user declarations.  */ +#line 23 "dtc-parser.y" + +#include <stdio.h> + +#include "dtc.h" +#include "srcpos.h" + +extern int yylex(void); + +extern struct boot_info *the_boot_info; +extern int treesource_error; + +static unsigned long long eval_literal(const char *s, int base, int bits); + + +/* Enabling traces.  */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + +/* Enabling verbose error messages.  */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +/* Enabling the token table.  */ +#ifndef YYTOKEN_TABLE +# define YYTOKEN_TABLE 0 +#endif + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +#line 37 "dtc-parser.y" +{ +	char *propnodename; +	char *literal; +	char *labelref; +	unsigned int cbase; +	uint8_t byte; +	struct data data; + +	uint64_t addr; +	cell_t cell; +	struct property *prop; +	struct property *proplist; +	struct node *node; +	struct node *nodelist; +	struct reserve_info *re; +} +/* Line 187 of yacc.c.  */ +#line 153 "dtc-parser.tab.c" +	YYSTYPE; +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 +#endif + +#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED +typedef struct YYLTYPE +{ +  int first_line; +  int first_column; +  int last_line; +  int last_column; +} YYLTYPE; +# define yyltype YYLTYPE /* obsolescent; will be withdrawn */ +# define YYLTYPE_IS_DECLARED 1 +# define YYLTYPE_IS_TRIVIAL 1 +#endif + + +/* Copy the second part of user declarations.  */ + + +/* Line 216 of yacc.c.  */ +#line 178 "dtc-parser.tab.c" + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#elif (defined __STDC__ || defined __C99__FUNC__ \ +     || defined __cplusplus || defined _MSC_VER) +typedef signed char yytype_int8; +#else +typedef short int yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +#  define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +#  define YYSIZE_T size_t +# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ +     || defined __cplusplus || defined _MSC_VER) +#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */ +#  define YYSIZE_T size_t +# else +#  define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if YYENABLE_NLS +#  if ENABLE_NLS +#   include <libintl.h> /* INFRINGES ON USER NAME SPACE */ +#   define YY_(msgid) dgettext ("bison-runtime", msgid) +#  endif +# endif +# ifndef YY_ +#  define YY_(msgid) msgid +# endif +#endif + +/* Suppress unused-variable warnings by "using" E.  */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(e) ((void) (e)) +#else +# define YYUSE(e) /* empty */ +#endif + +/* Identity function, used to suppress warnings about constant conditions.  */ +#ifndef lint +# define YYID(n) (n) +#else +#if (defined __STDC__ || defined __C99__FUNC__ \ +     || defined __cplusplus || defined _MSC_VER) +static int +YYID (int i) +#else +static int +YYID (i) +    int i; +#endif +{ +  return i; +} +#endif + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols.  */ + +# ifdef YYSTACK_USE_ALLOCA +#  if YYSTACK_USE_ALLOCA +#   ifdef __GNUC__ +#    define YYSTACK_ALLOC __builtin_alloca +#   elif defined __BUILTIN_VA_ARG_INCR +#    include <alloca.h> /* INFRINGES ON USER NAME SPACE */ +#   elif defined _AIX +#    define YYSTACK_ALLOC __alloca +#   elif defined _MSC_VER +#    include <malloc.h> /* INFRINGES ON USER NAME SPACE */ +#    define alloca _alloca +#   else +#    define YYSTACK_ALLOC alloca +#    if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ +     || defined __cplusplus || defined _MSC_VER) +#     include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +#     ifndef _STDLIB_H +#      define _STDLIB_H 1 +#     endif +#    endif +#   endif +#  endif +# endif + +# ifdef YYSTACK_ALLOC +   /* Pacify GCC's `empty if-body' warning.  */ +#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) +#  ifndef YYSTACK_ALLOC_MAXIMUM +    /* The OS might guarantee only one guard page at the bottom of the stack, +       and a page size can be as small as 4096 bytes.  So we cannot safely +       invoke alloca (N) if N exceeds 4096.  Use a slightly smaller number +       to allow for a few compiler-allocated temporary stack slots.  */ +#   define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +#  endif +# else +#  define YYSTACK_ALLOC YYMALLOC +#  define YYSTACK_FREE YYFREE +#  ifndef YYSTACK_ALLOC_MAXIMUM +#   define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +#  endif +#  if (defined __cplusplus && ! defined _STDLIB_H \ +       && ! ((defined YYMALLOC || defined malloc) \ +	     && (defined YYFREE || defined free))) +#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +#   ifndef _STDLIB_H +#    define _STDLIB_H 1 +#   endif +#  endif +#  ifndef YYMALLOC +#   define YYMALLOC malloc +#   if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ +     || defined __cplusplus || defined _MSC_VER) +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +#   endif +#  endif +#  ifndef YYFREE +#   define YYFREE free +#   if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ +     || defined __cplusplus || defined _MSC_VER) +void free (void *); /* INFRINGES ON USER NAME SPACE */ +#   endif +#  endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ +     && (! defined __cplusplus \ +	 || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \ +	     && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member.  */ +union yyalloc +{ +  yytype_int16 yyss; +  YYSTYPE yyvs; +    YYLTYPE yyls; +}; + +/* The size of the maximum gap between one aligned stack and the next.  */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with +   N elements.  */ +# define YYSTACK_BYTES(N) \ +     ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \ +      + 2 * YYSTACK_GAP_MAXIMUM) + +/* Copy COUNT objects from FROM to TO.  The source and destination do +   not overlap.  */ +# ifndef YYCOPY +#  if defined __GNUC__ && 1 < __GNUC__ +#   define YYCOPY(To, From, Count) \ +      __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +#  else +#   define YYCOPY(To, From, Count)		\ +      do					\ +	{					\ +	  YYSIZE_T yyi;				\ +	  for (yyi = 0; yyi < (Count); yyi++)	\ +	    (To)[yyi] = (From)[yyi];		\ +	}					\ +      while (YYID (0)) +#  endif +# endif + +/* Relocate STACK from its old location to the new one.  The +   local variables YYSIZE and YYSTACKSIZE give the old and new number of +   elements in the stack, and YYPTR gives the new location of the +   stack.  Advance YYPTR to a properly aligned location for the next +   stack.  */ +# define YYSTACK_RELOCATE(Stack)					\ +    do									\ +      {									\ +	YYSIZE_T yynewbytes;						\ +	YYCOPY (&yyptr->Stack, Stack, yysize);				\ +	Stack = &yyptr->Stack;						\ +	yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ +	yyptr += yynewbytes / sizeof (*yyptr);				\ +      }									\ +    while (YYID (0)) + +#endif + +/* YYFINAL -- State number of the termination state.  */ +#define YYFINAL  9 +/* YYLAST -- Last index in YYTABLE.  */ +#define YYLAST   73 + +/* YYNTOKENS -- Number of terminals.  */ +#define YYNTOKENS  27 +/* YYNNTS -- Number of nonterminals.  */ +#define YYNNTS  20 +/* YYNRULES -- Number of rules.  */ +#define YYNRULES  45 +/* YYNRULES -- Number of states.  */ +#define YYNSTATES  76 + +/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */ +#define YYUNDEFTOK  2 +#define YYMAXUTOK   268 + +#define YYTRANSLATE(YYX)						\ +  ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX.  */ +static const yytype_uint8 yytranslate[] = +{ +       0,     2,     2,     2,     2,     2,     2,     2,     2,     2, +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2, +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2, +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2, +      24,    26,     2,     2,    25,    15,     2,    16,     2,     2, +       2,     2,     2,     2,     2,     2,     2,     2,     2,    14, +      20,    19,    21,     2,     2,     2,     2,     2,     2,     2, +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2, +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2, +       2,    22,     2,    23,     2,     2,     2,     2,     2,     2, +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2, +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2, +       2,     2,     2,    17,     2,    18,     2,     2,     2,     2, +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2, +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2, +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2, +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2, +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2, +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2, +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2, +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2, +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2, +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2, +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2, +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2, +       2,     2,     2,     2,     2,     2,     1,     2,     3,     4, +       5,     6,     7,     8,     9,    10,    11,    12,    13 +}; + +#if YYDEBUG +/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in +   YYRHS.  */ +static const yytype_uint8 yyprhs[] = +{ +       0,     0,     3,     8,    11,    12,    15,    21,    22,    25, +      27,    34,    36,    38,    41,    47,    48,    51,    57,    61, +      64,    69,    74,    77,    87,    93,    96,    97,   100,   103, +     104,   107,   110,   113,   114,   116,   118,   121,   122,   125, +     128,   129,   132,   135,   139,   140 +}; + +/* YYRHS -- A `-1'-separated list of the rules' RHS.  */ +static const yytype_int8 yyrhs[] = +{ +      28,     0,    -1,     3,    14,    29,    34,    -1,    31,    34, +      -1,    -1,    30,    29,    -1,    46,     4,    33,    33,    14, +      -1,    -1,    32,    31,    -1,    30,    -1,    46,     4,    33, +      15,    33,    14,    -1,     6,    -1,     7,    -1,    16,    35, +      -1,    17,    36,    44,    18,    14,    -1,    -1,    36,    37, +      -1,    46,     5,    19,    38,    14,    -1,    46,     5,    14, +      -1,    39,    10,    -1,    39,    20,    40,    21,    -1,    39, +      22,    43,    23,    -1,    39,    12,    -1,    39,    13,    24, +      10,    25,    33,    25,    33,    26,    -1,    39,    13,    24, +      10,    26,    -1,    38,    11,    -1,    -1,    38,    25,    -1, +      39,    11,    -1,    -1,    40,    42,    -1,    40,    12,    -1, +      40,    11,    -1,    -1,     8,    -1,     6,    -1,    41,     7, +      -1,    -1,    43,     9,    -1,    43,    11,    -1,    -1,    45, +      44,    -1,    45,    37,    -1,    46,     5,    35,    -1,    -1, +      11,    -1 +}; + +/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */ +static const yytype_uint16 yyrline[] = +{ +       0,    89,    89,    93,   101,   104,   111,   119,   122,   129, +     133,   140,   144,   151,   158,   166,   169,   176,   180,   187, +     191,   195,   199,   203,   220,   231,   239,   242,   246,   254, +     257,   261,   266,   274,   277,   281,   285,   293,   296,   300, +     308,   311,   315,   323,   331,   334 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. +   First, the terminals, then, starting at YYNTOKENS, nonterminals.  */ +static const char *const yytname[] = +{ +  "$end", "error", "$undefined", "DT_V1", "DT_MEMRESERVE", +  "DT_PROPNODENAME", "DT_LITERAL", "DT_LEGACYLITERAL", "DT_BASE", +  "DT_BYTE", "DT_STRING", "DT_LABEL", "DT_REF", "DT_INCBIN", "';'", "'-'", +  "'/'", "'{'", "'}'", "'='", "'<'", "'>'", "'['", "']'", "'('", "','", +  "')'", "$accept", "sourcefile", "memreserves", "memreserve", +  "v0_memreserves", "v0_memreserve", "addr", "devicetree", "nodedef", +  "proplist", "propdef", "propdata", "propdataprefix", "celllist", +  "cellbase", "cellval", "bytestring", "subnodes", "subnode", "label", 0 +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to +   token YYLEX-NUM.  */ +static const yytype_uint16 yytoknum[] = +{ +       0,   256,   257,   258,   259,   260,   261,   262,   263,   264, +     265,   266,   267,   268,    59,    45,    47,   123,   125,    61, +      60,    62,    91,    93,    40,    44,    41 +}; +# endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */ +static const yytype_uint8 yyr1[] = +{ +       0,    27,    28,    28,    29,    29,    30,    31,    31,    32, +      32,    33,    33,    34,    35,    36,    36,    37,    37,    38, +      38,    38,    38,    38,    38,    38,    39,    39,    39,    40, +      40,    40,    40,    41,    41,    42,    42,    43,    43,    43, +      44,    44,    44,    45,    46,    46 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */ +static const yytype_uint8 yyr2[] = +{ +       0,     2,     4,     2,     0,     2,     5,     0,     2,     1, +       6,     1,     1,     2,     5,     0,     2,     5,     3,     2, +       4,     4,     2,     9,     5,     2,     0,     2,     2,     0, +       2,     2,     2,     0,     1,     1,     2,     0,     2,     2, +       0,     2,     2,     3,     0,     1 +}; + +/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state +   STATE-NUM when YYTABLE doesn't specify something else to do.  Zero +   means the default is an error.  */ +static const yytype_uint8 yydefact[] = +{ +       7,     0,    45,     0,     9,     0,     7,     0,     4,     1, +       0,     3,     8,     0,     0,     4,     0,    15,    13,    11, +      12,     0,     2,     5,     0,    40,     0,     0,     0,    16, +       0,    40,     0,     0,     6,     0,    42,    41,     0,    10, +      14,    18,    26,    43,     0,     0,    25,    17,    27,    19, +      28,    22,     0,    29,    37,     0,    33,     0,     0,    35, +      34,    32,    31,    20,     0,    30,    38,    39,    21,     0, +      24,    36,     0,     0,     0,    23 +}; + +/* YYDEFGOTO[NTERM-NUM].  */ +static const yytype_int8 yydefgoto[] = +{ +      -1,     3,    14,     4,     5,     6,    27,    11,    18,    25, +      29,    44,    45,    56,    64,    65,    57,    30,    31,     7 +}; + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing +   STATE-NUM.  */ +#define YYPACT_NINF -14 +static const yytype_int8 yypact[] = +{ +      30,   -11,   -14,     7,   -14,    -1,    27,    13,    27,   -14, +       8,   -14,   -14,    40,    -1,    27,    35,   -14,   -14,   -14, +     -14,    21,   -14,   -14,    40,    24,    40,    28,    40,   -14, +      32,    24,    46,    38,   -14,    39,   -14,   -14,    26,   -14, +     -14,   -14,   -14,   -14,    -9,    10,   -14,   -14,   -14,   -14, +     -14,   -14,    31,   -14,   -14,    44,    -2,     3,    23,   -14, +     -14,   -14,   -14,   -14,    50,   -14,   -14,   -14,   -14,    40, +     -14,   -14,    33,    40,    36,   -14 +}; + +/* YYPGOTO[NTERM-NUM].  */ +static const yytype_int8 yypgoto[] = +{ +     -14,   -14,    48,    29,    53,   -14,   -13,    47,    34,   -14, +      37,   -14,   -14,   -14,   -14,   -14,   -14,    42,   -14,    -7 +}; + +/* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If +   positive, shift that token.  If negative, reduce the rule which +   number is the opposite.  If zero, do what YYDEFACT says. +   If YYTABLE_NINF, syntax error.  */ +#define YYTABLE_NINF -45 +static const yytype_int8 yytable[] = +{ +      21,    16,    46,     8,    59,    47,    60,     9,    16,    61, +      62,    28,    66,    33,    67,    10,    48,    13,    32,    63, +      49,    50,    51,    52,    32,    17,    68,    19,    20,   -44, +      53,   -44,    54,     1,   -44,     2,    26,    15,     2,    24, +      41,     2,    34,    17,    15,    42,    19,    20,    69,    70, +      35,    38,    39,    40,    58,    55,    72,    71,    73,    12, +      74,    22,    75,    23,     0,     0,     0,     0,    36,     0, +       0,     0,    43,    37 +}; + +static const yytype_int8 yycheck[] = +{ +      13,     8,    11,    14,     6,    14,     8,     0,    15,    11, +      12,    24,     9,    26,    11,    16,    25,     4,    25,    21, +      10,    11,    12,    13,    31,    17,    23,     6,     7,     5, +      20,     4,    22,     3,     4,    11,    15,     8,    11,     4, +      14,    11,    14,    17,    15,    19,     6,     7,    25,    26, +      18,     5,    14,    14,    10,    24,    69,     7,    25,     6, +      73,    14,    26,    15,    -1,    -1,    -1,    -1,    31,    -1, +      -1,    -1,    38,    31 +}; + +/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing +   symbol of state STATE-NUM.  */ +static const yytype_uint8 yystos[] = +{ +       0,     3,    11,    28,    30,    31,    32,    46,    14,     0, +      16,    34,    31,     4,    29,    30,    46,    17,    35,     6, +       7,    33,    34,    29,     4,    36,    15,    33,    33,    37, +      44,    45,    46,    33,    14,    18,    37,    44,     5,    14, +      14,    14,    19,    35,    38,    39,    11,    14,    25,    10, +      11,    12,    13,    20,    22,    24,    40,    43,    10,     6, +       8,    11,    12,    21,    41,    42,     9,    11,    23,    25, +      26,     7,    33,    25,    33,    26 +}; + +#define yyerrok		(yyerrstatus = 0) +#define yyclearin	(yychar = YYEMPTY) +#define YYEMPTY		(-2) +#define YYEOF		0 + +#define YYACCEPT	goto yyacceptlab +#define YYABORT		goto yyabortlab +#define YYERROR		goto yyerrorlab + + +/* Like YYERROR except do call yyerror.  This remains here temporarily +   to ease the transition to the new meaning of YYERROR, for GCC. +   Once GCC version 2 has supplanted version 1, this can go.  */ + +#define YYFAIL		goto yyerrlab + +#define YYRECOVERING()  (!!yyerrstatus) + +#define YYBACKUP(Token, Value)					\ +do								\ +  if (yychar == YYEMPTY && yylen == 1)				\ +    {								\ +      yychar = (Token);						\ +      yylval = (Value);						\ +      yytoken = YYTRANSLATE (yychar);				\ +      YYPOPSTACK (1);						\ +      goto yybackup;						\ +    }								\ +  else								\ +    {								\ +      yyerror (YY_("syntax error: cannot back up")); \ +      YYERROR;							\ +    }								\ +while (YYID (0)) + + +#define YYTERROR	1 +#define YYERRCODE	256 + + +/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. +   If N is 0, then set CURRENT to the empty location which ends +   the previous symbol: RHS[0] (always defined).  */ + +#define YYRHSLOC(Rhs, K) ((Rhs)[K]) +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N)				\ +    do									\ +      if (YYID (N))                                                    \ +	{								\ +	  (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;	\ +	  (Current).first_column = YYRHSLOC (Rhs, 1).first_column;	\ +	  (Current).last_line    = YYRHSLOC (Rhs, N).last_line;		\ +	  (Current).last_column  = YYRHSLOC (Rhs, N).last_column;	\ +	}								\ +      else								\ +	{								\ +	  (Current).first_line   = (Current).last_line   =		\ +	    YYRHSLOC (Rhs, 0).last_line;				\ +	  (Current).first_column = (Current).last_column =		\ +	    YYRHSLOC (Rhs, 0).last_column;				\ +	}								\ +    while (YYID (0)) +#endif + + +/* YY_LOCATION_PRINT -- Print the location on the stream. +   This macro was not mandated originally: define only if we know +   we won't break user code: when these are the locations we know.  */ + +#ifndef YY_LOCATION_PRINT +# if YYLTYPE_IS_TRIVIAL +#  define YY_LOCATION_PRINT(File, Loc)			\ +     fprintf (File, "%d.%d-%d.%d",			\ +	      (Loc).first_line, (Loc).first_column,	\ +	      (Loc).last_line,  (Loc).last_column) +# else +#  define YY_LOCATION_PRINT(File, Loc) ((void) 0) +# endif +#endif + + +/* YYLEX -- calling `yylex' with the right arguments.  */ + +#ifdef YYLEX_PARAM +# define YYLEX yylex (YYLEX_PARAM) +#else +# define YYLEX yylex () +#endif + +/* Enable debugging if requested.  */ +#if YYDEBUG + +# ifndef YYFPRINTF +#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */ +#  define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args)			\ +do {						\ +  if (yydebug)					\ +    YYFPRINTF Args;				\ +} while (YYID (0)) + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location)			  \ +do {									  \ +  if (yydebug)								  \ +    {									  \ +      YYFPRINTF (stderr, "%s ", Title);					  \ +      yy_symbol_print (stderr,						  \ +		  Type, Value, Location); \ +      YYFPRINTF (stderr, "\n");						  \ +    }									  \ +} while (YYID (0)) + + +/*--------------------------------. +| Print this symbol on YYOUTPUT.  | +`--------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ +     || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp) +#else +static void +yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp) +    FILE *yyoutput; +    int yytype; +    YYSTYPE const * const yyvaluep; +    YYLTYPE const * const yylocationp; +#endif +{ +  if (!yyvaluep) +    return; +  YYUSE (yylocationp); +# ifdef YYPRINT +  if (yytype < YYNTOKENS) +    YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# else +  YYUSE (yyoutput); +# endif +  switch (yytype) +    { +      default: +	break; +    } +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT.  | +`--------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ +     || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp) +#else +static void +yy_symbol_print (yyoutput, yytype, yyvaluep, yylocationp) +    FILE *yyoutput; +    int yytype; +    YYSTYPE const * const yyvaluep; +    YYLTYPE const * const yylocationp; +#endif +{ +  if (yytype < YYNTOKENS) +    YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); +  else +    YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); + +  YY_LOCATION_PRINT (yyoutput, *yylocationp); +  YYFPRINTF (yyoutput, ": "); +  yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp); +  YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included).                                                   | +`------------------------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ +     || defined __cplusplus || defined _MSC_VER) +static void +yy_stack_print (yytype_int16 *bottom, yytype_int16 *top) +#else +static void +yy_stack_print (bottom, top) +    yytype_int16 *bottom; +    yytype_int16 *top; +#endif +{ +  YYFPRINTF (stderr, "Stack now"); +  for (; bottom <= top; ++bottom) +    YYFPRINTF (stderr, " %d", *bottom); +  YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top)				\ +do {								\ +  if (yydebug)							\ +    yy_stack_print ((Bottom), (Top));				\ +} while (YYID (0)) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced.  | +`------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ +     || defined __cplusplus || defined _MSC_VER) +static void +yy_reduce_print (YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule) +#else +static void +yy_reduce_print (yyvsp, yylsp, yyrule) +    YYSTYPE *yyvsp; +    YYLTYPE *yylsp; +    int yyrule; +#endif +{ +  int yynrhs = yyr2[yyrule]; +  int yyi; +  unsigned long int yylno = yyrline[yyrule]; +  YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", +	     yyrule - 1, yylno); +  /* The symbols being reduced.  */ +  for (yyi = 0; yyi < yynrhs; yyi++) +    { +      fprintf (stderr, "   $%d = ", yyi + 1); +      yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], +		       &(yyvsp[(yyi + 1) - (yynrhs)]) +		       , &(yylsp[(yyi + 1) - (yynrhs)])		       ); +      fprintf (stderr, "\n"); +    } +} + +# define YY_REDUCE_PRINT(Rule)		\ +do {					\ +  if (yydebug)				\ +    yy_reduce_print (yyvsp, yylsp, Rule); \ +} while (YYID (0)) + +/* Nonzero means print parse trace.  It is left uninitialized so that +   multiple parsers can coexist.  */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks.  */ +#ifndef	YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only +   if the built-in stack extension method is used). + +   Do not make this value too large; the results are undefined if +   YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) +   evaluated with infinite-precision integer arithmetic.  */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +#  if defined __GLIBC__ && defined _STRING_H +#   define yystrlen strlen +#  else +/* Return the length of YYSTR.  */ +#if (defined __STDC__ || defined __C99__FUNC__ \ +     || defined __cplusplus || defined _MSC_VER) +static YYSIZE_T +yystrlen (const char *yystr) +#else +static YYSIZE_T +yystrlen (yystr) +    const char *yystr; +#endif +{ +  YYSIZE_T yylen; +  for (yylen = 0; yystr[yylen]; yylen++) +    continue; +  return yylen; +} +#  endif +# endif + +# ifndef yystpcpy +#  if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +#   define yystpcpy stpcpy +#  else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in +   YYDEST.  */ +#if (defined __STDC__ || defined __C99__FUNC__ \ +     || defined __cplusplus || defined _MSC_VER) +static char * +yystpcpy (char *yydest, const char *yysrc) +#else +static char * +yystpcpy (yydest, yysrc) +    char *yydest; +    const char *yysrc; +#endif +{ +  char *yyd = yydest; +  const char *yys = yysrc; + +  while ((*yyd++ = *yys++) != '\0') +    continue; + +  return yyd - 1; +} +#  endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary +   quotes and backslashes, so that it's suitable for yyerror.  The +   heuristic is that double-quoting is unnecessary unless the string +   contains an apostrophe, a comma, or backslash (other than +   backslash-backslash).  YYSTR is taken from yytname.  If YYRES is +   null, do not copy; instead, return the length of what the result +   would have been.  */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ +  if (*yystr == '"') +    { +      YYSIZE_T yyn = 0; +      char const *yyp = yystr; + +      for (;;) +	switch (*++yyp) +	  { +	  case '\'': +	  case ',': +	    goto do_not_strip_quotes; + +	  case '\\': +	    if (*++yyp != '\\') +	      goto do_not_strip_quotes; +	    /* Fall through.  */ +	  default: +	    if (yyres) +	      yyres[yyn] = *yyp; +	    yyn++; +	    break; + +	  case '"': +	    if (yyres) +	      yyres[yyn] = '\0'; +	    return yyn; +	  } +    do_not_strip_quotes: ; +    } + +  if (! yyres) +    return yystrlen (yystr); + +  return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into YYRESULT an error message about the unexpected token +   YYCHAR while in state YYSTATE.  Return the number of bytes copied, +   including the terminating null byte.  If YYRESULT is null, do not +   copy anything; just return the number of bytes that would be +   copied.  As a special case, return 0 if an ordinary "syntax error" +   message will do.  Return YYSIZE_MAXIMUM if overflow occurs during +   size calculation.  */ +static YYSIZE_T +yysyntax_error (char *yyresult, int yystate, int yychar) +{ +  int yyn = yypact[yystate]; + +  if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) +    return 0; +  else +    { +      int yytype = YYTRANSLATE (yychar); +      YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); +      YYSIZE_T yysize = yysize0; +      YYSIZE_T yysize1; +      int yysize_overflow = 0; +      enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; +      char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; +      int yyx; + +# if 0 +      /* This is so xgettext sees the translatable formats that are +	 constructed on the fly.  */ +      YY_("syntax error, unexpected %s"); +      YY_("syntax error, unexpected %s, expecting %s"); +      YY_("syntax error, unexpected %s, expecting %s or %s"); +      YY_("syntax error, unexpected %s, expecting %s or %s or %s"); +      YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); +# endif +      char *yyfmt; +      char const *yyf; +      static char const yyunexpected[] = "syntax error, unexpected %s"; +      static char const yyexpecting[] = ", expecting %s"; +      static char const yyor[] = " or %s"; +      char yyformat[sizeof yyunexpected +		    + sizeof yyexpecting - 1 +		    + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) +		       * (sizeof yyor - 1))]; +      char const *yyprefix = yyexpecting; + +      /* Start YYX at -YYN if negative to avoid negative indexes in +	 YYCHECK.  */ +      int yyxbegin = yyn < 0 ? -yyn : 0; + +      /* Stay within bounds of both yycheck and yytname.  */ +      int yychecklim = YYLAST - yyn + 1; +      int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; +      int yycount = 1; + +      yyarg[0] = yytname[yytype]; +      yyfmt = yystpcpy (yyformat, yyunexpected); + +      for (yyx = yyxbegin; yyx < yyxend; ++yyx) +	if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) +	  { +	    if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) +	      { +		yycount = 1; +		yysize = yysize0; +		yyformat[sizeof yyunexpected - 1] = '\0'; +		break; +	      } +	    yyarg[yycount++] = yytname[yyx]; +	    yysize1 = yysize + yytnamerr (0, yytname[yyx]); +	    yysize_overflow |= (yysize1 < yysize); +	    yysize = yysize1; +	    yyfmt = yystpcpy (yyfmt, yyprefix); +	    yyprefix = yyor; +	  } + +      yyf = YY_(yyformat); +      yysize1 = yysize + yystrlen (yyf); +      yysize_overflow |= (yysize1 < yysize); +      yysize = yysize1; + +      if (yysize_overflow) +	return YYSIZE_MAXIMUM; + +      if (yyresult) +	{ +	  /* Avoid sprintf, as that infringes on the user's name space. +	     Don't have undefined behavior even if the translation +	     produced a string with the wrong number of "%s"s.  */ +	  char *yyp = yyresult; +	  int yyi = 0; +	  while ((*yyp = *yyf) != '\0') +	    { +	      if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) +		{ +		  yyp += yytnamerr (yyp, yyarg[yyi++]); +		  yyf += 2; +		} +	      else +		{ +		  yyp++; +		  yyf++; +		} +	    } +	} +      return yysize; +    } +} +#endif /* YYERROR_VERBOSE */ + + +/*-----------------------------------------------. +| Release the memory associated to this symbol.  | +`-----------------------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ +     || defined __cplusplus || defined _MSC_VER) +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocationp) +#else +static void +yydestruct (yymsg, yytype, yyvaluep, yylocationp) +    const char *yymsg; +    int yytype; +    YYSTYPE *yyvaluep; +    YYLTYPE *yylocationp; +#endif +{ +  YYUSE (yyvaluep); +  YYUSE (yylocationp); + +  if (!yymsg) +    yymsg = "Deleting"; +  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + +  switch (yytype) +    { + +      default: +	break; +    } +} + + +/* Prevent warnings from -Wmissing-prototypes.  */ + +#ifdef YYPARSE_PARAM +#if defined __STDC__ || defined __cplusplus +int yyparse (void *YYPARSE_PARAM); +#else +int yyparse (); +#endif +#else /* ! YYPARSE_PARAM */ +#if defined __STDC__ || defined __cplusplus +int yyparse (void); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ + + + +/* The look-ahead symbol.  */ +int yychar; + +/* The semantic value of the look-ahead symbol.  */ +YYSTYPE yylval; + +/* Number of syntax errors so far.  */ +int yynerrs; +/* Location data for the look-ahead symbol.  */ +YYLTYPE yylloc; + + + +/*----------. +| yyparse.  | +`----------*/ + +#ifdef YYPARSE_PARAM +#if (defined __STDC__ || defined __C99__FUNC__ \ +     || defined __cplusplus || defined _MSC_VER) +int +yyparse (void *YYPARSE_PARAM) +#else +int +yyparse (YYPARSE_PARAM) +    void *YYPARSE_PARAM; +#endif +#else /* ! YYPARSE_PARAM */ +#if (defined __STDC__ || defined __C99__FUNC__ \ +     || defined __cplusplus || defined _MSC_VER) +int +yyparse (void) +#else +int +yyparse () + +#endif +#endif +{ +   +  int yystate; +  int yyn; +  int yyresult; +  /* Number of tokens to shift before error messages enabled.  */ +  int yyerrstatus; +  /* Look-ahead token as an internal (translated) token number.  */ +  int yytoken = 0; +#if YYERROR_VERBOSE +  /* Buffer for error messages, and its allocated size.  */ +  char yymsgbuf[128]; +  char *yymsg = yymsgbuf; +  YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + +  /* Three stacks and their tools: +     `yyss': related to states, +     `yyvs': related to semantic values, +     `yyls': related to locations. + +     Refer to the stacks thru separate pointers, to allow yyoverflow +     to reallocate them elsewhere.  */ + +  /* The state stack.  */ +  yytype_int16 yyssa[YYINITDEPTH]; +  yytype_int16 *yyss = yyssa; +  yytype_int16 *yyssp; + +  /* The semantic value stack.  */ +  YYSTYPE yyvsa[YYINITDEPTH]; +  YYSTYPE *yyvs = yyvsa; +  YYSTYPE *yyvsp; + +  /* The location stack.  */ +  YYLTYPE yylsa[YYINITDEPTH]; +  YYLTYPE *yyls = yylsa; +  YYLTYPE *yylsp; +  /* The locations where the error started and ended.  */ +  YYLTYPE yyerror_range[2]; + +#define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N), yylsp -= (N)) + +  YYSIZE_T yystacksize = YYINITDEPTH; + +  /* The variables used to return semantic value and location from the +     action routines.  */ +  YYSTYPE yyval; +  YYLTYPE yyloc; + +  /* The number of symbols on the RHS of the reduced rule. +     Keep to zero when no symbol should be popped.  */ +  int yylen = 0; + +  YYDPRINTF ((stderr, "Starting parse\n")); + +  yystate = 0; +  yyerrstatus = 0; +  yynerrs = 0; +  yychar = YYEMPTY;		/* Cause a token to be read.  */ + +  /* Initialize stack pointers. +     Waste one element of value and location stack +     so that they stay on the same level as the state stack. +     The wasted elements are never initialized.  */ + +  yyssp = yyss; +  yyvsp = yyvs; +  yylsp = yyls; +#if YYLTYPE_IS_TRIVIAL +  /* Initialize the default location before parsing starts.  */ +  yylloc.first_line   = yylloc.last_line   = 1; +  yylloc.first_column = yylloc.last_column = 0; +#endif + +  goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate.  | +`------------------------------------------------------------*/ + yynewstate: +  /* In all cases, when you get here, the value and location stacks +     have just been pushed.  So pushing a state here evens the stacks.  */ +  yyssp++; + + yysetstate: +  *yyssp = yystate; + +  if (yyss + yystacksize - 1 <= yyssp) +    { +      /* Get the current used size of the three stacks, in elements.  */ +      YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow +      { +	/* Give user a chance to reallocate the stack.  Use copies of +	   these so that the &'s don't force the real ones into +	   memory.  */ +	YYSTYPE *yyvs1 = yyvs; +	yytype_int16 *yyss1 = yyss; +	YYLTYPE *yyls1 = yyls; + +	/* Each stack pointer address is followed by the size of the +	   data in use in that stack, in bytes.  This used to be a +	   conditional around just the two extra args, but that might +	   be undefined if yyoverflow is a macro.  */ +	yyoverflow (YY_("memory exhausted"), +		    &yyss1, yysize * sizeof (*yyssp), +		    &yyvs1, yysize * sizeof (*yyvsp), +		    &yyls1, yysize * sizeof (*yylsp), +		    &yystacksize); +	yyls = yyls1; +	yyss = yyss1; +	yyvs = yyvs1; +      } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE +      goto yyexhaustedlab; +# else +      /* Extend the stack our own way.  */ +      if (YYMAXDEPTH <= yystacksize) +	goto yyexhaustedlab; +      yystacksize *= 2; +      if (YYMAXDEPTH < yystacksize) +	yystacksize = YYMAXDEPTH; + +      { +	yytype_int16 *yyss1 = yyss; +	union yyalloc *yyptr = +	  (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); +	if (! yyptr) +	  goto yyexhaustedlab; +	YYSTACK_RELOCATE (yyss); +	YYSTACK_RELOCATE (yyvs); +	YYSTACK_RELOCATE (yyls); +#  undef YYSTACK_RELOCATE +	if (yyss1 != yyssa) +	  YYSTACK_FREE (yyss1); +      } +# endif +#endif /* no yyoverflow */ + +      yyssp = yyss + yysize - 1; +      yyvsp = yyvs + yysize - 1; +      yylsp = yyls + yysize - 1; + +      YYDPRINTF ((stderr, "Stack size increased to %lu\n", +		  (unsigned long int) yystacksize)); + +      if (yyss + yystacksize - 1 <= yyssp) +	YYABORT; +    } + +  YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + +  goto yybackup; + +/*-----------. +| yybackup.  | +`-----------*/ +yybackup: + +  /* Do appropriate processing given the current state.  Read a +     look-ahead token if we need one and don't already have one.  */ + +  /* First try to decide what to do without reference to look-ahead token.  */ +  yyn = yypact[yystate]; +  if (yyn == YYPACT_NINF) +    goto yydefault; + +  /* Not known => get a look-ahead token if don't already have one.  */ + +  /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol.  */ +  if (yychar == YYEMPTY) +    { +      YYDPRINTF ((stderr, "Reading a token: ")); +      yychar = YYLEX; +    } + +  if (yychar <= YYEOF) +    { +      yychar = yytoken = YYEOF; +      YYDPRINTF ((stderr, "Now at end of input.\n")); +    } +  else +    { +      yytoken = YYTRANSLATE (yychar); +      YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); +    } + +  /* If the proper action on seeing token YYTOKEN is to reduce or to +     detect an error, take that action.  */ +  yyn += yytoken; +  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) +    goto yydefault; +  yyn = yytable[yyn]; +  if (yyn <= 0) +    { +      if (yyn == 0 || yyn == YYTABLE_NINF) +	goto yyerrlab; +      yyn = -yyn; +      goto yyreduce; +    } + +  if (yyn == YYFINAL) +    YYACCEPT; + +  /* Count tokens shifted since error; after three, turn off error +     status.  */ +  if (yyerrstatus) +    yyerrstatus--; + +  /* Shift the look-ahead token.  */ +  YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + +  /* Discard the shifted token unless it is eof.  */ +  if (yychar != YYEOF) +    yychar = YYEMPTY; + +  yystate = yyn; +  *++yyvsp = yylval; +  *++yylsp = yylloc; +  goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state.  | +`-----------------------------------------------------------*/ +yydefault: +  yyn = yydefact[yystate]; +  if (yyn == 0) +    goto yyerrlab; +  goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction.  | +`-----------------------------*/ +yyreduce: +  /* yyn is the number of a rule to reduce with.  */ +  yylen = yyr2[yyn]; + +  /* If YYLEN is nonzero, implement the default value of the action: +     `$$ = $1'. + +     Otherwise, the following line sets YYVAL to garbage. +     This behavior is undocumented and Bison +     users should not rely upon it.  Assigning to YYVAL +     unconditionally makes the parser a bit smaller, and it avoids a +     GCC warning that YYVAL may be used uninitialized.  */ +  yyval = yyvsp[1-yylen]; + +  /* Default location.  */ +  YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen); +  YY_REDUCE_PRINT (yyn); +  switch (yyn) +    { +        case 2: +#line 90 "dtc-parser.y" +    { +			the_boot_info = build_boot_info((yyvsp[(3) - (4)].re), (yyvsp[(4) - (4)].node), 0); +		;} +    break; + +  case 3: +#line 94 "dtc-parser.y" +    { +			the_boot_info = build_boot_info((yyvsp[(1) - (2)].re), (yyvsp[(2) - (2)].node), 0); +		;} +    break; + +  case 4: +#line 101 "dtc-parser.y" +    { +			(yyval.re) = NULL; +		;} +    break; + +  case 5: +#line 105 "dtc-parser.y" +    { +			(yyval.re) = chain_reserve_entry((yyvsp[(1) - (2)].re), (yyvsp[(2) - (2)].re)); +		;} +    break; + +  case 6: +#line 112 "dtc-parser.y" +    { +			(yyval.re) = build_reserve_entry((yyvsp[(3) - (5)].addr), (yyvsp[(4) - (5)].addr), (yyvsp[(1) - (5)].labelref)); +		;} +    break; + +  case 7: +#line 119 "dtc-parser.y" +    { +			(yyval.re) = NULL; +		;} +    break; + +  case 8: +#line 123 "dtc-parser.y" +    { +			(yyval.re) = chain_reserve_entry((yyvsp[(1) - (2)].re), (yyvsp[(2) - (2)].re)); +		;} +    break; + +  case 9: +#line 130 "dtc-parser.y" +    { +			(yyval.re) = (yyvsp[(1) - (1)].re); +		;} +    break; + +  case 10: +#line 134 "dtc-parser.y" +    { +			(yyval.re) = build_reserve_entry((yyvsp[(3) - (6)].addr), (yyvsp[(5) - (6)].addr) - (yyvsp[(3) - (6)].addr) + 1, (yyvsp[(1) - (6)].labelref)); +		;} +    break; + +  case 11: +#line 141 "dtc-parser.y" +    { +			(yyval.addr) = eval_literal((yyvsp[(1) - (1)].literal), 0, 64); +		;} +    break; + +  case 12: +#line 145 "dtc-parser.y" +    { +			(yyval.addr) = eval_literal((yyvsp[(1) - (1)].literal), 16, 64); +		;} +    break; + +  case 13: +#line 152 "dtc-parser.y" +    { +			(yyval.node) = name_node((yyvsp[(2) - (2)].node), "", NULL); +		;} +    break; + +  case 14: +#line 159 "dtc-parser.y" +    { +			(yyval.node) = build_node((yyvsp[(2) - (5)].proplist), (yyvsp[(3) - (5)].nodelist)); +		;} +    break; + +  case 15: +#line 166 "dtc-parser.y" +    { +			(yyval.proplist) = NULL; +		;} +    break; + +  case 16: +#line 170 "dtc-parser.y" +    { +			(yyval.proplist) = chain_property((yyvsp[(2) - (2)].prop), (yyvsp[(1) - (2)].proplist)); +		;} +    break; + +  case 17: +#line 177 "dtc-parser.y" +    { +			(yyval.prop) = build_property((yyvsp[(2) - (5)].propnodename), (yyvsp[(4) - (5)].data), (yyvsp[(1) - (5)].labelref)); +		;} +    break; + +  case 18: +#line 181 "dtc-parser.y" +    { +			(yyval.prop) = build_property((yyvsp[(2) - (3)].propnodename), empty_data, (yyvsp[(1) - (3)].labelref)); +		;} +    break; + +  case 19: +#line 188 "dtc-parser.y" +    { +			(yyval.data) = data_merge((yyvsp[(1) - (2)].data), (yyvsp[(2) - (2)].data)); +		;} +    break; + +  case 20: +#line 192 "dtc-parser.y" +    { +			(yyval.data) = data_merge((yyvsp[(1) - (4)].data), (yyvsp[(3) - (4)].data)); +		;} +    break; + +  case 21: +#line 196 "dtc-parser.y" +    { +			(yyval.data) = data_merge((yyvsp[(1) - (4)].data), (yyvsp[(3) - (4)].data)); +		;} +    break; + +  case 22: +#line 200 "dtc-parser.y" +    { +			(yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), REF_PATH, (yyvsp[(2) - (2)].labelref)); +		;} +    break; + +  case 23: +#line 204 "dtc-parser.y" +    { +			struct search_path path = { srcpos_file->dir, NULL, NULL }; +			struct dtc_file *file = dtc_open_file((yyvsp[(4) - (9)].data).val, &path); +			struct data d = empty_data; + +			if ((yyvsp[(6) - (9)].addr) != 0) +				if (fseek(file->file, (yyvsp[(6) - (9)].addr), SEEK_SET) != 0) +					yyerrorf("Couldn't seek to offset %llu in \"%s\": %s", +						 (unsigned long long)(yyvsp[(6) - (9)].addr), +						 (yyvsp[(4) - (9)].data).val, strerror(errno)); + +			d = data_copy_file(file->file, (yyvsp[(8) - (9)].addr)); + +			(yyval.data) = data_merge((yyvsp[(1) - (9)].data), d); +			dtc_close_file(file); +		;} +    break; + +  case 24: +#line 221 "dtc-parser.y" +    { +			struct search_path path = { srcpos_file->dir, NULL, NULL }; +			struct dtc_file *file = dtc_open_file((yyvsp[(4) - (5)].data).val, &path); +			struct data d = empty_data; + +			d = data_copy_file(file->file, -1); + +			(yyval.data) = data_merge((yyvsp[(1) - (5)].data), d); +			dtc_close_file(file); +		;} +    break; + +  case 25: +#line 232 "dtc-parser.y" +    { +			(yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref)); +		;} +    break; + +  case 26: +#line 239 "dtc-parser.y" +    { +			(yyval.data) = empty_data; +		;} +    break; + +  case 27: +#line 243 "dtc-parser.y" +    { +			(yyval.data) = (yyvsp[(1) - (2)].data); +		;} +    break; + +  case 28: +#line 247 "dtc-parser.y" +    { +			(yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref)); +		;} +    break; + +  case 29: +#line 254 "dtc-parser.y" +    { +			(yyval.data) = empty_data; +		;} +    break; + +  case 30: +#line 258 "dtc-parser.y" +    { +			(yyval.data) = data_append_cell((yyvsp[(1) - (2)].data), (yyvsp[(2) - (2)].cell)); +		;} +    break; + +  case 31: +#line 262 "dtc-parser.y" +    { +			(yyval.data) = data_append_cell(data_add_marker((yyvsp[(1) - (2)].data), REF_PHANDLE, +							      (yyvsp[(2) - (2)].labelref)), -1); +		;} +    break; + +  case 32: +#line 267 "dtc-parser.y" +    { +			(yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref)); +		;} +    break; + +  case 33: +#line 274 "dtc-parser.y" +    { +			(yyval.cbase) = 16; +		;} +    break; + +  case 35: +#line 282 "dtc-parser.y" +    { +			(yyval.cell) = eval_literal((yyvsp[(1) - (1)].literal), 0, 32); +		;} +    break; + +  case 36: +#line 286 "dtc-parser.y" +    { +			(yyval.cell) = eval_literal((yyvsp[(2) - (2)].literal), (yyvsp[(1) - (2)].cbase), 32); +		;} +    break; + +  case 37: +#line 293 "dtc-parser.y" +    { +			(yyval.data) = empty_data; +		;} +    break; + +  case 38: +#line 297 "dtc-parser.y" +    { +			(yyval.data) = data_append_byte((yyvsp[(1) - (2)].data), (yyvsp[(2) - (2)].byte)); +		;} +    break; + +  case 39: +#line 301 "dtc-parser.y" +    { +			(yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref)); +		;} +    break; + +  case 40: +#line 308 "dtc-parser.y" +    { +			(yyval.nodelist) = NULL; +		;} +    break; + +  case 41: +#line 312 "dtc-parser.y" +    { +			(yyval.nodelist) = chain_node((yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].nodelist)); +		;} +    break; + +  case 42: +#line 316 "dtc-parser.y" +    { +			yyerror("syntax error: properties must precede subnodes"); +			YYERROR; +		;} +    break; + +  case 43: +#line 324 "dtc-parser.y" +    { +			(yyval.node) = name_node((yyvsp[(3) - (3)].node), (yyvsp[(2) - (3)].propnodename), (yyvsp[(1) - (3)].labelref)); +		;} +    break; + +  case 44: +#line 331 "dtc-parser.y" +    { +			(yyval.labelref) = NULL; +		;} +    break; + +  case 45: +#line 335 "dtc-parser.y" +    { +			(yyval.labelref) = (yyvsp[(1) - (1)].labelref); +		;} +    break; + + +/* Line 1267 of yacc.c.  */ +#line 1780 "dtc-parser.tab.c" +      default: break; +    } +  YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + +  YYPOPSTACK (yylen); +  yylen = 0; +  YY_STACK_PRINT (yyss, yyssp); + +  *++yyvsp = yyval; +  *++yylsp = yyloc; + +  /* Now `shift' the result of the reduction.  Determine what state +     that goes to, based on the state we popped back to and the rule +     number reduced by.  */ + +  yyn = yyr1[yyn]; + +  yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; +  if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) +    yystate = yytable[yystate]; +  else +    yystate = yydefgoto[yyn - YYNTOKENS]; + +  goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: +  /* If not already recovering from an error, report this error.  */ +  if (!yyerrstatus) +    { +      ++yynerrs; +#if ! YYERROR_VERBOSE +      yyerror (YY_("syntax error")); +#else +      { +	YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); +	if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) +	  { +	    YYSIZE_T yyalloc = 2 * yysize; +	    if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) +	      yyalloc = YYSTACK_ALLOC_MAXIMUM; +	    if (yymsg != yymsgbuf) +	      YYSTACK_FREE (yymsg); +	    yymsg = (char *) YYSTACK_ALLOC (yyalloc); +	    if (yymsg) +	      yymsg_alloc = yyalloc; +	    else +	      { +		yymsg = yymsgbuf; +		yymsg_alloc = sizeof yymsgbuf; +	      } +	  } + +	if (0 < yysize && yysize <= yymsg_alloc) +	  { +	    (void) yysyntax_error (yymsg, yystate, yychar); +	    yyerror (yymsg); +	  } +	else +	  { +	    yyerror (YY_("syntax error")); +	    if (yysize != 0) +	      goto yyexhaustedlab; +	  } +      } +#endif +    } + +  yyerror_range[0] = yylloc; + +  if (yyerrstatus == 3) +    { +      /* If just tried and failed to reuse look-ahead token after an +	 error, discard it.  */ + +      if (yychar <= YYEOF) +	{ +	  /* Return failure if at end of input.  */ +	  if (yychar == YYEOF) +	    YYABORT; +	} +      else +	{ +	  yydestruct ("Error: discarding", +		      yytoken, &yylval, &yylloc); +	  yychar = YYEMPTY; +	} +    } + +  /* Else will try to reuse look-ahead token after shifting the error +     token.  */ +  goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR.  | +`---------------------------------------------------*/ +yyerrorlab: + +  /* Pacify compilers like GCC when the user code never invokes +     YYERROR and the label yyerrorlab therefore never appears in user +     code.  */ +  if (/*CONSTCOND*/ 0) +     goto yyerrorlab; + +  yyerror_range[0] = yylsp[1-yylen]; +  /* Do not reclaim the symbols of the rule which action triggered +     this YYERROR.  */ +  YYPOPSTACK (yylen); +  yylen = 0; +  YY_STACK_PRINT (yyss, yyssp); +  yystate = *yyssp; +  goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR.  | +`-------------------------------------------------------------*/ +yyerrlab1: +  yyerrstatus = 3;	/* Each real token shifted decrements this.  */ + +  for (;;) +    { +      yyn = yypact[yystate]; +      if (yyn != YYPACT_NINF) +	{ +	  yyn += YYTERROR; +	  if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) +	    { +	      yyn = yytable[yyn]; +	      if (0 < yyn) +		break; +	    } +	} + +      /* Pop the current state because it cannot handle the error token.  */ +      if (yyssp == yyss) +	YYABORT; + +      yyerror_range[0] = *yylsp; +      yydestruct ("Error: popping", +		  yystos[yystate], yyvsp, yylsp); +      YYPOPSTACK (1); +      yystate = *yyssp; +      YY_STACK_PRINT (yyss, yyssp); +    } + +  if (yyn == YYFINAL) +    YYACCEPT; + +  *++yyvsp = yylval; + +  yyerror_range[1] = yylloc; +  /* Using YYLLOC is tempting, but would change the location of +     the look-ahead.  YYLOC is available though.  */ +  YYLLOC_DEFAULT (yyloc, (yyerror_range - 1), 2); +  *++yylsp = yyloc; + +  /* Shift the error token.  */ +  YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + +  yystate = yyn; +  goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here.  | +`-------------------------------------*/ +yyacceptlab: +  yyresult = 0; +  goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here.  | +`-----------------------------------*/ +yyabortlab: +  yyresult = 1; +  goto yyreturn; + +#ifndef yyoverflow +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here.  | +`-------------------------------------------------*/ +yyexhaustedlab: +  yyerror (YY_("memory exhausted")); +  yyresult = 2; +  /* Fall through.  */ +#endif + +yyreturn: +  if (yychar != YYEOF && yychar != YYEMPTY) +     yydestruct ("Cleanup: discarding lookahead", +		 yytoken, &yylval, &yylloc); +  /* Do not reclaim the symbols of the rule which action triggered +     this YYABORT or YYACCEPT.  */ +  YYPOPSTACK (yylen); +  YY_STACK_PRINT (yyss, yyssp); +  while (yyssp != yyss) +    { +      yydestruct ("Cleanup: popping", +		  yystos[*yyssp], yyvsp, yylsp); +      YYPOPSTACK (1); +    } +#ifndef yyoverflow +  if (yyss != yyssa) +    YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE +  if (yymsg != yymsgbuf) +    YYSTACK_FREE (yymsg); +#endif +  /* Make sure YYID is used.  */ +  return YYID (yyresult); +} + + +#line 340 "dtc-parser.y" + + +void yyerrorf(char const *s, ...) +{ +	const char *fname = srcpos_file ? srcpos_file->name : "<no-file>"; +	va_list va; +	va_start(va, s); + +	if (strcmp(fname, "-") == 0) +		fname = "stdin"; + +	fprintf(stderr, "%s:%d ", fname, yylloc.first_line); +	vfprintf(stderr, s, va); +	fprintf(stderr, "\n"); + +	treesource_error = 1; +	va_end(va); +} + +void yyerror (char const *s) +{ +	yyerrorf("%s", s); +} + +static unsigned long long eval_literal(const char *s, int base, int bits) +{ +	unsigned long long val; +	char *e; + +	errno = 0; +	val = strtoull(s, &e, base); +	if (*e) +		yyerror("bad characters in literal"); +	else if ((errno == ERANGE) +		 || ((bits < 64) && (val >= (1ULL << bits)))) +		yyerror("literal out of range"); +	else if (errno != 0) +		yyerror("bad literal"); +	return val; +} + diff --git a/scripts/dtc/dtc-parser.tab.h_shipped b/scripts/dtc/dtc-parser.tab.h_shipped new file mode 100644 index 00000000000..ba99100d55c --- /dev/null +++ b/scripts/dtc/dtc-parser.tab.h_shipped @@ -0,0 +1,113 @@ +/* A Bison parser, made by GNU Bison 2.3.  */ + +/* Skeleton interface for Bison's Yacc-like parsers in C + +   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 +   Free Software Foundation, Inc. + +   This program is free software; you can redistribute it and/or modify +   it under the terms of the GNU General Public License as published by +   the Free Software Foundation; either version 2, or (at your option) +   any later version. + +   This program is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +   GNU General Public License for more details. + +   You should have received a copy of the GNU General Public License +   along with this program; if not, write to the Free Software +   Foundation, Inc., 51 Franklin Street, Fifth Floor, +   Boston, MA 02110-1301, USA.  */ + +/* As a special exception, you may create a larger work that contains +   part or all of the Bison parser skeleton and distribute that work +   under terms of your choice, so long as that work isn't itself a +   parser generator using the skeleton or a modified version thereof +   as a parser skeleton.  Alternatively, if you modify or redistribute +   the parser skeleton itself, you may (at your option) remove this +   special exception, which will cause the skeleton and the resulting +   Bison output files to be licensed under the GNU General Public +   License without this special exception. + +   This special exception was added by the Free Software Foundation in +   version 2.2 of Bison.  */ + +/* Tokens.  */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE +   /* Put the tokens into the symbol table, so that GDB and other debuggers +      know about them.  */ +   enum yytokentype { +     DT_V1 = 258, +     DT_MEMRESERVE = 259, +     DT_PROPNODENAME = 260, +     DT_LITERAL = 261, +     DT_LEGACYLITERAL = 262, +     DT_BASE = 263, +     DT_BYTE = 264, +     DT_STRING = 265, +     DT_LABEL = 266, +     DT_REF = 267, +     DT_INCBIN = 268 +   }; +#endif +/* Tokens.  */ +#define DT_V1 258 +#define DT_MEMRESERVE 259 +#define DT_PROPNODENAME 260 +#define DT_LITERAL 261 +#define DT_LEGACYLITERAL 262 +#define DT_BASE 263 +#define DT_BYTE 264 +#define DT_STRING 265 +#define DT_LABEL 266 +#define DT_REF 267 +#define DT_INCBIN 268 + + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +#line 37 "dtc-parser.y" +{ +	char *propnodename; +	char *literal; +	char *labelref; +	unsigned int cbase; +	uint8_t byte; +	struct data data; + +	uint64_t addr; +	cell_t cell; +	struct property *prop; +	struct property *proplist; +	struct node *node; +	struct node *nodelist; +	struct reserve_info *re; +} +/* Line 1489 of yacc.c.  */ +#line 92 "dtc-parser.tab.h" +	YYSTYPE; +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 +#endif + +extern YYSTYPE yylval; + +#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED +typedef struct YYLTYPE +{ +  int first_line; +  int first_column; +  int last_line; +  int last_column; +} YYLTYPE; +# define yyltype YYLTYPE /* obsolescent; will be withdrawn */ +# define YYLTYPE_IS_DECLARED 1 +# define YYLTYPE_IS_TRIVIAL 1 +#endif + +extern YYLTYPE yylloc; diff --git a/scripts/dtc/dtc-parser.y b/scripts/dtc/dtc-parser.y new file mode 100644 index 00000000000..b2ab562420e --- /dev/null +++ b/scripts/dtc/dtc-parser.y @@ -0,0 +1,379 @@ +/* + * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005. + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + *  General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 + *                                                                   USA + */ + +%locations + +%{ +#include <stdio.h> + +#include "dtc.h" +#include "srcpos.h" + +extern int yylex(void); + +extern struct boot_info *the_boot_info; +extern int treesource_error; + +static unsigned long long eval_literal(const char *s, int base, int bits); +%} + +%union { +	char *propnodename; +	char *literal; +	char *labelref; +	unsigned int cbase; +	uint8_t byte; +	struct data data; + +	uint64_t addr; +	cell_t cell; +	struct property *prop; +	struct property *proplist; +	struct node *node; +	struct node *nodelist; +	struct reserve_info *re; +} + +%token DT_V1 +%token DT_MEMRESERVE +%token <propnodename> DT_PROPNODENAME +%token <literal> DT_LITERAL +%token <literal> DT_LEGACYLITERAL +%token <cbase> DT_BASE +%token <byte> DT_BYTE +%token <data> DT_STRING +%token <labelref> DT_LABEL +%token <labelref> DT_REF +%token DT_INCBIN + +%type <data> propdata +%type <data> propdataprefix +%type <re> memreserve +%type <re> memreserves +%type <re> v0_memreserve +%type <re> v0_memreserves +%type <addr> addr +%type <data> celllist +%type <cbase> cellbase +%type <cell> cellval +%type <data> bytestring +%type <prop> propdef +%type <proplist> proplist + +%type <node> devicetree +%type <node> nodedef +%type <node> subnode +%type <nodelist> subnodes +%type <labelref> label + +%% + +sourcefile: +	  DT_V1 ';' memreserves devicetree +		{ +			the_boot_info = build_boot_info($3, $4, 0); +		} +	| v0_memreserves devicetree +		{ +			the_boot_info = build_boot_info($1, $2, 0); +		} +	; + +memreserves: +	  /* empty */ +		{ +			$$ = NULL; +		} +	| memreserve memreserves +		{ +			$$ = chain_reserve_entry($1, $2); +		} +	; + +memreserve: +	  label DT_MEMRESERVE addr addr ';' +		{ +			$$ = build_reserve_entry($3, $4, $1); +		} +	; + +v0_memreserves: +	  /* empty */ +		{ +			$$ = NULL; +		} +	| v0_memreserve v0_memreserves +		{ +			$$ = chain_reserve_entry($1, $2); +		}; +	; + +v0_memreserve: +	  memreserve +		{ +			$$ = $1; +		} +	| label DT_MEMRESERVE addr '-' addr ';' +		{ +			$$ = build_reserve_entry($3, $5 - $3 + 1, $1); +		} +	; + +addr: +	  DT_LITERAL +		{ +			$$ = eval_literal($1, 0, 64); +		} +	| DT_LEGACYLITERAL +		{ +			$$ = eval_literal($1, 16, 64); +		} +	  ; + +devicetree: +	  '/' nodedef +		{ +			$$ = name_node($2, "", NULL); +		} +	; + +nodedef: +	  '{' proplist subnodes '}' ';' +		{ +			$$ = build_node($2, $3); +		} +	; + +proplist: +	  /* empty */ +		{ +			$$ = NULL; +		} +	| proplist propdef +		{ +			$$ = chain_property($2, $1); +		} +	; + +propdef: +	  label DT_PROPNODENAME '=' propdata ';' +		{ +			$$ = build_property($2, $4, $1); +		} +	| label DT_PROPNODENAME ';' +		{ +			$$ = build_property($2, empty_data, $1); +		} +	; + +propdata: +	  propdataprefix DT_STRING +		{ +			$$ = data_merge($1, $2); +		} +	| propdataprefix '<' celllist '>' +		{ +			$$ = data_merge($1, $3); +		} +	| propdataprefix '[' bytestring ']' +		{ +			$$ = data_merge($1, $3); +		} +	| propdataprefix DT_REF +		{ +			$$ = data_add_marker($1, REF_PATH, $2); +		} +	| propdataprefix DT_INCBIN '(' DT_STRING ',' addr ',' addr ')' +		{ +			struct search_path path = { srcpos_file->dir, NULL, NULL }; +			struct dtc_file *file = dtc_open_file($4.val, &path); +			struct data d = empty_data; + +			if ($6 != 0) +				if (fseek(file->file, $6, SEEK_SET) != 0) +					yyerrorf("Couldn't seek to offset %llu in \"%s\": %s", +						 (unsigned long long)$6, +						 $4.val, strerror(errno)); + +			d = data_copy_file(file->file, $8); + +			$$ = data_merge($1, d); +			dtc_close_file(file); +		} +	| propdataprefix DT_INCBIN '(' DT_STRING ')' +		{ +			struct search_path path = { srcpos_file->dir, NULL, NULL }; +			struct dtc_file *file = dtc_open_file($4.val, &path); +			struct data d = empty_data; + +			d = data_copy_file(file->file, -1); + +			$$ = data_merge($1, d); +			dtc_close_file(file); +		} +	| propdata DT_LABEL +		{ +			$$ = data_add_marker($1, LABEL, $2); +		} +	; + +propdataprefix: +	  /* empty */ +		{ +			$$ = empty_data; +		} +	| propdata ',' +		{ +			$$ = $1; +		} +	| propdataprefix DT_LABEL +		{ +			$$ = data_add_marker($1, LABEL, $2); +		} +	; + +celllist: +	  /* empty */ +		{ +			$$ = empty_data; +		} +	| celllist cellval +		{ +			$$ = data_append_cell($1, $2); +		} +	| celllist DT_REF +		{ +			$$ = data_append_cell(data_add_marker($1, REF_PHANDLE, +							      $2), -1); +		} +	| celllist DT_LABEL +		{ +			$$ = data_add_marker($1, LABEL, $2); +		} +	; + +cellbase: +	  /* empty */ +		{ +			$$ = 16; +		} +	| DT_BASE +	; + +cellval: +	  DT_LITERAL +		{ +			$$ = eval_literal($1, 0, 32); +		} +	| cellbase DT_LEGACYLITERAL +		{ +			$$ = eval_literal($2, $1, 32); +		} +	; + +bytestring: +	  /* empty */ +		{ +			$$ = empty_data; +		} +	| bytestring DT_BYTE +		{ +			$$ = data_append_byte($1, $2); +		} +	| bytestring DT_LABEL +		{ +			$$ = data_add_marker($1, LABEL, $2); +		} +	; + +subnodes: +	  /* empty */ +		{ +			$$ = NULL; +		} +	|  subnode subnodes +		{ +			$$ = chain_node($1, $2); +		} +	| subnode propdef +		{ +			yyerror("syntax error: properties must precede subnodes"); +			YYERROR; +		} +	; + +subnode: +	  label DT_PROPNODENAME nodedef +		{ +			$$ = name_node($3, $2, $1); +		} +	; + +label: +	  /* empty */ +		{ +			$$ = NULL; +		} +	| DT_LABEL +		{ +			$$ = $1; +		} +	; + +%% + +void yyerrorf(char const *s, ...) +{ +	const char *fname = srcpos_file ? srcpos_file->name : "<no-file>"; +	va_list va; +	va_start(va, s); + +	if (strcmp(fname, "-") == 0) +		fname = "stdin"; + +	fprintf(stderr, "%s:%d ", fname, yylloc.first_line); +	vfprintf(stderr, s, va); +	fprintf(stderr, "\n"); + +	treesource_error = 1; +	va_end(va); +} + +void yyerror (char const *s) +{ +	yyerrorf("%s", s); +} + +static unsigned long long eval_literal(const char *s, int base, int bits) +{ +	unsigned long long val; +	char *e; + +	errno = 0; +	val = strtoull(s, &e, base); +	if (*e) +		yyerror("bad characters in literal"); +	else if ((errno == ERANGE) +		 || ((bits < 64) && (val >= (1ULL << bits)))) +		yyerror("literal out of range"); +	else if (errno != 0) +		yyerror("bad literal"); +	return val; +} diff --git a/scripts/dtc/dtc.c b/scripts/dtc/dtc.c new file mode 100644 index 00000000000..d8fd43b4ac1 --- /dev/null +++ b/scripts/dtc/dtc.c @@ -0,0 +1,226 @@ +/* + * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005. + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + *  General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 + *                                                                   USA + */ + +#include "dtc.h" +#include "srcpos.h" + +#include "version_gen.h" + +/* + * Command line options + */ +int quiet;		/* Level of quietness */ +int reservenum;		/* Number of memory reservation slots */ +int minsize;		/* Minimum blob size */ +int padsize;		/* Additional padding to blob */ + +char *join_path(const char *path, const char *name) +{ +	int lenp = strlen(path); +	int lenn = strlen(name); +	int len; +	int needslash = 1; +	char *str; + +	len = lenp + lenn + 2; +	if ((lenp > 0) && (path[lenp-1] == '/')) { +		needslash = 0; +		len--; +	} + +	str = xmalloc(len); +	memcpy(str, path, lenp); +	if (needslash) { +		str[lenp] = '/'; +		lenp++; +	} +	memcpy(str+lenp, name, lenn+1); +	return str; +} + +static void fill_fullpaths(struct node *tree, const char *prefix) +{ +	struct node *child; +	const char *unit; + +	tree->fullpath = join_path(prefix, tree->name); + +	unit = strchr(tree->name, '@'); +	if (unit) +		tree->basenamelen = unit - tree->name; +	else +		tree->basenamelen = strlen(tree->name); + +	for_each_child(tree, child) +		fill_fullpaths(child, tree->fullpath); +} + +static void  __attribute__ ((noreturn)) usage(void) +{ +	fprintf(stderr, "Usage:\n"); +	fprintf(stderr, "\tdtc [options] <input file>\n"); +	fprintf(stderr, "\nOptions:\n"); +	fprintf(stderr, "\t-h\n"); +	fprintf(stderr, "\t\tThis help text\n"); +	fprintf(stderr, "\t-q\n"); +	fprintf(stderr, "\t\tQuiet: -q suppress warnings, -qq errors, -qqq all\n"); +	fprintf(stderr, "\t-I <input format>\n"); +	fprintf(stderr, "\t\tInput formats are:\n"); +	fprintf(stderr, "\t\t\tdts - device tree source text\n"); +	fprintf(stderr, "\t\t\tdtb - device tree blob\n"); +	fprintf(stderr, "\t\t\tfs - /proc/device-tree style directory\n"); +	fprintf(stderr, "\t-o <output file>\n"); +	fprintf(stderr, "\t-O <output format>\n"); +	fprintf(stderr, "\t\tOutput formats are:\n"); +	fprintf(stderr, "\t\t\tdts - device tree source text\n"); +	fprintf(stderr, "\t\t\tdtb - device tree blob\n"); +	fprintf(stderr, "\t\t\tasm - assembler source\n"); +	fprintf(stderr, "\t-V <output version>\n"); +	fprintf(stderr, "\t\tBlob version to produce, defaults to %d (relevant for dtb\n\t\tand asm output only)\n", DEFAULT_FDT_VERSION); +	fprintf(stderr, "\t-R <number>\n"); +	fprintf(stderr, "\t\tMake space for <number> reserve map entries (relevant for \n\t\tdtb and asm output only)\n"); +	fprintf(stderr, "\t-S <bytes>\n"); +	fprintf(stderr, "\t\tMake the blob at least <bytes> long (extra space)\n"); +	fprintf(stderr, "\t-p <bytes>\n"); +	fprintf(stderr, "\t\tAdd padding to the blob of <bytes> long (extra space)\n"); +	fprintf(stderr, "\t-b <number>\n"); +	fprintf(stderr, "\t\tSet the physical boot cpu\n"); +	fprintf(stderr, "\t-f\n"); +	fprintf(stderr, "\t\tForce - try to produce output even if the input tree has errors\n"); +	fprintf(stderr, "\t-v\n"); +	fprintf(stderr, "\t\tPrint DTC version and exit\n"); +	exit(3); +} + +int main(int argc, char *argv[]) +{ +	struct boot_info *bi; +	const char *inform = "dts"; +	const char *outform = "dts"; +	const char *outname = "-"; +	int force = 0, check = 0; +	const char *arg; +	int opt; +	FILE *outf = NULL; +	int outversion = DEFAULT_FDT_VERSION; +	long long cmdline_boot_cpuid = -1; + +	quiet      = 0; +	reservenum = 0; +	minsize    = 0; +	padsize    = 0; + +	while ((opt = getopt(argc, argv, "hI:O:o:V:R:S:p:fcqb:v")) != EOF) { +		switch (opt) { +		case 'I': +			inform = optarg; +			break; +		case 'O': +			outform = optarg; +			break; +		case 'o': +			outname = optarg; +			break; +		case 'V': +			outversion = strtol(optarg, NULL, 0); +			break; +		case 'R': +			reservenum = strtol(optarg, NULL, 0); +			break; +		case 'S': +			minsize = strtol(optarg, NULL, 0); +			break; +		case 'p': +			padsize = strtol(optarg, NULL, 0); +			break; +		case 'f': +			force = 1; +			break; +		case 'c': +			check = 1; +			break; +		case 'q': +			quiet++; +			break; +		case 'b': +			cmdline_boot_cpuid = strtoll(optarg, NULL, 0); +			break; +		case 'v': +			printf("Version: %s\n", DTC_VERSION); +			exit(0); +		case 'h': +		default: +			usage(); +		} +	} + +	if (argc > (optind+1)) +		usage(); +	else if (argc < (optind+1)) +		arg = "-"; +	else +		arg = argv[optind]; + +	/* minsize and padsize are mutually exclusive */ +	if (minsize && padsize) +		die("Can't set both -p and -S\n"); + +	fprintf(stderr, "DTC: %s->%s  on file \"%s\"\n", +		inform, outform, arg); + +	if (streq(inform, "dts")) +		bi = dt_from_source(arg); +	else if (streq(inform, "fs")) +		bi = dt_from_fs(arg); +	else if(streq(inform, "dtb")) +		bi = dt_from_blob(arg); +	else +		die("Unknown input format \"%s\"\n", inform); + +	if (cmdline_boot_cpuid != -1) +		bi->boot_cpuid_phys = cmdline_boot_cpuid; + +	fill_fullpaths(bi->dt, ""); +	process_checks(force, bi); + + +	if (streq(outname, "-")) { +		outf = stdout; +	} else { +		outf = fopen(outname, "w"); +		if (! outf) +			die("Couldn't open output file %s: %s\n", +			    outname, strerror(errno)); +	} + +	if (streq(outform, "dts")) { +		dt_to_source(outf, bi); +	} else if (streq(outform, "dtb")) { +		dt_to_blob(outf, bi, outversion); +	} else if (streq(outform, "asm")) { +		dt_to_asm(outf, bi, outversion); +	} else if (streq(outform, "null")) { +		/* do nothing */ +	} else { +		die("Unknown output format \"%s\"\n", outform); +	} + +	exit(0); +} diff --git a/scripts/dtc/dtc.h b/scripts/dtc/dtc.h new file mode 100644 index 00000000000..08d54c87008 --- /dev/null +++ b/scripts/dtc/dtc.h @@ -0,0 +1,246 @@ +#ifndef _DTC_H +#define _DTC_H + +/* + * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005. + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + *  General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 + *                                                                   USA + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdint.h> +#include <stdarg.h> +#include <assert.h> +#include <ctype.h> +#include <errno.h> +#include <unistd.h> + +#include <libfdt_env.h> +#include <fdt.h> + +#define DEFAULT_FDT_VERSION	17 +/* + * Command line options + */ +extern int quiet;		/* Level of quietness */ +extern int reservenum;		/* Number of memory reservation slots */ +extern int minsize;		/* Minimum blob size */ +extern int padsize;		/* Additional padding to blob */ + +static inline void __attribute__((noreturn)) die(char * str, ...) +{ +	va_list ap; + +	va_start(ap, str); +	fprintf(stderr, "FATAL ERROR: "); +	vfprintf(stderr, str, ap); +	exit(1); +} + +static inline void *xmalloc(size_t len) +{ +	void *new = malloc(len); + +	if (! new) +		die("malloc() failed\n"); + +	return new; +} + +static inline void *xrealloc(void *p, size_t len) +{ +	void *new = realloc(p, len); + +	if (! new) +		die("realloc() failed (len=%d)\n", len); + +	return new; +} + +typedef uint32_t cell_t; + + +#define streq(a, b)	(strcmp((a), (b)) == 0) +#define strneq(a, b, n)	(strncmp((a), (b), (n)) == 0) + +#define ALIGN(x, a)	(((x) + (a) - 1) & ~((a) - 1)) +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +/* Data blobs */ +enum markertype { +	REF_PHANDLE, +	REF_PATH, +	LABEL, +}; + +struct  marker { +	enum markertype type; +	int offset; +	char *ref; +	struct marker *next; +}; + +struct data { +	int len; +	char *val; +	struct marker *markers; +}; + + +#define empty_data ((struct data){ /* all .members = 0 or NULL */ }) + +#define for_each_marker(m) \ +	for (; (m); (m) = (m)->next) +#define for_each_marker_of_type(m, t) \ +	for_each_marker(m) \ +		if ((m)->type == (t)) + +void data_free(struct data d); + +struct data data_grow_for(struct data d, int xlen); + +struct data data_copy_mem(const char *mem, int len); +struct data data_copy_escape_string(const char *s, int len); +struct data data_copy_file(FILE *f, size_t len); + +struct data data_append_data(struct data d, const void *p, int len); +struct data data_insert_at_marker(struct data d, struct marker *m, +				  const void *p, int len); +struct data data_merge(struct data d1, struct data d2); +struct data data_append_cell(struct data d, cell_t word); +struct data data_append_re(struct data d, const struct fdt_reserve_entry *re); +struct data data_append_addr(struct data d, uint64_t addr); +struct data data_append_byte(struct data d, uint8_t byte); +struct data data_append_zeroes(struct data d, int len); +struct data data_append_align(struct data d, int align); + +struct data data_add_marker(struct data d, enum markertype type, char *ref); + +int data_is_one_string(struct data d); + +/* DT constraints */ + +#define MAX_PROPNAME_LEN	31 +#define MAX_NODENAME_LEN	31 + +/* Live trees */ +struct property { +	char *name; +	struct data val; + +	struct property *next; + +	char *label; +}; + +struct node { +	char *name; +	struct property *proplist; +	struct node *children; + +	struct node *parent; +	struct node *next_sibling; + +	char *fullpath; +	int basenamelen; + +	cell_t phandle; +	int addr_cells, size_cells; + +	char *label; +}; + +#define for_each_property(n, p) \ +	for ((p) = (n)->proplist; (p); (p) = (p)->next) + +#define for_each_child(n, c)	\ +	for ((c) = (n)->children; (c); (c) = (c)->next_sibling) + +struct property *build_property(char *name, struct data val, char *label); +struct property *chain_property(struct property *first, struct property *list); +struct property *reverse_properties(struct property *first); + +struct node *build_node(struct property *proplist, struct node *children); +struct node *name_node(struct node *node, char *name, char *label); +struct node *chain_node(struct node *first, struct node *list); + +void add_property(struct node *node, struct property *prop); +void add_child(struct node *parent, struct node *child); + +const char *get_unitname(struct node *node); +struct property *get_property(struct node *node, const char *propname); +cell_t propval_cell(struct property *prop); +struct node *get_subnode(struct node *node, const char *nodename); +struct node *get_node_by_path(struct node *tree, const char *path); +struct node *get_node_by_label(struct node *tree, const char *label); +struct node *get_node_by_phandle(struct node *tree, cell_t phandle); +struct node *get_node_by_ref(struct node *tree, const char *ref); +cell_t get_node_phandle(struct node *root, struct node *node); + +/* Boot info (tree plus memreserve information */ + +struct reserve_info { +	struct fdt_reserve_entry re; + +	struct reserve_info *next; + +	char *label; +}; + +struct reserve_info *build_reserve_entry(uint64_t start, uint64_t len, char *label); +struct reserve_info *chain_reserve_entry(struct reserve_info *first, +					 struct reserve_info *list); +struct reserve_info *add_reserve_entry(struct reserve_info *list, +				       struct reserve_info *new); + + +struct boot_info { +	struct reserve_info *reservelist; +	struct node *dt;		/* the device tree */ +	uint32_t boot_cpuid_phys; +}; + +struct boot_info *build_boot_info(struct reserve_info *reservelist, +				  struct node *tree, uint32_t boot_cpuid_phys); + +/* Checks */ + +void process_checks(int force, struct boot_info *bi); + +/* Flattened trees */ + +void dt_to_blob(FILE *f, struct boot_info *bi, int version); +void dt_to_asm(FILE *f, struct boot_info *bi, int version); + +struct boot_info *dt_from_blob(const char *fname); + +/* Tree source */ + +void dt_to_source(FILE *f, struct boot_info *bi); +struct boot_info *dt_from_source(const char *f); + +/* FS trees */ + +struct boot_info *dt_from_fs(const char *dirname); + +/* misc */ + +char *join_path(const char *path, const char *name); + +#endif /* _DTC_H */ diff --git a/scripts/dtc/flattree.c b/scripts/dtc/flattree.c new file mode 100644 index 00000000000..76acd28c068 --- /dev/null +++ b/scripts/dtc/flattree.c @@ -0,0 +1,906 @@ +/* + * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005. + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + *  General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 + *                                                                   USA + */ + +#include "dtc.h" +#include "srcpos.h" + +#define FTF_FULLPATH	0x1 +#define FTF_VARALIGN	0x2 +#define FTF_NAMEPROPS	0x4 +#define FTF_BOOTCPUID	0x8 +#define FTF_STRTABSIZE	0x10 +#define FTF_STRUCTSIZE	0x20 +#define FTF_NOPS	0x40 + +static struct version_info { +	int version; +	int last_comp_version; +	int hdr_size; +	int flags; +} version_table[] = { +	{1, 1, FDT_V1_SIZE, +	 FTF_FULLPATH|FTF_VARALIGN|FTF_NAMEPROPS}, +	{2, 1, FDT_V2_SIZE, +	 FTF_FULLPATH|FTF_VARALIGN|FTF_NAMEPROPS|FTF_BOOTCPUID}, +	{3, 1, FDT_V3_SIZE, +	 FTF_FULLPATH|FTF_VARALIGN|FTF_NAMEPROPS|FTF_BOOTCPUID|FTF_STRTABSIZE}, +	{16, 16, FDT_V3_SIZE, +	 FTF_BOOTCPUID|FTF_STRTABSIZE|FTF_NOPS}, +	{17, 16, FDT_V17_SIZE, +	 FTF_BOOTCPUID|FTF_STRTABSIZE|FTF_STRUCTSIZE|FTF_NOPS}, +}; + +struct emitter { +	void (*cell)(void *, cell_t); +	void (*string)(void *, char *, int); +	void (*align)(void *, int); +	void (*data)(void *, struct data); +	void (*beginnode)(void *, const char *); +	void (*endnode)(void *, const char *); +	void (*property)(void *, const char *); +}; + +static void bin_emit_cell(void *e, cell_t val) +{ +	struct data *dtbuf = e; + +	*dtbuf = data_append_cell(*dtbuf, val); +} + +static void bin_emit_string(void *e, char *str, int len) +{ +	struct data *dtbuf = e; + +	if (len == 0) +		len = strlen(str); + +	*dtbuf = data_append_data(*dtbuf, str, len); +	*dtbuf = data_append_byte(*dtbuf, '\0'); +} + +static void bin_emit_align(void *e, int a) +{ +	struct data *dtbuf = e; + +	*dtbuf = data_append_align(*dtbuf, a); +} + +static void bin_emit_data(void *e, struct data d) +{ +	struct data *dtbuf = e; + +	*dtbuf = data_append_data(*dtbuf, d.val, d.len); +} + +static void bin_emit_beginnode(void *e, const char *label) +{ +	bin_emit_cell(e, FDT_BEGIN_NODE); +} + +static void bin_emit_endnode(void *e, const char *label) +{ +	bin_emit_cell(e, FDT_END_NODE); +} + +static void bin_emit_property(void *e, const char *label) +{ +	bin_emit_cell(e, FDT_PROP); +} + +static struct emitter bin_emitter = { +	.cell = bin_emit_cell, +	.string = bin_emit_string, +	.align = bin_emit_align, +	.data = bin_emit_data, +	.beginnode = bin_emit_beginnode, +	.endnode = bin_emit_endnode, +	.property = bin_emit_property, +}; + +static void emit_label(FILE *f, const char *prefix, const char *label) +{ +	fprintf(f, "\t.globl\t%s_%s\n", prefix, label); +	fprintf(f, "%s_%s:\n", prefix, label); +	fprintf(f, "_%s_%s:\n", prefix, label); +} + +static void emit_offset_label(FILE *f, const char *label, int offset) +{ +	fprintf(f, "\t.globl\t%s\n", label); +	fprintf(f, "%s\t= . + %d\n", label, offset); +} + +static void asm_emit_cell(void *e, cell_t val) +{ +	FILE *f = e; + +	fprintf(f, "\t.long\t0x%x\n", val); +} + +static void asm_emit_string(void *e, char *str, int len) +{ +	FILE *f = e; +	char c = 0; + +	if (len != 0) { +		/* XXX: ewww */ +		c = str[len]; +		str[len] = '\0'; +	} + +	fprintf(f, "\t.string\t\"%s\"\n", str); + +	if (len != 0) { +		str[len] = c; +	} +} + +static void asm_emit_align(void *e, int a) +{ +	FILE *f = e; + +	fprintf(f, "\t.balign\t%d\n", a); +} + +static void asm_emit_data(void *e, struct data d) +{ +	FILE *f = e; +	int off = 0; +	struct marker *m = d.markers; + +	for_each_marker_of_type(m, LABEL) +		emit_offset_label(f, m->ref, m->offset); + +	while ((d.len - off) >= sizeof(uint32_t)) { +		fprintf(f, "\t.long\t0x%x\n", +			fdt32_to_cpu(*((uint32_t *)(d.val+off)))); +		off += sizeof(uint32_t); +	} + +	while ((d.len - off) >= 1) { +		fprintf(f, "\t.byte\t0x%hhx\n", d.val[off]); +		off += 1; +	} + +	assert(off == d.len); +} + +static void asm_emit_beginnode(void *e, const char *label) +{ +	FILE *f = e; + +	if (label) { +		fprintf(f, "\t.globl\t%s\n", label); +		fprintf(f, "%s:\n", label); +	} +	fprintf(f, "\t.long\tFDT_BEGIN_NODE\n"); +} + +static void asm_emit_endnode(void *e, const char *label) +{ +	FILE *f = e; + +	fprintf(f, "\t.long\tFDT_END_NODE\n"); +	if (label) { +		fprintf(f, "\t.globl\t%s_end\n", label); +		fprintf(f, "%s_end:\n", label); +	} +} + +static void asm_emit_property(void *e, const char *label) +{ +	FILE *f = e; + +	if (label) { +		fprintf(f, "\t.globl\t%s\n", label); +		fprintf(f, "%s:\n", label); +	} +	fprintf(f, "\t.long\tFDT_PROP\n"); +} + +static struct emitter asm_emitter = { +	.cell = asm_emit_cell, +	.string = asm_emit_string, +	.align = asm_emit_align, +	.data = asm_emit_data, +	.beginnode = asm_emit_beginnode, +	.endnode = asm_emit_endnode, +	.property = asm_emit_property, +}; + +static int stringtable_insert(struct data *d, const char *str) +{ +	int i; + +	/* FIXME: do this more efficiently? */ + +	for (i = 0; i < d->len; i++) { +		if (streq(str, d->val + i)) +			return i; +	} + +	*d = data_append_data(*d, str, strlen(str)+1); +	return i; +} + +static void flatten_tree(struct node *tree, struct emitter *emit, +			 void *etarget, struct data *strbuf, +			 struct version_info *vi) +{ +	struct property *prop; +	struct node *child; +	int seen_name_prop = 0; + +	emit->beginnode(etarget, tree->label); + +	if (vi->flags & FTF_FULLPATH) +		emit->string(etarget, tree->fullpath, 0); +	else +		emit->string(etarget, tree->name, 0); + +	emit->align(etarget, sizeof(cell_t)); + +	for_each_property(tree, prop) { +		int nameoff; + +		if (streq(prop->name, "name")) +			seen_name_prop = 1; + +		nameoff = stringtable_insert(strbuf, prop->name); + +		emit->property(etarget, prop->label); +		emit->cell(etarget, prop->val.len); +		emit->cell(etarget, nameoff); + +		if ((vi->flags & FTF_VARALIGN) && (prop->val.len >= 8)) +			emit->align(etarget, 8); + +		emit->data(etarget, prop->val); +		emit->align(etarget, sizeof(cell_t)); +	} + +	if ((vi->flags & FTF_NAMEPROPS) && !seen_name_prop) { +		emit->property(etarget, NULL); +		emit->cell(etarget, tree->basenamelen+1); +		emit->cell(etarget, stringtable_insert(strbuf, "name")); + +		if ((vi->flags & FTF_VARALIGN) && ((tree->basenamelen+1) >= 8)) +			emit->align(etarget, 8); + +		emit->string(etarget, tree->name, tree->basenamelen); +		emit->align(etarget, sizeof(cell_t)); +	} + +	for_each_child(tree, child) { +		flatten_tree(child, emit, etarget, strbuf, vi); +	} + +	emit->endnode(etarget, tree->label); +} + +static struct data flatten_reserve_list(struct reserve_info *reservelist, +				 struct version_info *vi) +{ +	struct reserve_info *re; +	struct data d = empty_data; +	static struct fdt_reserve_entry null_re = {0,0}; +	int    j; + +	for (re = reservelist; re; re = re->next) { +		d = data_append_re(d, &re->re); +	} +	/* +	 * Add additional reserved slots if the user asked for them. +	 */ +	for (j = 0; j < reservenum; j++) { +		d = data_append_re(d, &null_re); +	} + +	return d; +} + +static void make_fdt_header(struct fdt_header *fdt, +			    struct version_info *vi, +			    int reservesize, int dtsize, int strsize, +			    int boot_cpuid_phys) +{ +	int reserve_off; + +	reservesize += sizeof(struct fdt_reserve_entry); + +	memset(fdt, 0xff, sizeof(*fdt)); + +	fdt->magic = cpu_to_fdt32(FDT_MAGIC); +	fdt->version = cpu_to_fdt32(vi->version); +	fdt->last_comp_version = cpu_to_fdt32(vi->last_comp_version); + +	/* Reserve map should be doubleword aligned */ +	reserve_off = ALIGN(vi->hdr_size, 8); + +	fdt->off_mem_rsvmap = cpu_to_fdt32(reserve_off); +	fdt->off_dt_struct = cpu_to_fdt32(reserve_off + reservesize); +	fdt->off_dt_strings = cpu_to_fdt32(reserve_off + reservesize +					  + dtsize); +	fdt->totalsize = cpu_to_fdt32(reserve_off + reservesize + dtsize + strsize); + +	if (vi->flags & FTF_BOOTCPUID) +		fdt->boot_cpuid_phys = cpu_to_fdt32(boot_cpuid_phys); +	if (vi->flags & FTF_STRTABSIZE) +		fdt->size_dt_strings = cpu_to_fdt32(strsize); +	if (vi->flags & FTF_STRUCTSIZE) +		fdt->size_dt_struct = cpu_to_fdt32(dtsize); +} + +void dt_to_blob(FILE *f, struct boot_info *bi, int version) +{ +	struct version_info *vi = NULL; +	int i; +	struct data blob       = empty_data; +	struct data reservebuf = empty_data; +	struct data dtbuf      = empty_data; +	struct data strbuf     = empty_data; +	struct fdt_header fdt; +	int padlen = 0; + +	for (i = 0; i < ARRAY_SIZE(version_table); i++) { +		if (version_table[i].version == version) +			vi = &version_table[i]; +	} +	if (!vi) +		die("Unknown device tree blob version %d\n", version); + +	flatten_tree(bi->dt, &bin_emitter, &dtbuf, &strbuf, vi); +	bin_emit_cell(&dtbuf, FDT_END); + +	reservebuf = flatten_reserve_list(bi->reservelist, vi); + +	/* Make header */ +	make_fdt_header(&fdt, vi, reservebuf.len, dtbuf.len, strbuf.len, +			bi->boot_cpuid_phys); + +	/* +	 * If the user asked for more space than is used, adjust the totalsize. +	 */ +	if (minsize > 0) { +		padlen = minsize - fdt32_to_cpu(fdt.totalsize); +		if ((padlen < 0) && (quiet < 1)) +			fprintf(stderr, +				"Warning: blob size %d >= minimum size %d\n", +				fdt32_to_cpu(fdt.totalsize), minsize); +	} + +	if (padsize > 0) +		padlen = padsize; + +	if (padlen > 0) { +		int tsize = fdt32_to_cpu(fdt.totalsize); +		tsize += padlen; +		fdt.totalsize = cpu_to_fdt32(tsize); +	} + +	/* +	 * Assemble the blob: start with the header, add with alignment +	 * the reserve buffer, add the reserve map terminating zeroes, +	 * the device tree itself, and finally the strings. +	 */ +	blob = data_append_data(blob, &fdt, vi->hdr_size); +	blob = data_append_align(blob, 8); +	blob = data_merge(blob, reservebuf); +	blob = data_append_zeroes(blob, sizeof(struct fdt_reserve_entry)); +	blob = data_merge(blob, dtbuf); +	blob = data_merge(blob, strbuf); + +	/* +	 * If the user asked for more space than is used, pad out the blob. +	 */ +	if (padlen > 0) +		blob = data_append_zeroes(blob, padlen); + +	fwrite(blob.val, blob.len, 1, f); + +	if (ferror(f)) +		die("Error writing device tree blob: %s\n", strerror(errno)); + +	/* +	 * data_merge() frees the right-hand element so only the blob +	 * remains to be freed. +	 */ +	data_free(blob); +} + +static void dump_stringtable_asm(FILE *f, struct data strbuf) +{ +	const char *p; +	int len; + +	p = strbuf.val; + +	while (p < (strbuf.val + strbuf.len)) { +		len = strlen(p); +		fprintf(f, "\t.string \"%s\"\n", p); +		p += len+1; +	} +} + +void dt_to_asm(FILE *f, struct boot_info *bi, int version) +{ +	struct version_info *vi = NULL; +	int i; +	struct data strbuf = empty_data; +	struct reserve_info *re; +	const char *symprefix = "dt"; + +	for (i = 0; i < ARRAY_SIZE(version_table); i++) { +		if (version_table[i].version == version) +			vi = &version_table[i]; +	} +	if (!vi) +		die("Unknown device tree blob version %d\n", version); + +	fprintf(f, "/* autogenerated by dtc, do not edit */\n\n"); +	fprintf(f, "#define FDT_MAGIC 0x%x\n", FDT_MAGIC); +	fprintf(f, "#define FDT_BEGIN_NODE 0x%x\n", FDT_BEGIN_NODE); +	fprintf(f, "#define FDT_END_NODE 0x%x\n", FDT_END_NODE); +	fprintf(f, "#define FDT_PROP 0x%x\n", FDT_PROP); +	fprintf(f, "#define FDT_END 0x%x\n", FDT_END); +	fprintf(f, "\n"); + +	emit_label(f, symprefix, "blob_start"); +	emit_label(f, symprefix, "header"); +	fprintf(f, "\t.long\tFDT_MAGIC\t\t\t\t/* magic */\n"); +	fprintf(f, "\t.long\t_%s_blob_abs_end - _%s_blob_start\t/* totalsize */\n", +		symprefix, symprefix); +	fprintf(f, "\t.long\t_%s_struct_start - _%s_blob_start\t/* off_dt_struct */\n", +		symprefix, symprefix); +	fprintf(f, "\t.long\t_%s_strings_start - _%s_blob_start\t/* off_dt_strings */\n", +		symprefix, symprefix); +	fprintf(f, "\t.long\t_%s_reserve_map - _%s_blob_start\t/* off_dt_strings */\n", +		symprefix, symprefix); +	fprintf(f, "\t.long\t%d\t\t\t\t\t/* version */\n", vi->version); +	fprintf(f, "\t.long\t%d\t\t\t\t\t/* last_comp_version */\n", +		vi->last_comp_version); + +	if (vi->flags & FTF_BOOTCPUID) +		fprintf(f, "\t.long\t%i\t\t\t\t\t/* boot_cpuid_phys */\n", +			bi->boot_cpuid_phys); + +	if (vi->flags & FTF_STRTABSIZE) +		fprintf(f, "\t.long\t_%s_strings_end - _%s_strings_start\t/* size_dt_strings */\n", +			symprefix, symprefix); + +	if (vi->flags & FTF_STRUCTSIZE) +		fprintf(f, "\t.long\t_%s_struct_end - _%s_struct_start\t/* size_dt_struct */\n", +			symprefix, symprefix); + +	/* +	 * Reserve map entries. +	 * Align the reserve map to a doubleword boundary. +	 * Each entry is an (address, size) pair of u64 values. +	 * Always supply a zero-sized temination entry. +	 */ +	asm_emit_align(f, 8); +	emit_label(f, symprefix, "reserve_map"); + +	fprintf(f, "/* Memory reserve map from source file */\n"); + +	/* +	 * Use .long on high and low halfs of u64s to avoid .quad +	 * as it appears .quad isn't available in some assemblers. +	 */ +	for (re = bi->reservelist; re; re = re->next) { +		if (re->label) { +			fprintf(f, "\t.globl\t%s\n", re->label); +			fprintf(f, "%s:\n", re->label); +		} +		fprintf(f, "\t.long\t0x%08x, 0x%08x\n", +			(unsigned int)(re->re.address >> 32), +			(unsigned int)(re->re.address & 0xffffffff)); +		fprintf(f, "\t.long\t0x%08x, 0x%08x\n", +			(unsigned int)(re->re.size >> 32), +			(unsigned int)(re->re.size & 0xffffffff)); +	} +	for (i = 0; i < reservenum; i++) { +		fprintf(f, "\t.long\t0, 0\n\t.long\t0, 0\n"); +	} + +	fprintf(f, "\t.long\t0, 0\n\t.long\t0, 0\n"); + +	emit_label(f, symprefix, "struct_start"); +	flatten_tree(bi->dt, &asm_emitter, f, &strbuf, vi); +	fprintf(f, "\t.long\tFDT_END\n"); +	emit_label(f, symprefix, "struct_end"); + +	emit_label(f, symprefix, "strings_start"); +	dump_stringtable_asm(f, strbuf); +	emit_label(f, symprefix, "strings_end"); + +	emit_label(f, symprefix, "blob_end"); + +	/* +	 * If the user asked for more space than is used, pad it out. +	 */ +	if (minsize > 0) { +		fprintf(f, "\t.space\t%d - (_%s_blob_end - _%s_blob_start), 0\n", +			minsize, symprefix, symprefix); +	} +	if (padsize > 0) { +		fprintf(f, "\t.space\t%d, 0\n", padsize); +	} +	emit_label(f, symprefix, "blob_abs_end"); + +	data_free(strbuf); +} + +struct inbuf { +	char *base, *limit, *ptr; +}; + +static void inbuf_init(struct inbuf *inb, void *base, void *limit) +{ +	inb->base = base; +	inb->limit = limit; +	inb->ptr = inb->base; +} + +static void flat_read_chunk(struct inbuf *inb, void *p, int len) +{ +	if ((inb->ptr + len) > inb->limit) +		die("Premature end of data parsing flat device tree\n"); + +	memcpy(p, inb->ptr, len); + +	inb->ptr += len; +} + +static uint32_t flat_read_word(struct inbuf *inb) +{ +	uint32_t val; + +	assert(((inb->ptr - inb->base) % sizeof(val)) == 0); + +	flat_read_chunk(inb, &val, sizeof(val)); + +	return fdt32_to_cpu(val); +} + +static void flat_realign(struct inbuf *inb, int align) +{ +	int off = inb->ptr - inb->base; + +	inb->ptr = inb->base + ALIGN(off, align); +	if (inb->ptr > inb->limit) +		die("Premature end of data parsing flat device tree\n"); +} + +static char *flat_read_string(struct inbuf *inb) +{ +	int len = 0; +	const char *p = inb->ptr; +	char *str; + +	do { +		if (p >= inb->limit) +			die("Premature end of data parsing flat device tree\n"); +		len++; +	} while ((*p++) != '\0'); + +	str = strdup(inb->ptr); + +	inb->ptr += len; + +	flat_realign(inb, sizeof(uint32_t)); + +	return str; +} + +static struct data flat_read_data(struct inbuf *inb, int len) +{ +	struct data d = empty_data; + +	if (len == 0) +		return empty_data; + +	d = data_grow_for(d, len); +	d.len = len; + +	flat_read_chunk(inb, d.val, len); + +	flat_realign(inb, sizeof(uint32_t)); + +	return d; +} + +static char *flat_read_stringtable(struct inbuf *inb, int offset) +{ +	const char *p; + +	p = inb->base + offset; +	while (1) { +		if (p >= inb->limit || p < inb->base) +			die("String offset %d overruns string table\n", +			    offset); + +		if (*p == '\0') +			break; + +		p++; +	} + +	return strdup(inb->base + offset); +} + +static struct property *flat_read_property(struct inbuf *dtbuf, +					   struct inbuf *strbuf, int flags) +{ +	uint32_t proplen, stroff; +	char *name; +	struct data val; + +	proplen = flat_read_word(dtbuf); +	stroff = flat_read_word(dtbuf); + +	name = flat_read_stringtable(strbuf, stroff); + +	if ((flags & FTF_VARALIGN) && (proplen >= 8)) +		flat_realign(dtbuf, 8); + +	val = flat_read_data(dtbuf, proplen); + +	return build_property(name, val, NULL); +} + + +static struct reserve_info *flat_read_mem_reserve(struct inbuf *inb) +{ +	struct reserve_info *reservelist = NULL; +	struct reserve_info *new; +	const char *p; +	struct fdt_reserve_entry re; + +	/* +	 * Each entry is a pair of u64 (addr, size) values for 4 cell_t's. +	 * List terminates at an entry with size equal to zero. +	 * +	 * First pass, count entries. +	 */ +	p = inb->ptr; +	while (1) { +		flat_read_chunk(inb, &re, sizeof(re)); +		re.address  = fdt64_to_cpu(re.address); +		re.size = fdt64_to_cpu(re.size); +		if (re.size == 0) +			break; + +		new = build_reserve_entry(re.address, re.size, NULL); +		reservelist = add_reserve_entry(reservelist, new); +	} + +	return reservelist; +} + + +static char *nodename_from_path(const char *ppath, const char *cpath) +{ +	int plen; + +	plen = strlen(ppath); + +	if (!strneq(ppath, cpath, plen)) +		die("Path \"%s\" is not valid as a child of \"%s\"\n", +		    cpath, ppath); + +	/* root node is a special case */ +	if (!streq(ppath, "/")) +		plen++; + +	return strdup(cpath + plen); +} + +static struct node *unflatten_tree(struct inbuf *dtbuf, +				   struct inbuf *strbuf, +				   const char *parent_flatname, int flags) +{ +	struct node *node; +	char *flatname; +	uint32_t val; + +	node = build_node(NULL, NULL); + +	flatname = flat_read_string(dtbuf); + +	if (flags & FTF_FULLPATH) +		node->name = nodename_from_path(parent_flatname, flatname); +	else +		node->name = flatname; + +	do { +		struct property *prop; +		struct node *child; + +		val = flat_read_word(dtbuf); +		switch (val) { +		case FDT_PROP: +			if (node->children) +				fprintf(stderr, "Warning: Flat tree input has " +					"subnodes preceding a property.\n"); +			prop = flat_read_property(dtbuf, strbuf, flags); +			add_property(node, prop); +			break; + +		case FDT_BEGIN_NODE: +			child = unflatten_tree(dtbuf,strbuf, flatname, flags); +			add_child(node, child); +			break; + +		case FDT_END_NODE: +			break; + +		case FDT_END: +			die("Premature FDT_END in device tree blob\n"); +			break; + +		case FDT_NOP: +			if (!(flags & FTF_NOPS)) +				fprintf(stderr, "Warning: NOP tag found in flat tree" +					" version <16\n"); + +			/* Ignore */ +			break; + +		default: +			die("Invalid opcode word %08x in device tree blob\n", +			    val); +		} +	} while (val != FDT_END_NODE); + +	return node; +} + + +struct boot_info *dt_from_blob(const char *fname) +{ +	struct dtc_file *dtcf; +	uint32_t magic, totalsize, version, size_dt, boot_cpuid_phys; +	uint32_t off_dt, off_str, off_mem_rsvmap; +	int rc; +	char *blob; +	struct fdt_header *fdt; +	char *p; +	struct inbuf dtbuf, strbuf; +	struct inbuf memresvbuf; +	int sizeleft; +	struct reserve_info *reservelist; +	struct node *tree; +	uint32_t val; +	int flags = 0; + +	dtcf = dtc_open_file(fname, NULL); + +	rc = fread(&magic, sizeof(magic), 1, dtcf->file); +	if (ferror(dtcf->file)) +		die("Error reading DT blob magic number: %s\n", +		    strerror(errno)); +	if (rc < 1) { +		if (feof(dtcf->file)) +			die("EOF reading DT blob magic number\n"); +		else +			die("Mysterious short read reading magic number\n"); +	} + +	magic = fdt32_to_cpu(magic); +	if (magic != FDT_MAGIC) +		die("Blob has incorrect magic number\n"); + +	rc = fread(&totalsize, sizeof(totalsize), 1, dtcf->file); +	if (ferror(dtcf->file)) +		die("Error reading DT blob size: %s\n", strerror(errno)); +	if (rc < 1) { +		if (feof(dtcf->file)) +			die("EOF reading DT blob size\n"); +		else +			die("Mysterious short read reading blob size\n"); +	} + +	totalsize = fdt32_to_cpu(totalsize); +	if (totalsize < FDT_V1_SIZE) +		die("DT blob size (%d) is too small\n", totalsize); + +	blob = xmalloc(totalsize); + +	fdt = (struct fdt_header *)blob; +	fdt->magic = cpu_to_fdt32(magic); +	fdt->totalsize = cpu_to_fdt32(totalsize); + +	sizeleft = totalsize - sizeof(magic) - sizeof(totalsize); +	p = blob + sizeof(magic)  + sizeof(totalsize); + +	while (sizeleft) { +		if (feof(dtcf->file)) +			die("EOF before reading %d bytes of DT blob\n", +			    totalsize); + +		rc = fread(p, 1, sizeleft, dtcf->file); +		if (ferror(dtcf->file)) +			die("Error reading DT blob: %s\n", +			    strerror(errno)); + +		sizeleft -= rc; +		p += rc; +	} + +	off_dt = fdt32_to_cpu(fdt->off_dt_struct); +	off_str = fdt32_to_cpu(fdt->off_dt_strings); +	off_mem_rsvmap = fdt32_to_cpu(fdt->off_mem_rsvmap); +	version = fdt32_to_cpu(fdt->version); +	boot_cpuid_phys = fdt32_to_cpu(fdt->boot_cpuid_phys); + +	if (off_mem_rsvmap >= totalsize) +		die("Mem Reserve structure offset exceeds total size\n"); + +	if (off_dt >= totalsize) +		die("DT structure offset exceeds total size\n"); + +	if (off_str > totalsize) +		die("String table offset exceeds total size\n"); + +	if (version >= 3) { +		uint32_t size_str = fdt32_to_cpu(fdt->size_dt_strings); +		if (off_str+size_str > totalsize) +			die("String table extends past total size\n"); +		inbuf_init(&strbuf, blob + off_str, blob + off_str + size_str); +	} else { +		inbuf_init(&strbuf, blob + off_str, blob + totalsize); +	} + +	if (version >= 17) { +		size_dt = fdt32_to_cpu(fdt->size_dt_struct); +		if (off_dt+size_dt > totalsize) +			die("Structure block extends past total size\n"); +	} + +	if (version < 16) { +		flags |= FTF_FULLPATH | FTF_NAMEPROPS | FTF_VARALIGN; +	} else { +		flags |= FTF_NOPS; +	} + +	inbuf_init(&memresvbuf, +		   blob + off_mem_rsvmap, blob + totalsize); +	inbuf_init(&dtbuf, blob + off_dt, blob + totalsize); + +	reservelist = flat_read_mem_reserve(&memresvbuf); + +	val = flat_read_word(&dtbuf); + +	if (val != FDT_BEGIN_NODE) +		die("Device tree blob doesn't begin with FDT_BEGIN_NODE (begins with 0x%08x)\n", val); + +	tree = unflatten_tree(&dtbuf, &strbuf, "", flags); + +	val = flat_read_word(&dtbuf); +	if (val != FDT_END) +		die("Device tree blob doesn't end with FDT_END\n"); + +	free(blob); + +	dtc_close_file(dtcf); + +	return build_boot_info(reservelist, tree, boot_cpuid_phys); +} diff --git a/scripts/dtc/fstree.c b/scripts/dtc/fstree.c new file mode 100644 index 00000000000..766b2694d93 --- /dev/null +++ b/scripts/dtc/fstree.c @@ -0,0 +1,92 @@ +/* + * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005. + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + *  General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 + *                                                                   USA + */ + +#include "dtc.h" + +#include <dirent.h> +#include <sys/stat.h> + +static struct node *read_fstree(const char *dirname) +{ +	DIR *d; +	struct dirent *de; +	struct stat st; +	struct node *tree; + +	d = opendir(dirname); +	if (!d) +		die("Couldn't opendir() \"%s\": %s\n", dirname, strerror(errno)); + +	tree = build_node(NULL, NULL); + +	while ((de = readdir(d)) != NULL) { +		char *tmpnam; + +		if (streq(de->d_name, ".") +		    || streq(de->d_name, "..")) +			continue; + +		tmpnam = join_path(dirname, de->d_name); + +		if (lstat(tmpnam, &st) < 0) +			die("stat(%s): %s\n", tmpnam, strerror(errno)); + +		if (S_ISREG(st.st_mode)) { +			struct property *prop; +			FILE *pfile; + +			pfile = fopen(tmpnam, "r"); +			if (! pfile) { +				fprintf(stderr, +					"WARNING: Cannot open %s: %s\n", +					tmpnam, strerror(errno)); +			} else { +				prop = build_property(strdup(de->d_name), +						      data_copy_file(pfile, +								     st.st_size), +						      NULL); +				add_property(tree, prop); +				fclose(pfile); +			} +		} else if (S_ISDIR(st.st_mode)) { +			struct node *newchild; + +			newchild = read_fstree(tmpnam); +			newchild = name_node(newchild, strdup(de->d_name), +					     NULL); +			add_child(tree, newchild); +		} + +		free(tmpnam); +	} + +	return tree; +} + +struct boot_info *dt_from_fs(const char *dirname) +{ +	struct node *tree; + +	tree = read_fstree(dirname); +	tree = name_node(tree, "", NULL); + +	return build_boot_info(NULL, tree, 0); +} + diff --git a/scripts/dtc/libfdt/Makefile.libfdt b/scripts/dtc/libfdt/Makefile.libfdt new file mode 100644 index 00000000000..6c42acfa21e --- /dev/null +++ b/scripts/dtc/libfdt/Makefile.libfdt @@ -0,0 +1,8 @@ +# Makefile.libfdt +# +# This is not a complete Makefile of itself.  Instead, it is designed to +# be easily embeddable into other systems of Makefiles. +# +LIBFDT_INCLUDES = fdt.h libfdt.h +LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c +LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o) diff --git a/scripts/dtc/libfdt/fdt.c b/scripts/dtc/libfdt/fdt.c new file mode 100644 index 00000000000..2acaec5923a --- /dev/null +++ b/scripts/dtc/libfdt/fdt.c @@ -0,0 +1,201 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + *  a) This library is free software; you can redistribute it and/or + *     modify it under the terms of the GNU General Public License as + *     published by the Free Software Foundation; either version 2 of the + *     License, or (at your option) any later version. + * + *     This library is distributed in the hope that it will be useful, + *     but WITHOUT ANY WARRANTY; without even the implied warranty of + *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *     GNU General Public License for more details. + * + *     You should have received a copy of the GNU General Public + *     License along with this library; if not, write to the Free + *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + *     MA 02110-1301 USA + * + * Alternatively, + * + *  b) Redistribution and use in source and binary forms, with or + *     without modification, are permitted provided that the following + *     conditions are met: + * + *     1. Redistributions of source code must retain the above + *        copyright notice, this list of conditions and the following + *        disclaimer. + *     2. Redistributions in binary form must reproduce the above + *        copyright notice, this list of conditions and the following + *        disclaimer in the documentation and/or other materials + *        provided with the distribution. + * + *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "libfdt_env.h" + +#include <fdt.h> +#include <libfdt.h> + +#include "libfdt_internal.h" + +int fdt_check_header(const void *fdt) +{ +	if (fdt_magic(fdt) == FDT_MAGIC) { +		/* Complete tree */ +		if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) +			return -FDT_ERR_BADVERSION; +		if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION) +			return -FDT_ERR_BADVERSION; +	} else if (fdt_magic(fdt) == FDT_SW_MAGIC) { +		/* Unfinished sequential-write blob */ +		if (fdt_size_dt_struct(fdt) == 0) +			return -FDT_ERR_BADSTATE; +	} else { +		return -FDT_ERR_BADMAGIC; +	} + +	return 0; +} + +const void *fdt_offset_ptr(const void *fdt, int offset, int len) +{ +	const char *p; + +	if (fdt_version(fdt) >= 0x11) +		if (((offset + len) < offset) +		    || ((offset + len) > fdt_size_dt_struct(fdt))) +			return NULL; + +	p = _fdt_offset_ptr(fdt, offset); + +	if (p + len < p) +		return NULL; +	return p; +} + +uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset) +{ +	const uint32_t *tagp, *lenp; +	uint32_t tag; +	const char *p; + +	if (offset % FDT_TAGSIZE) +		return -1; + +	tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE); +	if (! tagp) +		return FDT_END; /* premature end */ +	tag = fdt32_to_cpu(*tagp); +	offset += FDT_TAGSIZE; + +	switch (tag) { +	case FDT_BEGIN_NODE: +		/* skip name */ +		do { +			p = fdt_offset_ptr(fdt, offset++, 1); +		} while (p && (*p != '\0')); +		if (! p) +			return FDT_END; +		break; +	case FDT_PROP: +		lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp)); +		if (! lenp) +			return FDT_END; +		/* skip name offset, length and value */ +		offset += 2*FDT_TAGSIZE + fdt32_to_cpu(*lenp); +		break; +	} + +	if (nextoffset) +		*nextoffset = FDT_TAGALIGN(offset); + +	return tag; +} + +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; +} + +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; +} + +const char *_fdt_find_string(const char *strtab, int tabsize, const char *s) +{ +	int len = strlen(s) + 1; +	const char *last = strtab + tabsize - len; +	const char *p; + +	for (p = strtab; p <= last; p++) +		if (memcmp(p, s, len) == 0) +			return p; +	return NULL; +} + +int fdt_move(const void *fdt, void *buf, int bufsize) +{ +	FDT_CHECK_HEADER(fdt); + +	if (fdt_totalsize(fdt) > bufsize) +		return -FDT_ERR_NOSPACE; + +	memmove(buf, fdt, fdt_totalsize(fdt)); +	return 0; +} diff --git a/scripts/dtc/libfdt/fdt.h b/scripts/dtc/libfdt/fdt.h new file mode 100644 index 00000000000..48ccfd91000 --- /dev/null +++ b/scripts/dtc/libfdt/fdt.h @@ -0,0 +1,60 @@ +#ifndef _FDT_H +#define _FDT_H + +#ifndef __ASSEMBLY__ + +struct fdt_header { +	uint32_t magic;			 /* magic word FDT_MAGIC */ +	uint32_t totalsize;		 /* total size of DT block */ +	uint32_t off_dt_struct;		 /* offset to structure */ +	uint32_t off_dt_strings;	 /* offset to strings */ +	uint32_t off_mem_rsvmap;	 /* offset to memory reserve map */ +	uint32_t version;		 /* format version */ +	uint32_t last_comp_version;	 /* last compatible version */ + +	/* version 2 fields below */ +	uint32_t boot_cpuid_phys;	 /* Which physical CPU id we're +					    booting on */ +	/* version 3 fields below */ +	uint32_t size_dt_strings;	 /* size of the strings block */ + +	/* version 17 fields below */ +	uint32_t size_dt_struct;	 /* size of the structure block */ +}; + +struct fdt_reserve_entry { +	uint64_t address; +	uint64_t size; +}; + +struct fdt_node_header { +	uint32_t tag; +	char name[0]; +}; + +struct fdt_property { +	uint32_t tag; +	uint32_t len; +	uint32_t nameoff; +	char data[0]; +}; + +#endif /* !__ASSEMBLY */ + +#define FDT_MAGIC	0xd00dfeed	/* 4: version, 4: total size */ +#define FDT_TAGSIZE	sizeof(uint32_t) + +#define FDT_BEGIN_NODE	0x1		/* Start node: full name */ +#define FDT_END_NODE	0x2		/* End node */ +#define FDT_PROP	0x3		/* Property: name off, +					   size, content */ +#define FDT_NOP		0x4		/* nop */ +#define FDT_END		0x9 + +#define FDT_V1_SIZE	(7*sizeof(uint32_t)) +#define FDT_V2_SIZE	(FDT_V1_SIZE + sizeof(uint32_t)) +#define FDT_V3_SIZE	(FDT_V2_SIZE + sizeof(uint32_t)) +#define FDT_V16_SIZE	FDT_V3_SIZE +#define FDT_V17_SIZE	(FDT_V16_SIZE + sizeof(uint32_t)) + +#endif /* _FDT_H */ diff --git a/scripts/dtc/libfdt/fdt_ro.c b/scripts/dtc/libfdt/fdt_ro.c new file mode 100644 index 00000000000..fbbba44fcd0 --- /dev/null +++ b/scripts/dtc/libfdt/fdt_ro.c @@ -0,0 +1,469 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + *  a) This library is free software; you can redistribute it and/or + *     modify it under the terms of the GNU General Public License as + *     published by the Free Software Foundation; either version 2 of the + *     License, or (at your option) any later version. + * + *     This library is distributed in the hope that it will be useful, + *     but WITHOUT ANY WARRANTY; without even the implied warranty of + *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *     GNU General Public License for more details. + * + *     You should have received a copy of the GNU General Public + *     License along with this library; if not, write to the Free + *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + *     MA 02110-1301 USA + * + * Alternatively, + * + *  b) Redistribution and use in source and binary forms, with or + *     without modification, are permitted provided that the following + *     conditions are met: + * + *     1. Redistributions of source code must retain the above + *        copyright notice, this list of conditions and the following + *        disclaimer. + *     2. Redistributions in binary form must reproduce the above + *        copyright notice, this list of conditions and the following + *        disclaimer in the documentation and/or other materials + *        provided with the distribution. + * + *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "libfdt_env.h" + +#include <fdt.h> +#include <libfdt.h> + +#include "libfdt_internal.h" + +static int _fdt_nodename_eq(const void *fdt, int offset, +			    const char *s, int len) +{ +	const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1); + +	if (! p) +		/* short match */ +		return 0; + +	if (memcmp(p, s, len) != 0) +		return 0; + +	if (p[len] == '\0') +		return 1; +	else if (!memchr(s, '@', len) && (p[len] == '@')) +		return 1; +	else +		return 0; +} + +const char *fdt_string(const void *fdt, int stroffset) +{ +	return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset; +} + +int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) +{ +	FDT_CHECK_HEADER(fdt); +	*address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address); +	*size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size); +	return 0; +} + +int fdt_num_mem_rsv(const void *fdt) +{ +	int i = 0; + +	while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0) +		i++; +	return i; +} + +int fdt_subnode_offset_namelen(const void *fdt, int offset, +			       const char *name, int namelen) +{ +	int depth; + +	FDT_CHECK_HEADER(fdt); + +	for (depth = 0, offset = fdt_next_node(fdt, offset, &depth); +	     (offset >= 0) && (depth > 0); +	     offset = fdt_next_node(fdt, offset, &depth)) { +		if (depth < 0) +			return -FDT_ERR_NOTFOUND; +		else if ((depth == 1) +			 && _fdt_nodename_eq(fdt, offset, name, namelen)) +			return offset; +	} + +	if (offset < 0) +		return offset; /* error */ +	else +		return -FDT_ERR_NOTFOUND; +} + +int fdt_subnode_offset(const void *fdt, int parentoffset, +		       const char *name) +{ +	return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name)); +} + +int fdt_path_offset(const void *fdt, const char *path) +{ +	const char *end = path + strlen(path); +	const char *p = path; +	int offset = 0; + +	FDT_CHECK_HEADER(fdt); + +	if (*path != '/') +		return -FDT_ERR_BADPATH; + +	while (*p) { +		const char *q; + +		while (*p == '/') +			p++; +		if (! *p) +			return offset; +		q = strchr(p, '/'); +		if (! q) +			q = end; + +		offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p); +		if (offset < 0) +			return offset; + +		p = q; +	} + +	return offset; +} + +const char *fdt_get_name(const void *fdt, int nodeoffset, int *len) +{ +	const struct fdt_node_header *nh = _fdt_offset_ptr(fdt, nodeoffset); +	int err; + +	if (((err = fdt_check_header(fdt)) != 0) +	    || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0)) +			goto fail; + +	if (len) +		*len = strlen(nh->name); + +	return nh->name; + + fail: +	if (len) +		*len = err; +	return NULL; +} + +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) +	    || ((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: +			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 (strcmp(fdt_string(fdt, namestroff), name) == 0) { +				/* 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; +} + +const void *fdt_getprop(const void *fdt, int nodeoffset, +		  const char *name, int *lenp) +{ +	const struct fdt_property *prop; + +	prop = fdt_get_property(fdt, nodeoffset, name, lenp); +	if (! prop) +		return NULL; + +	return prop->data; +} + +uint32_t fdt_get_phandle(const void *fdt, int nodeoffset) +{ +	const uint32_t *php; +	int len; + +	php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len); +	if (!php || (len != sizeof(*php))) +		return 0; + +	return fdt32_to_cpu(*php); +} + +int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) +{ +	int pdepth = 0, p = 0; +	int offset, depth, namelen; +	const char *name; + +	FDT_CHECK_HEADER(fdt); + +	if (buflen < 2) +		return -FDT_ERR_NOSPACE; + +	for (offset = 0, depth = 0; +	     (offset >= 0) && (offset <= nodeoffset); +	     offset = fdt_next_node(fdt, offset, &depth)) { +		if (pdepth < depth) +			continue; /* overflowed buffer */ + +		while (pdepth > depth) { +			do { +				p--; +			} while (buf[p-1] != '/'); +			pdepth--; +		} + +		name = fdt_get_name(fdt, offset, &namelen); +		if (!name) +			return namelen; +		if ((p + namelen + 1) <= buflen) { +			memcpy(buf + p, name, namelen); +			p += namelen; +			buf[p++] = '/'; +			pdepth++; +		} + +		if (offset == nodeoffset) { +			if (pdepth < (depth + 1)) +				return -FDT_ERR_NOSPACE; + +			if (p > 1) /* special case so that root path is "/", not "" */ +				p--; +			buf[p] = '\0'; +			return p; +		} +	} + +	if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) +		return -FDT_ERR_BADOFFSET; +	else if (offset == -FDT_ERR_BADOFFSET) +		return -FDT_ERR_BADSTRUCTURE; + +	return offset; /* error from fdt_next_node() */ +} + +int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, +				 int supernodedepth, int *nodedepth) +{ +	int offset, depth; +	int supernodeoffset = -FDT_ERR_INTERNAL; + +	FDT_CHECK_HEADER(fdt); + +	if (supernodedepth < 0) +		return -FDT_ERR_NOTFOUND; + +	for (offset = 0, depth = 0; +	     (offset >= 0) && (offset <= nodeoffset); +	     offset = fdt_next_node(fdt, offset, &depth)) { +		if (depth == supernodedepth) +			supernodeoffset = offset; + +		if (offset == nodeoffset) { +			if (nodedepth) +				*nodedepth = depth; + +			if (supernodedepth > depth) +				return -FDT_ERR_NOTFOUND; +			else +				return supernodeoffset; +		} +	} + +	if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) +		return -FDT_ERR_BADOFFSET; +	else if (offset == -FDT_ERR_BADOFFSET) +		return -FDT_ERR_BADSTRUCTURE; + +	return offset; /* error from fdt_next_node() */ +} + +int fdt_node_depth(const void *fdt, int nodeoffset) +{ +	int nodedepth; +	int err; + +	err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth); +	if (err) +		return (err < 0) ? err : -FDT_ERR_INTERNAL; +	return nodedepth; +} + +int fdt_parent_offset(const void *fdt, int nodeoffset) +{ +	int nodedepth = fdt_node_depth(fdt, nodeoffset); + +	if (nodedepth < 0) +		return nodedepth; +	return fdt_supernode_atdepth_offset(fdt, nodeoffset, +					    nodedepth - 1, NULL); +} + +int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, +				  const char *propname, +				  const void *propval, int proplen) +{ +	int offset; +	const void *val; +	int len; + +	FDT_CHECK_HEADER(fdt); + +	/* 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. */ +	for (offset = fdt_next_node(fdt, startoffset, NULL); +	     offset >= 0; +	     offset = fdt_next_node(fdt, offset, NULL)) { +		val = fdt_getprop(fdt, offset, propname, &len); +		if (val && (len == proplen) +		    && (memcmp(val, propval, len) == 0)) +			return offset; +	} + +	return offset; /* error from fdt_next_node() */ +} + +int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle) +{ +	if ((phandle == 0) || (phandle == -1)) +		return -FDT_ERR_BADPHANDLE; +	phandle = cpu_to_fdt32(phandle); +	return fdt_node_offset_by_prop_value(fdt, -1, "linux,phandle", +					     &phandle, sizeof(phandle)); +} + +int _stringlist_contains(const char *strlist, int listlen, const char *str) +{ +	int len = strlen(str); +	const char *p; + +	while (listlen >= len) { +		if (memcmp(str, strlist, len+1) == 0) +			return 1; +		p = memchr(strlist, '\0', listlen); +		if (!p) +			return 0; /* malformed strlist.. */ +		listlen -= (p-strlist) + 1; +		strlist = p + 1; +	} +	return 0; +} + +int fdt_node_check_compatible(const void *fdt, int nodeoffset, +			      const char *compatible) +{ +	const void *prop; +	int len; + +	prop = fdt_getprop(fdt, nodeoffset, "compatible", &len); +	if (!prop) +		return len; +	if (_stringlist_contains(prop, len, compatible)) +		return 0; +	else +		return 1; +} + +int fdt_node_offset_by_compatible(const void *fdt, int startoffset, +				  const char *compatible) +{ +	int offset, err; + +	FDT_CHECK_HEADER(fdt); + +	/* 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. */ +	for (offset = fdt_next_node(fdt, startoffset, NULL); +	     offset >= 0; +	     offset = fdt_next_node(fdt, offset, NULL)) { +		err = fdt_node_check_compatible(fdt, offset, compatible); +		if ((err < 0) && (err != -FDT_ERR_NOTFOUND)) +			return err; +		else if (err == 0) +			return offset; +	} + +	return offset; /* error from fdt_next_node() */ +} diff --git a/scripts/dtc/libfdt/fdt_rw.c b/scripts/dtc/libfdt/fdt_rw.c new file mode 100644 index 00000000000..8e7ec4cb7bc --- /dev/null +++ b/scripts/dtc/libfdt/fdt_rw.c @@ -0,0 +1,463 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + *  a) This library is free software; you can redistribute it and/or + *     modify it under the terms of the GNU General Public License as + *     published by the Free Software Foundation; either version 2 of the + *     License, or (at your option) any later version. + * + *     This library is distributed in the hope that it will be useful, + *     but WITHOUT ANY WARRANTY; without even the implied warranty of + *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *     GNU General Public License for more details. + * + *     You should have received a copy of the GNU General Public + *     License along with this library; if not, write to the Free + *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + *     MA 02110-1301 USA + * + * Alternatively, + * + *  b) Redistribution and use in source and binary forms, with or + *     without modification, are permitted provided that the following + *     conditions are met: + * + *     1. Redistributions of source code must retain the above + *        copyright notice, this list of conditions and the following + *        disclaimer. + *     2. Redistributions in binary form must reproduce the above + *        copyright notice, this list of conditions and the following + *        disclaimer in the documentation and/or other materials + *        provided with the distribution. + * + *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "libfdt_env.h" + +#include <fdt.h> +#include <libfdt.h> + +#include "libfdt_internal.h" + +static int _fdt_blocks_misordered(const void *fdt, +			      int mem_rsv_size, int struct_size) +{ +	return (fdt_off_mem_rsvmap(fdt) < FDT_ALIGN(sizeof(struct fdt_header), 8)) +		|| (fdt_off_dt_struct(fdt) < +		    (fdt_off_mem_rsvmap(fdt) + mem_rsv_size)) +		|| (fdt_off_dt_strings(fdt) < +		    (fdt_off_dt_struct(fdt) + struct_size)) +		|| (fdt_totalsize(fdt) < +		    (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt))); +} + +static int _fdt_rw_check_header(void *fdt) +{ +	FDT_CHECK_HEADER(fdt); + +	if (fdt_version(fdt) < 17) +		return -FDT_ERR_BADVERSION; +	if (_fdt_blocks_misordered(fdt, sizeof(struct fdt_reserve_entry), +				   fdt_size_dt_struct(fdt))) +		return -FDT_ERR_BADLAYOUT; +	if (fdt_version(fdt) > 17) +		fdt_set_version(fdt, 17); + +	return 0; +} + +#define FDT_RW_CHECK_HEADER(fdt) \ +	{ \ +		int err; \ +		if ((err = _fdt_rw_check_header(fdt)) != 0) \ +			return err; \ +	} + +static inline int _fdt_data_size(void *fdt) +{ +	return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt); +} + +static int _fdt_splice(void *fdt, void *splicepoint, int oldlen, int newlen) +{ +	char *p = splicepoint; +	char *end = (char *)fdt + _fdt_data_size(fdt); + +	if (((p + oldlen) < p) || ((p + oldlen) > end)) +		return -FDT_ERR_BADOFFSET; +	if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt))) +		return -FDT_ERR_NOSPACE; +	memmove(p + newlen, p + oldlen, end - p - oldlen); +	return 0; +} + +static int _fdt_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p, +			       int oldn, int newn) +{ +	int delta = (newn - oldn) * sizeof(*p); +	int err; +	err = _fdt_splice(fdt, p, oldn * sizeof(*p), newn * sizeof(*p)); +	if (err) +		return err; +	fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta); +	fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta); +	return 0; +} + +static int _fdt_splice_struct(void *fdt, void *p, +			      int oldlen, int newlen) +{ +	int delta = newlen - oldlen; +	int err; + +	if ((err = _fdt_splice(fdt, p, oldlen, newlen))) +		return err; + +	fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta); +	fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta); +	return 0; +} + +static int _fdt_splice_string(void *fdt, int newlen) +{ +	void *p = (char *)fdt +		+ fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt); +	int err; + +	if ((err = _fdt_splice(fdt, p, 0, newlen))) +		return err; + +	fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen); +	return 0; +} + +static int _fdt_find_add_string(void *fdt, const char *s) +{ +	char *strtab = (char *)fdt + fdt_off_dt_strings(fdt); +	const char *p; +	char *new; +	int len = strlen(s) + 1; +	int err; + +	p = _fdt_find_string(strtab, fdt_size_dt_strings(fdt), s); +	if (p) +		/* found it */ +		return (p - strtab); + +	new = strtab + fdt_size_dt_strings(fdt); +	err = _fdt_splice_string(fdt, len); +	if (err) +		return err; + +	memcpy(new, s, len); +	return (new - strtab); +} + +int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size) +{ +	struct fdt_reserve_entry *re; +	int err; + +	FDT_RW_CHECK_HEADER(fdt); + +	re = _fdt_mem_rsv_w(fdt, fdt_num_mem_rsv(fdt)); +	err = _fdt_splice_mem_rsv(fdt, re, 0, 1); +	if (err) +		return err; + +	re->address = cpu_to_fdt64(address); +	re->size = cpu_to_fdt64(size); +	return 0; +} + +int fdt_del_mem_rsv(void *fdt, int n) +{ +	struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n); +	int err; + +	FDT_RW_CHECK_HEADER(fdt); + +	if (n >= fdt_num_mem_rsv(fdt)) +		return -FDT_ERR_NOTFOUND; + +	err = _fdt_splice_mem_rsv(fdt, re, 1, 0); +	if (err) +		return err; +	return 0; +} + +static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name, +				int len, struct fdt_property **prop) +{ +	int oldlen; +	int err; + +	*prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); +	if (! (*prop)) +		return oldlen; + +	if ((err = _fdt_splice_struct(fdt, (*prop)->data, FDT_TAGALIGN(oldlen), +				      FDT_TAGALIGN(len)))) +		return err; + +	(*prop)->len = cpu_to_fdt32(len); +	return 0; +} + +static int _fdt_add_property(void *fdt, int nodeoffset, const char *name, +			     int len, struct fdt_property **prop) +{ +	int proplen; +	int nextoffset; +	int namestroff; +	int err; + +	if ((nextoffset = _fdt_check_node_offset(fdt, nodeoffset)) < 0) +		return nextoffset; + +	namestroff = _fdt_find_add_string(fdt, name); +	if (namestroff < 0) +		return namestroff; + +	*prop = _fdt_offset_ptr_w(fdt, nextoffset); +	proplen = sizeof(**prop) + FDT_TAGALIGN(len); + +	err = _fdt_splice_struct(fdt, *prop, 0, proplen); +	if (err) +		return err; + +	(*prop)->tag = cpu_to_fdt32(FDT_PROP); +	(*prop)->nameoff = cpu_to_fdt32(namestroff); +	(*prop)->len = cpu_to_fdt32(len); +	return 0; +} + +int fdt_set_name(void *fdt, int nodeoffset, const char *name) +{ +	char *namep; +	int oldlen, newlen; +	int err; + +	FDT_RW_CHECK_HEADER(fdt); + +	namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen); +	if (!namep) +		return oldlen; + +	newlen = strlen(name); + +	err = _fdt_splice_struct(fdt, namep, FDT_TAGALIGN(oldlen+1), +				 FDT_TAGALIGN(newlen+1)); +	if (err) +		return err; + +	memcpy(namep, name, newlen+1); +	return 0; +} + +int fdt_setprop(void *fdt, int nodeoffset, const char *name, +		const void *val, int len) +{ +	struct fdt_property *prop; +	int err; + +	FDT_RW_CHECK_HEADER(fdt); + +	err = _fdt_resize_property(fdt, nodeoffset, name, len, &prop); +	if (err == -FDT_ERR_NOTFOUND) +		err = _fdt_add_property(fdt, nodeoffset, name, len, &prop); +	if (err) +		return err; + +	memcpy(prop->data, val, len); +	return 0; +} + +int fdt_delprop(void *fdt, int nodeoffset, const char *name) +{ +	struct fdt_property *prop; +	int len, proplen; + +	FDT_RW_CHECK_HEADER(fdt); + +	prop = fdt_get_property_w(fdt, nodeoffset, name, &len); +	if (! prop) +		return len; + +	proplen = sizeof(*prop) + FDT_TAGALIGN(len); +	return _fdt_splice_struct(fdt, prop, proplen, 0); +} + +int fdt_add_subnode_namelen(void *fdt, int parentoffset, +			    const char *name, int namelen) +{ +	struct fdt_node_header *nh; +	int offset, nextoffset; +	int nodelen; +	int err; +	uint32_t tag; +	uint32_t *endtag; + +	FDT_RW_CHECK_HEADER(fdt); + +	offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen); +	if (offset >= 0) +		return -FDT_ERR_EXISTS; +	else if (offset != -FDT_ERR_NOTFOUND) +		return offset; + +	/* Try to place the new node after the parent's properties */ +	fdt_next_tag(fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */ +	do { +		offset = nextoffset; +		tag = fdt_next_tag(fdt, offset, &nextoffset); +	} while ((tag == FDT_PROP) || (tag == FDT_NOP)); + +	nh = _fdt_offset_ptr_w(fdt, offset); +	nodelen = sizeof(*nh) + FDT_TAGALIGN(namelen+1) + FDT_TAGSIZE; + +	err = _fdt_splice_struct(fdt, nh, 0, nodelen); +	if (err) +		return err; + +	nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); +	memset(nh->name, 0, FDT_TAGALIGN(namelen+1)); +	memcpy(nh->name, name, namelen); +	endtag = (uint32_t *)((char *)nh + nodelen - FDT_TAGSIZE); +	*endtag = cpu_to_fdt32(FDT_END_NODE); + +	return offset; +} + +int fdt_add_subnode(void *fdt, int parentoffset, const char *name) +{ +	return fdt_add_subnode_namelen(fdt, parentoffset, name, strlen(name)); +} + +int fdt_del_node(void *fdt, int nodeoffset) +{ +	int endoffset; + +	FDT_RW_CHECK_HEADER(fdt); + +	endoffset = _fdt_node_end_offset(fdt, nodeoffset); +	if (endoffset < 0) +		return endoffset; + +	return _fdt_splice_struct(fdt, _fdt_offset_ptr_w(fdt, nodeoffset), +				  endoffset - nodeoffset, 0); +} + +static void _fdt_packblocks(const char *old, char *new, +			    int mem_rsv_size, int struct_size) +{ +	int mem_rsv_off, struct_off, strings_off; + +	mem_rsv_off = FDT_ALIGN(sizeof(struct fdt_header), 8); +	struct_off = mem_rsv_off + mem_rsv_size; +	strings_off = struct_off + struct_size; + +	memmove(new + mem_rsv_off, old + fdt_off_mem_rsvmap(old), mem_rsv_size); +	fdt_set_off_mem_rsvmap(new, mem_rsv_off); + +	memmove(new + struct_off, old + fdt_off_dt_struct(old), struct_size); +	fdt_set_off_dt_struct(new, struct_off); +	fdt_set_size_dt_struct(new, struct_size); + +	memmove(new + strings_off, old + fdt_off_dt_strings(old), +		fdt_size_dt_strings(old)); +	fdt_set_off_dt_strings(new, strings_off); +	fdt_set_size_dt_strings(new, fdt_size_dt_strings(old)); +} + +int fdt_open_into(const void *fdt, void *buf, int bufsize) +{ +	int err; +	int mem_rsv_size, struct_size; +	int newsize; +	const char *fdtstart = fdt; +	const char *fdtend = fdtstart + fdt_totalsize(fdt); +	char *tmp; + +	FDT_CHECK_HEADER(fdt); + +	mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) +		* sizeof(struct fdt_reserve_entry); + +	if (fdt_version(fdt) >= 17) { +		struct_size = fdt_size_dt_struct(fdt); +	} else { +		struct_size = 0; +		while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END) +			; +	} + +	if (!_fdt_blocks_misordered(fdt, mem_rsv_size, struct_size)) { +		/* no further work necessary */ +		err = fdt_move(fdt, buf, bufsize); +		if (err) +			return err; +		fdt_set_version(buf, 17); +		fdt_set_size_dt_struct(buf, struct_size); +		fdt_set_totalsize(buf, bufsize); +		return 0; +	} + +	/* Need to reorder */ +	newsize = FDT_ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size +		+ struct_size + fdt_size_dt_strings(fdt); + +	if (bufsize < newsize) +		return -FDT_ERR_NOSPACE; + +	/* First attempt to build converted tree at beginning of buffer */ +	tmp = buf; +	/* But if that overlaps with the old tree... */ +	if (((tmp + newsize) > fdtstart) && (tmp < fdtend)) { +		/* Try right after the old tree instead */ +		tmp = (char *)(uintptr_t)fdtend; +		if ((tmp + newsize) > ((char *)buf + bufsize)) +			return -FDT_ERR_NOSPACE; +	} + +	_fdt_packblocks(fdt, tmp, mem_rsv_size, struct_size); +	memmove(buf, tmp, newsize); + +	fdt_set_magic(buf, FDT_MAGIC); +	fdt_set_totalsize(buf, bufsize); +	fdt_set_version(buf, 17); +	fdt_set_last_comp_version(buf, 16); +	fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt)); + +	return 0; +} + +int fdt_pack(void *fdt) +{ +	int mem_rsv_size; + +	FDT_RW_CHECK_HEADER(fdt); + +	mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) +		* sizeof(struct fdt_reserve_entry); +	_fdt_packblocks(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt)); +	fdt_set_totalsize(fdt, _fdt_data_size(fdt)); + +	return 0; +} diff --git a/scripts/dtc/libfdt/fdt_strerror.c b/scripts/dtc/libfdt/fdt_strerror.c new file mode 100644 index 00000000000..e6c3ceee8c5 --- /dev/null +++ b/scripts/dtc/libfdt/fdt_strerror.c @@ -0,0 +1,96 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + *  a) This library is free software; you can redistribute it and/or + *     modify it under the terms of the GNU General Public License as + *     published by the Free Software Foundation; either version 2 of the + *     License, or (at your option) any later version. + * + *     This library is distributed in the hope that it will be useful, + *     but WITHOUT ANY WARRANTY; without even the implied warranty of + *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *     GNU General Public License for more details. + * + *     You should have received a copy of the GNU General Public + *     License along with this library; if not, write to the Free + *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + *     MA 02110-1301 USA + * + * Alternatively, + * + *  b) Redistribution and use in source and binary forms, with or + *     without modification, are permitted provided that the following + *     conditions are met: + * + *     1. Redistributions of source code must retain the above + *        copyright notice, this list of conditions and the following + *        disclaimer. + *     2. Redistributions in binary form must reproduce the above + *        copyright notice, this list of conditions and the following + *        disclaimer in the documentation and/or other materials + *        provided with the distribution. + * + *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "libfdt_env.h" + +#include <fdt.h> +#include <libfdt.h> + +#include "libfdt_internal.h" + +struct fdt_errtabent { +	const char *str; +}; + +#define FDT_ERRTABENT(val) \ +	[(val)] = { .str = #val, } + +static struct fdt_errtabent fdt_errtable[] = { +	FDT_ERRTABENT(FDT_ERR_NOTFOUND), +	FDT_ERRTABENT(FDT_ERR_EXISTS), +	FDT_ERRTABENT(FDT_ERR_NOSPACE), + +	FDT_ERRTABENT(FDT_ERR_BADOFFSET), +	FDT_ERRTABENT(FDT_ERR_BADPATH), +	FDT_ERRTABENT(FDT_ERR_BADSTATE), + +	FDT_ERRTABENT(FDT_ERR_TRUNCATED), +	FDT_ERRTABENT(FDT_ERR_BADMAGIC), +	FDT_ERRTABENT(FDT_ERR_BADVERSION), +	FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE), +	FDT_ERRTABENT(FDT_ERR_BADLAYOUT), +}; +#define FDT_ERRTABSIZE	(sizeof(fdt_errtable) / sizeof(fdt_errtable[0])) + +const char *fdt_strerror(int errval) +{ +	if (errval > 0) +		return "<valid offset/length>"; +	else if (errval == 0) +		return "<no error>"; +	else if (errval > -FDT_ERRTABSIZE) { +		const char *s = fdt_errtable[-errval].str; + +		if (s) +			return s; +	} + +	return "<unknown error>"; +} diff --git a/scripts/dtc/libfdt/fdt_sw.c b/scripts/dtc/libfdt/fdt_sw.c new file mode 100644 index 00000000000..698329e0cca --- /dev/null +++ b/scripts/dtc/libfdt/fdt_sw.c @@ -0,0 +1,257 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + *  a) This library is free software; you can redistribute it and/or + *     modify it under the terms of the GNU General Public License as + *     published by the Free Software Foundation; either version 2 of the + *     License, or (at your option) any later version. + * + *     This library is distributed in the hope that it will be useful, + *     but WITHOUT ANY WARRANTY; without even the implied warranty of + *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *     GNU General Public License for more details. + * + *     You should have received a copy of the GNU General Public + *     License along with this library; if not, write to the Free + *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + *     MA 02110-1301 USA + * + * Alternatively, + * + *  b) Redistribution and use in source and binary forms, with or + *     without modification, are permitted provided that the following + *     conditions are met: + * + *     1. Redistributions of source code must retain the above + *        copyright notice, this list of conditions and the following + *        disclaimer. + *     2. Redistributions in binary form must reproduce the above + *        copyright notice, this list of conditions and the following + *        disclaimer in the documentation and/or other materials + *        provided with the distribution. + * + *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "libfdt_env.h" + +#include <fdt.h> +#include <libfdt.h> + +#include "libfdt_internal.h" + +static int _fdt_sw_check_header(void *fdt) +{ +	if (fdt_magic(fdt) != FDT_SW_MAGIC) +		return -FDT_ERR_BADMAGIC; +	/* FIXME: should check more details about the header state */ +	return 0; +} + +#define FDT_SW_CHECK_HEADER(fdt) \ +	{ \ +		int err; \ +		if ((err = _fdt_sw_check_header(fdt)) != 0) \ +			return err; \ +	} + +static void *_fdt_grab_space(void *fdt, int len) +{ +	int offset = fdt_size_dt_struct(fdt); +	int spaceleft; + +	spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt) +		- fdt_size_dt_strings(fdt); + +	if ((offset + len < offset) || (offset + len > spaceleft)) +		return NULL; + +	fdt_set_size_dt_struct(fdt, offset + len); +	return fdt_offset_ptr_w(fdt, offset, len); +} + +int fdt_create(void *buf, int bufsize) +{ +	void *fdt = buf; + +	if (bufsize < 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; +} + +int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size) +{ +	struct fdt_reserve_entry *re; +	int offset; + +	FDT_SW_CHECK_HEADER(fdt); + +	if (fdt_size_dt_struct(fdt)) +		return -FDT_ERR_BADSTATE; + +	offset = fdt_off_dt_struct(fdt); +	if ((offset + sizeof(*re)) > fdt_totalsize(fdt)) +		return -FDT_ERR_NOSPACE; + +	re = (struct fdt_reserve_entry *)((char *)fdt + offset); +	re->address = cpu_to_fdt64(addr); +	re->size = cpu_to_fdt64(size); + +	fdt_set_off_dt_struct(fdt, offset + sizeof(*re)); + +	return 0; +} + +int fdt_finish_reservemap(void *fdt) +{ +	return fdt_add_reservemap_entry(fdt, 0, 0); +} + +int fdt_begin_node(void *fdt, const char *name) +{ +	struct fdt_node_header *nh; +	int namelen = strlen(name) + 1; + +	FDT_SW_CHECK_HEADER(fdt); + +	nh = _fdt_grab_space(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen)); +	if (! nh) +		return -FDT_ERR_NOSPACE; + +	nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); +	memcpy(nh->name, name, namelen); +	return 0; +} + +int fdt_end_node(void *fdt) +{ +	uint32_t *en; + +	FDT_SW_CHECK_HEADER(fdt); + +	en = _fdt_grab_space(fdt, FDT_TAGSIZE); +	if (! en) +		return -FDT_ERR_NOSPACE; + +	*en = cpu_to_fdt32(FDT_END_NODE); +	return 0; +} + +static int _fdt_find_add_string(void *fdt, const char *s) +{ +	char *strtab = (char *)fdt + fdt_totalsize(fdt); +	const char *p; +	int strtabsize = fdt_size_dt_strings(fdt); +	int len = strlen(s) + 1; +	int struct_top, offset; + +	p = _fdt_find_string(strtab - strtabsize, strtabsize, s); +	if (p) +		return p - strtab; + +	/* Add it */ +	offset = -strtabsize - len; +	struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); +	if (fdt_totalsize(fdt) + offset < struct_top) +		return 0; /* no more room :( */ + +	memcpy(strtab + offset, s, len); +	fdt_set_size_dt_strings(fdt, strtabsize + len); +	return offset; +} + +int fdt_property(void *fdt, const char *name, const void *val, int len) +{ +	struct fdt_property *prop; +	int nameoff; + +	FDT_SW_CHECK_HEADER(fdt); + +	nameoff = _fdt_find_add_string(fdt, name); +	if (nameoff == 0) +		return -FDT_ERR_NOSPACE; + +	prop = _fdt_grab_space(fdt, sizeof(*prop) + FDT_TAGALIGN(len)); +	if (! prop) +		return -FDT_ERR_NOSPACE; + +	prop->tag = cpu_to_fdt32(FDT_PROP); +	prop->nameoff = cpu_to_fdt32(nameoff); +	prop->len = cpu_to_fdt32(len); +	memcpy(prop->data, val, len); +	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); + +	/* Add terminator */ +	end = _fdt_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; +} diff --git a/scripts/dtc/libfdt/fdt_wip.c b/scripts/dtc/libfdt/fdt_wip.c new file mode 100644 index 00000000000..a4652c6e787 --- /dev/null +++ b/scripts/dtc/libfdt/fdt_wip.c @@ -0,0 +1,145 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + *  a) This library is free software; you can redistribute it and/or + *     modify it under the terms of the GNU General Public License as + *     published by the Free Software Foundation; either version 2 of the + *     License, or (at your option) any later version. + * + *     This library is distributed in the hope that it will be useful, + *     but WITHOUT ANY WARRANTY; without even the implied warranty of + *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *     GNU General Public License for more details. + * + *     You should have received a copy of the GNU General Public + *     License along with this library; if not, write to the Free + *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + *     MA 02110-1301 USA + * + * Alternatively, + * + *  b) Redistribution and use in source and binary forms, with or + *     without modification, are permitted provided that the following + *     conditions are met: + * + *     1. Redistributions of source code must retain the above + *        copyright notice, this list of conditions and the following + *        disclaimer. + *     2. Redistributions in binary form must reproduce the above + *        copyright notice, this list of conditions and the following + *        disclaimer in the documentation and/or other materials + *        provided with the distribution. + * + *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "libfdt_env.h" + +#include <fdt.h> +#include <libfdt.h> + +#include "libfdt_internal.h" + +int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, +			const void *val, int len) +{ +	void *propval; +	int proplen; + +	propval = fdt_getprop_w(fdt, nodeoffset, name, &proplen); +	if (! propval) +		return proplen; + +	if (proplen != len) +		return -FDT_ERR_NOSPACE; + +	memcpy(propval, val, len); +	return 0; +} + +static void _fdt_nop_region(void *start, int len) +{ +	uint32_t *p; + +	for (p = start; (char *)p < ((char *)start + len); p++) +		*p = cpu_to_fdt32(FDT_NOP); +} + +int fdt_nop_property(void *fdt, int nodeoffset, const char *name) +{ +	struct fdt_property *prop; +	int len; + +	prop = fdt_get_property_w(fdt, nodeoffset, name, &len); +	if (! prop) +		return len; + +	_fdt_nop_region(prop, len + sizeof(*prop)); + +	return 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); +	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 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; +} + +int fdt_nop_node(void *fdt, int nodeoffset) +{ +	int endoffset; + +	endoffset = _fdt_node_end_offset(fdt, nodeoffset); +	if (endoffset < 0) +		return endoffset; + +	_fdt_nop_region(fdt_offset_ptr_w(fdt, nodeoffset, 0), +			endoffset - nodeoffset); +	return 0; +} diff --git a/scripts/dtc/libfdt/libfdt.h b/scripts/dtc/libfdt/libfdt.h new file mode 100644 index 00000000000..ce80e4fb41b --- /dev/null +++ b/scripts/dtc/libfdt/libfdt.h @@ -0,0 +1,1076 @@ +#ifndef _LIBFDT_H +#define _LIBFDT_H +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + *  a) This library is free software; you can redistribute it and/or + *     modify it under the terms of the GNU General Public License as + *     published by the Free Software Foundation; either version 2 of the + *     License, or (at your option) any later version. + * + *     This library is distributed in the hope that it will be useful, + *     but WITHOUT ANY WARRANTY; without even the implied warranty of + *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *     GNU General Public License for more details. + * + *     You should have received a copy of the GNU General Public + *     License along with this library; if not, write to the Free + *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + *     MA 02110-1301 USA + * + * Alternatively, + * + *  b) Redistribution and use in source and binary forms, with or + *     without modification, are permitted provided that the following + *     conditions are met: + * + *     1. Redistributions of source code must retain the above + *        copyright notice, this list of conditions and the following + *        disclaimer. + *     2. Redistributions in binary form must reproduce the above + *        copyright notice, this list of conditions and the following + *        disclaimer in the documentation and/or other materials + *        provided with the distribution. + * + *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <libfdt_env.h> +#include <fdt.h> + +#define FDT_FIRST_SUPPORTED_VERSION	0x10 +#define FDT_LAST_SUPPORTED_VERSION	0x11 + +/* Error codes: informative error codes */ +#define FDT_ERR_NOTFOUND	1 +	/* FDT_ERR_NOTFOUND: The requested node or property does not exist */ +#define FDT_ERR_EXISTS		2 +	/* FDT_ERR_EXISTS: Attemped to create a node or property which +	 * already exists */ +#define FDT_ERR_NOSPACE		3 +	/* FDT_ERR_NOSPACE: Operation needed to expand the device +	 * tree, but its buffer did not have sufficient space to +	 * contain the expanded tree. Use fdt_open_into() to move the +	 * device tree to a buffer with more space. */ + +/* Error codes: codes for bad parameters */ +#define FDT_ERR_BADOFFSET	4 +	/* FDT_ERR_BADOFFSET: Function was passed a structure block +	 * offset which is out-of-bounds, or which points to an +	 * unsuitable part of the structure for the operation. */ +#define FDT_ERR_BADPATH		5 +	/* FDT_ERR_BADPATH: Function was passed a badly formatted path +	 * (e.g. missing a leading / for a function which requires an +	 * absolute path) */ +#define FDT_ERR_BADPHANDLE	6 +	/* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle +	 * value.  phandle values of 0 and -1 are not permitted. */ +#define FDT_ERR_BADSTATE	7 +	/* FDT_ERR_BADSTATE: Function was passed an incomplete device +	 * tree created by the sequential-write functions, which is +	 * not sufficiently complete for the requested operation. */ + +/* Error codes: codes for bad device tree blobs */ +#define FDT_ERR_TRUNCATED	8 +	/* FDT_ERR_TRUNCATED: Structure block of the given device tree +	 * ends without an FDT_END tag. */ +#define FDT_ERR_BADMAGIC	9 +	/* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a +	 * device tree at all - it is missing the flattened device +	 * tree magic number. */ +#define FDT_ERR_BADVERSION	10 +	/* FDT_ERR_BADVERSION: Given device tree has a version which +	 * can't be handled by the requested operation.  For +	 * read-write functions, this may mean that fdt_open_into() is +	 * required to convert the tree to the expected version. */ +#define FDT_ERR_BADSTRUCTURE	11 +	/* FDT_ERR_BADSTRUCTURE: Given device tree has a corrupt +	 * structure block or other serious error (e.g. misnested +	 * nodes, or subnodes preceding properties). */ +#define FDT_ERR_BADLAYOUT	12 +	/* FDT_ERR_BADLAYOUT: For read-write functions, the given +	 * device tree has it's sub-blocks in an order that the +	 * function can't handle (memory reserve map, then structure, +	 * then strings).  Use fdt_open_into() to reorganize the tree +	 * into a form suitable for the read-write operations. */ + +/* "Can't happen" error indicating a bug in libfdt */ +#define FDT_ERR_INTERNAL	13 +	/* FDT_ERR_INTERNAL: libfdt has failed an internal assertion. +	 * Should never be returned, if it is, it indicates a bug in +	 * libfdt itself. */ + +#define FDT_ERR_MAX		13 + +/**********************************************************************/ +/* Low-level functions (you probably don't need these)                */ +/**********************************************************************/ + +const void *fdt_offset_ptr(const void *fdt, int offset, int checklen); +static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen) +{ +	return (void *)(uintptr_t)fdt_offset_ptr(fdt, offset, checklen); +} + +uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset); + +/**********************************************************************/ +/* Traversal functions                                                */ +/**********************************************************************/ + +int fdt_next_node(const void *fdt, int offset, int *depth); + +/**********************************************************************/ +/* General functions                                                  */ +/**********************************************************************/ + +#define fdt_get_header(fdt, field) \ +	(fdt32_to_cpu(((const struct fdt_header *)(fdt))->field)) +#define fdt_magic(fdt) 			(fdt_get_header(fdt, magic)) +#define fdt_totalsize(fdt)		(fdt_get_header(fdt, totalsize)) +#define fdt_off_dt_struct(fdt)		(fdt_get_header(fdt, off_dt_struct)) +#define fdt_off_dt_strings(fdt)		(fdt_get_header(fdt, off_dt_strings)) +#define fdt_off_mem_rsvmap(fdt)		(fdt_get_header(fdt, off_mem_rsvmap)) +#define fdt_version(fdt)		(fdt_get_header(fdt, version)) +#define fdt_last_comp_version(fdt) 	(fdt_get_header(fdt, last_comp_version)) +#define fdt_boot_cpuid_phys(fdt) 	(fdt_get_header(fdt, boot_cpuid_phys)) +#define fdt_size_dt_strings(fdt) 	(fdt_get_header(fdt, size_dt_strings)) +#define fdt_size_dt_struct(fdt)		(fdt_get_header(fdt, size_dt_struct)) + +#define __fdt_set_hdr(name) \ +	static inline void fdt_set_##name(void *fdt, uint32_t val) \ +	{ \ +		struct fdt_header *fdth = fdt; \ +		fdth->name = cpu_to_fdt32(val); \ +	} +__fdt_set_hdr(magic); +__fdt_set_hdr(totalsize); +__fdt_set_hdr(off_dt_struct); +__fdt_set_hdr(off_dt_strings); +__fdt_set_hdr(off_mem_rsvmap); +__fdt_set_hdr(version); +__fdt_set_hdr(last_comp_version); +__fdt_set_hdr(boot_cpuid_phys); +__fdt_set_hdr(size_dt_strings); +__fdt_set_hdr(size_dt_struct); +#undef __fdt_set_hdr + +/** + * fdt_check_header - sanity check a device tree or possible device tree + * @fdt: pointer to data which might be a flattened device tree + * + * fdt_check_header() checks that the given buffer contains what + * appears to be a flattened device tree with sane information in its + * header. + * + * returns: + *     0, if the buffer appears to contain a valid device tree + *     -FDT_ERR_BADMAGIC, + *     -FDT_ERR_BADVERSION, + *     -FDT_ERR_BADSTATE, standard meanings, as above + */ +int fdt_check_header(const void *fdt); + +/** + * fdt_move - move a device tree around in memory + * @fdt: pointer to the device tree to move + * @buf: pointer to memory where the device is to be moved + * @bufsize: size of the memory space at buf + * + * fdt_move() relocates, if possible, the device tree blob located at + * fdt to the buffer at buf of size bufsize.  The buffer may overlap + * with the existing device tree blob at fdt.  Therefore, + *     fdt_move(fdt, fdt, fdt_totalsize(fdt)) + * should always succeed. + * + * returns: + *     0, on success + *     -FDT_ERR_NOSPACE, bufsize is insufficient to contain the device tree + *     -FDT_ERR_BADMAGIC, + *     -FDT_ERR_BADVERSION, + *     -FDT_ERR_BADSTATE, standard meanings + */ +int fdt_move(const void *fdt, void *buf, int bufsize); + +/**********************************************************************/ +/* Read-only functions                                                */ +/**********************************************************************/ + +/** + * fdt_string - retrieve a string from the strings block of a device tree + * @fdt: pointer to the device tree blob + * @stroffset: offset of the string within the strings block (native endian) + * + * fdt_string() retrieves a pointer to a single string from the + * strings block of the device tree blob at fdt. + * + * returns: + *     a pointer to the string, on success + *     NULL, if stroffset is out of bounds + */ +const char *fdt_string(const void *fdt, int stroffset); + +/** + * fdt_num_mem_rsv - retrieve the number of memory reserve map entries + * @fdt: pointer to the device tree blob + * + * Returns the number of entries in the device tree blob's memory + * reservation map.  This does not include the terminating 0,0 entry + * or any other (0,0) entries reserved for expansion. + * + * returns: + *     the number of entries + */ +int fdt_num_mem_rsv(const void *fdt); + +/** + * fdt_get_mem_rsv - retrieve one memory reserve map entry + * @fdt: pointer to the device tree blob + * @address, @size: pointers to 64-bit variables + * + * On success, *address and *size will contain the address and size of + * the n-th reserve map entry from the device tree blob, in + * native-endian format. + * + * returns: + *     0, on success + *     -FDT_ERR_BADMAGIC, + *     -FDT_ERR_BADVERSION, + *     -FDT_ERR_BADSTATE, standard meanings + */ +int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size); + +/** + * fdt_subnode_offset_namelen - find a subnode based on substring + * @fdt: pointer to the device tree blob + * @parentoffset: structure block offset of a node + * @name: name of the subnode to locate + * @namelen: number of characters of name to consider + * + * Identical to fdt_subnode_offset(), but only examine the first + * namelen characters of name for matching the subnode name.  This is + * useful for finding subnodes based on a portion of a larger string, + * such as a full path. + */ +int fdt_subnode_offset_namelen(const void *fdt, int parentoffset, +			       const char *name, int namelen); +/** + * fdt_subnode_offset - find a subnode of a given node + * @fdt: pointer to the device tree blob + * @parentoffset: structure block offset of a node + * @name: name of the subnode to locate + * + * fdt_subnode_offset() finds a subnode of the node at structure block + * offset parentoffset with the given name.  name may include a unit + * address, in which case fdt_subnode_offset() will find the subnode + * with that unit address, or the unit address may be omitted, in + * which case fdt_subnode_offset() will find an arbitrary subnode + * whose name excluding unit address matches the given name. + * + * returns: + *	structure block offset of the requested subnode (>=0), on success + *	-FDT_ERR_NOTFOUND, if the requested subnode does not exist + *	-FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag + *      -FDT_ERR_BADMAGIC, + *	-FDT_ERR_BADVERSION, + *	-FDT_ERR_BADSTATE, + *	-FDT_ERR_BADSTRUCTURE, + *	-FDT_ERR_TRUNCATED, standard meanings. + */ +int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name); + +/** + * fdt_path_offset - find a tree node by its full path + * @fdt: pointer to the device tree blob + * @path: full path of the node to locate + * + * fdt_path_offset() finds a node of a given path in the device tree. + * Each path component may omit the unit address portion, but the + * results of this are undefined if any such path component is + * ambiguous (that is if there are multiple nodes at the relevant + * level matching the given component, differentiated only by unit + * address). + * + * returns: + *	structure block offset of the node with the requested path (>=0), on success + *	-FDT_ERR_BADPATH, given path does not begin with '/' or is invalid + *	-FDT_ERR_NOTFOUND, if the requested node does not exist + *      -FDT_ERR_BADMAGIC, + *	-FDT_ERR_BADVERSION, + *	-FDT_ERR_BADSTATE, + *	-FDT_ERR_BADSTRUCTURE, + *	-FDT_ERR_TRUNCATED, standard meanings. + */ +int fdt_path_offset(const void *fdt, const char *path); + +/** + * fdt_get_name - retrieve the name of a given node + * @fdt: pointer to the device tree blob + * @nodeoffset: structure block offset of the starting node + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * + * fdt_get_name() retrieves the name (including unit address) of the + * device tree node at structure block offset nodeoffset.  If lenp is + * non-NULL, the length of this name is also returned, in the integer + * pointed to by lenp. + * + * returns: + *	pointer to the node's name, on success + *		If lenp is non-NULL, *lenp contains the length of that name (>=0) + *	NULL, on error + *		if lenp is non-NULL *lenp contains an error code (<0): + *		-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + *		-FDT_ERR_BADMAGIC, + *		-FDT_ERR_BADVERSION, + *		-FDT_ERR_BADSTATE, standard meanings + */ +const char *fdt_get_name(const void *fdt, int nodeoffset, int *lenp); + +/** + * fdt_get_property - find a given property in a given node + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to find + * @name: name of the property to find + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * + * fdt_get_property() retrieves a pointer to the fdt_property + * structure within the device tree blob corresponding to the property + * named 'name' of the node at offset nodeoffset.  If lenp is + * non-NULL, the length of the property value is also returned, in the + * integer pointed to by lenp. + * + * returns: + *	pointer to the structure representing the property + *		if lenp is non-NULL, *lenp contains the length of the property + *		value (>=0) + *	NULL, on error + *		if lenp is non-NULL, *lenp contains an error code (<0): + *		-FDT_ERR_NOTFOUND, node does not have named property + *		-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + *		-FDT_ERR_BADMAGIC, + *		-FDT_ERR_BADVERSION, + *		-FDT_ERR_BADSTATE, + *		-FDT_ERR_BADSTRUCTURE, + *		-FDT_ERR_TRUNCATED, standard meanings + */ +const struct fdt_property *fdt_get_property(const void *fdt, int nodeoffset, +					    const char *name, int *lenp); +static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset, +						      const char *name, +						      int *lenp) +{ +	return (struct fdt_property *)(uintptr_t) +		fdt_get_property(fdt, nodeoffset, name, lenp); +} + +/** + * fdt_getprop - retrieve the value of a given property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to find + * @name: name of the property to find + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * + * fdt_getprop() retrieves a pointer to the value of the property + * named 'name' of the node at offset nodeoffset (this will be a + * pointer to within the device blob itself, not a copy of the value). + * If lenp is non-NULL, the length of the property value is also + * returned, in the integer pointed to by lenp. + * + * returns: + *	pointer to the property's value + *		if lenp is non-NULL, *lenp contains the length of the property + *		value (>=0) + *	NULL, on error + *		if lenp is non-NULL, *lenp contains an error code (<0): + *		-FDT_ERR_NOTFOUND, node does not have named property + *		-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + *		-FDT_ERR_BADMAGIC, + *		-FDT_ERR_BADVERSION, + *		-FDT_ERR_BADSTATE, + *		-FDT_ERR_BADSTRUCTURE, + *		-FDT_ERR_TRUNCATED, standard meanings + */ +const void *fdt_getprop(const void *fdt, int nodeoffset, +			const char *name, int *lenp); +static inline void *fdt_getprop_w(void *fdt, int nodeoffset, +				  const char *name, int *lenp) +{ +	return (void *)(uintptr_t)fdt_getprop(fdt, nodeoffset, name, lenp); +} + +/** + * fdt_get_phandle - retrieve the phandle of a given node + * @fdt: pointer to the device tree blob + * @nodeoffset: structure block offset of the node + * + * fdt_get_phandle() retrieves the phandle of the device tree node at + * structure block offset nodeoffset. + * + * returns: + *	the phandle of the node at nodeoffset, on success (!= 0, != -1) + *	0, if the node has no phandle, or another error occurs + */ +uint32_t fdt_get_phandle(const void *fdt, int nodeoffset); + +/** + * fdt_get_path - determine the full path of a node + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose path to find + * @buf: character buffer to contain the returned path (will be overwritten) + * @buflen: size of the character buffer at buf + * + * fdt_get_path() computes the full path of the node at offset + * nodeoffset, and records that path in the buffer at buf. + * + * NOTE: This function is expensive, as it must scan the device tree + * structure from the start to nodeoffset. + * + * returns: + *	0, on success + *		buf contains the absolute path of the node at + *		nodeoffset, as a NUL-terminated string. + * 	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + *	-FDT_ERR_NOSPACE, the path of the given node is longer than (bufsize-1) + *		characters and will not fit in the given buffer. + *	-FDT_ERR_BADMAGIC, + *	-FDT_ERR_BADVERSION, + *	-FDT_ERR_BADSTATE, + *	-FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen); + +/** + * fdt_supernode_atdepth_offset - find a specific ancestor of a node + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose parent to find + * @supernodedepth: depth of the ancestor to find + * @nodedepth: pointer to an integer variable (will be overwritten) or NULL + * + * fdt_supernode_atdepth_offset() finds an ancestor of the given node + * at a specific depth from the root (where the root itself has depth + * 0, its immediate subnodes depth 1 and so forth).  So + *	fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, NULL); + * will always return 0, the offset of the root node.  If the node at + * nodeoffset has depth D, then: + *	fdt_supernode_atdepth_offset(fdt, nodeoffset, D, NULL); + * will return nodeoffset itself. + * + * NOTE: This function is expensive, as it must scan the device tree + * structure from the start to nodeoffset. + * + * returns: + + *	structure block offset of the node at node offset's ancestor + *		of depth supernodedepth (>=0), on success + * 	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag +*	-FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of nodeoffset + *	-FDT_ERR_BADMAGIC, + *	-FDT_ERR_BADVERSION, + *	-FDT_ERR_BADSTATE, + *	-FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, +				 int supernodedepth, int *nodedepth); + +/** + * fdt_node_depth - find the depth of a given node + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose parent to find + * + * fdt_node_depth() finds the depth of a given node.  The root node + * has depth 0, its immediate subnodes depth 1 and so forth. + * + * NOTE: This function is expensive, as it must scan the device tree + * structure from the start to nodeoffset. + * + * returns: + *	depth of the node at nodeoffset (>=0), on success + * 	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + *	-FDT_ERR_BADMAGIC, + *	-FDT_ERR_BADVERSION, + *	-FDT_ERR_BADSTATE, + *	-FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_node_depth(const void *fdt, int nodeoffset); + +/** + * fdt_parent_offset - find the parent of a given node + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose parent to find + * + * fdt_parent_offset() locates the parent node of a given node (that + * is, it finds the offset of the node which contains the node at + * nodeoffset as a subnode). + * + * NOTE: This function is expensive, as it must scan the device tree + * structure from the start to nodeoffset, *twice*. + * + * returns: + *	structure block offset of the parent of the node at nodeoffset + *		(>=0), on success + * 	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + *	-FDT_ERR_BADMAGIC, + *	-FDT_ERR_BADVERSION, + *	-FDT_ERR_BADSTATE, + *	-FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_parent_offset(const void *fdt, int nodeoffset); + +/** + * fdt_node_offset_by_prop_value - find nodes with a given property value + * @fdt: pointer to the device tree blob + * @startoffset: only find nodes after this offset + * @propname: property name to check + * @propval: property value to search for + * @proplen: length of the value in propval + * + * fdt_node_offset_by_prop_value() returns the offset of the first + * node after startoffset, which has a property named propname whose + * value is of length proplen and has value equal to propval; or if + * startoffset is -1, the very first such node in the tree. + * + * To iterate through all nodes matching the criterion, the following + * idiom can be used: + *	offset = fdt_node_offset_by_prop_value(fdt, -1, propname, + *					       propval, proplen); + *	while (offset != -FDT_ERR_NOTFOUND) { + *		// other code here + *		offset = fdt_node_offset_by_prop_value(fdt, offset, propname, + *						       propval, proplen); + *	} + * + * Note the -1 in the first call to the function, if 0 is used here + * instead, the function will never locate the root node, even if it + * matches the criterion. + * + * returns: + *	structure block offset of the located node (>= 0, >startoffset), + *		 on success + *	-FDT_ERR_NOTFOUND, no node matching the criterion exists in the + *		tree after startoffset + * 	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + *	-FDT_ERR_BADMAGIC, + *	-FDT_ERR_BADVERSION, + *	-FDT_ERR_BADSTATE, + *	-FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, +				  const char *propname, +				  const void *propval, int proplen); + +/** + * fdt_node_offset_by_phandle - find the node with a given phandle + * @fdt: pointer to the device tree blob + * @phandle: phandle value + * + * fdt_node_offset_by_phandle() returns the offset of the node + * which has the given phandle value.  If there is more than one node + * in the tree with the given phandle (an invalid tree), results are + * undefined. + * + * returns: + *	structure block offset of the located node (>= 0), on success + *	-FDT_ERR_NOTFOUND, no node with that phandle exists + *	-FDT_ERR_BADPHANDLE, given phandle value was invalid (0 or -1) + *	-FDT_ERR_BADMAGIC, + *	-FDT_ERR_BADVERSION, + *	-FDT_ERR_BADSTATE, + *	-FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle); + +/** + * fdt_node_check_compatible: check a node's compatible property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of a tree node + * @compatible: string to match against + * + * + * fdt_node_check_compatible() returns 0 if the given node contains a + * 'compatible' property with the given string as one of its elements, + * it returns non-zero otherwise, or on error. + * + * returns: + *	0, if the node has a 'compatible' property listing the given string + *	1, if the node has a 'compatible' property, but it does not list + *		the given string + *	-FDT_ERR_NOTFOUND, if the given node has no 'compatible' property + * 	-FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag + *	-FDT_ERR_BADMAGIC, + *	-FDT_ERR_BADVERSION, + *	-FDT_ERR_BADSTATE, + *	-FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_node_check_compatible(const void *fdt, int nodeoffset, +			      const char *compatible); + +/** + * fdt_node_offset_by_compatible - find nodes with a given 'compatible' value + * @fdt: pointer to the device tree blob + * @startoffset: only find nodes after this offset + * @compatible: 'compatible' string to match against + * + * fdt_node_offset_by_compatible() returns the offset of the first + * node after startoffset, which has a 'compatible' property which + * lists the given compatible string; or if startoffset is -1, the + * very first such node in the tree. + * + * To iterate through all nodes matching the criterion, the following + * idiom can be used: + *	offset = fdt_node_offset_by_compatible(fdt, -1, compatible); + *	while (offset != -FDT_ERR_NOTFOUND) { + *		// other code here + *		offset = fdt_node_offset_by_compatible(fdt, offset, compatible); + *	} + * + * Note the -1 in the first call to the function, if 0 is used here + * instead, the function will never locate the root node, even if it + * matches the criterion. + * + * returns: + *	structure block offset of the located node (>= 0, >startoffset), + *		 on success + *	-FDT_ERR_NOTFOUND, no node matching the criterion exists in the + *		tree after startoffset + * 	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + *	-FDT_ERR_BADMAGIC, + *	-FDT_ERR_BADVERSION, + *	-FDT_ERR_BADSTATE, + *	-FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_node_offset_by_compatible(const void *fdt, int startoffset, +				  const char *compatible); + +/**********************************************************************/ +/* Write-in-place functions                                           */ +/**********************************************************************/ + +/** + * fdt_setprop_inplace - change a property's value, but not its size + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: pointer to data to replace the property value with + * @len: length of the property value + * + * fdt_setprop_inplace() replaces the value of a given property with + * the data in val, of length len.  This function cannot change the + * size of a property, and so will only work if len is equal to the + * current length of the property. + * + * This function will alter only the bytes in the blob which contain + * the given property value, and will not alter or move any other part + * of the tree. + * + * returns: + *	0, on success + *	-FDT_ERR_NOSPACE, if len is not equal to the property's current length + *	-FDT_ERR_NOTFOUND, node does not have the named property + *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + *	-FDT_ERR_BADMAGIC, + *	-FDT_ERR_BADVERSION, + *	-FDT_ERR_BADSTATE, + *	-FDT_ERR_BADSTRUCTURE, + *	-FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, +			const void *val, int len); + +/** + * fdt_setprop_inplace_cell - change the value of a single-cell property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: cell (32-bit integer) value to replace the property with + * + * fdt_setprop_inplace_cell() replaces the value of a given property + * with the 32-bit integer cell value in val, converting val to + * big-endian if necessary.  This function cannot change the size of a + * property, and so will only work if the property already exists and + * has length 4. + * + * This function will alter only the bytes in the blob which contain + * the given property value, and will not alter or move any other part + * of the tree. + * + * returns: + *	0, on success + *	-FDT_ERR_NOSPACE, if the property's length is not equal to 4 +  *	-FDT_ERR_NOTFOUND, node does not have the named property + *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + *	-FDT_ERR_BADMAGIC, + *	-FDT_ERR_BADVERSION, + *	-FDT_ERR_BADSTATE, + *	-FDT_ERR_BADSTRUCTURE, + *	-FDT_ERR_TRUNCATED, standard meanings + */ +static inline int fdt_setprop_inplace_cell(void *fdt, int nodeoffset, +					   const char *name, uint32_t val) +{ +	val = cpu_to_fdt32(val); +	return fdt_setprop_inplace(fdt, nodeoffset, name, &val, sizeof(val)); +} + +/** + * fdt_nop_property - replace a property with nop tags + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to nop + * @name: name of the property to nop + * + * fdt_nop_property() will replace a given property's representation + * in the blob with FDT_NOP tags, effectively removing it from the + * tree. + * + * This function will alter only the bytes in the blob which contain + * the property, and will not alter or move any other part of the + * tree. + * + * returns: + *	0, on success + *	-FDT_ERR_NOTFOUND, node does not have the named property + *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + *	-FDT_ERR_BADMAGIC, + *	-FDT_ERR_BADVERSION, + *	-FDT_ERR_BADSTATE, + *	-FDT_ERR_BADSTRUCTURE, + *	-FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_nop_property(void *fdt, int nodeoffset, const char *name); + +/** + * fdt_nop_node - replace a node (subtree) with nop tags + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node to nop + * + * fdt_nop_node() will replace a given node's representation in the + * blob, including all its subnodes, if any, with FDT_NOP tags, + * effectively removing it from the tree. + * + * This function will alter only the bytes in the blob which contain + * the node and its properties and subnodes, and will not alter or + * move any other part of the tree. + * + * returns: + *	0, on success + *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + *	-FDT_ERR_BADMAGIC, + *	-FDT_ERR_BADVERSION, + *	-FDT_ERR_BADSTATE, + *	-FDT_ERR_BADSTRUCTURE, + *	-FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_nop_node(void *fdt, int nodeoffset); + +/**********************************************************************/ +/* Sequential write functions                                         */ +/**********************************************************************/ + +int fdt_create(void *buf, int bufsize); +int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size); +int fdt_finish_reservemap(void *fdt); +int fdt_begin_node(void *fdt, const char *name); +int fdt_property(void *fdt, const char *name, const void *val, int len); +static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val) +{ +	val = cpu_to_fdt32(val); +	return fdt_property(fdt, name, &val, sizeof(val)); +} +#define fdt_property_string(fdt, name, str) \ +	fdt_property(fdt, name, str, strlen(str)+1) +int fdt_end_node(void *fdt); +int fdt_finish(void *fdt); + +/**********************************************************************/ +/* Read-write functions                                               */ +/**********************************************************************/ + +int fdt_open_into(const void *fdt, void *buf, int bufsize); +int fdt_pack(void *fdt); + +/** + * fdt_add_mem_rsv - add one memory reserve map entry + * @fdt: pointer to the device tree blob + * @address, @size: 64-bit values (native endian) + * + * Adds a reserve map entry to the given blob reserving a region at + * address address of length size. + * + * This function will insert data into the reserve map and will + * therefore change the indexes of some entries in the table. + * + * returns: + *	0, on success + *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to + *		contain the new reservation entry + *	-FDT_ERR_BADMAGIC, + *	-FDT_ERR_BADVERSION, + *	-FDT_ERR_BADSTATE, + *	-FDT_ERR_BADSTRUCTURE, + *	-FDT_ERR_BADLAYOUT, + *	-FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size); + +/** + * fdt_del_mem_rsv - remove a memory reserve map entry + * @fdt: pointer to the device tree blob + * @n: entry to remove + * + * fdt_del_mem_rsv() removes the n-th memory reserve map entry from + * the blob. + * + * This function will delete data from the reservation table and will + * therefore change the indexes of some entries in the table. + * + * returns: + *	0, on success + *	-FDT_ERR_NOTFOUND, there is no entry of the given index (i.e. there + *		are less than n+1 reserve map entries) + *	-FDT_ERR_BADMAGIC, + *	-FDT_ERR_BADVERSION, + *	-FDT_ERR_BADSTATE, + *	-FDT_ERR_BADSTRUCTURE, + *	-FDT_ERR_BADLAYOUT, + *	-FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_del_mem_rsv(void *fdt, int n); + +/** + * fdt_set_name - change the name of a given node + * @fdt: pointer to the device tree blob + * @nodeoffset: structure block offset of a node + * @name: name to give the node + * + * fdt_set_name() replaces the name (including unit address, if any) + * of the given node with the given string.  NOTE: this function can't + * efficiently check if the new name is unique amongst the given + * node's siblings; results are undefined if this function is invoked + * with a name equal to one of the given node's siblings. + * + * This function may insert or delete data from the blob, and will + * therefore change the offsets of some existing nodes. + * + * returns: + *	0, on success + *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob + *		to contain the new name + *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + *	-FDT_ERR_BADMAGIC, + *	-FDT_ERR_BADVERSION, + *	-FDT_ERR_BADSTATE, standard meanings + */ +int fdt_set_name(void *fdt, int nodeoffset, const char *name); + +/** + * fdt_setprop - create or change a property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: pointer to data to set the property value to + * @len: length of the property value + * + * fdt_setprop() sets the value of the named property in the given + * node to the given value and length, creating the property if it + * does not already exist. + * + * This function may insert or delete data from the blob, and will + * therefore change the offsets of some existing nodes. + * + * returns: + *	0, on success + *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to + *		contain the new property value + *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + *	-FDT_ERR_BADLAYOUT, + *	-FDT_ERR_BADMAGIC, + *	-FDT_ERR_BADVERSION, + *	-FDT_ERR_BADSTATE, + *	-FDT_ERR_BADSTRUCTURE, + *	-FDT_ERR_BADLAYOUT, + *	-FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_setprop(void *fdt, int nodeoffset, const char *name, +		const void *val, int len); + +/** + * fdt_setprop_cell - set a property to a single cell value + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: 32-bit integer value for the property (native endian) + * + * fdt_setprop_cell() sets the value of the named property in the + * given node to the given cell value (converting to big-endian if + * necessary), or creates a new property with that value if it does + * not already exist. + * + * This function may insert or delete data from the blob, and will + * therefore change the offsets of some existing nodes. + * + * returns: + *	0, on success + *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to + *		contain the new property value + *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + *	-FDT_ERR_BADLAYOUT, + *	-FDT_ERR_BADMAGIC, + *	-FDT_ERR_BADVERSION, + *	-FDT_ERR_BADSTATE, + *	-FDT_ERR_BADSTRUCTURE, + *	-FDT_ERR_BADLAYOUT, + *	-FDT_ERR_TRUNCATED, standard meanings + */ +static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name, +				   uint32_t val) +{ +	val = cpu_to_fdt32(val); +	return fdt_setprop(fdt, nodeoffset, name, &val, sizeof(val)); +} + +/** + * fdt_setprop_string - set a property to a string value + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @str: string value for the property + * + * fdt_setprop_string() sets the value of the named property in the + * given node to the given string value (using the length of the + * string to determine the new length of the property), or creates a + * new property with that value if it does not already exist. + * + * This function may insert or delete data from the blob, and will + * therefore change the offsets of some existing nodes. + * + * returns: + *	0, on success + *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to + *		contain the new property value + *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + *	-FDT_ERR_BADLAYOUT, + *	-FDT_ERR_BADMAGIC, + *	-FDT_ERR_BADVERSION, + *	-FDT_ERR_BADSTATE, + *	-FDT_ERR_BADSTRUCTURE, + *	-FDT_ERR_BADLAYOUT, + *	-FDT_ERR_TRUNCATED, standard meanings + */ +#define fdt_setprop_string(fdt, nodeoffset, name, str) \ +	fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1) + +/** + * fdt_delprop - delete a property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to nop + * @name: name of the property to nop + * + * fdt_del_property() will delete the given property. + * + * This function will delete data from the blob, and will therefore + * change the offsets of some existing nodes. + * + * returns: + *	0, on success + *	-FDT_ERR_NOTFOUND, node does not have the named property + *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + *	-FDT_ERR_BADLAYOUT, + *	-FDT_ERR_BADMAGIC, + *	-FDT_ERR_BADVERSION, + *	-FDT_ERR_BADSTATE, + *	-FDT_ERR_BADSTRUCTURE, + *	-FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_delprop(void *fdt, int nodeoffset, const char *name); + +/** + * fdt_add_subnode_namelen - creates a new node based on substring + * @fdt: pointer to the device tree blob + * @parentoffset: structure block offset of a node + * @name: name of the subnode to locate + * @namelen: number of characters of name to consider + * + * Identical to fdt_add_subnode(), but use only the first namelen + * characters of name as the name of the new node.  This is useful for + * creating subnodes based on a portion of a larger string, such as a + * full path. + */ +int fdt_add_subnode_namelen(void *fdt, int parentoffset, +			    const char *name, int namelen); + +/** + * fdt_add_subnode - creates a new node + * @fdt: pointer to the device tree blob + * @parentoffset: structure block offset of a node + * @name: name of the subnode to locate + * + * fdt_add_subnode() creates a new node as a subnode of the node at + * structure block offset parentoffset, with the given name (which + * should include the unit address, if any). + * + * This function will insert data into the blob, and will therefore + * change the offsets of some existing nodes. + + * returns: + *	structure block offset of the created nodeequested subnode (>=0), on success + *	-FDT_ERR_NOTFOUND, if the requested subnode does not exist + *	-FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag + *	-FDT_ERR_EXISTS, if the node at parentoffset already has a subnode of + *		the given name + *	-FDT_ERR_NOSPACE, if there is insufficient free space in the + *		blob to contain the new node + *	-FDT_ERR_NOSPACE + *	-FDT_ERR_BADLAYOUT + *      -FDT_ERR_BADMAGIC, + *	-FDT_ERR_BADVERSION, + *	-FDT_ERR_BADSTATE, + *	-FDT_ERR_BADSTRUCTURE, + *	-FDT_ERR_TRUNCATED, standard meanings. + */ +int fdt_add_subnode(void *fdt, int parentoffset, const char *name); + +/** + * fdt_del_node - delete a node (subtree) + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node to nop + * + * fdt_del_node() will remove the given node, including all its + * subnodes if any, from the blob. + * + * This function will delete data from the blob, and will therefore + * change the offsets of some existing nodes. + * + * returns: + *	0, on success + *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + *	-FDT_ERR_BADLAYOUT, + *	-FDT_ERR_BADMAGIC, + *	-FDT_ERR_BADVERSION, + *	-FDT_ERR_BADSTATE, + *	-FDT_ERR_BADSTRUCTURE, + *	-FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_del_node(void *fdt, int nodeoffset); + +/**********************************************************************/ +/* Debugging / informational functions                                */ +/**********************************************************************/ + +const char *fdt_strerror(int errval); + +#endif /* _LIBFDT_H */ diff --git a/scripts/dtc/libfdt/libfdt_env.h b/scripts/dtc/libfdt/libfdt_env.h new file mode 100644 index 00000000000..449bf602daf --- /dev/null +++ b/scripts/dtc/libfdt/libfdt_env.h @@ -0,0 +1,23 @@ +#ifndef _LIBFDT_ENV_H +#define _LIBFDT_ENV_H + +#include <stddef.h> +#include <stdint.h> +#include <string.h> + +#define _B(n)	((unsigned long long)((uint8_t *)&x)[n]) +static inline uint32_t fdt32_to_cpu(uint32_t x) +{ +	return (_B(0) << 24) | (_B(1) << 16) | (_B(2) << 8) | _B(3); +} +#define cpu_to_fdt32(x) fdt32_to_cpu(x) + +static inline uint64_t fdt64_to_cpu(uint64_t x) +{ +	return (_B(0) << 56) | (_B(1) << 48) | (_B(2) << 40) | (_B(3) << 32) +		| (_B(4) << 24) | (_B(5) << 16) | (_B(6) << 8) | _B(7); +} +#define cpu_to_fdt64(x) fdt64_to_cpu(x) +#undef _B + +#endif /* _LIBFDT_ENV_H */ diff --git a/scripts/dtc/libfdt/libfdt_internal.h b/scripts/dtc/libfdt/libfdt_internal.h new file mode 100644 index 00000000000..46eb93e4af5 --- /dev/null +++ b/scripts/dtc/libfdt/libfdt_internal.h @@ -0,0 +1,95 @@ +#ifndef _LIBFDT_INTERNAL_H +#define _LIBFDT_INTERNAL_H +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + *  a) This library is free software; you can redistribute it and/or + *     modify it under the terms of the GNU General Public License as + *     published by the Free Software Foundation; either version 2 of the + *     License, or (at your option) any later version. + * + *     This library is distributed in the hope that it will be useful, + *     but WITHOUT ANY WARRANTY; without even the implied warranty of + *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *     GNU General Public License for more details. + * + *     You should have received a copy of the GNU General Public + *     License along with this library; if not, write to the Free + *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + *     MA 02110-1301 USA + * + * Alternatively, + * + *  b) Redistribution and use in source and binary forms, with or + *     without modification, are permitted provided that the following + *     conditions are met: + * + *     1. Redistributions of source code must retain the above + *        copyright notice, this list of conditions and the following + *        disclaimer. + *     2. Redistributions in binary form must reproduce the above + *        copyright notice, this list of conditions and the following + *        disclaimer in the documentation and/or other materials + *        provided with the distribution. + * + *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include <fdt.h> + +#define FDT_ALIGN(x, a)		(((x) + (a) - 1) & ~((a) - 1)) +#define FDT_TAGALIGN(x)		(FDT_ALIGN((x), FDT_TAGSIZE)) + +#define FDT_CHECK_HEADER(fdt) \ +	{ \ +		int err; \ +		if ((err = fdt_check_header(fdt)) != 0) \ +			return err; \ +	} + +uint32_t _fdt_next_tag(const void *fdt, int startoffset, int *nextoffset); +int _fdt_check_node_offset(const void *fdt, int offset); +const char *_fdt_find_string(const char *strtab, int tabsize, const char *s); +int _fdt_node_end_offset(void *fdt, int nodeoffset); + +static inline const void *_fdt_offset_ptr(const void *fdt, int offset) +{ +	return (const char *)fdt + fdt_off_dt_struct(fdt) + offset; +} + +static inline void *_fdt_offset_ptr_w(void *fdt, int offset) +{ +	return (void *)(uintptr_t)_fdt_offset_ptr(fdt, offset); +} + +static inline const struct fdt_reserve_entry *_fdt_mem_rsv(const void *fdt, int n) +{ +	const struct fdt_reserve_entry *rsv_table = +		(const struct fdt_reserve_entry *) +		((const char *)fdt + fdt_off_mem_rsvmap(fdt)); + +	return rsv_table + n; +} +static inline struct fdt_reserve_entry *_fdt_mem_rsv_w(void *fdt, int n) +{ +	return (void *)(uintptr_t)_fdt_mem_rsv(fdt, n); +} + +#define FDT_SW_MAGIC		(~FDT_MAGIC) + +#endif /* _LIBFDT_INTERNAL_H */ diff --git a/scripts/dtc/livetree.c b/scripts/dtc/livetree.c new file mode 100644 index 00000000000..0ca3de550b3 --- /dev/null +++ b/scripts/dtc/livetree.c @@ -0,0 +1,308 @@ +/* + * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005. + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + *  General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 + *                                                                   USA + */ + +#include "dtc.h" + +/* + * Tree building functions + */ + +struct property *build_property(char *name, struct data val, char *label) +{ +	struct property *new = xmalloc(sizeof(*new)); + +	new->name = name; +	new->val = val; + +	new->next = NULL; + +	new->label = label; + +	return new; +} + +struct property *chain_property(struct property *first, struct property *list) +{ +	assert(first->next == NULL); + +	first->next = list; +	return first; +} + +struct property *reverse_properties(struct property *first) +{ +	struct property *p = first; +	struct property *head = NULL; +	struct property *next; + +	while (p) { +		next = p->next; +		p->next = head; +		head = p; +		p = next; +	} +	return head; +} + +struct node *build_node(struct property *proplist, struct node *children) +{ +	struct node *new = xmalloc(sizeof(*new)); +	struct node *child; + +	memset(new, 0, sizeof(*new)); + +	new->proplist = reverse_properties(proplist); +	new->children = children; + +	for_each_child(new, child) { +		child->parent = new; +	} + +	return new; +} + +struct node *name_node(struct node *node, char *name, char * label) +{ +	assert(node->name == NULL); + +	node->name = name; + +	node->label = label; + +	return node; +} + +struct node *chain_node(struct node *first, struct node *list) +{ +	assert(first->next_sibling == NULL); + +	first->next_sibling = list; +	return first; +} + +void add_property(struct node *node, struct property *prop) +{ +	struct property **p; + +	prop->next = NULL; + +	p = &node->proplist; +	while (*p) +		p = &((*p)->next); + +	*p = prop; +} + +void add_child(struct node *parent, struct node *child) +{ +	struct node **p; + +	child->next_sibling = NULL; +	child->parent = parent; + +	p = &parent->children; +	while (*p) +		p = &((*p)->next_sibling); + +	*p = child; +} + +struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size, +					 char *label) +{ +	struct reserve_info *new = xmalloc(sizeof(*new)); + +	new->re.address = address; +	new->re.size = size; + +	new->next = NULL; + +	new->label = label; + +	return new; +} + +struct reserve_info *chain_reserve_entry(struct reserve_info *first, +					struct reserve_info *list) +{ +	assert(first->next == NULL); + +	first->next = list; +	return first; +} + +struct reserve_info *add_reserve_entry(struct reserve_info *list, +				      struct reserve_info *new) +{ +	struct reserve_info *last; + +	new->next = NULL; + +	if (! list) +		return new; + +	for (last = list; last->next; last = last->next) +		; + +	last->next = new; + +	return list; +} + +struct boot_info *build_boot_info(struct reserve_info *reservelist, +				  struct node *tree, uint32_t boot_cpuid_phys) +{ +	struct boot_info *bi; + +	bi = xmalloc(sizeof(*bi)); +	bi->reservelist = reservelist; +	bi->dt = tree; +	bi->boot_cpuid_phys = boot_cpuid_phys; + +	return bi; +} + +/* + * Tree accessor functions + */ + +const char *get_unitname(struct node *node) +{ +	if (node->name[node->basenamelen] == '\0') +		return ""; +	else +		return node->name + node->basenamelen + 1; +} + +struct property *get_property(struct node *node, const char *propname) +{ +	struct property *prop; + +	for_each_property(node, prop) +		if (streq(prop->name, propname)) +			return prop; + +	return NULL; +} + +cell_t propval_cell(struct property *prop) +{ +	assert(prop->val.len == sizeof(cell_t)); +	return fdt32_to_cpu(*((cell_t *)prop->val.val)); +} + +struct node *get_subnode(struct node *node, const char *nodename) +{ +	struct node *child; + +	for_each_child(node, child) +		if (streq(child->name, nodename)) +			return child; + +	return NULL; +} + +struct node *get_node_by_path(struct node *tree, const char *path) +{ +	const char *p; +	struct node *child; + +	if (!path || ! (*path)) +		return tree; + +	while (path[0] == '/') +		path++; + +	p = strchr(path, '/'); + +	for_each_child(tree, child) { +		if (p && strneq(path, child->name, p-path)) +			return get_node_by_path(child, p+1); +		else if (!p && streq(path, child->name)) +			return child; +	} + +	return NULL; +} + +struct node *get_node_by_label(struct node *tree, const char *label) +{ +	struct node *child, *node; + +	assert(label && (strlen(label) > 0)); + +	if (tree->label && streq(tree->label, label)) +		return tree; + +	for_each_child(tree, child) { +		node = get_node_by_label(child, label); +		if (node) +			return node; +	} + +	return NULL; +} + +struct node *get_node_by_phandle(struct node *tree, cell_t phandle) +{ +	struct node *child, *node; + +	assert((phandle != 0) && (phandle != -1)); + +	if (tree->phandle == phandle) +		return tree; + +	for_each_child(tree, child) { +		node = get_node_by_phandle(child, phandle); +		if (node) +			return node; +	} + +	return NULL; +} + +struct node *get_node_by_ref(struct node *tree, const char *ref) +{ +	if (ref[0] == '/') +		return get_node_by_path(tree, ref); +	else +		return get_node_by_label(tree, ref); +} + +cell_t get_node_phandle(struct node *root, struct node *node) +{ +	static cell_t phandle = 1; /* FIXME: ick, static local */ + +	if ((node->phandle != 0) && (node->phandle != -1)) +		return node->phandle; + +	assert(! get_property(node, "linux,phandle")); + +	while (get_node_by_phandle(root, phandle)) +		phandle++; + +	node->phandle = phandle; +	add_property(node, +		     build_property("linux,phandle", +				    data_append_cell(empty_data, phandle), +				    NULL)); + +	return node->phandle; +} diff --git a/scripts/dtc/srcpos.c b/scripts/dtc/srcpos.c new file mode 100644 index 00000000000..9641b7628b4 --- /dev/null +++ b/scripts/dtc/srcpos.c @@ -0,0 +1,116 @@ +/* + * Copyright 2007 Jon Loeliger, Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + *  General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 + *                                                                   USA + */ + +#include "dtc.h" +#include "srcpos.h" + +/* + * Like yylineno, this is the current open file pos. + */ + +struct dtc_file *srcpos_file; + +static int dtc_open_one(struct dtc_file *file, +                        const char *search, +                        const char *fname) +{ +	char *fullname; + +	if (search) { +		fullname = xmalloc(strlen(search) + strlen(fname) + 2); + +		strcpy(fullname, search); +		strcat(fullname, "/"); +		strcat(fullname, fname); +	} else { +		fullname = strdup(fname); +	} + +	file->file = fopen(fullname, "r"); +	if (!file->file) { +		free(fullname); +		return 0; +	} + +	file->name = fullname; +	return 1; +} + + +struct dtc_file *dtc_open_file(const char *fname, +                               const struct search_path *search) +{ +	static const struct search_path default_search = { NULL, NULL, NULL }; + +	struct dtc_file *file; +	const char *slash; + +	file = xmalloc(sizeof(struct dtc_file)); + +	slash = strrchr(fname, '/'); +	if (slash) { +		char *dir = xmalloc(slash - fname + 1); + +		memcpy(dir, fname, slash - fname); +		dir[slash - fname] = 0; +		file->dir = dir; +	} else { +		file->dir = NULL; +	} + +	if (streq(fname, "-")) { +		file->name = "stdin"; +		file->file = stdin; +		return file; +	} + +	if (fname[0] == '/') { +		file->file = fopen(fname, "r"); +		if (!file->file) +			goto fail; + +		file->name = strdup(fname); +		return file; +	} + +	if (!search) +		search = &default_search; + +	while (search) { +		if (dtc_open_one(file, search->dir, fname)) +			return file; + +		if (errno != ENOENT) +			goto fail; + +		search = search->next; +	} + +fail: +	die("Couldn't open \"%s\": %s\n", fname, strerror(errno)); +} + +void dtc_close_file(struct dtc_file *file) +{ +	if (fclose(file->file)) +		die("Error closing \"%s\": %s\n", file->name, strerror(errno)); + +	free(file->dir); +	free(file); +} diff --git a/scripts/dtc/srcpos.h b/scripts/dtc/srcpos.h new file mode 100644 index 00000000000..e17c7c04db8 --- /dev/null +++ b/scripts/dtc/srcpos.h @@ -0,0 +1,85 @@ +/* + * Copyright 2007 Jon Loeliger, Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + *  General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 + *                                                                   USA + */ + +/* + * Augment the standard YYLTYPE with a filenum index into an + * array of all opened filenames. + */ + +#include <stdio.h> + +struct dtc_file { +	char *dir; +	const char *name; +	FILE *file; +}; + +#if ! defined(YYLTYPE) && ! defined(YYLTYPE_IS_DECLARED) +typedef struct YYLTYPE { +    int first_line; +    int first_column; +    int last_line; +    int last_column; +    struct dtc_file *file; +} YYLTYPE; + +#define YYLTYPE_IS_DECLARED	1 +#define YYLTYPE_IS_TRIVIAL	1 +#endif + +/* Cater to old parser templates. */ +#ifndef YYID +#define YYID(n)	(n) +#endif + +#define YYLLOC_DEFAULT(Current, Rhs, N)					\ +    do									\ +      if (YYID (N))							\ +	{								\ +	  (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;	\ +	  (Current).first_column = YYRHSLOC (Rhs, 1).first_column;	\ +	  (Current).last_line    = YYRHSLOC (Rhs, N).last_line;		\ +	  (Current).last_column  = YYRHSLOC (Rhs, N).last_column;	\ +	  (Current).file         = YYRHSLOC (Rhs, N).file;		\ +	}								\ +      else								\ +	{								\ +	  (Current).first_line   = (Current).last_line   =		\ +	    YYRHSLOC (Rhs, 0).last_line;				\ +	  (Current).first_column = (Current).last_column =		\ +	    YYRHSLOC (Rhs, 0).last_column;				\ +	  (Current).file         = YYRHSLOC (Rhs, 0).file;		\ +	}								\ +    while (YYID (0)) + + + +extern void yyerror(char const *); +extern void yyerrorf(char const *, ...) __attribute__((format(printf, 1, 2))); + +extern struct dtc_file *srcpos_file; + +struct search_path { +	const char *dir; /* NULL for current directory */ +	struct search_path *prev, *next; +}; + +extern struct dtc_file *dtc_open_file(const char *fname, +                                      const struct search_path *search); +extern void dtc_close_file(struct dtc_file *file); diff --git a/scripts/dtc/treesource.c b/scripts/dtc/treesource.c new file mode 100644 index 00000000000..ebeb6eb2790 --- /dev/null +++ b/scripts/dtc/treesource.c @@ -0,0 +1,278 @@ +/* + * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005. + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + *  General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 + *                                                                   USA + */ + +#include "dtc.h" +#include "srcpos.h" + +extern FILE *yyin; +extern int yyparse(void); + +struct boot_info *the_boot_info; +int treesource_error; + +struct boot_info *dt_from_source(const char *fname) +{ +	the_boot_info = NULL; +	treesource_error = 0; + +	srcpos_file = dtc_open_file(fname, NULL); +	yyin = srcpos_file->file; + +	if (yyparse() != 0) +		die("Unable to parse input tree\n"); + +	if (treesource_error) +		die("Syntax error parsing input tree\n"); + +	return the_boot_info; +} + +static void write_prefix(FILE *f, int level) +{ +	int i; + +	for (i = 0; i < level; i++) +		fputc('\t', f); +} + +int isstring(char c) +{ +	return (isprint(c) +		|| (c == '\0') +		|| strchr("\a\b\t\n\v\f\r", c)); +} + +static void write_propval_string(FILE *f, struct data val) +{ +	const char *str = val.val; +	int i; +	int newchunk = 1; +	struct marker *m = val.markers; + +	assert(str[val.len-1] == '\0'); + +	for (i = 0; i < (val.len-1); i++) { +		char c = str[i]; + +		if (newchunk) { +			while (m && (m->offset <= i)) { +				if (m->type == LABEL) { +					assert(m->offset == i); +					fprintf(f, "%s: ", m->ref); +				} +				m = m->next; +			} +			fprintf(f, "\""); +			newchunk = 0; +		} + +		switch (c) { +		case '\a': +			fprintf(f, "\\a"); +			break; +		case '\b': +			fprintf(f, "\\b"); +			break; +		case '\t': +			fprintf(f, "\\t"); +			break; +		case '\n': +			fprintf(f, "\\n"); +			break; +		case '\v': +			fprintf(f, "\\v"); +			break; +		case '\f': +			fprintf(f, "\\f"); +			break; +		case '\r': +			fprintf(f, "\\r"); +			break; +		case '\\': +			fprintf(f, "\\\\"); +			break; +		case '\"': +			fprintf(f, "\\\""); +			break; +		case '\0': +			fprintf(f, "\", "); +			newchunk = 1; +			break; +		default: +			if (isprint(c)) +				fprintf(f, "%c", c); +			else +				fprintf(f, "\\x%02hhx", c); +		} +	} +	fprintf(f, "\""); + +	/* Wrap up any labels at the end of the value */ +	for_each_marker_of_type(m, LABEL) { +		assert (m->offset == val.len); +		fprintf(f, " %s:", m->ref); +	} +} + +static void write_propval_cells(FILE *f, struct data val) +{ +	void *propend = val.val + val.len; +	cell_t *cp = (cell_t *)val.val; +	struct marker *m = val.markers; + +	fprintf(f, "<"); +	for (;;) { +		while (m && (m->offset <= ((char *)cp - val.val))) { +			if (m->type == LABEL) { +				assert(m->offset == ((char *)cp - val.val)); +				fprintf(f, "%s: ", m->ref); +			} +			m = m->next; +		} + +		fprintf(f, "0x%x", fdt32_to_cpu(*cp++)); +		if ((void *)cp >= propend) +			break; +		fprintf(f, " "); +	} + +	/* Wrap up any labels at the end of the value */ +	for_each_marker_of_type(m, LABEL) { +		assert (m->offset == val.len); +		fprintf(f, " %s:", m->ref); +	} +	fprintf(f, ">"); +} + +static void write_propval_bytes(FILE *f, struct data val) +{ +	void *propend = val.val + val.len; +	const char *bp = val.val; +	struct marker *m = val.markers; + +	fprintf(f, "["); +	for (;;) { +		while (m && (m->offset == (bp-val.val))) { +			if (m->type == LABEL) +				fprintf(f, "%s: ", m->ref); +			m = m->next; +		} + +		fprintf(f, "%02hhx", *bp++); +		if ((const void *)bp >= propend) +			break; +		fprintf(f, " "); +	} + +	/* Wrap up any labels at the end of the value */ +	for_each_marker_of_type(m, LABEL) { +		assert (m->offset == val.len); +		fprintf(f, " %s:", m->ref); +	} +	fprintf(f, "]"); +} + +static void write_propval(FILE *f, struct property *prop) +{ +	int len = prop->val.len; +	const char *p = prop->val.val; +	struct marker *m = prop->val.markers; +	int nnotstring = 0, nnul = 0; +	int nnotstringlbl = 0, nnotcelllbl = 0; +	int i; + +	if (len == 0) { +		fprintf(f, ";\n"); +		return; +	} + +	for (i = 0; i < len; i++) { +		if (! isstring(p[i])) +			nnotstring++; +		if (p[i] == '\0') +			nnul++; +	} + +	for_each_marker_of_type(m, LABEL) { +		if ((m->offset > 0) && (prop->val.val[m->offset - 1] != '\0')) +			nnotstringlbl++; +		if ((m->offset % sizeof(cell_t)) != 0) +			nnotcelllbl++; +	} + +	fprintf(f, " = "); +	if ((p[len-1] == '\0') && (nnotstring == 0) && (nnul < (len-nnul)) +	    && (nnotstringlbl == 0)) { +		write_propval_string(f, prop->val); +	} else if (((len % sizeof(cell_t)) == 0) && (nnotcelllbl == 0)) { +		write_propval_cells(f, prop->val); +	} else { +		write_propval_bytes(f, prop->val); +	} + +	fprintf(f, ";\n"); +} + +static void write_tree_source_node(FILE *f, struct node *tree, int level) +{ +	struct property *prop; +	struct node *child; + +	write_prefix(f, level); +	if (tree->label) +		fprintf(f, "%s: ", tree->label); +	if (tree->name && (*tree->name)) +		fprintf(f, "%s {\n", tree->name); +	else +		fprintf(f, "/ {\n"); + +	for_each_property(tree, prop) { +		write_prefix(f, level+1); +		if (prop->label) +			fprintf(f, "%s: ", prop->label); +		fprintf(f, "%s", prop->name); +		write_propval(f, prop); +	} +	for_each_child(tree, child) { +		fprintf(f, "\n"); +		write_tree_source_node(f, child, level+1); +	} +	write_prefix(f, level); +	fprintf(f, "};\n"); +} + + +void dt_to_source(FILE *f, struct boot_info *bi) +{ +	struct reserve_info *re; + +	fprintf(f, "/dts-v1/;\n\n"); + +	for (re = bi->reservelist; re; re = re->next) { +		if (re->label) +			fprintf(f, "%s: ", re->label); +		fprintf(f, "/memreserve/\t0x%016llx 0x%016llx;\n", +			(unsigned long long)re->re.address, +			(unsigned long long)re->re.size); +	} + +	write_tree_source_node(f, bi->dt, 0); +} + diff --git a/scripts/dtc/version_gen.h b/scripts/dtc/version_gen.h new file mode 100644 index 00000000000..658ff42429d --- /dev/null +++ b/scripts/dtc/version_gen.h @@ -0,0 +1 @@ +#define DTC_VERSION "DTC 1.2.0" | 
