This commit is contained in:
Uwe Kleine-König 2025-07-04 09:36:41 +02:00 committed by GitHub
commit 52a78c354f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 334 additions and 44 deletions

5
dtc.c
View file

@ -338,9 +338,14 @@ int main(int argc, char *argv[])
if (auto_label_aliases)
generate_label_tree(dti, "aliases", false);
generate_labels_from_tree(dti, "__symbols__");
if (generate_symbols)
generate_label_tree(dti, "__symbols__", true);
fixup_phandles(dti, "__fixups__");
local_fixup_phandles(dti, "__local_fixups__");
if (generate_fixups) {
generate_fixups_tree(dti, "__fixups__");
generate_local_fixups_tree(dti, "__local_fixups__");

6
dtc.h
View file

@ -339,9 +339,12 @@ struct dt_info *build_dt_info(unsigned int dtsflags,
struct reserve_info *reservelist,
struct node *tree, uint32_t boot_cpuid_phys);
void sort_tree(struct dt_info *dti);
void generate_labels_from_tree(struct dt_info *dti, const char *name);
void generate_label_tree(struct dt_info *dti, const char *name, bool allocph);
void generate_fixups_tree(struct dt_info *dti, const char *name);
void fixup_phandles(struct dt_info *dti, const char *name);
void generate_local_fixups_tree(struct dt_info *dti, const char *name);
void local_fixup_phandles(struct dt_info *dti, const char *name);
/* Checks */
@ -357,6 +360,9 @@ struct dt_info *dt_from_blob(const char *fname);
/* Tree source */
void property_add_marker(struct property *prop,
enum markertype type, unsigned int offset, char *ref);
void add_phandle_marker(struct dt_info *dti, struct property *prop, unsigned int offset);
void dt_to_source(FILE *f, struct dt_info *dti);
struct dt_info *dt_from_source(const char *f);

View file

@ -807,6 +807,7 @@ struct dt_info *dt_from_blob(const char *fname)
struct node *tree;
uint32_t val;
int flags = 0;
unsigned int dtsflags = DTSF_V1;
f = srcfile_relative_open(fname, NULL);
@ -919,5 +920,8 @@ struct dt_info *dt_from_blob(const char *fname)
fclose(f);
return build_dt_info(DTSF_V1, reservelist, tree, boot_cpuid_phys);
if (get_subnode(tree, "__fixups__") || get_subnode(tree, "__local_fixups__"))
dtsflags |= DTSF_PLUGIN;
return build_dt_info(dtsflags, reservelist, tree, boot_cpuid_phys);
}

View file

@ -1046,6 +1046,27 @@ static void generate_local_fixups_tree_internal(struct dt_info *dti,
generate_local_fixups_tree_internal(dti, lfn, c);
}
void generate_labels_from_tree(struct dt_info *dti, const char *name)
{
struct node *an;
struct property *p;
an = get_subnode(dti->dt, name);
if (!an)
return;
for_each_property(an, p) {
struct node *labeled_node;
labeled_node = get_node_by_path(dti->dt, p->val.val);
if (labeled_node)
add_label(&labeled_node->labels, p->name);
else if (quiet < 1)
fprintf(stderr, "Warning: Path %s referenced in property %s/%s missing",
p->val.val, name, p->name);
}
}
void generate_label_tree(struct dt_info *dti, const char *name, bool allocph)
{
if (!any_label_tree(dti, dti->dt))
@ -1069,6 +1090,102 @@ void generate_fixups_tree(struct dt_info *dti, const char *name)
dti->dt);
}
void fixup_phandles(struct dt_info *dti, const char *name)
{
struct node *an;
struct property *fp;
an = get_subnode(dti->dt, name);
if (!an)
return;
for_each_property(an, fp) {
char *fnext = fp->val.val;
char *fv;
unsigned int fl;
while ((fl = fp->val.len - (fnext - fp->val.val))) {
char *propname, *soffset;
struct node *n;
struct property *p;
long offset;
fv = fnext;
fnext = memchr(fv, 0, fl);
if (!fnext) {
if (quiet < 1)
fprintf(stderr, "Warning: Malformed fixup entry for label %s\n",
fp->name);
break;
}
fnext += 1;
propname = memchr(fv, ':', fnext - 1 - fv);
if (!propname) {
if (quiet < 1)
fprintf(stderr, "Warning: Malformed fixup entry for label %s\n",
fp->name);
continue;
}
propname++;
soffset = memchr(propname, ':', fnext - 1 - propname);
if (!soffset) {
if (quiet < 1)
fprintf(stderr, "Warning: Malformed fixup entry for label %s\n",
fp->name);
continue;
}
soffset++;
/*
* temporarily modify the property to not have to create
* a copy for the node path.
*/
*(propname - 1) = '\0';
n = get_node_by_path(dti->dt, fv);
if (!n && quiet < 1)
fprintf(stderr, "Warning: Label %s references non-existing node %s\n",
fp->name, fv);
*(propname - 1) = ':';
if (!n)
continue;
/*
* temporarily modify the property to not have to create
* a copy for the property name.
*/
*(soffset - 1) = '\0';
p = get_property(n, propname);
if (!p && quiet < 1)
fprintf(stderr, "Warning: Label %s references non-existing property %s in node %s\n",
fp->name, n->fullpath, propname);
*(soffset - 1) = ':';
if (!p)
continue;
offset = strtol(soffset, NULL, 0);
if (offset < 0 || offset + 4 > p->val.len) {
if (quiet < 1)
fprintf(stderr,
"Warning: Label %s contains invalid offset for property %s in node %s\n",
fp->name, p->name, n->fullpath);
continue;
}
property_add_marker(p, REF_PHANDLE, offset, fp->name);
}
}
}
void generate_local_fixups_tree(struct dt_info *dti, const char *name)
{
struct node *n = get_subnode(dti->dt, name);
@ -1082,3 +1199,60 @@ void generate_local_fixups_tree(struct dt_info *dti, const char *name)
build_and_name_child_node(dti->dt, name),
dti->dt);
}
static void local_fixup_phandles_node(struct dt_info *dti, struct node *lf, struct node *n)
{
struct property *lfp;
struct node *lfsubnode;
for_each_property(lf, lfp) {
struct property *p = get_property(n, lfp->name);
fdt32_t *offsets = (fdt32_t *)lfp->val.val;
size_t i;
if (!p) {
if (quiet < 1)
fprintf(stderr, "Warning: Property %s in %s referenced in __local_fixups__ missing\n",
lfp->name, n->fullpath);
continue;
}
/*
* Each property in the __local_fixups__ tree is a concatenation
* of offsets, so it must be a multiple of sizeof(fdt32_t).
*/
if (lfp->val.len % sizeof(fdt32_t)) {
if (quiet < 1)
fprintf(stderr, "Warning: property %s in /__local_fixups__%s malformed\n",
lfp->name, n->fullpath);
continue;
}
for (i = 0; i < lfp->val.len / sizeof(fdt32_t); i++)
add_phandle_marker(dti, p, dtb_ld32(offsets + i));
}
for_each_child(lf, lfsubnode) {
struct node *subnode = get_subnode(n, lfsubnode->name);
if (!subnode) {
if (quiet < 1)
fprintf(stderr, "Warning: node %s/%s referenced in __local_fixups__ missing\n",
lfsubnode->name, n->fullpath);
continue;
}
local_fixup_phandles_node(dti, lfsubnode, subnode);
}
}
void local_fixup_phandles(struct dt_info *dti, const char *name)
{
struct node *an;
an = get_subnode(dti->dt, name);
if (!an)
return;
local_fixup_phandles_node(dti, an, dti->dt);
}

23
tests/over-determined.dts Normal file
View file

@ -0,0 +1,23 @@
/dts-v1/;
/plugin/;
/ {
labelfornodea: nodea {
property = <&labelfornodea>;
};
nodeb {
property = <&nonexisting>;
};
__fixups__ {
nonexisting = "/nodeb:property:0";
};
__local_fixups__ {
nodea {
property = <0>;
};
};
};

View file

@ -570,6 +570,10 @@ dtc_tests () {
run_dtc_test -I dts -O dtb -o dtc_sized_cells.test.dtb "$SRCDIR/sized_cells.dts"
run_test sized_cells dtc_sized_cells.test.dtb
run_dtc_test -I dts -O dts -o over-determined-once.test.dts "$SRCDIR/over-determined.dts"
run_dtc_test -I dts -O dts -o over-determined-twice.test.dts "over-determined-once.test.dts"
run_wrap_test cmp over-determined-once.test.dts over-determined-twice.test.dts
run_dtc_test -I dts -O dtb -o dtc_extra-terminating-null.test.dtb "$SRCDIR/extra-terminating-null.dts"
run_test extra-terminating-null dtc_extra-terminating-null.test.dtb

View file

@ -139,35 +139,93 @@ static const char *delim_end[] = {
[TYPE_STRING] = "",
};
static void add_string_markers(struct property *prop)
/*
* The invariants in the marker list are:
* - offsets are non-strictly monotonically increasing
* - for a single offset there is at most one type marker
* - for a single offset that has both a type marker and non-type markers, the
* type marker appears before the others.
*/
static struct marker **add_marker(struct marker **mi,
enum markertype type, unsigned int offset, char *ref)
{
int l, len = prop->val.len;
const char *p = prop->val.val;
struct marker *nm;
for (l = strlen(p) + 1; l < len; l += strlen(p + l) + 1) {
struct marker *m, **nextp;
while (*mi && (*mi)->offset < offset)
mi = &(*mi)->next;
m = xmalloc(sizeof(*m));
m->offset = l;
m->type = TYPE_STRING;
m->ref = NULL;
m->next = NULL;
/* Find the end of the markerlist */
nextp = &prop->val.markers;
while (*nextp)
nextp = &((*nextp)->next);
*nextp = m;
}
if (*mi && (*mi)->offset == offset && is_type_marker((*mi)->type)) {
if (is_type_marker(type))
return mi;
mi = &(*mi)->next;
}
static enum markertype guess_value_type(struct property *prop)
if (*mi && (*mi)->offset == offset && type == (*mi)->type)
return mi;
nm = xmalloc(sizeof(*nm));
nm->type = type;
nm->offset = offset;
nm->ref = ref;
nm->next = *mi;
*mi = nm;
return &nm->next;
}
void property_add_marker(struct property *prop,
enum markertype type, unsigned int offset, char *ref)
{
int len = prop->val.len;
const char *p = prop->val.val;
struct marker *m = prop->val.markers;
add_marker(&prop->val.markers, type, offset, ref);
}
static void add_string_markers(struct property *prop, unsigned int offset, int len)
{
int l;
const char *p = prop->val.val + offset;
struct marker **mi = &prop->val.markers;
for (l = strlen(p) + 1; l < len; l += strlen(p + l) + 1)
mi = add_marker(mi, TYPE_STRING, offset + l, NULL);
}
void add_phandle_marker(struct dt_info *dti, struct property *prop, unsigned int offset)
{
cell_t phandle;
struct node *refn;
char *ref;
if (prop->val.len < offset + 4) {
if (quiet < 1)
fprintf(stderr,
"Warning: property %s too short to contain a phandle at offset %u\n",
prop->name, offset);
}
phandle = dtb_ld32(prop->val.val + offset);
refn = get_node_by_phandle(dti->dt, phandle);
if (!refn) {
if (quiet < 1)
fprintf(stderr,
"Warning: node referenced by phandle 0x%x in property %s not found\n",
phandle, prop->name);
return;
}
if (refn->labels)
ref = refn->labels->label;
else
ref = refn->fullpath;
add_marker(&prop->val.markers, REF_PHANDLE, offset, ref);
}
static enum markertype guess_value_type(struct property *prop, unsigned int offset, int len)
{
const char *p = prop->val.val + offset;
int nnotstring = 0, nnul = 0;
int nnotstringlbl = 0, nnotcelllbl = 0;
int i;
for (i = 0; i < len; i++) {
@ -177,30 +235,49 @@ static enum markertype guess_value_type(struct property *prop)
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++;
}
if ((p[len-1] == '\0') && (nnotstring == 0) && (nnul <= (len-nnul))
&& (nnotstringlbl == 0)) {
if ((p[len-1] == '\0') && (nnotstring == 0) && (nnul <= len - nnul)) {
if (nnul > 1)
add_string_markers(prop);
add_string_markers(prop, offset, len);
return TYPE_STRING;
} else if (((len % sizeof(cell_t)) == 0) && (nnotcelllbl == 0)) {
} else if ((len % sizeof(cell_t)) == 0) {
return TYPE_UINT32;
}
return TYPE_UINT8;
}
static void guess_type_markers(struct property *prop)
{
struct marker **m = &prop->val.markers;
unsigned int offset = 0;
for (m = &prop->val.markers; *m; m = &((*m)->next)) {
if (is_type_marker((*m)->type))
/* assume the whole property is already marked */
return;
if ((*m)->offset > offset) {
m = add_marker(m, guess_value_type(prop, offset, (*m)->offset - offset),
offset, NULL);
offset = (*m)->offset;
}
if ((*m)->type == REF_PHANDLE) {
m = add_marker(m, TYPE_UINT32, offset, NULL);
offset += 4;
}
}
if (offset < prop->val.len)
add_marker(m, guess_value_type(prop, offset, prop->val.len - offset),
offset, NULL);
}
static void write_propval(FILE *f, struct property *prop)
{
size_t len = prop->val.len;
struct marker *m = prop->val.markers;
struct marker dummy_marker;
struct marker *m;
enum markertype emit_type = TYPE_NONE;
char *srcstr;
@ -219,14 +296,8 @@ static void write_propval(FILE *f, struct property *prop)
fprintf(f, " =");
if (!next_type_marker(m)) {
/* data type information missing, need to guess */
dummy_marker.type = guess_value_type(prop);
dummy_marker.next = prop->val.markers;
dummy_marker.offset = 0;
dummy_marker.ref = NULL;
m = &dummy_marker;
}
guess_type_markers(prop);
m = prop->val.markers;
for_each_marker(m) {
size_t chunk_len = (m->next ? m->next->offset : len) - m->offset;
@ -347,7 +418,10 @@ void dt_to_source(FILE *f, struct dt_info *dti)
{
struct reserve_info *re;
fprintf(f, "/dts-v1/;\n\n");
fprintf(f, "/dts-v1/;\n");
if (dti->dtsflags & DTSF_PLUGIN)
fprintf(f, "/plugin/;\n");
fprintf(f, "\n");
for (re = dti->reservelist; re; re = re->next) {
struct label *l;