mirror of
https://github.com/Fishwaldo/build.git
synced 2025-03-26 08:41:54 +00:00
2341 lines
71 KiB
Diff
2341 lines
71 KiB
Diff
|
diff --git a/scripts/dtc/checks.c b/scripts/dtc/checks.c
|
||
|
index 3d18e45..5adfc8f 100644
|
||
|
--- a/scripts/dtc/checks.c
|
||
|
+++ b/scripts/dtc/checks.c
|
||
|
@@ -72,17 +72,16 @@ struct check {
|
||
|
#define CHECK(_nm, _fn, _d, ...) \
|
||
|
CHECK_ENTRY(_nm, _fn, _d, false, false, __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, ...)
|
||
|
+static inline void PRINTF(3, 4) check_msg(struct check *c, struct dt_info *dti,
|
||
|
+ const char *fmt, ...)
|
||
|
{
|
||
|
va_list ap;
|
||
|
va_start(ap, fmt);
|
||
|
|
||
|
if ((c->warn && (quiet < 1))
|
||
|
|| (c->error && (quiet < 2))) {
|
||
|
- fprintf(stderr, "%s (%s): ",
|
||
|
+ fprintf(stderr, "%s: %s (%s): ",
|
||
|
+ strcmp(dti->outname, "-") ? dti->outname : "<stdout>",
|
||
|
(c->error) ? "ERROR" : "Warning", c->name);
|
||
|
vfprintf(stderr, fmt, ap);
|
||
|
fprintf(stderr, "\n");
|
||
|
@@ -90,11 +89,11 @@ static inline void check_msg(struct check *c, const char *fmt, ...)
|
||
|
va_end(ap);
|
||
|
}
|
||
|
|
||
|
-#define FAIL(c, ...) \
|
||
|
- do { \
|
||
|
- TRACE((c), "\t\tFAILED at %s:%d", __FILE__, __LINE__); \
|
||
|
- (c)->status = FAILED; \
|
||
|
- check_msg((c), __VA_ARGS__); \
|
||
|
+#define FAIL(c, dti, ...) \
|
||
|
+ do { \
|
||
|
+ TRACE((c), "\t\tFAILED at %s:%d", __FILE__, __LINE__); \
|
||
|
+ (c)->status = FAILED; \
|
||
|
+ check_msg((c), dti, __VA_ARGS__); \
|
||
|
} while (0)
|
||
|
|
||
|
static void check_nodes_props(struct check *c, struct dt_info *dti, struct node *node)
|
||
|
@@ -127,7 +126,7 @@ static bool run_check(struct check *c, struct dt_info *dti)
|
||
|
error = error || run_check(prq, dti);
|
||
|
if (prq->status != PASSED) {
|
||
|
c->status = PREREQ;
|
||
|
- check_msg(c, "Failed prerequisite '%s'",
|
||
|
+ check_msg(c, dti, "Failed prerequisite '%s'",
|
||
|
c->prereq[i]->name);
|
||
|
}
|
||
|
}
|
||
|
@@ -157,7 +156,7 @@ static bool run_check(struct check *c, struct dt_info *dti)
|
||
|
static inline void check_always_fail(struct check *c, struct dt_info *dti,
|
||
|
struct node *node)
|
||
|
{
|
||
|
- FAIL(c, "always_fail check");
|
||
|
+ FAIL(c, dti, "always_fail check");
|
||
|
}
|
||
|
CHECK(always_fail, check_always_fail, NULL);
|
||
|
|
||
|
@@ -172,7 +171,7 @@ static void check_is_string(struct check *c, struct dt_info *dti,
|
||
|
return; /* Not present, assumed ok */
|
||
|
|
||
|
if (!data_is_one_string(prop->val))
|
||
|
- FAIL(c, "\"%s\" property in %s is not a string",
|
||
|
+ FAIL(c, dti, "\"%s\" property in %s is not a string",
|
||
|
propname, node->fullpath);
|
||
|
}
|
||
|
#define WARNING_IF_NOT_STRING(nm, propname) \
|
||
|
@@ -191,7 +190,7 @@ static void check_is_cell(struct check *c, struct dt_info *dti,
|
||
|
return; /* Not present, assumed ok */
|
||
|
|
||
|
if (prop->val.len != sizeof(cell_t))
|
||
|
- FAIL(c, "\"%s\" property in %s is not a single cell",
|
||
|
+ FAIL(c, dti, "\"%s\" property in %s is not a single cell",
|
||
|
propname, node->fullpath);
|
||
|
}
|
||
|
#define WARNING_IF_NOT_CELL(nm, propname) \
|
||
|
@@ -213,7 +212,7 @@ static void check_duplicate_node_names(struct check *c, struct dt_info *dti,
|
||
|
child2;
|
||
|
child2 = child2->next_sibling)
|
||
|
if (streq(child->name, child2->name))
|
||
|
- FAIL(c, "Duplicate node name %s",
|
||
|
+ FAIL(c, dti, "Duplicate node name %s",
|
||
|
child->fullpath);
|
||
|
}
|
||
|
ERROR(duplicate_node_names, check_duplicate_node_names, NULL);
|
||
|
@@ -228,7 +227,7 @@ static void check_duplicate_property_names(struct check *c, struct dt_info *dti,
|
||
|
if (prop2->deleted)
|
||
|
continue;
|
||
|
if (streq(prop->name, prop2->name))
|
||
|
- FAIL(c, "Duplicate property name %s in %s",
|
||
|
+ FAIL(c, dti, "Duplicate property name %s in %s",
|
||
|
prop->name, node->fullpath);
|
||
|
}
|
||
|
}
|
||
|
@@ -239,6 +238,7 @@ static void check_duplicate_property_names(struct check *c, struct dt_info *dti,
|
||
|
#define UPPERCASE "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||
|
#define DIGITS "0123456789"
|
||
|
#define PROPNODECHARS LOWERCASE UPPERCASE DIGITS ",._+*#?-"
|
||
|
+#define PROPNODECHARSSTRICT LOWERCASE UPPERCASE DIGITS ",-"
|
||
|
|
||
|
static void check_node_name_chars(struct check *c, struct dt_info *dti,
|
||
|
struct node *node)
|
||
|
@@ -246,16 +246,27 @@ static void check_node_name_chars(struct check *c, struct dt_info *dti,
|
||
|
int n = strspn(node->name, c->data);
|
||
|
|
||
|
if (n < strlen(node->name))
|
||
|
- FAIL(c, "Bad character '%c' in node %s",
|
||
|
+ FAIL(c, dti, "Bad character '%c' in node %s",
|
||
|
node->name[n], node->fullpath);
|
||
|
}
|
||
|
ERROR(node_name_chars, check_node_name_chars, PROPNODECHARS "@");
|
||
|
|
||
|
+static void check_node_name_chars_strict(struct check *c, struct dt_info *dti,
|
||
|
+ struct node *node)
|
||
|
+{
|
||
|
+ int n = strspn(node->name, c->data);
|
||
|
+
|
||
|
+ if (n < node->basenamelen)
|
||
|
+ FAIL(c, dti, "Character '%c' not recommended in node %s",
|
||
|
+ node->name[n], node->fullpath);
|
||
|
+}
|
||
|
+CHECK(node_name_chars_strict, check_node_name_chars_strict, PROPNODECHARSSTRICT);
|
||
|
+
|
||
|
static void check_node_name_format(struct check *c, struct dt_info *dti,
|
||
|
struct node *node)
|
||
|
{
|
||
|
if (strchr(get_unitname(node), '@'))
|
||
|
- FAIL(c, "Node %s has multiple '@' characters in name",
|
||
|
+ FAIL(c, dti, "Node %s has multiple '@' characters in name",
|
||
|
node->fullpath);
|
||
|
}
|
||
|
ERROR(node_name_format, check_node_name_format, NULL, &node_name_chars);
|
||
|
@@ -274,11 +285,11 @@ static void check_unit_address_vs_reg(struct check *c, struct dt_info *dti,
|
||
|
|
||
|
if (prop) {
|
||
|
if (!unitname[0])
|
||
|
- FAIL(c, "Node %s has a reg or ranges property, but no unit name",
|
||
|
+ FAIL(c, dti, "Node %s has a reg or ranges property, but no unit name",
|
||
|
node->fullpath);
|
||
|
} else {
|
||
|
if (unitname[0])
|
||
|
- FAIL(c, "Node %s has a unit name, but no reg property",
|
||
|
+ FAIL(c, dti, "Node %s has a unit name, but no reg property",
|
||
|
node->fullpath);
|
||
|
}
|
||
|
}
|
||
|
@@ -293,12 +304,44 @@ static void check_property_name_chars(struct check *c, struct dt_info *dti,
|
||
|
int n = strspn(prop->name, c->data);
|
||
|
|
||
|
if (n < strlen(prop->name))
|
||
|
- FAIL(c, "Bad character '%c' in property name \"%s\", node %s",
|
||
|
+ FAIL(c, dti, "Bad character '%c' in property name \"%s\", node %s",
|
||
|
prop->name[n], prop->name, node->fullpath);
|
||
|
}
|
||
|
}
|
||
|
ERROR(property_name_chars, check_property_name_chars, PROPNODECHARS);
|
||
|
|
||
|
+static void check_property_name_chars_strict(struct check *c,
|
||
|
+ struct dt_info *dti,
|
||
|
+ struct node *node)
|
||
|
+{
|
||
|
+ struct property *prop;
|
||
|
+
|
||
|
+ for_each_property(node, prop) {
|
||
|
+ const char *name = prop->name;
|
||
|
+ int n = strspn(name, c->data);
|
||
|
+
|
||
|
+ if (n == strlen(prop->name))
|
||
|
+ continue;
|
||
|
+
|
||
|
+ /* Certain names are whitelisted */
|
||
|
+ if (streq(name, "device_type"))
|
||
|
+ continue;
|
||
|
+
|
||
|
+ /*
|
||
|
+ * # is only allowed at the beginning of property names not counting
|
||
|
+ * the vendor prefix.
|
||
|
+ */
|
||
|
+ if (name[n] == '#' && ((n == 0) || (name[n-1] == ','))) {
|
||
|
+ name += n + 1;
|
||
|
+ n = strspn(name, c->data);
|
||
|
+ }
|
||
|
+ if (n < strlen(name))
|
||
|
+ FAIL(c, dti, "Character '%c' not recommended in property name \"%s\", node %s",
|
||
|
+ name[n], prop->name, node->fullpath);
|
||
|
+ }
|
||
|
+}
|
||
|
+CHECK(property_name_chars_strict, check_property_name_chars_strict, PROPNODECHARSSTRICT);
|
||
|
+
|
||
|
#define DESCLABEL_FMT "%s%s%s%s%s"
|
||
|
#define DESCLABEL_ARGS(node,prop,mark) \
|
||
|
((mark) ? "value of " : ""), \
|
||
|
@@ -327,7 +370,7 @@ static void check_duplicate_label(struct check *c, struct dt_info *dti,
|
||
|
return;
|
||
|
|
||
|
if ((othernode != node) || (otherprop != prop) || (othermark != mark))
|
||
|
- FAIL(c, "Duplicate label '%s' on " DESCLABEL_FMT
|
||
|
+ FAIL(c, dti, "Duplicate label '%s' on " DESCLABEL_FMT
|
||
|
" and " DESCLABEL_FMT,
|
||
|
label, DESCLABEL_ARGS(node, prop, mark),
|
||
|
DESCLABEL_ARGS(othernode, otherprop, othermark));
|
||
|
@@ -367,7 +410,7 @@ static cell_t check_phandle_prop(struct check *c, struct dt_info *dti,
|
||
|
return 0;
|
||
|
|
||
|
if (prop->val.len != sizeof(cell_t)) {
|
||
|
- FAIL(c, "%s has bad length (%d) %s property",
|
||
|
+ FAIL(c, dti, "%s has bad length (%d) %s property",
|
||
|
node->fullpath, prop->val.len, prop->name);
|
||
|
return 0;
|
||
|
}
|
||
|
@@ -379,7 +422,7 @@ static cell_t check_phandle_prop(struct check *c, struct dt_info *dti,
|
||
|
/* "Set this node's phandle equal to some
|
||
|
* other node's phandle". That's nonsensical
|
||
|
* by construction. */ {
|
||
|
- FAIL(c, "%s in %s is a reference to another node",
|
||
|
+ FAIL(c, dti, "%s in %s is a reference to another node",
|
||
|
prop->name, node->fullpath);
|
||
|
}
|
||
|
/* But setting this node's phandle equal to its own
|
||
|
@@ -393,7 +436,7 @@ static cell_t check_phandle_prop(struct check *c, struct dt_info *dti,
|
||
|
phandle = propval_cell(prop);
|
||
|
|
||
|
if ((phandle == 0) || (phandle == -1)) {
|
||
|
- FAIL(c, "%s has bad value (0x%x) in %s property",
|
||
|
+ FAIL(c, dti, "%s has bad value (0x%x) in %s property",
|
||
|
node->fullpath, phandle, prop->name);
|
||
|
return 0;
|
||
|
}
|
||
|
@@ -420,7 +463,7 @@ static void check_explicit_phandles(struct check *c, struct dt_info *dti,
|
||
|
return;
|
||
|
|
||
|
if (linux_phandle && phandle && (phandle != linux_phandle))
|
||
|
- FAIL(c, "%s has mismatching 'phandle' and 'linux,phandle'"
|
||
|
+ FAIL(c, dti, "%s has mismatching 'phandle' and 'linux,phandle'"
|
||
|
" properties", node->fullpath);
|
||
|
|
||
|
if (linux_phandle && !phandle)
|
||
|
@@ -428,7 +471,7 @@ static void check_explicit_phandles(struct check *c, struct dt_info *dti,
|
||
|
|
||
|
other = get_node_by_phandle(root, phandle);
|
||
|
if (other && (other != node)) {
|
||
|
- FAIL(c, "%s has duplicated phandle 0x%x (seen before at %s)",
|
||
|
+ FAIL(c, dti, "%s has duplicated phandle 0x%x (seen before at %s)",
|
||
|
node->fullpath, phandle, other->fullpath);
|
||
|
return;
|
||
|
}
|
||
|
@@ -453,7 +496,7 @@ static void check_name_properties(struct check *c, struct dt_info *dti,
|
||
|
|
||
|
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"
|
||
|
+ FAIL(c, dti, "\"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.
|
||
|
@@ -488,16 +531,16 @@ static void fixup_phandle_references(struct check *c, struct dt_info *dti,
|
||
|
refnode = get_node_by_ref(dt, m->ref);
|
||
|
if (! refnode) {
|
||
|
if (!(dti->dtsflags & DTSF_PLUGIN))
|
||
|
- FAIL(c, "Reference to non-existent node or "
|
||
|
+ FAIL(c, dti, "Reference to non-existent node or "
|
||
|
"label \"%s\"\n", m->ref);
|
||
|
else /* mark the entry as unresolved */
|
||
|
- *((cell_t *)(prop->val.val + m->offset)) =
|
||
|
+ *((fdt32_t *)(prop->val.val + m->offset)) =
|
||
|
cpu_to_fdt32(0xffffffff);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
phandle = get_node_phandle(dt, refnode);
|
||
|
- *((cell_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle);
|
||
|
+ *((fdt32_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
@@ -520,7 +563,7 @@ static void fixup_path_references(struct check *c, struct dt_info *dti,
|
||
|
|
||
|
refnode = get_node_by_ref(dt, m->ref);
|
||
|
if (!refnode) {
|
||
|
- FAIL(c, "Reference to non-existent node or label \"%s\"\n",
|
||
|
+ FAIL(c, dti, "Reference to non-existent node or label \"%s\"\n",
|
||
|
m->ref);
|
||
|
continue;
|
||
|
}
|
||
|
@@ -579,19 +622,19 @@ static void check_reg_format(struct check *c, struct dt_info *dti,
|
||
|
return; /* No "reg", that's fine */
|
||
|
|
||
|
if (!node->parent) {
|
||
|
- FAIL(c, "Root node has a \"reg\" property");
|
||
|
+ FAIL(c, dti, "Root node has a \"reg\" property");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (prop->val.len == 0)
|
||
|
- FAIL(c, "\"reg\" property in %s is empty", node->fullpath);
|
||
|
+ FAIL(c, dti, "\"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 (!entrylen || (prop->val.len % entrylen) != 0)
|
||
|
- FAIL(c, "\"reg\" property in %s has invalid length (%d bytes) "
|
||
|
+ FAIL(c, dti, "\"reg\" property in %s has invalid length (%d bytes) "
|
||
|
"(#address-cells == %d, #size-cells == %d)",
|
||
|
node->fullpath, prop->val.len, addr_cells, size_cells);
|
||
|
}
|
||
|
@@ -608,7 +651,7 @@ static void check_ranges_format(struct check *c, struct dt_info *dti,
|
||
|
return;
|
||
|
|
||
|
if (!node->parent) {
|
||
|
- FAIL(c, "Root node has a \"ranges\" property");
|
||
|
+ FAIL(c, dti, "Root node has a \"ranges\" property");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
@@ -620,17 +663,17 @@ static void check_ranges_format(struct check *c, struct dt_info *dti,
|
||
|
|
||
|
if (prop->val.len == 0) {
|
||
|
if (p_addr_cells != c_addr_cells)
|
||
|
- FAIL(c, "%s has empty \"ranges\" property but its "
|
||
|
+ FAIL(c, dti, "%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 "
|
||
|
+ FAIL(c, dti, "%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) "
|
||
|
+ FAIL(c, dti, "\"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);
|
||
|
@@ -638,6 +681,229 @@ static void check_ranges_format(struct check *c, struct dt_info *dti,
|
||
|
}
|
||
|
WARNING(ranges_format, check_ranges_format, NULL, &addr_size_cells);
|
||
|
|
||
|
+static const struct bus_type pci_bus = {
|
||
|
+ .name = "PCI",
|
||
|
+};
|
||
|
+
|
||
|
+static void check_pci_bridge(struct check *c, struct dt_info *dti, struct node *node)
|
||
|
+{
|
||
|
+ struct property *prop;
|
||
|
+ cell_t *cells;
|
||
|
+
|
||
|
+ prop = get_property(node, "device_type");
|
||
|
+ if (!prop || !streq(prop->val.val, "pci"))
|
||
|
+ return;
|
||
|
+
|
||
|
+ node->bus = &pci_bus;
|
||
|
+
|
||
|
+ if (!strneq(node->name, "pci", node->basenamelen) &&
|
||
|
+ !strneq(node->name, "pcie", node->basenamelen))
|
||
|
+ FAIL(c, dti, "Node %s node name is not \"pci\" or \"pcie\"",
|
||
|
+ node->fullpath);
|
||
|
+
|
||
|
+ prop = get_property(node, "ranges");
|
||
|
+ if (!prop)
|
||
|
+ FAIL(c, dti, "Node %s missing ranges for PCI bridge (or not a bridge)",
|
||
|
+ node->fullpath);
|
||
|
+
|
||
|
+ if (node_addr_cells(node) != 3)
|
||
|
+ FAIL(c, dti, "Node %s incorrect #address-cells for PCI bridge",
|
||
|
+ node->fullpath);
|
||
|
+ if (node_size_cells(node) != 2)
|
||
|
+ FAIL(c, dti, "Node %s incorrect #size-cells for PCI bridge",
|
||
|
+ node->fullpath);
|
||
|
+
|
||
|
+ prop = get_property(node, "bus-range");
|
||
|
+ if (!prop) {
|
||
|
+ FAIL(c, dti, "Node %s missing bus-range for PCI bridge",
|
||
|
+ node->fullpath);
|
||
|
+ return;
|
||
|
+ }
|
||
|
+ if (prop->val.len != (sizeof(cell_t) * 2)) {
|
||
|
+ FAIL(c, dti, "Node %s bus-range must be 2 cells",
|
||
|
+ node->fullpath);
|
||
|
+ return;
|
||
|
+ }
|
||
|
+ cells = (cell_t *)prop->val.val;
|
||
|
+ if (fdt32_to_cpu(cells[0]) > fdt32_to_cpu(cells[1]))
|
||
|
+ FAIL(c, dti, "Node %s bus-range 1st cell must be less than or equal to 2nd cell",
|
||
|
+ node->fullpath);
|
||
|
+ if (fdt32_to_cpu(cells[1]) > 0xff)
|
||
|
+ FAIL(c, dti, "Node %s bus-range maximum bus number must be less than 256",
|
||
|
+ node->fullpath);
|
||
|
+}
|
||
|
+WARNING(pci_bridge, check_pci_bridge, NULL,
|
||
|
+ &device_type_is_string, &addr_size_cells);
|
||
|
+
|
||
|
+static void check_pci_device_bus_num(struct check *c, struct dt_info *dti, struct node *node)
|
||
|
+{
|
||
|
+ struct property *prop;
|
||
|
+ unsigned int bus_num, min_bus, max_bus;
|
||
|
+ cell_t *cells;
|
||
|
+
|
||
|
+ if (!node->parent || (node->parent->bus != &pci_bus))
|
||
|
+ return;
|
||
|
+
|
||
|
+ prop = get_property(node, "reg");
|
||
|
+ if (!prop)
|
||
|
+ return;
|
||
|
+
|
||
|
+ cells = (cell_t *)prop->val.val;
|
||
|
+ bus_num = (fdt32_to_cpu(cells[0]) & 0x00ff0000) >> 16;
|
||
|
+
|
||
|
+ prop = get_property(node->parent, "bus-range");
|
||
|
+ if (!prop) {
|
||
|
+ min_bus = max_bus = 0;
|
||
|
+ } else {
|
||
|
+ cells = (cell_t *)prop->val.val;
|
||
|
+ min_bus = fdt32_to_cpu(cells[0]);
|
||
|
+ max_bus = fdt32_to_cpu(cells[0]);
|
||
|
+ }
|
||
|
+ if ((bus_num < min_bus) || (bus_num > max_bus))
|
||
|
+ FAIL(c, dti, "Node %s PCI bus number %d out of range, expected (%d - %d)",
|
||
|
+ node->fullpath, bus_num, min_bus, max_bus);
|
||
|
+}
|
||
|
+WARNING(pci_device_bus_num, check_pci_device_bus_num, NULL, ®_format, &pci_bridge);
|
||
|
+
|
||
|
+static void check_pci_device_reg(struct check *c, struct dt_info *dti, struct node *node)
|
||
|
+{
|
||
|
+ struct property *prop;
|
||
|
+ const char *unitname = get_unitname(node);
|
||
|
+ char unit_addr[5];
|
||
|
+ unsigned int dev, func, reg;
|
||
|
+ cell_t *cells;
|
||
|
+
|
||
|
+ if (!node->parent || (node->parent->bus != &pci_bus))
|
||
|
+ return;
|
||
|
+
|
||
|
+ prop = get_property(node, "reg");
|
||
|
+ if (!prop) {
|
||
|
+ FAIL(c, dti, "Node %s missing PCI reg property", node->fullpath);
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ cells = (cell_t *)prop->val.val;
|
||
|
+ if (cells[1] || cells[2])
|
||
|
+ FAIL(c, dti, "Node %s PCI reg config space address cells 2 and 3 must be 0",
|
||
|
+ node->fullpath);
|
||
|
+
|
||
|
+ reg = fdt32_to_cpu(cells[0]);
|
||
|
+ dev = (reg & 0xf800) >> 11;
|
||
|
+ func = (reg & 0x700) >> 8;
|
||
|
+
|
||
|
+ if (reg & 0xff000000)
|
||
|
+ FAIL(c, dti, "Node %s PCI reg address is not configuration space",
|
||
|
+ node->fullpath);
|
||
|
+ if (reg & 0x000000ff)
|
||
|
+ FAIL(c, dti, "Node %s PCI reg config space address register number must be 0",
|
||
|
+ node->fullpath);
|
||
|
+
|
||
|
+ if (func == 0) {
|
||
|
+ snprintf(unit_addr, sizeof(unit_addr), "%x", dev);
|
||
|
+ if (streq(unitname, unit_addr))
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ snprintf(unit_addr, sizeof(unit_addr), "%x,%x", dev, func);
|
||
|
+ if (streq(unitname, unit_addr))
|
||
|
+ return;
|
||
|
+
|
||
|
+ FAIL(c, dti, "Node %s PCI unit address format error, expected \"%s\"",
|
||
|
+ node->fullpath, unit_addr);
|
||
|
+}
|
||
|
+WARNING(pci_device_reg, check_pci_device_reg, NULL, ®_format, &pci_bridge);
|
||
|
+
|
||
|
+static const struct bus_type simple_bus = {
|
||
|
+ .name = "simple-bus",
|
||
|
+};
|
||
|
+
|
||
|
+static bool node_is_compatible(struct node *node, const char *compat)
|
||
|
+{
|
||
|
+ struct property *prop;
|
||
|
+ const char *str, *end;
|
||
|
+
|
||
|
+ prop = get_property(node, "compatible");
|
||
|
+ if (!prop)
|
||
|
+ return false;
|
||
|
+
|
||
|
+ for (str = prop->val.val, end = str + prop->val.len; str < end;
|
||
|
+ str += strnlen(str, end - str) + 1) {
|
||
|
+ if (strneq(str, compat, end - str))
|
||
|
+ return true;
|
||
|
+ }
|
||
|
+ return false;
|
||
|
+}
|
||
|
+
|
||
|
+static void check_simple_bus_bridge(struct check *c, struct dt_info *dti, struct node *node)
|
||
|
+{
|
||
|
+ if (node_is_compatible(node, "simple-bus"))
|
||
|
+ node->bus = &simple_bus;
|
||
|
+}
|
||
|
+WARNING(simple_bus_bridge, check_simple_bus_bridge, NULL, &addr_size_cells);
|
||
|
+
|
||
|
+static void check_simple_bus_reg(struct check *c, struct dt_info *dti, struct node *node)
|
||
|
+{
|
||
|
+ struct property *prop;
|
||
|
+ const char *unitname = get_unitname(node);
|
||
|
+ char unit_addr[17];
|
||
|
+ unsigned int size;
|
||
|
+ uint64_t reg = 0;
|
||
|
+ cell_t *cells = NULL;
|
||
|
+
|
||
|
+ if (!node->parent || (node->parent->bus != &simple_bus))
|
||
|
+ return;
|
||
|
+
|
||
|
+ prop = get_property(node, "reg");
|
||
|
+ if (prop)
|
||
|
+ cells = (cell_t *)prop->val.val;
|
||
|
+ else {
|
||
|
+ prop = get_property(node, "ranges");
|
||
|
+ if (prop && prop->val.len)
|
||
|
+ /* skip of child address */
|
||
|
+ cells = ((cell_t *)prop->val.val) + node_addr_cells(node);
|
||
|
+ }
|
||
|
+
|
||
|
+ if (!cells) {
|
||
|
+ if (node->parent->parent && !(node->bus == &simple_bus))
|
||
|
+ FAIL(c, dti, "Node %s missing or empty reg/ranges property", node->fullpath);
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ size = node_addr_cells(node->parent);
|
||
|
+ while (size--)
|
||
|
+ reg = (reg << 32) | fdt32_to_cpu(*(cells++));
|
||
|
+
|
||
|
+ snprintf(unit_addr, sizeof(unit_addr), "%lx", reg);
|
||
|
+ if (!streq(unitname, unit_addr))
|
||
|
+ FAIL(c, dti, "Node %s simple-bus unit address format error, expected \"%s\"",
|
||
|
+ node->fullpath, unit_addr);
|
||
|
+}
|
||
|
+WARNING(simple_bus_reg, check_simple_bus_reg, NULL, ®_format, &simple_bus_bridge);
|
||
|
+
|
||
|
+static void check_unit_address_format(struct check *c, struct dt_info *dti,
|
||
|
+ struct node *node)
|
||
|
+{
|
||
|
+ const char *unitname = get_unitname(node);
|
||
|
+
|
||
|
+ if (node->parent && node->parent->bus)
|
||
|
+ return;
|
||
|
+
|
||
|
+ if (!unitname[0])
|
||
|
+ return;
|
||
|
+
|
||
|
+ if (!strncmp(unitname, "0x", 2)) {
|
||
|
+ FAIL(c, dti, "Node %s unit name should not have leading \"0x\"",
|
||
|
+ node->fullpath);
|
||
|
+ /* skip over 0x for next test */
|
||
|
+ unitname += 2;
|
||
|
+ }
|
||
|
+ if (unitname[0] == '0' && isxdigit(unitname[1]))
|
||
|
+ FAIL(c, dti, "Node %s unit name should not have leading 0s",
|
||
|
+ node->fullpath);
|
||
|
+}
|
||
|
+WARNING(unit_address_format, check_unit_address_format, NULL,
|
||
|
+ &node_name_format, &pci_bridge, &simple_bus_bridge);
|
||
|
+
|
||
|
/*
|
||
|
* Style checks
|
||
|
*/
|
||
|
@@ -656,11 +922,11 @@ static void check_avoid_default_addr_size(struct check *c, struct dt_info *dti,
|
||
|
return;
|
||
|
|
||
|
if (node->parent->addr_cells == -1)
|
||
|
- FAIL(c, "Relying on default #address-cells value for %s",
|
||
|
+ FAIL(c, dti, "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",
|
||
|
+ FAIL(c, dti, "Relying on default #size-cells value for %s",
|
||
|
node->fullpath);
|
||
|
}
|
||
|
WARNING(avoid_default_addr_size, check_avoid_default_addr_size, NULL,
|
||
|
@@ -684,7 +950,7 @@ static void check_obsolete_chosen_interrupt_controller(struct check *c,
|
||
|
|
||
|
prop = get_property(chosen, "interrupt-controller");
|
||
|
if (prop)
|
||
|
- FAIL(c, "/chosen has obsolete \"interrupt-controller\" "
|
||
|
+ FAIL(c, dti, "/chosen has obsolete \"interrupt-controller\" "
|
||
|
"property");
|
||
|
}
|
||
|
WARNING(obsolete_chosen_interrupt_controller,
|
||
|
@@ -703,9 +969,20 @@ static void check_obsolete_chosen_interrupt_controller(struct check *c,
|
||
|
&address_cells_is_cell, &size_cells_is_cell, &interrupt_cells_is_cell,
|
||
|
&device_type_is_string, &model_is_string, &status_is_string,
|
||
|
|
||
|
+ &property_name_chars_strict,
|
||
|
+ &node_name_chars_strict,
|
||
|
+
|
||
|
&addr_size_cells, ®_format, &ranges_format,
|
||
|
|
||
|
&unit_address_vs_reg,
|
||
|
+ &unit_address_format,
|
||
|
+
|
||
|
+ &pci_bridge,
|
||
|
+ &pci_device_reg,
|
||
|
+ &pci_device_bus_num,
|
||
|
+
|
||
|
+ &simple_bus_bridge,
|
||
|
+ &simple_bus_reg,
|
||
|
|
||
|
&avoid_default_addr_size,
|
||
|
&obsolete_chosen_interrupt_controller,
|
||
|
diff --git a/scripts/dtc/data.c b/scripts/dtc/data.c
|
||
|
index 8cae237..aa37a16 100644
|
||
|
--- a/scripts/dtc/data.c
|
||
|
+++ b/scripts/dtc/data.c
|
||
|
@@ -171,9 +171,9 @@ struct data data_merge(struct data d1, struct data d2)
|
||
|
struct data data_append_integer(struct data d, uint64_t value, int bits)
|
||
|
{
|
||
|
uint8_t value_8;
|
||
|
- uint16_t value_16;
|
||
|
- uint32_t value_32;
|
||
|
- uint64_t value_64;
|
||
|
+ fdt16_t value_16;
|
||
|
+ fdt32_t value_32;
|
||
|
+ fdt64_t value_64;
|
||
|
|
||
|
switch (bits) {
|
||
|
case 8:
|
||
|
@@ -197,14 +197,14 @@ struct data data_append_integer(struct data d, uint64_t value, int bits)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
-struct data data_append_re(struct data d, const struct fdt_reserve_entry *re)
|
||
|
+struct data data_append_re(struct data d, uint64_t address, uint64_t size)
|
||
|
{
|
||
|
- struct fdt_reserve_entry bere;
|
||
|
+ struct fdt_reserve_entry re;
|
||
|
|
||
|
- bere.address = cpu_to_fdt64(re->address);
|
||
|
- bere.size = cpu_to_fdt64(re->size);
|
||
|
+ re.address = cpu_to_fdt64(address);
|
||
|
+ re.size = cpu_to_fdt64(size);
|
||
|
|
||
|
- return data_append_data(d, &bere, sizeof(bere));
|
||
|
+ return data_append_data(d, &re, sizeof(re));
|
||
|
}
|
||
|
|
||
|
struct data data_append_cell(struct data d, cell_t word)
|
||
|
diff --git a/scripts/dtc/dtc-lexer.l b/scripts/dtc/dtc-lexer.l
|
||
|
index c600603..fd825eb 100644
|
||
|
--- a/scripts/dtc/dtc-lexer.l
|
||
|
+++ b/scripts/dtc/dtc-lexer.l
|
||
|
@@ -62,7 +62,8 @@ static int dts_version = 1;
|
||
|
|
||
|
static void push_input_file(const char *filename);
|
||
|
static bool pop_input_file(void);
|
||
|
-static void lexical_error(const char *fmt, ...);
|
||
|
+static void PRINTF(1, 2) lexical_error(const char *fmt, ...);
|
||
|
+
|
||
|
%}
|
||
|
|
||
|
%%
|
||
|
diff --git a/scripts/dtc/dtc-parser.y b/scripts/dtc/dtc-parser.y
|
||
|
index b2fd4d1..ca3f500 100644
|
||
|
--- a/scripts/dtc/dtc-parser.y
|
||
|
+++ b/scripts/dtc/dtc-parser.y
|
||
|
@@ -171,10 +171,10 @@ devicetree:
|
||
|
{
|
||
|
struct node *target = get_node_by_ref($1, $3);
|
||
|
|
||
|
- add_label(&target->labels, $2);
|
||
|
- if (target)
|
||
|
+ if (target) {
|
||
|
+ add_label(&target->labels, $2);
|
||
|
merge_nodes(target, $4);
|
||
|
- else
|
||
|
+ } else
|
||
|
ERROR(&@3, "Label or path %s not found", $3);
|
||
|
$$ = $1;
|
||
|
}
|
||
|
diff --git a/scripts/dtc/dtc.c b/scripts/dtc/dtc.c
|
||
|
index a4edf4c..f5eed9d 100644
|
||
|
--- a/scripts/dtc/dtc.c
|
||
|
+++ b/scripts/dtc/dtc.c
|
||
|
@@ -138,7 +138,7 @@ static const char *guess_type_by_name(const char *fname, const char *fallback)
|
||
|
static const char *guess_input_format(const char *fname, const char *fallback)
|
||
|
{
|
||
|
struct stat statbuf;
|
||
|
- uint32_t magic;
|
||
|
+ fdt32_t magic;
|
||
|
FILE *f;
|
||
|
|
||
|
if (stat(fname, &statbuf) != 0)
|
||
|
@@ -159,8 +159,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 (fdt32_to_cpu(magic) == FDT_MAGIC)
|
||
|
return "dtb";
|
||
|
|
||
|
return guess_type_by_name(fname, fallback);
|
||
|
@@ -216,7 +215,7 @@ int main(int argc, char *argv[])
|
||
|
alignsize = strtol(optarg, NULL, 0);
|
||
|
if (!is_power_of_2(alignsize))
|
||
|
die("Invalid argument \"%d\" to -a option\n",
|
||
|
- optarg);
|
||
|
+ alignsize);
|
||
|
break;
|
||
|
case 'f':
|
||
|
force = true;
|
||
|
@@ -309,6 +308,8 @@ int main(int argc, char *argv[])
|
||
|
else
|
||
|
die("Unknown input format \"%s\"\n", inform);
|
||
|
|
||
|
+ dti->outname = outname;
|
||
|
+
|
||
|
if (depfile) {
|
||
|
fputc('\n', depfile);
|
||
|
fclose(depfile);
|
||
|
diff --git a/scripts/dtc/dtc.h b/scripts/dtc/dtc.h
|
||
|
index c6f125c..fc24e17 100644
|
||
|
--- a/scripts/dtc/dtc.h
|
||
|
+++ b/scripts/dtc/dtc.h
|
||
|
@@ -43,7 +43,6 @@
|
||
|
#define debug(...)
|
||
|
#endif
|
||
|
|
||
|
-
|
||
|
#define DEFAULT_FDT_VERSION 17
|
||
|
|
||
|
/*
|
||
|
@@ -114,7 +113,7 @@ struct data data_insert_at_marker(struct data d, struct marker *m,
|
||
|
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_integer(struct data d, uint64_t word, int bits);
|
||
|
-struct data data_append_re(struct data d, const struct fdt_reserve_entry *re);
|
||
|
+struct data data_append_re(struct data d, uint64_t address, uint64_t size);
|
||
|
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);
|
||
|
@@ -136,6 +135,10 @@ struct label {
|
||
|
struct label *next;
|
||
|
};
|
||
|
|
||
|
+struct bus_type {
|
||
|
+ const char *name;
|
||
|
+};
|
||
|
+
|
||
|
struct property {
|
||
|
bool deleted;
|
||
|
char *name;
|
||
|
@@ -162,6 +165,7 @@ struct node {
|
||
|
int addr_cells, size_cells;
|
||
|
|
||
|
struct label *labels;
|
||
|
+ const struct bus_type *bus;
|
||
|
};
|
||
|
|
||
|
#define for_each_label_withdel(l0, l) \
|
||
|
@@ -227,7 +231,7 @@ struct marker *get_marker_label(struct node *tree, const char *label,
|
||
|
/* Boot info (tree plus memreserve information */
|
||
|
|
||
|
struct reserve_info {
|
||
|
- struct fdt_reserve_entry re;
|
||
|
+ uint64_t address, size;
|
||
|
|
||
|
struct reserve_info *next;
|
||
|
|
||
|
@@ -246,6 +250,7 @@ struct dt_info {
|
||
|
struct reserve_info *reservelist;
|
||
|
uint32_t boot_cpuid_phys;
|
||
|
struct node *dt; /* the device tree */
|
||
|
+ const char *outname; /* filename being written to, "-" for stdout */
|
||
|
};
|
||
|
|
||
|
/* DTS version flags definitions */
|
||
|
diff --git a/scripts/dtc/fdtdump.c b/scripts/dtc/fdtdump.c
|
||
|
index 207a46d..fa3b561 100644
|
||
|
--- a/scripts/dtc/fdtdump.c
|
||
|
+++ b/scripts/dtc/fdtdump.c
|
||
|
@@ -2,48 +2,49 @@
|
||
|
* fdtdump.c - Contributed by Pantelis Antoniou <pantelis.antoniou AT gmail.com>
|
||
|
*/
|
||
|
|
||
|
+#include <stdbool.h>
|
||
|
#include <stdint.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include <ctype.h>
|
||
|
|
||
|
-#include <fdt.h>
|
||
|
+#include <libfdt.h>
|
||
|
#include <libfdt_env.h>
|
||
|
+#include <fdt.h>
|
||
|
|
||
|
#include "util.h"
|
||
|
|
||
|
+#define FDT_MAGIC_SIZE 4
|
||
|
+#define MAX_VERSION 17
|
||
|
+
|
||
|
#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
|
||
|
#define PALIGN(p, a) ((void *)(ALIGN((unsigned long)(p), (a))))
|
||
|
-#define GET_CELL(p) (p += 4, *((const uint32_t *)(p-4)))
|
||
|
+#define GET_CELL(p) (p += 4, *((const fdt32_t *)(p-4)))
|
||
|
|
||
|
-static void print_data(const char *data, int len)
|
||
|
+static const char *tagname(uint32_t tag)
|
||
|
{
|
||
|
- int i;
|
||
|
- const char *p = data;
|
||
|
-
|
||
|
- /* no data, don't print */
|
||
|
- if (len == 0)
|
||
|
- return;
|
||
|
-
|
||
|
- if (util_is_printable_string(data, len)) {
|
||
|
- printf(" = \"%s\"", (const char *)data);
|
||
|
- } else if ((len % 4) == 0) {
|
||
|
- printf(" = <");
|
||
|
- for (i = 0; i < len; i += 4)
|
||
|
- printf("0x%08x%s", fdt32_to_cpu(GET_CELL(p)),
|
||
|
- i < (len - 4) ? " " : "");
|
||
|
- printf(">");
|
||
|
- } else {
|
||
|
- printf(" = [");
|
||
|
- for (i = 0; i < len; i++)
|
||
|
- printf("%02x%s", *p++, i < len - 1 ? " " : "");
|
||
|
- printf("]");
|
||
|
- }
|
||
|
+ static const char * const names[] = {
|
||
|
+#define TN(t) [t] = #t
|
||
|
+ TN(FDT_BEGIN_NODE),
|
||
|
+ TN(FDT_END_NODE),
|
||
|
+ TN(FDT_PROP),
|
||
|
+ TN(FDT_NOP),
|
||
|
+ TN(FDT_END),
|
||
|
+#undef TN
|
||
|
+ };
|
||
|
+ if (tag < ARRAY_SIZE(names))
|
||
|
+ if (names[tag])
|
||
|
+ return names[tag];
|
||
|
+ return "FDT_???";
|
||
|
}
|
||
|
|
||
|
-static void dump_blob(void *blob)
|
||
|
+#define dumpf(fmt, args...) \
|
||
|
+ do { if (debug) printf("// " fmt, ## args); } while (0)
|
||
|
+
|
||
|
+static void dump_blob(void *blob, bool debug)
|
||
|
{
|
||
|
+ uintptr_t blob_off = (uintptr_t)blob;
|
||
|
struct fdt_header *bph = blob;
|
||
|
uint32_t off_mem_rsvmap = fdt32_to_cpu(bph->off_mem_rsvmap);
|
||
|
uint32_t off_dt = fdt32_to_cpu(bph->off_dt_struct);
|
||
|
@@ -90,14 +91,15 @@ static void dump_blob(void *blob)
|
||
|
if (addr == 0 && size == 0)
|
||
|
break;
|
||
|
|
||
|
- printf("/memreserve/ %llx %llx;\n",
|
||
|
+ printf("/memreserve/ %#llx %#llx;\n",
|
||
|
(unsigned long long)addr, (unsigned long long)size);
|
||
|
}
|
||
|
|
||
|
p = p_struct;
|
||
|
while ((tag = fdt32_to_cpu(GET_CELL(p))) != FDT_END) {
|
||
|
|
||
|
- /* printf("tag: 0x%08x (%d)\n", tag, p - p_struct); */
|
||
|
+ dumpf("%04zx: tag: 0x%08x (%s)\n",
|
||
|
+ (uintptr_t)p - blob_off - 4, tag, tagname(tag));
|
||
|
|
||
|
if (tag == FDT_BEGIN_NODE) {
|
||
|
s = p;
|
||
|
@@ -136,27 +138,108 @@ static void dump_blob(void *blob)
|
||
|
|
||
|
p = PALIGN(p + sz, 4);
|
||
|
|
||
|
+ dumpf("%04zx: string: %s\n", (uintptr_t)s - blob_off, s);
|
||
|
+ dumpf("%04zx: value\n", (uintptr_t)t - blob_off);
|
||
|
printf("%*s%s", depth * shift, "", s);
|
||
|
- print_data(t, sz);
|
||
|
+ utilfdt_print_data(t, sz);
|
||
|
printf(";\n");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
+/* Usage related data. */
|
||
|
+static const char usage_synopsis[] = "fdtdump [options] <file>";
|
||
|
+static const char usage_short_opts[] = "ds" USAGE_COMMON_SHORT_OPTS;
|
||
|
+static struct option const usage_long_opts[] = {
|
||
|
+ {"debug", no_argument, NULL, 'd'},
|
||
|
+ {"scan", no_argument, NULL, 's'},
|
||
|
+ USAGE_COMMON_LONG_OPTS
|
||
|
+};
|
||
|
+static const char * const usage_opts_help[] = {
|
||
|
+ "Dump debug information while decoding the file",
|
||
|
+ "Scan for an embedded fdt in file",
|
||
|
+ USAGE_COMMON_OPTS_HELP
|
||
|
+};
|
||
|
+
|
||
|
+static bool valid_header(char *p, off_t len)
|
||
|
+{
|
||
|
+ if (len < sizeof(struct fdt_header) ||
|
||
|
+ fdt_magic(p) != FDT_MAGIC ||
|
||
|
+ fdt_version(p) > MAX_VERSION ||
|
||
|
+ fdt_last_comp_version(p) > MAX_VERSION ||
|
||
|
+ fdt_totalsize(p) >= len ||
|
||
|
+ fdt_off_dt_struct(p) >= len ||
|
||
|
+ fdt_off_dt_strings(p) >= len)
|
||
|
+ return 0;
|
||
|
+ else
|
||
|
+ return 1;
|
||
|
+}
|
||
|
|
||
|
int main(int argc, char *argv[])
|
||
|
{
|
||
|
+ int opt;
|
||
|
+ const char *file;
|
||
|
char *buf;
|
||
|
-
|
||
|
- if (argc < 2) {
|
||
|
- fprintf(stderr, "supply input filename\n");
|
||
|
- return 5;
|
||
|
+ bool debug = false;
|
||
|
+ bool scan = false;
|
||
|
+ off_t len;
|
||
|
+
|
||
|
+ fprintf(stderr, "\n"
|
||
|
+"**** fdtdump is a low-level debugging tool, not meant for general use.\n"
|
||
|
+"**** If you want to decompile a dtb, you probably want\n"
|
||
|
+"**** dtc -I dtb -O dts <filename>\n\n"
|
||
|
+ );
|
||
|
+ while ((opt = util_getopt_long()) != EOF) {
|
||
|
+ switch (opt) {
|
||
|
+ case_USAGE_COMMON_FLAGS
|
||
|
+
|
||
|
+ case 'd':
|
||
|
+ debug = true;
|
||
|
+ break;
|
||
|
+ case 's':
|
||
|
+ scan = true;
|
||
|
+ break;
|
||
|
+ }
|
||
|
}
|
||
|
-
|
||
|
- buf = utilfdt_read(argv[1]);
|
||
|
- if (buf)
|
||
|
- dump_blob(buf);
|
||
|
- else
|
||
|
- return 10;
|
||
|
+ if (optind != argc - 1)
|
||
|
+ usage("missing input filename");
|
||
|
+ file = argv[optind];
|
||
|
+
|
||
|
+ buf = utilfdt_read_len(file, &len);
|
||
|
+ if (!buf)
|
||
|
+ die("could not read: %s\n", file);
|
||
|
+
|
||
|
+ /* try and locate an embedded fdt in a bigger blob */
|
||
|
+ if (scan) {
|
||
|
+ unsigned char smagic[FDT_MAGIC_SIZE];
|
||
|
+ char *p = buf;
|
||
|
+ char *endp = buf + len;
|
||
|
+
|
||
|
+ fdt_set_magic(smagic, FDT_MAGIC);
|
||
|
+
|
||
|
+ /* poor man's memmem */
|
||
|
+ while ((endp - p) >= FDT_MAGIC_SIZE) {
|
||
|
+ p = memchr(p, smagic[0], endp - p - FDT_MAGIC_SIZE);
|
||
|
+ if (!p)
|
||
|
+ break;
|
||
|
+ if (fdt_magic(p) == FDT_MAGIC) {
|
||
|
+ /* try and validate the main struct */
|
||
|
+ off_t this_len = endp - p;
|
||
|
+ if (valid_header(p, this_len))
|
||
|
+ break;
|
||
|
+ if (debug)
|
||
|
+ printf("%s: skipping fdt magic at offset %#zx\n",
|
||
|
+ file, p - buf);
|
||
|
+ }
|
||
|
+ ++p;
|
||
|
+ }
|
||
|
+ if (!p || endp - p < sizeof(struct fdt_header))
|
||
|
+ die("%s: could not locate fdt magic\n", file);
|
||
|
+ printf("%s: found fdt at offset %#zx\n", file, p - buf);
|
||
|
+ buf = p;
|
||
|
+ } else if (!valid_header(buf, len))
|
||
|
+ die("%s: header is not valid\n", file);
|
||
|
+
|
||
|
+ dump_blob(buf, debug);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
diff --git a/scripts/dtc/fdtget.c b/scripts/dtc/fdtget.c
|
||
|
index c2fbab2..39f1742 100644
|
||
|
--- a/scripts/dtc/fdtget.c
|
||
|
+++ b/scripts/dtc/fdtget.c
|
||
|
@@ -105,7 +105,7 @@ static int show_data(struct display_info *disp, const char *data, int len)
|
||
|
for (i = 0; i < len; i += size, p += size) {
|
||
|
if (i)
|
||
|
printf(" ");
|
||
|
- value = size == 4 ? fdt32_to_cpu(*(const uint32_t *)p) :
|
||
|
+ value = size == 4 ? fdt32_to_cpu(*(const fdt32_t *)p) :
|
||
|
size == 2 ? (*p << 8) | p[1] : *p;
|
||
|
printf(fmt, value);
|
||
|
}
|
||
|
@@ -245,7 +245,7 @@ static int show_data_for_item(const void *blob, struct display_info *disp,
|
||
|
* @param filename Filename of blob file
|
||
|
* @param arg List of arguments to process
|
||
|
* @param arg_count Number of arguments
|
||
|
- * @param return 0 if ok, -ve on error
|
||
|
+ * @return 0 if ok, -ve on error
|
||
|
*/
|
||
|
static int do_fdtget(struct display_info *disp, const char *filename,
|
||
|
char **arg, int arg_count, int args_per_step)
|
||
|
@@ -266,44 +266,50 @@ static int do_fdtget(struct display_info *disp, const char *filename,
|
||
|
continue;
|
||
|
} else {
|
||
|
report_error(arg[i], node);
|
||
|
+ free(blob);
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
prop = args_per_step == 1 ? NULL : arg[i + 1];
|
||
|
|
||
|
- if (show_data_for_item(blob, disp, node, prop))
|
||
|
+ if (show_data_for_item(blob, disp, node, prop)) {
|
||
|
+ free(blob);
|
||
|
return -1;
|
||
|
+ }
|
||
|
}
|
||
|
+
|
||
|
+ free(blob);
|
||
|
+
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
-static const char *usage_msg =
|
||
|
- "fdtget - read values from device tree\n"
|
||
|
- "\n"
|
||
|
- "Each value is printed on a new line.\n\n"
|
||
|
- "Usage:\n"
|
||
|
+/* Usage related data. */
|
||
|
+static const char usage_synopsis[] =
|
||
|
+ "read values from device tree\n"
|
||
|
" fdtget <options> <dt file> [<node> <property>]...\n"
|
||
|
" fdtget -p <options> <dt file> [<node> ]...\n"
|
||
|
- "Options:\n"
|
||
|
- "\t-t <type>\tType of data\n"
|
||
|
- "\t-p\t\tList properties for each node\n"
|
||
|
- "\t-l\t\tList subnodes for each node\n"
|
||
|
- "\t-d\t\tDefault value to display when the property is "
|
||
|
- "missing\n"
|
||
|
- "\t-h\t\tPrint this help\n\n"
|
||
|
+ "\n"
|
||
|
+ "Each value is printed on a new line.\n"
|
||
|
USAGE_TYPE_MSG;
|
||
|
-
|
||
|
-static void usage(const char *msg)
|
||
|
-{
|
||
|
- if (msg)
|
||
|
- fprintf(stderr, "Error: %s\n\n", msg);
|
||
|
-
|
||
|
- fprintf(stderr, "%s", usage_msg);
|
||
|
- exit(2);
|
||
|
-}
|
||
|
+static const char usage_short_opts[] = "t:pld:" USAGE_COMMON_SHORT_OPTS;
|
||
|
+static struct option const usage_long_opts[] = {
|
||
|
+ {"type", a_argument, NULL, 't'},
|
||
|
+ {"properties", no_argument, NULL, 'p'},
|
||
|
+ {"list", no_argument, NULL, 'l'},
|
||
|
+ {"default", a_argument, NULL, 'd'},
|
||
|
+ USAGE_COMMON_LONG_OPTS,
|
||
|
+};
|
||
|
+static const char * const usage_opts_help[] = {
|
||
|
+ "Type of data",
|
||
|
+ "List properties for each node",
|
||
|
+ "List subnodes for each node",
|
||
|
+ "Default value to display when the property is missing",
|
||
|
+ USAGE_COMMON_OPTS_HELP
|
||
|
+};
|
||
|
|
||
|
int main(int argc, char *argv[])
|
||
|
{
|
||
|
+ int opt;
|
||
|
char *filename = NULL;
|
||
|
struct display_info disp;
|
||
|
int args_per_step = 2;
|
||
|
@@ -312,20 +318,14 @@ int main(int argc, char *argv[])
|
||
|
memset(&disp, '\0', sizeof(disp));
|
||
|
disp.size = -1;
|
||
|
disp.mode = MODE_SHOW_VALUE;
|
||
|
- for (;;) {
|
||
|
- int c = getopt(argc, argv, "d:hlpt:");
|
||
|
- if (c == -1)
|
||
|
- break;
|
||
|
-
|
||
|
- switch (c) {
|
||
|
- case 'h':
|
||
|
- case '?':
|
||
|
- usage(NULL);
|
||
|
+ while ((opt = util_getopt_long()) != EOF) {
|
||
|
+ switch (opt) {
|
||
|
+ case_USAGE_COMMON_FLAGS
|
||
|
|
||
|
case 't':
|
||
|
if (utilfdt_decode_type(optarg, &disp.type,
|
||
|
&disp.size))
|
||
|
- usage("Invalid type string");
|
||
|
+ usage("invalid type string");
|
||
|
break;
|
||
|
|
||
|
case 'p':
|
||
|
@@ -347,7 +347,7 @@ int main(int argc, char *argv[])
|
||
|
if (optind < argc)
|
||
|
filename = argv[optind++];
|
||
|
if (!filename)
|
||
|
- usage("Missing filename");
|
||
|
+ usage("missing filename");
|
||
|
|
||
|
argv += optind;
|
||
|
argc -= optind;
|
||
|
@@ -358,7 +358,7 @@ int main(int argc, char *argv[])
|
||
|
|
||
|
/* Check for node, property arguments */
|
||
|
if (args_per_step == 2 && (argc % 2))
|
||
|
- usage("Must have an even number of arguments");
|
||
|
+ usage("must have an even number of arguments");
|
||
|
|
||
|
if (do_fdtget(&disp, filename, argv, argc, args_per_step))
|
||
|
return 1;
|
||
|
diff --git a/scripts/dtc/fdtput.c b/scripts/dtc/fdtput.c
|
||
|
index f2197f5..8d8e934 100644
|
||
|
--- a/scripts/dtc/fdtput.c
|
||
|
+++ b/scripts/dtc/fdtput.c
|
||
|
@@ -32,6 +32,8 @@
|
||
|
enum oper_type {
|
||
|
OPER_WRITE_PROP, /* Write a property in a node */
|
||
|
OPER_CREATE_NODE, /* Create a new node */
|
||
|
+ OPER_REMOVE_NODE, /* Delete a node */
|
||
|
+ OPER_DELETE_PROP, /* Delete a property in a node */
|
||
|
};
|
||
|
|
||
|
struct display_info {
|
||
|
@@ -65,7 +67,7 @@ static void report_error(const char *name, int namelen, int err)
|
||
|
* @param arg List of arguments from command line
|
||
|
* @param arg_count Number of arguments (may be 0)
|
||
|
* @param valuep Returns buffer containing value
|
||
|
- * @param *value_len Returns length of value encoded
|
||
|
+ * @param value_len Returns length of value encoded
|
||
|
*/
|
||
|
static int encode_value(struct display_info *disp, char **arg, int arg_count,
|
||
|
char **valuep, int *value_len)
|
||
|
@@ -96,12 +98,7 @@ static int encode_value(struct display_info *disp, char **arg, int arg_count,
|
||
|
/* enlarge our value buffer by a suitable margin if needed */
|
||
|
if (upto + len > value_size) {
|
||
|
value_size = (upto + len) + 500;
|
||
|
- value = realloc(value, value_size);
|
||
|
- if (!value) {
|
||
|
- fprintf(stderr, "Out of mmory: cannot alloc "
|
||
|
- "%d bytes\n", value_size);
|
||
|
- return -1;
|
||
|
- }
|
||
|
+ value = xrealloc(value, value_size);
|
||
|
}
|
||
|
|
||
|
ptr = value + upto;
|
||
|
@@ -110,7 +107,7 @@ static int encode_value(struct display_info *disp, char **arg, int arg_count,
|
||
|
if (disp->verbose)
|
||
|
fprintf(stderr, "\tstring: '%s'\n", ptr);
|
||
|
} else {
|
||
|
- int *iptr = (int *)ptr;
|
||
|
+ fdt32_t *iptr = (fdt32_t *)ptr;
|
||
|
sscanf(*arg, fmt, &ival);
|
||
|
if (len == 4)
|
||
|
*iptr = cpu_to_fdt32(ival);
|
||
|
@@ -131,19 +128,59 @@ static int encode_value(struct display_info *disp, char **arg, int arg_count,
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
-static int store_key_value(void *blob, const char *node_name,
|
||
|
+#define ALIGN(x) (((x) + (FDT_TAGSIZE) - 1) & ~((FDT_TAGSIZE) - 1))
|
||
|
+
|
||
|
+static char *_realloc_fdt(char *fdt, int delta)
|
||
|
+{
|
||
|
+ int new_sz = fdt_totalsize(fdt) + delta;
|
||
|
+ fdt = xrealloc(fdt, new_sz);
|
||
|
+ fdt_open_into(fdt, fdt, new_sz);
|
||
|
+ return fdt;
|
||
|
+}
|
||
|
+
|
||
|
+static char *realloc_node(char *fdt, const char *name)
|
||
|
+{
|
||
|
+ int delta;
|
||
|
+ /* FDT_BEGIN_NODE, node name in off_struct and FDT_END_NODE */
|
||
|
+ delta = sizeof(struct fdt_node_header) + ALIGN(strlen(name) + 1)
|
||
|
+ + FDT_TAGSIZE;
|
||
|
+ return _realloc_fdt(fdt, delta);
|
||
|
+}
|
||
|
+
|
||
|
+static char *realloc_property(char *fdt, int nodeoffset,
|
||
|
+ const char *name, int newlen)
|
||
|
+{
|
||
|
+ int delta = 0;
|
||
|
+ int oldlen = 0;
|
||
|
+
|
||
|
+ if (!fdt_get_property(fdt, nodeoffset, name, &oldlen))
|
||
|
+ /* strings + property header */
|
||
|
+ delta = sizeof(struct fdt_property) + strlen(name) + 1;
|
||
|
+
|
||
|
+ if (newlen > oldlen)
|
||
|
+ /* actual value in off_struct */
|
||
|
+ delta += ALIGN(newlen) - ALIGN(oldlen);
|
||
|
+
|
||
|
+ return _realloc_fdt(fdt, delta);
|
||
|
+}
|
||
|
+
|
||
|
+static int store_key_value(char **blob, const char *node_name,
|
||
|
const char *property, const char *buf, int len)
|
||
|
{
|
||
|
int node;
|
||
|
int err;
|
||
|
|
||
|
- node = fdt_path_offset(blob, node_name);
|
||
|
+ node = fdt_path_offset(*blob, node_name);
|
||
|
if (node < 0) {
|
||
|
report_error(node_name, -1, node);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
- err = fdt_setprop(blob, node, property, buf, len);
|
||
|
+ err = fdt_setprop(*blob, node, property, buf, len);
|
||
|
+ if (err == -FDT_ERR_NOSPACE) {
|
||
|
+ *blob = realloc_property(*blob, node, property, len);
|
||
|
+ err = fdt_setprop(*blob, node, property, buf, len);
|
||
|
+ }
|
||
|
if (err) {
|
||
|
report_error(property, -1, err);
|
||
|
return -1;
|
||
|
@@ -161,7 +198,7 @@ static int store_key_value(void *blob, const char *node_name,
|
||
|
* @param in_path Path to process
|
||
|
* @return 0 if ok, -1 on error
|
||
|
*/
|
||
|
-static int create_paths(void *blob, const char *in_path)
|
||
|
+static int create_paths(char **blob, const char *in_path)
|
||
|
{
|
||
|
const char *path = in_path;
|
||
|
const char *sep;
|
||
|
@@ -177,10 +214,11 @@ static int create_paths(void *blob, const char *in_path)
|
||
|
if (!sep)
|
||
|
sep = path + strlen(path);
|
||
|
|
||
|
- node = fdt_subnode_offset_namelen(blob, offset, path,
|
||
|
+ node = fdt_subnode_offset_namelen(*blob, offset, path,
|
||
|
sep - path);
|
||
|
if (node == -FDT_ERR_NOTFOUND) {
|
||
|
- node = fdt_add_subnode_namelen(blob, offset, path,
|
||
|
+ *blob = realloc_node(*blob, path);
|
||
|
+ node = fdt_add_subnode_namelen(*blob, offset, path,
|
||
|
sep - path);
|
||
|
}
|
||
|
if (node < 0) {
|
||
|
@@ -203,7 +241,7 @@ static int create_paths(void *blob, const char *in_path)
|
||
|
* @param node_name Name of node to create
|
||
|
* @return new node offset if found, or -1 on failure
|
||
|
*/
|
||
|
-static int create_node(void *blob, const char *node_name)
|
||
|
+static int create_node(char **blob, const char *node_name)
|
||
|
{
|
||
|
int node = 0;
|
||
|
char *p;
|
||
|
@@ -215,15 +253,17 @@ static int create_node(void *blob, const char *node_name)
|
||
|
}
|
||
|
*p = '\0';
|
||
|
|
||
|
+ *blob = realloc_node(*blob, p + 1);
|
||
|
+
|
||
|
if (p > node_name) {
|
||
|
- node = fdt_path_offset(blob, node_name);
|
||
|
+ node = fdt_path_offset(*blob, node_name);
|
||
|
if (node < 0) {
|
||
|
report_error(node_name, -1, node);
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- node = fdt_add_subnode(blob, node, p + 1);
|
||
|
+ node = fdt_add_subnode(*blob, node, p + 1);
|
||
|
if (node < 0) {
|
||
|
report_error(p + 1, -1, node);
|
||
|
return -1;
|
||
|
@@ -232,11 +272,65 @@ static int create_node(void *blob, const char *node_name)
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
+/**
|
||
|
+ * Delete a property of a node in the fdt.
|
||
|
+ *
|
||
|
+ * @param blob FDT blob to write into
|
||
|
+ * @param node_name Path to node containing the property to delete
|
||
|
+ * @param prop_name Name of property to delete
|
||
|
+ * @return 0 on success, or -1 on failure
|
||
|
+ */
|
||
|
+static int delete_prop(char *blob, const char *node_name, const char *prop_name)
|
||
|
+{
|
||
|
+ int node = 0;
|
||
|
+
|
||
|
+ node = fdt_path_offset(blob, node_name);
|
||
|
+ if (node < 0) {
|
||
|
+ report_error(node_name, -1, node);
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+
|
||
|
+ node = fdt_delprop(blob, node, prop_name);
|
||
|
+ if (node < 0) {
|
||
|
+ report_error(node_name, -1, node);
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Delete a node in the fdt.
|
||
|
+ *
|
||
|
+ * @param blob FDT blob to write into
|
||
|
+ * @param node_name Name of node to delete
|
||
|
+ * @return 0 on success, or -1 on failure
|
||
|
+ */
|
||
|
+static int delete_node(char *blob, const char *node_name)
|
||
|
+{
|
||
|
+ int node = 0;
|
||
|
+
|
||
|
+ node = fdt_path_offset(blob, node_name);
|
||
|
+ if (node < 0) {
|
||
|
+ report_error(node_name, -1, node);
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+
|
||
|
+ node = fdt_del_node(blob, node);
|
||
|
+ if (node < 0) {
|
||
|
+ report_error(node_name, -1, node);
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
static int do_fdtput(struct display_info *disp, const char *filename,
|
||
|
char **arg, int arg_count)
|
||
|
{
|
||
|
- char *value;
|
||
|
+ char *value = NULL;
|
||
|
char *blob;
|
||
|
+ char *node;
|
||
|
int len, ret = 0;
|
||
|
|
||
|
blob = utilfdt_read(filename);
|
||
|
@@ -250,82 +344,102 @@ static int do_fdtput(struct display_info *disp, const char *filename,
|
||
|
* store them into the property.
|
||
|
*/
|
||
|
assert(arg_count >= 2);
|
||
|
- if (disp->auto_path && create_paths(blob, *arg))
|
||
|
+ if (disp->auto_path && create_paths(&blob, *arg))
|
||
|
return -1;
|
||
|
if (encode_value(disp, arg + 2, arg_count - 2, &value, &len) ||
|
||
|
- store_key_value(blob, *arg, arg[1], value, len))
|
||
|
+ store_key_value(&blob, *arg, arg[1], value, len))
|
||
|
ret = -1;
|
||
|
break;
|
||
|
case OPER_CREATE_NODE:
|
||
|
for (; ret >= 0 && arg_count--; arg++) {
|
||
|
if (disp->auto_path)
|
||
|
- ret = create_paths(blob, *arg);
|
||
|
+ ret = create_paths(&blob, *arg);
|
||
|
else
|
||
|
- ret = create_node(blob, *arg);
|
||
|
+ ret = create_node(&blob, *arg);
|
||
|
}
|
||
|
break;
|
||
|
+ case OPER_REMOVE_NODE:
|
||
|
+ for (; ret >= 0 && arg_count--; arg++)
|
||
|
+ ret = delete_node(blob, *arg);
|
||
|
+ break;
|
||
|
+ case OPER_DELETE_PROP:
|
||
|
+ node = *arg;
|
||
|
+ for (arg++; ret >= 0 && arg_count-- > 1; arg++)
|
||
|
+ ret = delete_prop(blob, node, *arg);
|
||
|
+ break;
|
||
|
}
|
||
|
- if (ret >= 0)
|
||
|
+ if (ret >= 0) {
|
||
|
+ fdt_pack(blob);
|
||
|
ret = utilfdt_write(filename, blob);
|
||
|
+ }
|
||
|
|
||
|
free(blob);
|
||
|
+
|
||
|
+ if (value) {
|
||
|
+ free(value);
|
||
|
+ }
|
||
|
+
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
-static const char *usage_msg =
|
||
|
- "fdtput - write a property value to a device tree\n"
|
||
|
- "\n"
|
||
|
- "The command line arguments are joined together into a single value.\n"
|
||
|
- "\n"
|
||
|
- "Usage:\n"
|
||
|
+/* Usage related data. */
|
||
|
+static const char usage_synopsis[] =
|
||
|
+ "write a property value to a device tree\n"
|
||
|
" fdtput <options> <dt file> <node> <property> [<value>...]\n"
|
||
|
" fdtput -c <options> <dt file> [<node>...]\n"
|
||
|
- "Options:\n"
|
||
|
- "\t-c\t\tCreate nodes if they don't already exist\n"
|
||
|
- "\t-p\t\tAutomatically create nodes as needed for the node path\n"
|
||
|
- "\t-t <type>\tType of data\n"
|
||
|
- "\t-v\t\tVerbose: display each value decoded from command line\n"
|
||
|
- "\t-h\t\tPrint this help\n\n"
|
||
|
+ " fdtput -r <options> <dt file> [<node>...]\n"
|
||
|
+ " fdtput -d <options> <dt file> <node> [<property>...]\n"
|
||
|
+ "\n"
|
||
|
+ "The command line arguments are joined together into a single value.\n"
|
||
|
USAGE_TYPE_MSG;
|
||
|
-
|
||
|
-static void usage(const char *msg)
|
||
|
-{
|
||
|
- if (msg)
|
||
|
- fprintf(stderr, "Error: %s\n\n", msg);
|
||
|
-
|
||
|
- fprintf(stderr, "%s", usage_msg);
|
||
|
- exit(2);
|
||
|
-}
|
||
|
+static const char usage_short_opts[] = "crdpt:v" USAGE_COMMON_SHORT_OPTS;
|
||
|
+static struct option const usage_long_opts[] = {
|
||
|
+ {"create", no_argument, NULL, 'c'},
|
||
|
+ {"remove", no_argument, NULL, 'r'},
|
||
|
+ {"delete", no_argument, NULL, 'd'},
|
||
|
+ {"auto-path", no_argument, NULL, 'p'},
|
||
|
+ {"type", a_argument, NULL, 't'},
|
||
|
+ {"verbose", no_argument, NULL, 'v'},
|
||
|
+ USAGE_COMMON_LONG_OPTS,
|
||
|
+};
|
||
|
+static const char * const usage_opts_help[] = {
|
||
|
+ "Create nodes if they don't already exist",
|
||
|
+ "Delete nodes (and any subnodes) if they already exist",
|
||
|
+ "Delete properties if they already exist",
|
||
|
+ "Automatically create nodes as needed for the node path",
|
||
|
+ "Type of data",
|
||
|
+ "Display each value decoded from command line",
|
||
|
+ USAGE_COMMON_OPTS_HELP
|
||
|
+};
|
||
|
|
||
|
int main(int argc, char *argv[])
|
||
|
{
|
||
|
+ int opt;
|
||
|
struct display_info disp;
|
||
|
char *filename = NULL;
|
||
|
|
||
|
memset(&disp, '\0', sizeof(disp));
|
||
|
disp.size = -1;
|
||
|
disp.oper = OPER_WRITE_PROP;
|
||
|
- for (;;) {
|
||
|
- int c = getopt(argc, argv, "chpt:v");
|
||
|
- if (c == -1)
|
||
|
- break;
|
||
|
-
|
||
|
+ while ((opt = util_getopt_long()) != EOF) {
|
||
|
/*
|
||
|
* TODO: add options to:
|
||
|
- * - delete property
|
||
|
- * - delete node (optionally recursively)
|
||
|
* - rename node
|
||
|
* - pack fdt before writing
|
||
|
* - set amount of free space when writing
|
||
|
- * - expand fdt if value doesn't fit
|
||
|
*/
|
||
|
- switch (c) {
|
||
|
+ switch (opt) {
|
||
|
+ case_USAGE_COMMON_FLAGS
|
||
|
+
|
||
|
case 'c':
|
||
|
disp.oper = OPER_CREATE_NODE;
|
||
|
break;
|
||
|
- case 'h':
|
||
|
- case '?':
|
||
|
- usage(NULL);
|
||
|
+ case 'r':
|
||
|
+ disp.oper = OPER_REMOVE_NODE;
|
||
|
+ break;
|
||
|
+ case 'd':
|
||
|
+ disp.oper = OPER_DELETE_PROP;
|
||
|
+ break;
|
||
|
case 'p':
|
||
|
disp.auto_path = 1;
|
||
|
break;
|
||
|
@@ -344,18 +458,22 @@ int main(int argc, char *argv[])
|
||
|
if (optind < argc)
|
||
|
filename = argv[optind++];
|
||
|
if (!filename)
|
||
|
- usage("Missing filename");
|
||
|
+ usage("missing filename");
|
||
|
|
||
|
argv += optind;
|
||
|
argc -= optind;
|
||
|
|
||
|
if (disp.oper == OPER_WRITE_PROP) {
|
||
|
if (argc < 1)
|
||
|
- usage("Missing node");
|
||
|
+ usage("missing node");
|
||
|
if (argc < 2)
|
||
|
- usage("Missing property");
|
||
|
+ usage("missing property");
|
||
|
}
|
||
|
|
||
|
+ if (disp.oper == OPER_DELETE_PROP)
|
||
|
+ if (argc < 1)
|
||
|
+ usage("missing node");
|
||
|
+
|
||
|
if (do_fdtput(&disp, filename, argv, argc))
|
||
|
return 1;
|
||
|
return 0;
|
||
|
diff --git a/scripts/dtc/flattree.c b/scripts/dtc/flattree.c
|
||
|
index ebac548..fcf7154 100644
|
||
|
--- a/scripts/dtc/flattree.c
|
||
|
+++ b/scripts/dtc/flattree.c
|
||
|
@@ -49,7 +49,7 @@
|
||
|
|
||
|
struct emitter {
|
||
|
void (*cell)(void *, cell_t);
|
||
|
- void (*string)(void *, char *, int);
|
||
|
+ void (*string)(void *, const char *, int);
|
||
|
void (*align)(void *, int);
|
||
|
void (*data)(void *, struct data);
|
||
|
void (*beginnode)(void *, struct label *labels);
|
||
|
@@ -64,7 +64,7 @@ static void bin_emit_cell(void *e, cell_t val)
|
||
|
*dtbuf = data_append_cell(*dtbuf, val);
|
||
|
}
|
||
|
|
||
|
-static void bin_emit_string(void *e, char *str, int len)
|
||
|
+static void bin_emit_string(void *e, const char *str, int len)
|
||
|
{
|
||
|
struct data *dtbuf = e;
|
||
|
|
||
|
@@ -144,22 +144,14 @@ static void asm_emit_cell(void *e, cell_t val)
|
||
|
(val >> 8) & 0xff, val & 0xff);
|
||
|
}
|
||
|
|
||
|
-static void asm_emit_string(void *e, char *str, int len)
|
||
|
+static void asm_emit_string(void *e, const 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;
|
||
|
- }
|
||
|
+ if (len != 0)
|
||
|
+ fprintf(f, "\t.string\t\"%.*s\"\n", len, str);
|
||
|
+ else
|
||
|
+ fprintf(f, "\t.string\t\"%s\"\n", str);
|
||
|
}
|
||
|
|
||
|
static void asm_emit_align(void *e, int a)
|
||
|
@@ -179,7 +171,7 @@ static void asm_emit_data(void *e, struct data d)
|
||
|
emit_offset_label(f, m->ref, m->offset);
|
||
|
|
||
|
while ((d.len - off) >= sizeof(uint32_t)) {
|
||
|
- asm_emit_cell(e, fdt32_to_cpu(*((uint32_t *)(d.val+off))));
|
||
|
+ asm_emit_cell(e, fdt32_to_cpu(*((fdt32_t *)(d.val+off))));
|
||
|
off += sizeof(uint32_t);
|
||
|
}
|
||
|
|
||
|
@@ -318,17 +310,16 @@ static struct data flatten_reserve_list(struct reserve_info *reservelist,
|
||
|
{
|
||
|
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);
|
||
|
+ d = data_append_re(d, re->address, re->size);
|
||
|
}
|
||
|
/*
|
||
|
* Add additional reserved slots if the user asked for them.
|
||
|
*/
|
||
|
for (j = 0; j < reservenum; j++) {
|
||
|
- d = data_append_re(d, &null_re);
|
||
|
+ d = data_append_re(d, 0, 0);
|
||
|
}
|
||
|
|
||
|
return d;
|
||
|
@@ -544,11 +535,11 @@ void dt_to_asm(FILE *f, struct dt_info *dti, int version)
|
||
|
fprintf(f, "\t.globl\t%s\n", l->label);
|
||
|
fprintf(f, "%s:\n", l->label);
|
||
|
}
|
||
|
- ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->re.address >> 32));
|
||
|
+ ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->address >> 32));
|
||
|
ASM_EMIT_BELONG(f, "0x%08x",
|
||
|
- (unsigned int)(re->re.address & 0xffffffff));
|
||
|
- ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->re.size >> 32));
|
||
|
- ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->re.size & 0xffffffff));
|
||
|
+ (unsigned int)(re->address & 0xffffffff));
|
||
|
+ ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->size >> 32));
|
||
|
+ ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->size & 0xffffffff));
|
||
|
}
|
||
|
for (i = 0; i < reservenum; i++) {
|
||
|
fprintf(f, "\t.long\t0, 0\n\t.long\t0, 0\n");
|
||
|
@@ -609,7 +600,7 @@ static void flat_read_chunk(struct inbuf *inb, void *p, int len)
|
||
|
|
||
|
static uint32_t flat_read_word(struct inbuf *inb)
|
||
|
{
|
||
|
- uint32_t val;
|
||
|
+ fdt32_t val;
|
||
|
|
||
|
assert(((inb->ptr - inb->base) % sizeof(val)) == 0);
|
||
|
|
||
|
@@ -718,13 +709,15 @@ static struct reserve_info *flat_read_mem_reserve(struct inbuf *inb)
|
||
|
* First pass, count entries.
|
||
|
*/
|
||
|
while (1) {
|
||
|
+ uint64_t address, size;
|
||
|
+
|
||
|
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)
|
||
|
+ address = fdt64_to_cpu(re.address);
|
||
|
+ size = fdt64_to_cpu(re.size);
|
||
|
+ if (size == 0)
|
||
|
break;
|
||
|
|
||
|
- new = build_reserve_entry(re.address, re.size);
|
||
|
+ new = build_reserve_entry(address, size);
|
||
|
reservelist = add_reserve_entry(reservelist, new);
|
||
|
}
|
||
|
|
||
|
@@ -817,6 +810,7 @@ static struct node *unflatten_tree(struct inbuf *dtbuf,
|
||
|
struct dt_info *dt_from_blob(const char *fname)
|
||
|
{
|
||
|
FILE *f;
|
||
|
+ fdt32_t magic_buf, totalsize_buf;
|
||
|
uint32_t magic, totalsize, version, size_dt, boot_cpuid_phys;
|
||
|
uint32_t off_dt, off_str, off_mem_rsvmap;
|
||
|
int rc;
|
||
|
@@ -833,7 +827,7 @@ struct dt_info *dt_from_blob(const char *fname)
|
||
|
|
||
|
f = srcfile_relative_open(fname, NULL);
|
||
|
|
||
|
- rc = fread(&magic, sizeof(magic), 1, f);
|
||
|
+ rc = fread(&magic_buf, sizeof(magic_buf), 1, f);
|
||
|
if (ferror(f))
|
||
|
die("Error reading DT blob magic number: %s\n",
|
||
|
strerror(errno));
|
||
|
@@ -844,11 +838,11 @@ struct dt_info *dt_from_blob(const char *fname)
|
||
|
die("Mysterious short read reading magic number\n");
|
||
|
}
|
||
|
|
||
|
- magic = fdt32_to_cpu(magic);
|
||
|
+ magic = fdt32_to_cpu(magic_buf);
|
||
|
if (magic != FDT_MAGIC)
|
||
|
die("Blob has incorrect magic number\n");
|
||
|
|
||
|
- rc = fread(&totalsize, sizeof(totalsize), 1, f);
|
||
|
+ rc = fread(&totalsize_buf, sizeof(totalsize_buf), 1, f);
|
||
|
if (ferror(f))
|
||
|
die("Error reading DT blob size: %s\n", strerror(errno));
|
||
|
if (rc < 1) {
|
||
|
@@ -858,7 +852,7 @@ struct dt_info *dt_from_blob(const char *fname)
|
||
|
die("Mysterious short read reading blob size\n");
|
||
|
}
|
||
|
|
||
|
- totalsize = fdt32_to_cpu(totalsize);
|
||
|
+ totalsize = fdt32_to_cpu(totalsize_buf);
|
||
|
if (totalsize < FDT_V1_SIZE)
|
||
|
die("DT blob size (%d) is too small\n", totalsize);
|
||
|
|
||
|
diff --git a/scripts/dtc/libfdt/fdt_empty_tree.c b/scripts/dtc/libfdt/fdt_empty_tree.c
|
||
|
index f72d13b..f2ae9b7 100644
|
||
|
--- a/scripts/dtc/libfdt/fdt_empty_tree.c
|
||
|
+++ b/scripts/dtc/libfdt/fdt_empty_tree.c
|
||
|
@@ -81,4 +81,3 @@ int fdt_create_empty_tree(void *buf, int bufsize)
|
||
|
|
||
|
return fdt_open_into(buf, buf, bufsize);
|
||
|
}
|
||
|
-
|
||
|
diff --git a/scripts/dtc/libfdt/fdt_ro.c b/scripts/dtc/libfdt/fdt_ro.c
|
||
|
index 3d00d2e..08de2cc 100644
|
||
|
--- a/scripts/dtc/libfdt/fdt_ro.c
|
||
|
+++ b/scripts/dtc/libfdt/fdt_ro.c
|
||
|
@@ -60,7 +60,7 @@ static int _fdt_nodename_eq(const void *fdt, int offset,
|
||
|
{
|
||
|
const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1);
|
||
|
|
||
|
- if (! p)
|
||
|
+ if (!p)
|
||
|
/* short match */
|
||
|
return 0;
|
||
|
|
||
|
@@ -327,7 +327,7 @@ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
|
||
|
const struct fdt_property *prop;
|
||
|
|
||
|
prop = fdt_get_property_namelen(fdt, nodeoffset, name, namelen, lenp);
|
||
|
- if (! prop)
|
||
|
+ if (!prop)
|
||
|
return NULL;
|
||
|
|
||
|
return prop->data;
|
||
|
diff --git a/scripts/dtc/libfdt/fdt_rw.c b/scripts/dtc/libfdt/fdt_rw.c
|
||
|
index 2eed4f5..8b487f6 100644
|
||
|
--- a/scripts/dtc/libfdt/fdt_rw.c
|
||
|
+++ b/scripts/dtc/libfdt/fdt_rw.c
|
||
|
@@ -207,7 +207,7 @@ static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name,
|
||
|
int err;
|
||
|
|
||
|
*prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
|
||
|
- if (! (*prop))
|
||
|
+ if (!*prop)
|
||
|
return oldlen;
|
||
|
|
||
|
if ((err = _fdt_splice_struct(fdt, (*prop)->data, FDT_TAGALIGN(oldlen),
|
||
|
@@ -283,7 +283,8 @@ int fdt_setprop(void *fdt, int nodeoffset, const char *name,
|
||
|
if (err)
|
||
|
return err;
|
||
|
|
||
|
- memcpy(prop->data, val, len);
|
||
|
+ if (len)
|
||
|
+ memcpy(prop->data, val, len);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
@@ -322,7 +323,7 @@ int fdt_delprop(void *fdt, int nodeoffset, const char *name)
|
||
|
FDT_RW_CHECK_HEADER(fdt);
|
||
|
|
||
|
prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
|
||
|
- if (! prop)
|
||
|
+ if (!prop)
|
||
|
return len;
|
||
|
|
||
|
proplen = sizeof(*prop) + FDT_TAGALIGN(len);
|
||
|
diff --git a/scripts/dtc/libfdt/fdt_sw.c b/scripts/dtc/libfdt/fdt_sw.c
|
||
|
index 6a80485..2bd15e7 100644
|
||
|
--- a/scripts/dtc/libfdt/fdt_sw.c
|
||
|
+++ b/scripts/dtc/libfdt/fdt_sw.c
|
||
|
@@ -220,7 +220,7 @@ static int _fdt_find_add_string(void *fdt, const char *s)
|
||
|
return offset;
|
||
|
}
|
||
|
|
||
|
-int fdt_property(void *fdt, const char *name, const void *val, int len)
|
||
|
+int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp)
|
||
|
{
|
||
|
struct fdt_property *prop;
|
||
|
int nameoff;
|
||
|
@@ -238,7 +238,19 @@ int fdt_property(void *fdt, const char *name, const void *val, int len)
|
||
|
prop->tag = cpu_to_fdt32(FDT_PROP);
|
||
|
prop->nameoff = cpu_to_fdt32(nameoff);
|
||
|
prop->len = cpu_to_fdt32(len);
|
||
|
- memcpy(prop->data, val, len);
|
||
|
+ *valp = prop->data;
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+int fdt_property(void *fdt, const char *name, const void *val, int len)
|
||
|
+{
|
||
|
+ void *ptr;
|
||
|
+ int ret;
|
||
|
+
|
||
|
+ ret = fdt_property_placeholder(fdt, name, len, &ptr);
|
||
|
+ if (ret)
|
||
|
+ return ret;
|
||
|
+ memcpy(ptr, val, len);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
diff --git a/scripts/dtc/libfdt/fdt_wip.c b/scripts/dtc/libfdt/fdt_wip.c
|
||
|
index 6aaab39..5e85919 100644
|
||
|
--- a/scripts/dtc/libfdt/fdt_wip.c
|
||
|
+++ b/scripts/dtc/libfdt/fdt_wip.c
|
||
|
@@ -82,7 +82,7 @@ int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
|
||
|
int proplen;
|
||
|
|
||
|
propval = fdt_getprop(fdt, nodeoffset, name, &proplen);
|
||
|
- if (! propval)
|
||
|
+ if (!propval)
|
||
|
return proplen;
|
||
|
|
||
|
if (proplen != len)
|
||
|
@@ -107,7 +107,7 @@ int fdt_nop_property(void *fdt, int nodeoffset, const char *name)
|
||
|
int len;
|
||
|
|
||
|
prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
|
||
|
- if (! prop)
|
||
|
+ if (!prop)
|
||
|
return len;
|
||
|
|
||
|
_fdt_nop_region(prop, len + sizeof(*prop));
|
||
|
diff --git a/scripts/dtc/libfdt/libfdt.h b/scripts/dtc/libfdt/libfdt.h
|
||
|
index b842b15..a248b1b 100644
|
||
|
--- a/scripts/dtc/libfdt/libfdt.h
|
||
|
+++ b/scripts/dtc/libfdt/libfdt.h
|
||
|
@@ -143,7 +143,9 @@
|
||
|
/* Low-level functions (you probably don't need these) */
|
||
|
/**********************************************************************/
|
||
|
|
||
|
+#ifndef SWIG /* This function is not useful in Python */
|
||
|
const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int checklen);
|
||
|
+#endif
|
||
|
static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen)
|
||
|
{
|
||
|
return (void *)(uintptr_t)fdt_offset_ptr(fdt, offset, checklen);
|
||
|
@@ -210,7 +212,6 @@ static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen)
|
||
|
/**********************************************************************/
|
||
|
/* 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))
|
||
|
@@ -354,8 +355,10 @@ static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen)
|
||
|
* useful for finding subnodes based on a portion of a larger string,
|
||
|
* such as a full path.
|
||
|
*/
|
||
|
+#ifndef SWIG /* Not available in Python */
|
||
|
int fdt_subnode_offset_namelen(const void *fdt, int parentoffset,
|
||
|
const char *name, int namelen);
|
||
|
+#endif
|
||
|
/**
|
||
|
* fdt_subnode_offset - find a subnode of a given node
|
||
|
* @fdt: pointer to the device tree blob
|
||
|
@@ -391,7 +394,9 @@ int fdt_subnode_offset_namelen(const void *fdt, int parentoffset,
|
||
|
* Identical to fdt_path_offset(), but only consider the first namelen
|
||
|
* characters of path as the path name.
|
||
|
*/
|
||
|
+#ifndef SWIG /* Not available in Python */
|
||
|
int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen);
|
||
|
+#endif
|
||
|
|
||
|
/**
|
||
|
* fdt_path_offset - find a tree node by its full path
|
||
|
@@ -550,10 +555,12 @@ const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
|
||
|
* Identical to fdt_get_property(), but only examine the first namelen
|
||
|
* characters of name for matching the property name.
|
||
|
*/
|
||
|
+#ifndef SWIG /* Not available in Python */
|
||
|
const struct fdt_property *fdt_get_property_namelen(const void *fdt,
|
||
|
int nodeoffset,
|
||
|
const char *name,
|
||
|
int namelen, int *lenp);
|
||
|
+#endif
|
||
|
|
||
|
/**
|
||
|
* fdt_get_property - find a given property in a given node
|
||
|
@@ -624,8 +631,10 @@ static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset,
|
||
|
* -FDT_ERR_BADSTRUCTURE,
|
||
|
* -FDT_ERR_TRUNCATED, standard meanings
|
||
|
*/
|
||
|
+#ifndef SWIG /* This function is not useful in Python */
|
||
|
const void *fdt_getprop_by_offset(const void *fdt, int offset,
|
||
|
const char **namep, int *lenp);
|
||
|
+#endif
|
||
|
|
||
|
/**
|
||
|
* fdt_getprop_namelen - get property value based on substring
|
||
|
@@ -638,6 +647,7 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset,
|
||
|
* Identical to fdt_getprop(), but only examine the first namelen
|
||
|
* characters of name for matching the property name.
|
||
|
*/
|
||
|
+#ifndef SWIG /* Not available in Python */
|
||
|
const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
|
||
|
const char *name, int namelen, int *lenp);
|
||
|
static inline void *fdt_getprop_namelen_w(void *fdt, int nodeoffset,
|
||
|
@@ -647,6 +657,7 @@ static inline void *fdt_getprop_namelen_w(void *fdt, int nodeoffset,
|
||
|
return (void *)(uintptr_t)fdt_getprop_namelen(fdt, nodeoffset, name,
|
||
|
namelen, lenp);
|
||
|
}
|
||
|
+#endif
|
||
|
|
||
|
/**
|
||
|
* fdt_getprop - retrieve the value of a given property
|
||
|
@@ -707,8 +718,10 @@ static inline void *fdt_getprop_w(void *fdt, int nodeoffset,
|
||
|
* Identical to fdt_get_alias(), but only examine the first namelen
|
||
|
* characters of name for matching the alias name.
|
||
|
*/
|
||
|
+#ifndef SWIG /* Not available in Python */
|
||
|
const char *fdt_get_alias_namelen(const void *fdt,
|
||
|
const char *name, int namelen);
|
||
|
+#endif
|
||
|
|
||
|
/**
|
||
|
* fdt_get_alias - retrieve the path referenced by a given alias
|
||
|
@@ -1106,10 +1119,12 @@ const char *fdt_stringlist_get(const void *fdt, int nodeoffset,
|
||
|
* of the name. It is useful when you want to manipulate only one value of
|
||
|
* an array and you have a string that doesn't end with \0.
|
||
|
*/
|
||
|
+#ifndef SWIG /* Not available in Python */
|
||
|
int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset,
|
||
|
const char *name, int namelen,
|
||
|
uint32_t idx, const void *val,
|
||
|
int len);
|
||
|
+#endif
|
||
|
|
||
|
/**
|
||
|
* fdt_setprop_inplace - change a property's value, but not its size
|
||
|
@@ -1139,8 +1154,10 @@ int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset,
|
||
|
* -FDT_ERR_BADSTRUCTURE,
|
||
|
* -FDT_ERR_TRUNCATED, standard meanings
|
||
|
*/
|
||
|
+#ifndef SWIG /* Not available in Python */
|
||
|
int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
|
||
|
const void *val, int len);
|
||
|
+#endif
|
||
|
|
||
|
/**
|
||
|
* fdt_setprop_inplace_u32 - change the value of a 32-bit integer property
|
||
|
@@ -1297,6 +1314,22 @@ static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val)
|
||
|
{
|
||
|
return fdt_property_u32(fdt, name, val);
|
||
|
}
|
||
|
+
|
||
|
+/**
|
||
|
+ * fdt_property_placeholder - add a new property and return a ptr to its value
|
||
|
+ *
|
||
|
+ * @fdt: pointer to the device tree blob
|
||
|
+ * @name: name of property to add
|
||
|
+ * @len: length of property value in bytes
|
||
|
+ * @valp: returns a pointer to where where the value should be placed
|
||
|
+ *
|
||
|
+ * returns:
|
||
|
+ * 0, on success
|
||
|
+ * -FDT_ERR_BADMAGIC,
|
||
|
+ * -FDT_ERR_NOSPACE, standard meanings
|
||
|
+ */
|
||
|
+int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp);
|
||
|
+
|
||
|
#define fdt_property_string(fdt, name, str) \
|
||
|
fdt_property(fdt, name, str, strlen(str)+1)
|
||
|
int fdt_end_node(void *fdt);
|
||
|
@@ -1527,6 +1560,36 @@ static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name,
|
||
|
#define fdt_setprop_string(fdt, nodeoffset, name, str) \
|
||
|
fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1)
|
||
|
|
||
|
+
|
||
|
+/**
|
||
|
+ * fdt_setprop_empty - set a property to an empty value
|
||
|
+ * @fdt: pointer to the device tree blob
|
||
|
+ * @nodeoffset: offset of the node whose property to change
|
||
|
+ * @name: name of the property to change
|
||
|
+ *
|
||
|
+ * fdt_setprop_empty() sets the value of the named property in the
|
||
|
+ * given node to an empty (zero length) value, or creates a new empty
|
||
|
+ * 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
|
||
|
+ */
|
||
|
+#define fdt_setprop_empty(fdt, nodeoffset, name) \
|
||
|
+ fdt_setprop((fdt), (nodeoffset), (name), NULL, 0)
|
||
|
+
|
||
|
/**
|
||
|
* fdt_appendprop - append to or create a property
|
||
|
* @fdt: pointer to the device tree blob
|
||
|
@@ -1704,8 +1767,10 @@ static inline int fdt_appendprop_cell(void *fdt, int nodeoffset,
|
||
|
* creating subnodes based on a portion of a larger string, such as a
|
||
|
* full path.
|
||
|
*/
|
||
|
+#ifndef SWIG /* Not available in Python */
|
||
|
int fdt_add_subnode_namelen(void *fdt, int parentoffset,
|
||
|
const char *name, int namelen);
|
||
|
+#endif
|
||
|
|
||
|
/**
|
||
|
* fdt_add_subnode - creates a new node
|
||
|
diff --git a/scripts/dtc/libfdt/libfdt_env.h b/scripts/dtc/libfdt/libfdt_env.h
|
||
|
index 99f936d..952056c 100644
|
||
|
--- a/scripts/dtc/libfdt/libfdt_env.h
|
||
|
+++ b/scripts/dtc/libfdt/libfdt_env.h
|
||
|
@@ -58,16 +58,16 @@
|
||
|
#include <string.h>
|
||
|
|
||
|
#ifdef __CHECKER__
|
||
|
-#define __force __attribute__((force))
|
||
|
-#define __bitwise __attribute__((bitwise))
|
||
|
+#define FDT_FORCE __attribute__((force))
|
||
|
+#define FDT_BITWISE __attribute__((bitwise))
|
||
|
#else
|
||
|
-#define __force
|
||
|
-#define __bitwise
|
||
|
+#define FDT_FORCE
|
||
|
+#define FDT_BITWISE
|
||
|
#endif
|
||
|
|
||
|
-typedef uint16_t __bitwise fdt16_t;
|
||
|
-typedef uint32_t __bitwise fdt32_t;
|
||
|
-typedef uint64_t __bitwise fdt64_t;
|
||
|
+typedef uint16_t FDT_BITWISE fdt16_t;
|
||
|
+typedef uint32_t FDT_BITWISE fdt32_t;
|
||
|
+typedef uint64_t FDT_BITWISE fdt64_t;
|
||
|
|
||
|
#define EXTRACT_BYTE(x, n) ((unsigned long long)((uint8_t *)&x)[n])
|
||
|
#define CPU_TO_FDT16(x) ((EXTRACT_BYTE(x, 0) << 8) | EXTRACT_BYTE(x, 1))
|
||
|
@@ -80,29 +80,29 @@
|
||
|
|
||
|
static inline uint16_t fdt16_to_cpu(fdt16_t x)
|
||
|
{
|
||
|
- return (__force uint16_t)CPU_TO_FDT16(x);
|
||
|
+ return (FDT_FORCE uint16_t)CPU_TO_FDT16(x);
|
||
|
}
|
||
|
static inline fdt16_t cpu_to_fdt16(uint16_t x)
|
||
|
{
|
||
|
- return (__force fdt16_t)CPU_TO_FDT16(x);
|
||
|
+ return (FDT_FORCE fdt16_t)CPU_TO_FDT16(x);
|
||
|
}
|
||
|
|
||
|
static inline uint32_t fdt32_to_cpu(fdt32_t x)
|
||
|
{
|
||
|
- return (__force uint32_t)CPU_TO_FDT32(x);
|
||
|
+ return (FDT_FORCE uint32_t)CPU_TO_FDT32(x);
|
||
|
}
|
||
|
static inline fdt32_t cpu_to_fdt32(uint32_t x)
|
||
|
{
|
||
|
- return (__force fdt32_t)CPU_TO_FDT32(x);
|
||
|
+ return (FDT_FORCE fdt32_t)CPU_TO_FDT32(x);
|
||
|
}
|
||
|
|
||
|
static inline uint64_t fdt64_to_cpu(fdt64_t x)
|
||
|
{
|
||
|
- return (__force uint64_t)CPU_TO_FDT64(x);
|
||
|
+ return (FDT_FORCE uint64_t)CPU_TO_FDT64(x);
|
||
|
}
|
||
|
static inline fdt64_t cpu_to_fdt64(uint64_t x)
|
||
|
{
|
||
|
- return (__force fdt64_t)CPU_TO_FDT64(x);
|
||
|
+ return (FDT_FORCE fdt64_t)CPU_TO_FDT64(x);
|
||
|
}
|
||
|
#undef CPU_TO_FDT64
|
||
|
#undef CPU_TO_FDT32
|
||
|
diff --git a/scripts/dtc/livetree.c b/scripts/dtc/livetree.c
|
||
|
index afa2f67..aecd278 100644
|
||
|
--- a/scripts/dtc/livetree.c
|
||
|
+++ b/scripts/dtc/livetree.c
|
||
|
@@ -242,7 +242,7 @@ void delete_property_by_name(struct node *node, char *name)
|
||
|
struct property *prop = node->proplist;
|
||
|
|
||
|
while (prop) {
|
||
|
- if (!strcmp(prop->name, name)) {
|
||
|
+ if (streq(prop->name, name)) {
|
||
|
delete_property(prop);
|
||
|
return;
|
||
|
}
|
||
|
@@ -275,7 +275,7 @@ void delete_node_by_name(struct node *parent, char *name)
|
||
|
struct node *node = parent->children;
|
||
|
|
||
|
while (node) {
|
||
|
- if (!strcmp(node->name, name)) {
|
||
|
+ if (streq(node->name, name)) {
|
||
|
delete_node(node);
|
||
|
return;
|
||
|
}
|
||
|
@@ -319,8 +319,8 @@ struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size)
|
||
|
|
||
|
memset(new, 0, sizeof(*new));
|
||
|
|
||
|
- new->re.address = address;
|
||
|
- new->re.size = size;
|
||
|
+ new->address = address;
|
||
|
+ new->size = size;
|
||
|
|
||
|
return new;
|
||
|
}
|
||
|
@@ -393,7 +393,7 @@ struct property *get_property(struct node *node, const char *propname)
|
||
|
cell_t propval_cell(struct property *prop)
|
||
|
{
|
||
|
assert(prop->val.len == sizeof(cell_t));
|
||
|
- return fdt32_to_cpu(*((cell_t *)prop->val.val));
|
||
|
+ return fdt32_to_cpu(*((fdt32_t *)prop->val.val));
|
||
|
}
|
||
|
|
||
|
struct property *get_property_by_label(struct node *tree, const char *label,
|
||
|
@@ -478,7 +478,8 @@ struct node *get_node_by_path(struct node *tree, const char *path)
|
||
|
p = strchr(path, '/');
|
||
|
|
||
|
for_each_child(tree, child) {
|
||
|
- if (p && strneq(path, child->name, p-path))
|
||
|
+ if (p && (strlen(child->name) == p-path) &&
|
||
|
+ strneq(path, child->name, p-path))
|
||
|
return get_node_by_path(child, p+1);
|
||
|
else if (!p && streq(path, child->name))
|
||
|
return child;
|
||
|
@@ -599,13 +600,13 @@ static int cmp_reserve_info(const void *ax, const void *bx)
|
||
|
a = *((const struct reserve_info * const *)ax);
|
||
|
b = *((const struct reserve_info * const *)bx);
|
||
|
|
||
|
- if (a->re.address < b->re.address)
|
||
|
+ if (a->address < b->address)
|
||
|
return -1;
|
||
|
- else if (a->re.address > b->re.address)
|
||
|
+ else if (a->address > b->address)
|
||
|
return 1;
|
||
|
- else if (a->re.size < b->re.size)
|
||
|
+ else if (a->size < b->size)
|
||
|
return -1;
|
||
|
- else if (a->re.size > b->re.size)
|
||
|
+ else if (a->size > b->size)
|
||
|
return 1;
|
||
|
else
|
||
|
return 0;
|
||
|
@@ -847,6 +848,8 @@ static void add_fixup_entry(struct dt_info *dti, struct node *fn,
|
||
|
xasprintf(&entry, "%s:%s:%u",
|
||
|
node->fullpath, prop->name, m->offset);
|
||
|
append_to_property(fn, m->ref, entry, strlen(entry) + 1);
|
||
|
+
|
||
|
+ free(entry);
|
||
|
}
|
||
|
|
||
|
static void generate_fixups_tree_internal(struct dt_info *dti,
|
||
|
@@ -900,7 +903,7 @@ static void add_local_fixup_entry(struct dt_info *dti,
|
||
|
struct node *refnode)
|
||
|
{
|
||
|
struct node *wn, *nwn; /* local fixup node, walk node, new */
|
||
|
- uint32_t value_32;
|
||
|
+ fdt32_t value_32;
|
||
|
char **compp;
|
||
|
int i, depth;
|
||
|
|
||
|
diff --git a/scripts/dtc/srcpos.c b/scripts/dtc/srcpos.c
|
||
|
index aa3aad0..9d38459 100644
|
||
|
--- a/scripts/dtc/srcpos.c
|
||
|
+++ b/scripts/dtc/srcpos.c
|
||
|
@@ -252,7 +252,7 @@ struct srcpos *
|
||
|
const char *fname = "<no-file>";
|
||
|
char *pos_str;
|
||
|
|
||
|
- if (pos)
|
||
|
+ if (pos->file && pos->file->name)
|
||
|
fname = pos->file->name;
|
||
|
|
||
|
|
||
|
diff --git a/scripts/dtc/srcpos.h b/scripts/dtc/srcpos.h
|
||
|
index 2cdfcd8..7caca82 100644
|
||
|
--- a/scripts/dtc/srcpos.h
|
||
|
+++ b/scripts/dtc/srcpos.h
|
||
|
@@ -22,6 +22,7 @@
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <stdbool.h>
|
||
|
+#include "util.h"
|
||
|
|
||
|
struct srcfile_state {
|
||
|
FILE *f;
|
||
|
@@ -106,12 +107,10 @@ struct srcpos {
|
||
|
extern struct srcpos *srcpos_copy(struct srcpos *pos);
|
||
|
extern char *srcpos_string(struct srcpos *pos);
|
||
|
|
||
|
-extern void srcpos_verror(struct srcpos *pos, const char *prefix,
|
||
|
- const char *fmt, va_list va)
|
||
|
- __attribute__((format(printf, 3, 0)));
|
||
|
-extern void srcpos_error(struct srcpos *pos, const char *prefix,
|
||
|
- const char *fmt, ...)
|
||
|
- __attribute__((format(printf, 3, 4)));
|
||
|
+extern void PRINTF(3, 0) srcpos_verror(struct srcpos *pos, const char *prefix,
|
||
|
+ const char *fmt, va_list va);
|
||
|
+extern void PRINTF(3, 4) srcpos_error(struct srcpos *pos, const char *prefix,
|
||
|
+ const char *fmt, ...);
|
||
|
|
||
|
extern void srcpos_set_line(char *f, int l);
|
||
|
|
||
|
diff --git a/scripts/dtc/treesource.c b/scripts/dtc/treesource.c
|
||
|
index c9d8967..2461a3d 100644
|
||
|
--- a/scripts/dtc/treesource.c
|
||
|
+++ b/scripts/dtc/treesource.c
|
||
|
@@ -137,7 +137,7 @@ static void write_propval_string(FILE *f, struct data val)
|
||
|
static void write_propval_cells(FILE *f, struct data val)
|
||
|
{
|
||
|
void *propend = val.val + val.len;
|
||
|
- cell_t *cp = (cell_t *)val.val;
|
||
|
+ fdt32_t *cp = (fdt32_t *)val.val;
|
||
|
struct marker *m = val.markers;
|
||
|
|
||
|
fprintf(f, "<");
|
||
|
@@ -275,8 +275,8 @@ void dt_to_source(FILE *f, struct dt_info *dti)
|
||
|
for_each_label(re->labels, l)
|
||
|
fprintf(f, "%s: ", l->label);
|
||
|
fprintf(f, "/memreserve/\t0x%016llx 0x%016llx;\n",
|
||
|
- (unsigned long long)re->re.address,
|
||
|
- (unsigned long long)re->re.size);
|
||
|
+ (unsigned long long)re->address,
|
||
|
+ (unsigned long long)re->size);
|
||
|
}
|
||
|
|
||
|
write_tree_source_node(f, dti->dt, 0);
|
||
|
diff --git a/scripts/dtc/util.c b/scripts/dtc/util.c
|
||
|
index 3550f86..9953c32 100644
|
||
|
--- a/scripts/dtc/util.c
|
||
|
+++ b/scripts/dtc/util.c
|
||
|
@@ -396,7 +396,7 @@ void utilfdt_print_data(const char *data, int len)
|
||
|
} while (s < data + len);
|
||
|
|
||
|
} else if ((len % 4) == 0) {
|
||
|
- const uint32_t *cell = (const uint32_t *)data;
|
||
|
+ const fdt32_t *cell = (const fdt32_t *)data;
|
||
|
|
||
|
printf(" = <");
|
||
|
for (i = 0, len /= 4; i < len; i++)
|
||
|
@@ -412,15 +412,16 @@ void utilfdt_print_data(const char *data, int len)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
-void util_version(void)
|
||
|
+void NORETURN util_version(void)
|
||
|
{
|
||
|
printf("Version: %s\n", DTC_VERSION);
|
||
|
exit(0);
|
||
|
}
|
||
|
|
||
|
-void util_usage(const char *errmsg, const char *synopsis,
|
||
|
- const char *short_opts, struct option const long_opts[],
|
||
|
- const char * const opts_help[])
|
||
|
+void NORETURN util_usage(const char *errmsg, const char *synopsis,
|
||
|
+ const char *short_opts,
|
||
|
+ struct option const long_opts[],
|
||
|
+ const char * const opts_help[])
|
||
|
{
|
||
|
FILE *fp = errmsg ? stderr : stdout;
|
||
|
const char a_arg[] = "<arg>";
|
||
|
diff --git a/scripts/dtc/util.h b/scripts/dtc/util.h
|
||
|
index f5c4f1b..ad5f411 100644
|
||
|
--- a/scripts/dtc/util.h
|
||
|
+++ b/scripts/dtc/util.h
|
||
|
@@ -25,9 +25,17 @@
|
||
|
* USA
|
||
|
*/
|
||
|
|
||
|
+#ifdef __GNUC__
|
||
|
+#define PRINTF(i, j) __attribute__((format (printf, i, j)))
|
||
|
+#define NORETURN __attribute__((noreturn))
|
||
|
+#else
|
||
|
+#define PRINTF(i, j)
|
||
|
+#define NORETURN
|
||
|
+#endif
|
||
|
+
|
||
|
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||
|
|
||
|
-static inline void __attribute__((noreturn)) die(const char *str, ...)
|
||
|
+static inline void NORETURN PRINTF(1, 2) die(const char *str, ...)
|
||
|
{
|
||
|
va_list ap;
|
||
|
|
||
|
@@ -53,13 +61,14 @@ static inline void *xrealloc(void *p, size_t len)
|
||
|
void *new = realloc(p, len);
|
||
|
|
||
|
if (!new)
|
||
|
- die("realloc() failed (len=%d)\n", len);
|
||
|
+ die("realloc() failed (len=%zd)\n", len);
|
||
|
|
||
|
return new;
|
||
|
}
|
||
|
|
||
|
extern char *xstrdup(const char *s);
|
||
|
-extern int xasprintf(char **strp, const char *fmt, ...);
|
||
|
+
|
||
|
+extern int PRINTF(2, 3) xasprintf(char **strp, const char *fmt, ...);
|
||
|
extern char *join_path(const char *path, const char *name);
|
||
|
|
||
|
/**
|
||
|
@@ -188,7 +197,7 @@ static inline void *xrealloc(void *p, size_t len)
|
||
|
/**
|
||
|
* Show source version and exit
|
||
|
*/
|
||
|
-void util_version(void) __attribute__((noreturn));
|
||
|
+void NORETURN util_version(void);
|
||
|
|
||
|
/**
|
||
|
* Show usage and exit
|
||
|
@@ -202,9 +211,10 @@ static inline void *xrealloc(void *p, size_t len)
|
||
|
* @param long_opts The structure of long options
|
||
|
* @param opts_help An array of help strings (should align with long_opts)
|
||
|
*/
|
||
|
-void util_usage(const char *errmsg, const char *synopsis,
|
||
|
- const char *short_opts, struct option const long_opts[],
|
||
|
- const char * const opts_help[]) __attribute__((noreturn));
|
||
|
+void NORETURN util_usage(const char *errmsg, const char *synopsis,
|
||
|
+ const char *short_opts,
|
||
|
+ struct option const long_opts[],
|
||
|
+ const char * const opts_help[]);
|
||
|
|
||
|
/**
|
||
|
* Show usage and exit
|
||
|
diff --git a/scripts/dtc/version_gen.h b/scripts/dtc/version_gen.h
|
||
|
index 16c2e53..74a2ffc 100644
|
||
|
--- a/scripts/dtc/version_gen.h
|
||
|
+++ b/scripts/dtc/version_gen.h
|
||
|
@@ -1 +1 @@
|
||
|
-#define DTC_VERSION "DTC 1.4.2-g0931cea3"
|
||
|
+#define DTC_VERSION "DTC 1.4.4-ga10cb3c8"
|
||
|
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
|
||
|
index ddf83d0..a0fb9e3 100644
|
||
|
--- a/scripts/Makefile.lib
|
||
|
+++ b/scripts/Makefile.lib
|
||
|
@@ -275,7 +275,11 @@ cmd_gzip = (cat $(filter-out FORCE,$^) | gzip -n -f -9 > $@) || \
|
||
|
|
||
|
# DTC
|
||
|
# ---------------------------------------------------------------------------
|
||
|
+ifeq ($(CONFIG_OF_CONFIGFS),y)
|
||
|
+DTC ?= $(objtree)/scripts/dtc/dtc -@
|
||
|
+else
|
||
|
DTC ?= $(objtree)/scripts/dtc/dtc
|
||
|
+endif
|
||
|
|
||
|
# Generate an assembly file to wrap the output of the device tree compiler
|
||
|
quiet_cmd_dt_S_dtb= DTB $@
|