]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[fdt] Add fdt_cells() to read cell-based properties such as "reg"
authorMichael Brown <mcb30@ipxe.org>
Tue, 15 Apr 2025 19:14:03 +0000 (20:14 +0100)
committerMichael Brown <mcb30@ipxe.org>
Tue, 15 Apr 2025 19:24:19 +0000 (20:24 +0100)
Add fdt_cells() to read scalar values encoded within a cell array,
reimplement fdt_u64() as a wrapper around this, and add fdt_u32() for
completeness.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/core/fdt.c
src/include/ipxe/fdt.h
src/tests/fdt_test.c

index 85394a8e0b9f2e0cbf151d9d6622e5089f715492..54f93028623c1f474d8f132b63e7f76aa0b1c73a 100644 (file)
@@ -468,19 +468,21 @@ const char * fdt_string ( struct fdt *fdt, unsigned int offset,
 }
 
 /**
- * Find integer property
+ * Get integer property
  *
  * @v fdt              Device tree
  * @v offset           Starting node offset
  * @v name             Property name
+ * @v index            Starting cell index
+ * @v count            Number of cells (or 0 to read all remaining cells)
  * @v value            Integer value to fill in
  * @ret rc             Return status code
  */
-int fdt_u64 ( struct fdt *fdt, unsigned int offset, const char *name,
-             uint64_t *value ) {
+int fdt_cells ( struct fdt *fdt, unsigned int offset, const char *name,
+               unsigned int index, unsigned int count, uint64_t *value ) {
        struct fdt_descriptor desc;
-       const uint8_t *data;
-       size_t remaining;
+       const uint32_t *cell;
+       unsigned int total;
        int rc;
 
        /* Clear value */
@@ -489,19 +491,73 @@ int fdt_u64 ( struct fdt *fdt, unsigned int offset, const char *name,
        /* Find property */
        if ( ( rc = fdt_property ( fdt, offset, name, &desc ) ) != 0 )
                return rc;
+       cell = desc.data;
 
-       /* Check range */
-       if ( desc.len > sizeof ( *value ) ) {
-               DBGC ( fdt, "FDT oversized integer property \"%s\"\n", name );
+       /* Determine number of cells */
+       total = ( desc.len / sizeof ( *cell ) );
+       if ( ( index > total ) || ( count > ( total - index ) ) ) {
+               DBGC ( fdt, "FDT truncated integer \"%s\"\n", name );
+               return -ERANGE;
+       }
+       if ( ! count )
+               count = ( total - index );
+       if ( count > ( sizeof ( *value ) / sizeof ( *cell ) ) ) {
+               DBGC ( fdt, "FDT overlength integer \"%s\"\n", name );
                return -ERANGE;
        }
 
-       /* Parse value */
-       data = desc.data;
-       remaining = desc.len;
-       while ( remaining-- ) {
-               *value <<= 8;
-               *value |= *(data++);
+       /* Read value */
+       for ( cell += index ; count ; cell++, count-- ) {
+               *value <<= 32;
+               *value |= be32_to_cpu ( *cell );
+       }
+
+       return 0;
+}
+
+/**
+ * Get 64-bit integer property
+ *
+ * @v fdt              Device tree
+ * @v offset           Starting node offset
+ * @v name             Property name
+ * @v value            Integer value to fill in
+ * @ret rc             Return status code
+ */
+int fdt_u64 ( struct fdt *fdt, unsigned int offset, const char *name,
+             uint64_t *value ) {
+       int rc;
+
+       /* Read value */
+       if ( ( rc = fdt_cells ( fdt, offset, name, 0, 0, value ) ) != 0 )
+               return rc;
+
+       return 0;
+}
+
+/**
+ * Get 32-bit integer property
+ *
+ * @v fdt              Device tree
+ * @v offset           Starting node offset
+ * @v name             Property name
+ * @v value            Integer value to fill in
+ * @ret rc             Return status code
+ */
+int fdt_u32 ( struct fdt *fdt, unsigned int offset, const char *name,
+             uint32_t *value ) {
+       uint64_t value64;
+       int rc;
+
+       /* Read value */
+       if ( ( rc = fdt_u64 ( fdt, offset, name, &value64 ) ) != 0 )
+               return rc;
+
+       /* Check range */
+       *value = value64;
+       if ( *value != value64 ) {
+               DBGC ( fdt, "FDT overlength 32-bit integer \"%s\"\n", name );
+               return -ERANGE;
        }
 
        return 0;
index a41dcaa30fbf5a8f11c1be1e897c879ab242ff45..fb0ae775229c53e3a7436ee172a64bfecf966bbb 100644 (file)
@@ -137,8 +137,13 @@ extern const char * fdt_strings ( struct fdt *fdt, unsigned int offset,
                                  const char *name, unsigned int *count );
 extern const char * fdt_string ( struct fdt *fdt, unsigned int offset,
                                 const char *name );
+extern int fdt_cells ( struct fdt *fdt, unsigned int offset, const char *name,
+                      unsigned int index, unsigned int count,
+                      uint64_t *value );
 extern int fdt_u64 ( struct fdt *fdt, unsigned int offset, const char *name,
                     uint64_t *value );
+extern int fdt_u32 ( struct fdt *fdt, unsigned int offset, const char *name,
+                    uint32_t *value );
 extern int fdt_mac ( struct fdt *fdt, unsigned int offset,
                     struct net_device *netdev );
 extern int fdt_parse ( struct fdt *fdt, struct fdt_header *hdr,
index 738966df844492f37837b9b79ffabf0aa66e3d97..0a143ec62d4ebd1eed1e4c787a6781bf7a23b529 100644 (file)
@@ -38,10 +38,10 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 
 /** Simplified QEMU sifive_u device tree blob */
 static const uint8_t sifive_u[] = {
-       0xd0, 0x0d, 0xfe, 0xed, 0x00, 0x00, 0x05, 0x43, 0x00, 0x00, 0x00, 0x38,
-       0x00, 0x00, 0x04, 0x68, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x11,
-       0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdb,
-       0x00, 0x00, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0xd0, 0x0d, 0xfe, 0xed, 0x00, 0x00, 0x05, 0x61, 0x00, 0x00, 0x00, 0x38,
+       0x00, 0x00, 0x04, 0x7c, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x11,
+       0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe5,
+       0x00, 0x00, 0x04, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03,
@@ -127,30 +127,32 @@ static const uint8_t sifive_u[] = {
        0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x16,
        0x00, 0x00, 0x00, 0x1b, 0x73, 0x69, 0x66, 0x69, 0x76, 0x65, 0x2c, 0x66,
        0x75, 0x35, 0x34, 0x30, 0x2d, 0x63, 0x30, 0x30, 0x30, 0x2d, 0x67, 0x65,
-       0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x65, 0x74, 0x68, 0x65,
-       0x72, 0x6e, 0x65, 0x74, 0x2d, 0x70, 0x68, 0x79, 0x40, 0x30, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x69,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02,
-       0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x09,
-       0x23, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2d, 0x63, 0x65, 0x6c,
-       0x6c, 0x73, 0x00, 0x23, 0x73, 0x69, 0x7a, 0x65, 0x2d, 0x63, 0x65, 0x6c,
-       0x6c, 0x73, 0x00, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62, 0x6c,
-       0x65, 0x00, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x00, 0x73, 0x74, 0x64, 0x6f,
-       0x75, 0x74, 0x2d, 0x70, 0x61, 0x74, 0x68, 0x00, 0x73, 0x65, 0x72, 0x69,
-       0x61, 0x6c, 0x30, 0x00, 0x65, 0x74, 0x68, 0x65, 0x72, 0x6e, 0x65, 0x74,
-       0x30, 0x00, 0x74, 0x69, 0x6d, 0x65, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x66,
-       0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x00, 0x64, 0x65, 0x76,
-       0x69, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x00, 0x72, 0x65, 0x67,
-       0x00, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x00, 0x72, 0x69, 0x73, 0x63,
-       0x76, 0x2c, 0x69, 0x73, 0x61, 0x00, 0x23, 0x69, 0x6e, 0x74, 0x65, 0x72,
-       0x72, 0x75, 0x70, 0x74, 0x2d, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x00, 0x69,
-       0x6e, 0x74, 0x65, 0x72, 0x72, 0x75, 0x70, 0x74, 0x2d, 0x63, 0x6f, 0x6e,
-       0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x00, 0x72, 0x61, 0x6e, 0x67,
-       0x65, 0x73, 0x00, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2d, 0x6d, 0x61, 0x63,
-       0x2d, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x00, 0x70, 0x68, 0x79,
-       0x2d, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x00, 0x70, 0x68, 0x79, 0x2d,
-       0x6d, 0x6f, 0x64, 0x65, 0x00, 0x72, 0x65, 0x67, 0x2d, 0x6e, 0x61, 0x6d,
-       0x65, 0x73, 0x00
+       0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08,
+       0x00, 0x00, 0x00, 0xdb, 0x00, 0x00, 0x00, 0x02, 0x54, 0x0b, 0xe4, 0x00,
+       0x00, 0x00, 0x00, 0x01, 0x65, 0x74, 0x68, 0x65, 0x72, 0x6e, 0x65, 0x74,
+       0x2d, 0x70, 0x68, 0x79, 0x40, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
+       0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02,
+       0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x09, 0x23, 0x61, 0x64, 0x64,
+       0x72, 0x65, 0x73, 0x73, 0x2d, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x00, 0x23,
+       0x73, 0x69, 0x7a, 0x65, 0x2d, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x00, 0x63,
+       0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62, 0x6c, 0x65, 0x00, 0x6d, 0x6f,
+       0x64, 0x65, 0x6c, 0x00, 0x73, 0x74, 0x64, 0x6f, 0x75, 0x74, 0x2d, 0x70,
+       0x61, 0x74, 0x68, 0x00, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x30, 0x00,
+       0x65, 0x74, 0x68, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x30, 0x00, 0x74, 0x69,
+       0x6d, 0x65, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x66, 0x72, 0x65, 0x71, 0x75,
+       0x65, 0x6e, 0x63, 0x79, 0x00, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f,
+       0x74, 0x79, 0x70, 0x65, 0x00, 0x72, 0x65, 0x67, 0x00, 0x73, 0x74, 0x61,
+       0x74, 0x75, 0x73, 0x00, 0x72, 0x69, 0x73, 0x63, 0x76, 0x2c, 0x69, 0x73,
+       0x61, 0x00, 0x23, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x72, 0x75, 0x70, 0x74,
+       0x2d, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x00, 0x69, 0x6e, 0x74, 0x65, 0x72,
+       0x72, 0x75, 0x70, 0x74, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c,
+       0x6c, 0x65, 0x72, 0x00, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x00, 0x6c,
+       0x6f, 0x63, 0x61, 0x6c, 0x2d, 0x6d, 0x61, 0x63, 0x2d, 0x61, 0x64, 0x64,
+       0x72, 0x65, 0x73, 0x73, 0x00, 0x70, 0x68, 0x79, 0x2d, 0x68, 0x61, 0x6e,
+       0x64, 0x6c, 0x65, 0x00, 0x70, 0x68, 0x79, 0x2d, 0x6d, 0x6f, 0x64, 0x65,
+       0x00, 0x72, 0x65, 0x67, 0x2d, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x00, 0x6d,
+       0x61, 0x78, 0x2d, 0x73, 0x70, 0x65, 0x65, 0x64, 0x00
 };
 
 /**
@@ -162,6 +164,7 @@ static void fdt_test_exec ( void ) {
        struct fdt_header *hdr;
        struct fdt fdt;
        const char *string;
+       uint32_t u32;
        uint64_t u64;
        unsigned int count;
        unsigned int offset;
@@ -194,11 +197,6 @@ static void fdt_test_exec ( void ) {
                                      &count ) ) == NULL );
        ok ( count == 0 );
 
-       /* Verify integer properties */
-       ok ( fdt_u64 ( &fdt, 0, "#address-cells", &u64 ) == 0 );
-       ok ( u64 == 2 );
-       ok ( fdt_u64 ( &fdt, 0, "#nonexistent", &u64 ) != 0 );
-
        /* Verify path lookup */
        ok ( fdt_path ( &fdt, "", &offset ) == 0 );
        ok ( offset == 0 );
@@ -214,6 +212,36 @@ static void fdt_test_exec ( void ) {
        ok ( fdt_path ( &fdt, "/nonexistent", &offset ) != 0 );
        ok ( fdt_path ( &fdt, "/cpus/nonexistent", &offset ) != 0 );
 
+       /* Verify 64-bit integer properties */
+       ok ( fdt_u64 ( &fdt, 0, "#address-cells", &u64 ) == 0 );
+       ok ( u64 == 2 );
+       ok ( fdt_path ( &fdt, "/soc/ethernet@10090000", &offset ) == 0 );
+       ok ( fdt_u64 ( &fdt, offset, "max-speed", &u64 ) == 0 );
+       ok ( u64 == 10000000000ULL );
+       ok ( fdt_u64 ( &fdt, offset, "#nonexistent", &u64 ) != 0 );
+
+       /* Verify 32-bit integer properties */
+       ok ( fdt_u32 ( &fdt, 0, "#address-cells", &u32 ) == 0 );
+       ok ( u32 == 2 );
+       ok ( fdt_u32 ( &fdt, 0, "#nonexistent", &u32 ) != 0 );
+       ok ( fdt_path ( &fdt, "/soc/ethernet@10090000", &offset ) == 0 );
+       ok ( fdt_u32 ( &fdt, offset, "max-speed", &u32 ) != 0 );
+
+       /* Verify cell properties */
+       ok ( fdt_path ( &fdt, "/soc/ethernet@10090000", &offset ) == 0 );
+       ok ( fdt_cells ( &fdt, offset, "reg", 4, 2, &u64 ) == 0 );
+       ok ( u64 == 0x100a0000 );
+       ok ( fdt_cells ( &fdt, offset, "reg", 6, 2, &u64 ) == 0 );
+       ok ( u64 == 0x1000 );
+       ok ( fdt_cells ( &fdt, offset, "reg", 0, 2, &u64 ) == 0 );
+       ok ( u64 == 0x10090000 );
+       ok ( fdt_cells ( &fdt, offset, "reg", 6, 0, &u64 ) == 0 );
+       ok ( u64 == 0x1000 );
+       ok ( fdt_cells ( &fdt, offset, "reg", 8, 0, &u64 ) == 0 );
+       ok ( u64 == 0 );
+       ok ( fdt_cells ( &fdt, offset, "reg", 7, 2, &u64 ) != 0 );
+       ok ( fdt_cells ( &fdt, offset, "notareg", 0, 1, &u64 ) != 0 );
+
        /* Verify alias lookup */
        ok ( fdt_alias ( &fdt, "serial0", &offset ) == 0 );
        ok ( ( string = fdt_string ( &fdt, offset, "compatible" ) ) != NULL );