Re: [PATCH v10 3/4] dtc: Plugin and fixup support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]



> On Nov 28, 2016, at 06:12 , David Gibson <david@xxxxxxxxxxxxxxxxxxxxx> wrote:
> 
> On Fri, Nov 25, 2016 at 02:32:10PM +0200, Pantelis Antoniou wrote:
>> This patch enable the generation of symbols & local fixup information
>> for trees compiled with the -@ (--symbols) option.
>> 
>> Using this patch labels in the tree and their users emit information
>> in __symbols__ and __local_fixups__ nodes.
>> 
>> The __fixups__ node make possible the dynamic resolution of phandle
>> references which are present in the plugin tree but lie in the
>> tree that are applying the overlay against.
>> 
>> While there is a new magic number for dynamic device tree/overlays blobs
>> it is by default enabled. Remember to use -M to generate compatible
>> blobs.
>> 
>> Signed-off-by: Pantelis Antoniou <pantelis.antoniou@xxxxxxxxxxxx>
>> Signed-off-by: Sascha Hauer <s.hauer@xxxxxxxxxxxxxx>
>> Signed-off-by: Jan Luebbe <jlu@xxxxxxxxxxxxxx>
>> ---
>> Documentation/manual.txt |  25 +++++-
>> checks.c                 |   8 +-
>> dtc-lexer.l              |   5 ++
>> dtc-parser.y             |  50 +++++++++--
>> dtc.c                    |  39 +++++++-
>> dtc.h                    |  20 ++++-
>> fdtdump.c                |   2 +-
>> flattree.c               |  17 ++--
>> fstree.c                 |   2 +-
>> libfdt/fdt.c             |   2 +-
>> libfdt/fdt.h             |   3 +-
>> livetree.c               | 225 ++++++++++++++++++++++++++++++++++++++++++++++-
>> tests/mangle-layout.c    |   7 +-
>> 13 files changed, 375 insertions(+), 30 deletions(-)
>> 
>> diff --git a/Documentation/manual.txt b/Documentation/manual.txt
>> index 398de32..094893b 100644
>> --- a/Documentation/manual.txt
>> +++ b/Documentation/manual.txt
>> @@ -119,6 +119,24 @@ Options:
>> 	Make space for <number> reserve map entries
>> 	Relevant for dtb and asm output only.
>> 
>> +    -@
>> +	Generates a __symbols__ node at the root node of the resulting blob
>> +	for any node labels used, and for any local references using phandles
>> +	it also generates a __local_fixups__ node that tracks them.
>> +
>> +	When using the /plugin/ tag all unresolved label references to
>> +	be tracked in the __fixups__ node, making dynamic resolution possible.
>> +
>> +    -A
>> +	Generate automatically aliases for all node labels. This is similar to
>> +	the -@ option (the __symbols__ node contain identical information) but
>> +	the semantics are slightly different since no phandles are automatically
>> +	generated for labeled nodes.
>> +
>> +    -M
>> +	Generate blobs with the old FDT magic number for device tree objects.
>> +	By default blobs use the DTBO FDT magic number instead.
>> +
>>     -S <bytes>
>> 	Ensure the blob at least <bytes> long, adding additional
>> 	space if needed.
>> @@ -146,13 +164,18 @@ Additionally, dtc performs various sanity checks on the tree.
>> Here is a very rough overview of the layout of a DTS source file:
>> 
>> 
>> -    sourcefile:   list_of_memreserve devicetree
>> +    sourcefile:   versioninfo plugindecl list_of_memreserve devicetree
>> 
>>     memreserve:   label 'memreserve' ADDR ADDR ';'
>> 		| label 'memreserve' ADDR '-' ADDR ';'
>> 
>>     devicetree:   '/' nodedef
>> 
>> +    versioninfo:  '/' 'dts-v1' '/' ';'
>> +
>> +    plugindecl:   '/' 'plugin' '/' ';'
>> +                | /* empty */
>> +
>>     nodedef:      '{' list_of_property list_of_subnode '}' ';'
>> 
>>     property:     label PROPNAME '=' propdata ';'
>> diff --git a/checks.c b/checks.c
>> index 2bd27a4..4292f4b 100644
>> --- a/checks.c
>> +++ b/checks.c
>> @@ -487,8 +487,12 @@ static void fixup_phandle_references(struct check *c, struct boot_info *bi,
>> 
>> 			refnode = get_node_by_ref(dt, m->ref);
>> 			if (! refnode) {
>> -				FAIL(c, "Reference to non-existent node or label \"%s\"\n",
>> -				     m->ref);
>> +				if (!(bi->versionflags & VF_PLUGIN))
>> +					FAIL(c, "Reference to non-existent node or "
>> +							"label \"%s\"\n", m->ref);
>> +				else /* mark the entry as unresolved */
>> +					*((cell_t *)(prop->val.val + m->offset)) =
>> +						cpu_to_fdt32(0xffffffff);
>> 				continue;
>> 			}
>> 
>> diff --git a/dtc-lexer.l b/dtc-lexer.l
>> index 790fbf6..40bbc87 100644
>> --- a/dtc-lexer.l
>> +++ b/dtc-lexer.l
>> @@ -121,6 +121,11 @@ static void lexical_error(const char *fmt, ...);
>> 			return DT_V1;
>> 		}
>> 
>> +<*>"/plugin/"	{
>> +			DPRINT("Keyword: /plugin/\n");
>> +			return DT_PLUGIN;
>> +		}
>> +
>> <*>"/memreserve/"	{
>> 			DPRINT("Keyword: /memreserve/\n");
>> 			BEGIN_DEFAULT();
>> diff --git a/dtc-parser.y b/dtc-parser.y
>> index 14aaf2e..1a1f660 100644
>> --- a/dtc-parser.y
>> +++ b/dtc-parser.y
>> @@ -19,6 +19,7 @@
>>  */
>> %{
>> #include <stdio.h>
>> +#include <inttypes.h>
>> 
>> #include "dtc.h"
>> #include "srcpos.h"
>> @@ -33,6 +34,7 @@ extern void yyerror(char const *s);
>> 
>> extern struct boot_info *the_boot_info;
>> extern bool treesource_error;
>> +
> 
> Extraneous whitespace change here
> 

OK.

>> %}
>> 
>> %union {
>> @@ -52,9 +54,11 @@ extern bool treesource_error;
>> 	struct node *nodelist;
>> 	struct reserve_info *re;
>> 	uint64_t integer;
>> +	unsigned int flags;
>> }
>> 
>> %token DT_V1
>> +%token DT_PLUGIN
>> %token DT_MEMRESERVE
>> %token DT_LSHIFT DT_RSHIFT DT_LE DT_GE DT_EQ DT_NE DT_AND DT_OR
>> %token DT_BITS
>> @@ -71,6 +75,8 @@ extern bool treesource_error;
>> 
>> %type <data> propdata
>> %type <data> propdataprefix
>> +%type <flags> versioninfo
>> +%type <flags> plugindecl
>> %type <re> memreserve
>> %type <re> memreserves
>> %type <array> arrayprefix
>> @@ -101,16 +107,34 @@ extern bool treesource_error;
>> %%
>> 
>> sourcefile:
>> -	  v1tag memreserves devicetree
>> +	  versioninfo plugindecl memreserves devicetree
>> +		{
>> +			the_boot_info = build_boot_info($1 | $2, $3, $4,
>> +							guess_boot_cpuid($4));
>> +		}
>> +	;
>> +
>> +versioninfo:
>> +	v1tag
>> 		{
>> -			the_boot_info = build_boot_info($2, $3,
>> -							guess_boot_cpuid($3));
>> +			$$ = VF_DT_V1;
>> 		}
>> 	;
>> 
>> v1tag:
>> 	  DT_V1 ';'
>> +	| DT_V1
>> 	| DT_V1 ';' v1tag
>> +
>> +plugindecl:
>> +	DT_PLUGIN ';'
>> +		{
>> +			$$ = VF_PLUGIN;
>> +		}
>> +	| /* empty */
>> +		{
>> +			$$ = 0;
>> +		}
>> 	;
>> 
>> memreserves:
>> @@ -161,10 +185,19 @@ devicetree:
>> 		{
>> 			struct node *target = get_node_by_ref($1, $2);
>> 
>> -			if (target)
>> +			if (target) {
>> 				merge_nodes(target, $3);
>> -			else
>> -				ERROR(&@2, "Label or path %s not found", $2);
>> +			} else {
>> +				/*
>> +				 * We rely on the rule being always:
>> +				 *   versioninfo plugindecl memreserves devicetree
>> +				 * so $-1 is what we want (plugindecl)
>> +				 */
>> +				if ($<flags>-1 & VF_PLUGIN)
> 
> o_O... ok.  I've never seen negative value references before.  Can you
> provide a link to some documentation saying this is actually supported
> usage in bison?  I wasn't able to find it when I looked.
> 

There is a section about inherited attributes in the flex & bison book by O’Reily.

https://books.google.gr/books?id=3Sr1V5J9_qMC&lpg=PP1&dq=flex%20bison&hl=el&pg=PP1#v=onepage&q=flex%20bison&f=false

There’s a direct link to the 2nd Edition of lex & yacc:

https://books.google.gr/books?id=fMPxfWfe67EC&lpg=PA183&ots=RcRSji2NAT&dq=yacc%20inherited%20attributes&hl=el&pg=PA183#v=onepage&q=yacc%20inherited%20attributes&f=false

>> +					add_orphan_node($1, $3, $2);
>> +				else
>> +					ERROR(&@2, "Label or path %s not found", $2);
>> +			}
>> 			$$ = $1;
>> 		}
>> 	| devicetree DT_DEL_NODE DT_REF ';'
>> @@ -179,6 +212,11 @@ devicetree:
>> 
>> 			$$ = $1;
>> 		}
>> +	| /* empty */
>> +		{
>> +			/* build empty node */
>> +			$$ = name_node(build_node(NULL, NULL), "");
>> +		}
>> 	;
>> 
>> nodedef:
>> diff --git a/dtc.c b/dtc.c
>> index 9dcf640..06e91bc 100644
>> --- a/dtc.c
>> +++ b/dtc.c
>> @@ -32,6 +32,9 @@ int minsize;		/* Minimum blob size */
>> int padsize;		/* Additional padding to blob */
>> int alignsize;		/* Additional padding to blob accroding to the alignsize */
>> int phandle_format = PHANDLE_BOTH;	/* Use linux,phandle or phandle properties */
>> +int symbol_fixup_support;	/* enable symbols & fixup support */
>> +int auto_label_aliases;		/* auto generate labels -> aliases */
>> +int no_dtbo_magic;		/* use old FDT magic values for objects */
>> 
>> static int is_power_of_2(int x)
>> {
>> @@ -59,7 +62,7 @@ static void fill_fullpaths(struct node *tree, const char *prefix)
>> #define FDT_VERSION(version)	_FDT_VERSION(version)
>> #define _FDT_VERSION(version)	#version
>> static const char usage_synopsis[] = "dtc [options] <input file>";
>> -static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:a:fb:i:H:sW:E:hv";
>> +static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:a:fb:i:H:sW:E:@AMhv";
>> static struct option const usage_long_opts[] = {
>> 	{"quiet",            no_argument, NULL, 'q'},
>> 	{"in-format",         a_argument, NULL, 'I'},
>> @@ -78,6 +81,9 @@ static struct option const usage_long_opts[] = {
>> 	{"phandle",           a_argument, NULL, 'H'},
>> 	{"warning",           a_argument, NULL, 'W'},
>> 	{"error",             a_argument, NULL, 'E'},
>> +	{"symbols",	     no_argument, NULL, '@'},
>> +	{"auto-alias",       no_argument, NULL, 'A'},
>> +	{"no-dtbo-magic",    no_argument, NULL, 'M'},
>> 	{"help",             no_argument, NULL, 'h'},
>> 	{"version",          no_argument, NULL, 'v'},
>> 	{NULL,               no_argument, NULL, 0x0},
>> @@ -109,6 +115,9 @@ static const char * const usage_opts_help[] = {
>> 	 "\t\tboth   - Both \"linux,phandle\" and \"phandle\" properties",
>> 	"\n\tEnable/disable warnings (prefix with \"no-\")",
>> 	"\n\tEnable/disable errors (prefix with \"no-\")",
>> +	"\n\tEnable symbols/fixup support",
>> +	"\n\tEnable auto-alias of labels",
>> +	"\n\tDo not use DTBO magic value for plugin objects",
>> 	"\n\tPrint this help and exit",
>> 	"\n\tPrint version and exit",
>> 	NULL,
>> @@ -153,7 +162,7 @@ static const char *guess_input_format(const char *fname, const char *fallback)
>> 	fclose(f);
>> 
>> 	magic = fdt32_to_cpu(magic);
>> -	if (magic == FDT_MAGIC)
>> +	if (magic == FDT_MAGIC || magic == FDT_MAGIC_DTBO)
>> 		return "dtb";
>> 
>> 	return guess_type_by_name(fname, fallback);
>> @@ -172,6 +181,7 @@ int main(int argc, char *argv[])
>> 	FILE *outf = NULL;
>> 	int outversion = DEFAULT_FDT_VERSION;
>> 	long long cmdline_boot_cpuid = -1;
>> +	fdt32_t out_magic = FDT_MAGIC;
>> 
>> 	quiet      = 0;
>> 	reservenum = 0;
>> @@ -249,6 +259,16 @@ int main(int argc, char *argv[])
>> 			parse_checks_option(false, true, optarg);
>> 			break;
>> 
>> +		case '@':
>> +			symbol_fixup_support = 1;
>> +			break;
>> +		case 'A':
>> +			auto_label_aliases = 1;
>> +			break;
>> +		case 'M':
>> +			no_dtbo_magic = 1;
>> +			break;
>> +
>> 		case 'h':
>> 			usage(NULL);
>> 		default:
>> @@ -306,6 +326,14 @@ int main(int argc, char *argv[])
>> 	fill_fullpaths(bi->dt, "");
>> 	process_checks(force, bi);
>> 
>> +	if (auto_label_aliases)
>> +		generate_label_tree(bi->dt, "aliases", false);
>> +
>> +	if (symbol_fixup_support) {
>> +		generate_label_tree(bi->dt, "__symbols__", true);
>> +		generate_fixups_tree(bi->dt);
> 
> Hang on.. this doesn't seem right.  I thought -@ controlled the
> __symbols__ side (i.e. the part upon which we overlay) rather than the
> fixups side (the part which overlays).  A dtbo could certainly have
> both, of course, but for base trees, wouldn't you have symbols without
> fixups?  And should it be illegal to try to build a /plugin/ without
> -@?

It does control both for now. For base trees having the fixup nodes
will allow us to do probe order dependency tracking in the future.
For plugins we need the __symbols__ node to support stacked overlays, i.e.
overlays referring label that were introduced by a previous overlay.  

For plugins there is no requirement for now to actually contain references to
be resolved. It can easily be enforced though. 

> 
>> +	}
>> +
>> 	if (sort)
>> 		sort_tree(bi);
>> 
>> @@ -318,12 +346,15 @@ int main(int argc, char *argv[])
>> 			    outname, strerror(errno));
>> 	}
>> 
>> +	if (!no_dtbo_magic && (bi->versionflags & VF_PLUGIN))
>> +		out_magic = FDT_MAGIC_DTBO;
>> +
>> 	if (streq(outform, "dts")) {
>> 		dt_to_source(outf, bi);
>> 	} else if (streq(outform, "dtb")) {
>> -		dt_to_blob(outf, bi, outversion);
>> +		dt_to_blob(outf, bi, out_magic, outversion);
>> 	} else if (streq(outform, "asm")) {
>> -		dt_to_asm(outf, bi, outversion);
>> +		dt_to_asm(outf, bi, out_magic, outversion);
>> 	} else if (streq(outform, "null")) {
>> 		/* do nothing */
>> 	} else {
>> diff --git a/dtc.h b/dtc.h
>> index 32009bc..581b3bf 100644
>> --- a/dtc.h
>> +++ b/dtc.h
>> @@ -55,6 +55,9 @@ extern int minsize;		/* Minimum blob size */
>> extern int padsize;		/* Additional padding to blob */
>> extern int alignsize;		/* Additional padding to blob accroding to the alignsize */
>> extern int phandle_format;	/* Use linux,phandle or phandle properties */
>> +extern int symbol_fixup_support;/* enable symbols & fixup support */
>> +extern int auto_label_aliases;	/* auto generate labels -> aliases */
>> +extern int no_dtbo_magic;	/* use old FDT magic values for objects */
>> 
>> #define PHANDLE_LEGACY	0x1
>> #define PHANDLE_EPAPR	0x2
>> @@ -195,6 +198,7 @@ struct node *build_node_delete(void);
>> struct node *name_node(struct node *node, char *name);
>> struct node *chain_node(struct node *first, struct node *list);
>> struct node *merge_nodes(struct node *old_node, struct node *new_node);
>> +void add_orphan_node(struct node *old_node, struct node *new_node, char *ref);
>> 
>> void add_property(struct node *node, struct property *prop);
>> void delete_property_by_name(struct node *node, char *name);
>> @@ -202,6 +206,8 @@ void delete_property(struct property *prop);
>> void add_child(struct node *parent, struct node *child);
>> void delete_node_by_name(struct node *parent, char *name);
>> void delete_node(struct node *node);
>> +void append_to_property(struct node *node,
>> +			char *name, const void *data, int len);
>> 
>> const char *get_unitname(struct node *node);
>> struct property *get_property(struct node *node, const char *propname);
>> @@ -237,14 +243,22 @@ struct reserve_info *add_reserve_entry(struct reserve_info *list,
>> 
>> 
>> struct boot_info {
>> +	unsigned int versionflags;
>> 	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,
>> +/* version flags definitions */
>> +#define VF_DT_V1	0x0001	/* /dts-v1/ */
>> +#define VF_PLUGIN	0x0002	/* /plugin/ */
>> +
>> +struct boot_info *build_boot_info(unsigned int versionflags,
>> +				  struct reserve_info *reservelist,
>> 				  struct node *tree, uint32_t boot_cpuid_phys);
>> void sort_tree(struct boot_info *bi);
>> +void generate_label_tree(struct node *dt, char *gen_node_name, bool allocph);
>> +void generate_fixups_tree(struct node *dt);
>> 
>> /* Checks */
>> 
>> @@ -253,8 +267,8 @@ void process_checks(bool 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);
>> +void dt_to_blob(FILE *f, struct boot_info *bi, fdt32_t magic, int version);
>> +void dt_to_asm(FILE *f, struct boot_info *bi, fdt32_t magic, int version);
>> 
>> struct boot_info *dt_from_blob(const char *fname);
>> 
>> diff --git a/fdtdump.c b/fdtdump.c
>> index a9a2484..dd63ac2 100644
>> --- a/fdtdump.c
>> +++ b/fdtdump.c
>> @@ -201,7 +201,7 @@ int main(int argc, char *argv[])
>> 			p = memchr(p, smagic[0], endp - p - FDT_MAGIC_SIZE);
>> 			if (!p)
>> 				break;
>> -			if (fdt_magic(p) == FDT_MAGIC) {
>> +			if (fdt_magic(p) == FDT_MAGIC || fdt_magic(p) == FDT_MAGIC_DTBO) {
>> 				/* try and validate the main struct */
>> 				off_t this_len = endp - p;
>> 				fdt32_t max_version = 17;
>> diff --git a/flattree.c b/flattree.c
>> index a9d9520..57d76cf 100644
>> --- a/flattree.c
>> +++ b/flattree.c
>> @@ -335,6 +335,7 @@ static struct data flatten_reserve_list(struct reserve_info *reservelist,
>> }
>> 
>> static void make_fdt_header(struct fdt_header *fdt,
>> +			    fdt32_t magic,
>> 			    struct version_info *vi,
>> 			    int reservesize, int dtsize, int strsize,
>> 			    int boot_cpuid_phys)
>> @@ -345,7 +346,7 @@ static void make_fdt_header(struct fdt_header *fdt,
>> 
>> 	memset(fdt, 0xff, sizeof(*fdt));
>> 
>> -	fdt->magic = cpu_to_fdt32(FDT_MAGIC);
>> +	fdt->magic = cpu_to_fdt32(magic);
>> 	fdt->version = cpu_to_fdt32(vi->version);
>> 	fdt->last_comp_version = cpu_to_fdt32(vi->last_comp_version);
>> 
>> @@ -366,7 +367,7 @@ static void make_fdt_header(struct fdt_header *fdt,
>> 		fdt->size_dt_struct = cpu_to_fdt32(dtsize);
>> }
>> 
>> -void dt_to_blob(FILE *f, struct boot_info *bi, int version)
>> +void dt_to_blob(FILE *f, struct boot_info *bi, fdt32_t magic, int version)
>> {
>> 	struct version_info *vi = NULL;
>> 	int i;
>> @@ -390,7 +391,7 @@ void dt_to_blob(FILE *f, struct boot_info *bi, int version)
>> 	reservebuf = flatten_reserve_list(bi->reservelist, vi);
>> 
>> 	/* Make header */
>> -	make_fdt_header(&fdt, vi, reservebuf.len, dtbuf.len, strbuf.len,
>> +	make_fdt_header(&fdt, magic, vi, reservebuf.len, dtbuf.len, strbuf.len,
>> 			bi->boot_cpuid_phys);
>> 
>> 	/*
>> @@ -467,7 +468,7 @@ static void dump_stringtable_asm(FILE *f, struct data strbuf)
>> 	}
>> }
>> 
>> -void dt_to_asm(FILE *f, struct boot_info *bi, int version)
>> +void dt_to_asm(FILE *f, struct boot_info *bi, fdt32_t magic, int version)
>> {
>> 	struct version_info *vi = NULL;
>> 	int i;
>> @@ -830,6 +831,7 @@ struct boot_info *dt_from_blob(const char *fname)
>> 	struct node *tree;
>> 	uint32_t val;
>> 	int flags = 0;
>> +	unsigned int versionflags = VF_DT_V1;
>> 
>> 	f = srcfile_relative_open(fname, NULL);
>> 
>> @@ -845,9 +847,12 @@ struct boot_info *dt_from_blob(const char *fname)
>> 	}
>> 
>> 	magic = fdt32_to_cpu(magic);
>> -	if (magic != FDT_MAGIC)
>> +	if (magic != FDT_MAGIC && magic != FDT_MAGIC_DTBO)
>> 		die("Blob has incorrect magic number\n");
>> 
>> +	if (magic == FDT_MAGIC_DTBO)
>> +		versionflags |= VF_PLUGIN;
> 
> Not particularly useful yet, but I wonder if we'll want some option to
> force treating dtb input as a plugin, for the case of old plugins
> which don't have the new magic number.
> 

It can easily be added.

>> +
>> 	rc = fread(&totalsize, sizeof(totalsize), 1, f);
>> 	if (ferror(f))
>> 		die("Error reading DT blob size: %s\n", strerror(errno));
>> @@ -942,5 +947,5 @@ struct boot_info *dt_from_blob(const char *fname)
>> 
>> 	fclose(f);
>> 
>> -	return build_boot_info(reservelist, tree, boot_cpuid_phys);
>> +	return build_boot_info(versionflags, reservelist, tree, boot_cpuid_phys);
>> }
>> diff --git a/fstree.c b/fstree.c
>> index 6d1beec..54f520b 100644
>> --- a/fstree.c
>> +++ b/fstree.c
>> @@ -86,6 +86,6 @@ struct boot_info *dt_from_fs(const char *dirname)
>> 	tree = read_fstree(dirname);
>> 	tree = name_node(tree, "");
>> 
>> -	return build_boot_info(NULL, tree, guess_boot_cpuid(tree));
>> +	return build_boot_info(VF_DT_V1, NULL, tree, guess_boot_cpuid(tree));
>> }
>> 
>> diff --git a/libfdt/fdt.c b/libfdt/fdt.c
>> index 22286a1..28d422c 100644
>> --- a/libfdt/fdt.c
>> +++ b/libfdt/fdt.c
>> @@ -57,7 +57,7 @@
>> 
>> int fdt_check_header(const void *fdt)
>> {
>> -	if (fdt_magic(fdt) == FDT_MAGIC) {
>> +	if (fdt_magic(fdt) == FDT_MAGIC || fdt_magic(fdt) == FDT_MAGIC_DTBO) {
>> 		/* Complete tree */
>> 		if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
>> 			return -FDT_ERR_BADVERSION;
>> diff --git a/libfdt/fdt.h b/libfdt/fdt.h
>> index 526aedb..493cd55 100644
>> --- a/libfdt/fdt.h
>> +++ b/libfdt/fdt.h
>> @@ -55,7 +55,7 @@
>> #ifndef __ASSEMBLY__
>> 
>> struct fdt_header {
>> -	fdt32_t magic;			 /* magic word FDT_MAGIC */
>> +	fdt32_t magic;			 /* magic word FDT_MAGIC[|_DTBO] */
>> 	fdt32_t totalsize;		 /* total size of DT block */
>> 	fdt32_t off_dt_struct;		 /* offset to structure */
>> 	fdt32_t off_dt_strings;		 /* offset to strings */
>> @@ -93,6 +93,7 @@ struct fdt_property {
>> #endif /* !__ASSEMBLY */
>> 
>> #define FDT_MAGIC	0xd00dfeed	/* 4: version, 4: total size */
>> +#define FDT_MAGIC_DTBO	0xd00dfdb0	/* DTBO magic */
>> #define FDT_TAGSIZE	sizeof(fdt32_t)
>> 
>> #define FDT_BEGIN_NODE	0x1		/* Start node: full name */
>> diff --git a/livetree.c b/livetree.c
>> index 3dc7559..f2c86bd 100644
>> --- a/livetree.c
>> +++ b/livetree.c
>> @@ -216,6 +216,31 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node)
>> 	return old_node;
>> }
>> 
>> +void add_orphan_node(struct node *dt, struct node *new_node, char *ref)
>> +{
>> +	static unsigned int next_orphan_fragment = 0;
>> +	struct node *node = build_node(NULL, NULL);
>> +	struct property *p;
>> +	struct data d = empty_data;
>> +	char *name;
>> +
>> +	memset(node, 0, sizeof(*node));
> 
> You don't need the memset() now that you're using build_node() above.
> 

OK

>> +
>> +	d = data_add_marker(d, REF_PHANDLE, ref);
>> +	d = data_append_integer(d, 0xffffffff, 32);
>> +
>> +	p = build_property("target", d);
>> +	add_property(node, p);
>> +
>> +	xasprintf(&name, "fragment@%u",
>> +			next_orphan_fragment++);
>> +	name_node(node, name);
>> +	name_node(new_node, "__overlay__");
> 
> You can do this more naturally if you do the name_node() here, then
> you can just pass the __overlay__ node into build_node() for the
> fragment@ node instead of having to explicitly add_child.
> 

Hmm, I’ll see if I can rework it like this.

>> +
>> +	add_child(dt, node);
>> +	add_child(node, new_node);
>> +}
>> +
>> struct node *chain_node(struct node *first, struct node *list)
>> {
>> 	assert(first->next_sibling == NULL);
>> @@ -296,6 +321,23 @@ void delete_node(struct node *node)
>> 	delete_labels(&node->labels);
>> }
>> 
>> +void append_to_property(struct node *node,
>> +				    char *name, const void *data, int len)
>> +{
>> +	struct data d;
>> +	struct property *p;
>> +
>> +	p = get_property(node, name);
>> +	if (p) {
>> +		d = data_append_data(p->val, data, len);
>> +		p->val = d;
>> +	} else {
>> +		d = data_append_data(empty_data, data, len);
>> +		p = build_property(name, d);
>> +		add_property(node, p);
>> +	}
>> +}
>> +
>> struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size)
>> {
>> 	struct reserve_info *new = xmalloc(sizeof(*new));
>> @@ -335,12 +377,14 @@ struct reserve_info *add_reserve_entry(struct reserve_info *list,
>> 	return list;
>> }
>> 
>> -struct boot_info *build_boot_info(struct reserve_info *reservelist,
>> +struct boot_info *build_boot_info(unsigned int versionflags,
>> +				  struct reserve_info *reservelist,
>> 				  struct node *tree, uint32_t boot_cpuid_phys)
>> {
>> 	struct boot_info *bi;
>> 
>> 	bi = xmalloc(sizeof(*bi));
>> +	bi->versionflags = versionflags;
>> 	bi->reservelist = reservelist;
>> 	bi->dt = tree;
>> 	bi->boot_cpuid_phys = boot_cpuid_phys;
>> @@ -709,3 +753,182 @@ void sort_tree(struct boot_info *bi)
>> 	sort_reserve_entries(bi);
>> 	sort_node(bi->dt);
>> }
>> +
>> +/* utility helper to avoid code duplication */
>> +static struct node *build_and_name_child_node(struct node *parent, char *name)
>> +{
>> +	struct node *node;
>> +
>> +	node = build_node(NULL, NULL);
>> +	name_node(node, xstrdup(name));
>> +	add_child(parent, node);
>> +
>> +	return node;
>> +}
>> +
>> +static void generate_label_tree_internal(struct node *dt, struct node *node,
>> +					 struct node *an, bool allocph)
>> +{
>> +	struct node *c;
>> +	struct property *p;
>> +	struct label *l;
>> +
>> +	/* if if there are labels */
>> +	if (node->labels) {
>> +		/* now add the label in the node */
>> +		for_each_label(node->labels, l) {
>> +			/* check whether the label already exists */
>> +			p = get_property(an, l->label);
>> +			if (p) {
>> +				fprintf(stderr, "WARNING: label %s already"
>> +					" exists in /%s", l->label,
>> +					an->name);
>> +				continue;
>> +			}
>> +
>> +			/* insert it */
>> +			p = build_property(l->label,
>> +				data_copy_mem(node->fullpath,
>> +						strlen(node->fullpath) + 1));
>> +			add_property(an, p);
>> +		}
>> +
>> +		/* force allocation of a phandle for this node */
>> +		if (allocph)
>> +			(void)get_node_phandle(dt, node);
>> +	}
>> +
>> +	for_each_child(node, c)
>> +		generate_label_tree_internal(dt, c, an, allocph);
>> +}
>> +
>> +void generate_label_tree(struct node *dt, char *gen_node_name, bool allocph)
>> +{
>> +	struct node *an;
>> +
>> +	for_each_child(dt, an)
>> +		if (streq(gen_node_name, an->name))
>> +			break;
>> +
>> +	if (!an)
>> +		an = build_and_name_child_node(dt, gen_node_name);
>> +	if (!an)
>> +		die("Could not build label node /%s\n", gen_node_name);
>> +
>> +	generate_label_tree_internal(dt, dt, an, allocph);
>> +}
>> +
>> +#define FIXUPS	"__fixups__"
>> +#define LOCAL_FIXUPS "__local_fixups__"
>> +
>> +static void add_fixup_entry(struct node *dt, struct node *node,
>> +		struct property *prop, struct marker *m)
>> +{
>> +	struct node *fn;	/* fixup node */
>> +	char *entry;
>> +
>> +	/* m->ref can only be a REF_PHANDLE, but check anyway */
>> +	assert(m->type == REF_PHANDLE);
>> +
>> +	/* fn is the node we're putting entries in */
>> +	fn = get_subnode(dt, FIXUPS);
>> +	assert(fn != NULL);
>> +
>> +	/* there shouldn't be any ':' in the arguments */
>> +	if (strchr(node->fullpath, ':') || strchr(prop->name, ':'))
>> +		die("arguments should not contain ':'\n");
>> +
>> +	xasprintf(&entry, "%s:%s:%u",
>> +			node->fullpath, prop->name, m->offset);
>> +	append_to_property(fn, m->ref, entry, strlen(entry) + 1);
>> +}
>> +
>> +static void add_local_fixup_entry(struct node *dt, struct node *node,
>> +		struct property *prop, struct marker *m,
>> +		struct node *refnode)
>> +{
>> +	struct node *lfn, *wn, *nwn;	/* local fixup node, walk node, new */
>> +	uint32_t value_32;
>> +	char *s, *e, *comp;
>> +	int len;
>> +
>> +	/* fn is the node we're putting entries in */
>> +	lfn = get_subnode(dt, LOCAL_FIXUPS);
>> +	assert(lfn != NULL);
>> +
>> +	/* walk the path components creating nodes if they don't exist */
>> +	comp = xmalloc(strlen(node->fullpath) + 1);
>> +	/* start skipping the first / */
>> +	s = node->fullpath + 1;
>> +	wn = lfn;
>> +	while (*s) {
>> +		/* retrieve path component */
>> +		e = strchr(s, '/');
>> +		if (e == NULL)
>> +			e = s + strlen(s);
>> +		len = e - s;
>> +		memcpy(comp, s, len);
>> +		comp[len] = '\0';
> 
> Parsing the fullpath into components seems an odd way of doing this.
> We have an actual handle on the node, and therefore all it's parents,
> which already have the individual path components split out.
> 

Hmm, I’ll see if it can be done. I don’t remember what was the original
cause for using this form.

>> +
>> +		/* if no node exists, create it */
>> +		nwn = get_subnode(wn, comp);
>> +		if (!nwn)
>> +			nwn = build_and_name_child_node(wn, comp);
>> +		wn = nwn;
>> +
>> +		/* last path component */
>> +		if (!*e)
>> +			break;
>> +
>> +		/* next path component */
>> +		s = e + 1;
>> +	}
>> +	free(comp);
>> +
>> +	value_32 = cpu_to_fdt32(m->offset);
>> +	append_to_property(wn, prop->name, &value_32, sizeof(value_32));
>> +}
>> +
>> +static void generate_fixups_tree_internal(struct node *dt, struct node *node)
>> +{
>> +	struct node *c;
>> +	struct property *prop;
>> +	struct marker *m;
>> +	struct node *refnode;
>> +
>> +	for_each_property(node, prop) {
>> +		m = prop->val.markers;
>> +		for_each_marker_of_type(m, REF_PHANDLE) {
>> +			refnode = get_node_by_ref(dt, m->ref);
>> +			if (!refnode)
>> +				add_fixup_entry(dt, node, prop, m);
>> +			else
>> +				add_local_fixup_entry(dt, node, prop, m,
>> +						refnode);
>> +		}
>> +	}
>> +
>> +	for_each_child(node, c)
>> +		generate_fixups_tree_internal(dt, c);
>> +}
>> +
>> +void generate_fixups_tree(struct node *dt)
>> +{
>> +	struct node *an;
>> +
>> +	for_each_child(dt, an)
>> +		if (streq(FIXUPS, an->name))
>> +			break;
>> +
>> +	if (!an)
>> +		build_and_name_child_node(dt, FIXUPS);
>> +
>> +	for_each_child(dt, an)
>> +		if (streq(LOCAL_FIXUPS, an->name))
>> +			break;
>> +
>> +	if (!an)
>> +		build_and_name_child_node(dt, LOCAL_FIXUPS);
>> +
>> +	generate_fixups_tree_internal(dt, dt);
>> +}
>> diff --git a/tests/mangle-layout.c b/tests/mangle-layout.c
>> index a76e51e..d29ebc6 100644
>> --- a/tests/mangle-layout.c
>> +++ b/tests/mangle-layout.c
>> @@ -42,7 +42,8 @@ static void expand_buf(struct bufstate *buf, int newsize)
>> 	buf->size = newsize;
>> }
>> 
>> -static void new_header(struct bufstate *buf, int version, const void *fdt)
>> +static void new_header(struct bufstate *buf, fdt32_t magic, int version,
>> +		       const void *fdt)
>> {
>> 	int hdrsize;
>> 
>> @@ -56,7 +57,7 @@ static void new_header(struct bufstate *buf, int version, const void *fdt)
>> 	expand_buf(buf, hdrsize);
>> 	memset(buf->buf, 0, hdrsize);
>> 
>> -	fdt_set_magic(buf->buf, FDT_MAGIC);
>> +	fdt_set_magic(buf->buf, magic);
>> 	fdt_set_version(buf->buf, version);
>> 	fdt_set_last_comp_version(buf->buf, 16);
>> 	fdt_set_boot_cpuid_phys(buf->buf, fdt_boot_cpuid_phys(fdt));
>> @@ -145,7 +146,7 @@ int main(int argc, char *argv[])
>> 	if (fdt_version(fdt) < 17)
>> 		CONFIG("Input tree must be v17");
>> 
>> -	new_header(&buf, version, fdt);
>> +	new_header(&buf, FDT_MAGIC, version, fdt);
>> 
>> 	while (*blockorder) {
>> 		add_block(&buf, version, *blockorder, fdt);
> 
> -- 
> David Gibson			| I'll have my music baroque, and my code
> david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
> 				| _way_ _around_!
> http://www.ozlabs.org/~dgibson

Regards

— Pantelis

--
To unsubscribe from this list: send the line "unsubscribe devicetree-compiler" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Device Tree]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux