mirror of
https://github.com/ipxe/ipxe
synced 2025-12-15 09:04:37 +03:00
[fdt] Add fdt_cells() to read cell-based properties such as "reg"
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>
This commit is contained in:
@@ -468,7 +468,55 @@ 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_cells ( struct fdt *fdt, unsigned int offset, const char *name,
|
||||
unsigned int index, unsigned int count, uint64_t *value ) {
|
||||
struct fdt_descriptor desc;
|
||||
const uint32_t *cell;
|
||||
unsigned int total;
|
||||
int rc;
|
||||
|
||||
/* Clear value */
|
||||
*value = 0;
|
||||
|
||||
/* Find property */
|
||||
if ( ( rc = fdt_property ( fdt, offset, name, &desc ) ) != 0 )
|
||||
return rc;
|
||||
cell = desc.data;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* 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
|
||||
@@ -478,32 +526,40 @@ const char * fdt_string ( struct fdt *fdt, unsigned int offset,
|
||||
*/
|
||||
int fdt_u64 ( struct fdt *fdt, unsigned int offset, const char *name,
|
||||
uint64_t *value ) {
|
||||
struct fdt_descriptor desc;
|
||||
const uint8_t *data;
|
||||
size_t remaining;
|
||||
int rc;
|
||||
|
||||
/* Clear value */
|
||||
*value = 0;
|
||||
/* Read value */
|
||||
if ( ( rc = fdt_cells ( fdt, offset, name, 0, 0, value ) ) != 0 )
|
||||
return rc;
|
||||
|
||||
/* Find property */
|
||||
if ( ( rc = fdt_property ( fdt, offset, name, &desc ) ) != 0 )
|
||||
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 */
|
||||
if ( desc.len > sizeof ( *value ) ) {
|
||||
DBGC ( fdt, "FDT oversized integer property \"%s\"\n", name );
|
||||
*value = value64;
|
||||
if ( *value != value64 ) {
|
||||
DBGC ( fdt, "FDT overlength 32-bit integer \"%s\"\n", name );
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
/* Parse value */
|
||||
data = desc.data;
|
||||
remaining = desc.len;
|
||||
while ( remaining-- ) {
|
||||
*value <<= 8;
|
||||
*value |= *(data++);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 );
|
||||
|
||||
Reference in New Issue
Block a user