mirror of
https://github.com/ipxe/ipxe
synced 2026-02-14 02:31:26 +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 fdt Device tree
|
||||||
* @v offset Starting node offset
|
* @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,
|
int fdt_u64 ( struct fdt *fdt, unsigned int offset, const char *name,
|
||||||
uint64_t *value ) {
|
uint64_t *value ) {
|
||||||
struct fdt_descriptor desc;
|
|
||||||
const uint8_t *data;
|
|
||||||
size_t remaining;
|
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* Clear value */
|
/* Read value */
|
||||||
*value = 0;
|
if ( ( rc = fdt_cells ( fdt, offset, name, 0, 0, value ) ) != 0 )
|
||||||
|
return rc;
|
||||||
|
|
||||||
/* Find property */
|
return 0;
|
||||||
if ( ( rc = fdt_property ( fdt, offset, name, &desc ) ) != 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;
|
return rc;
|
||||||
|
|
||||||
/* Check range */
|
/* Check range */
|
||||||
if ( desc.len > sizeof ( *value ) ) {
|
*value = value64;
|
||||||
DBGC ( fdt, "FDT oversized integer property \"%s\"\n", name );
|
if ( *value != value64 ) {
|
||||||
|
DBGC ( fdt, "FDT overlength 32-bit integer \"%s\"\n", name );
|
||||||
return -ERANGE;
|
return -ERANGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parse value */
|
|
||||||
data = desc.data;
|
|
||||||
remaining = desc.len;
|
|
||||||
while ( remaining-- ) {
|
|
||||||
*value <<= 8;
|
|
||||||
*value |= *(data++);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -137,8 +137,13 @@ extern const char * fdt_strings ( struct fdt *fdt, unsigned int offset,
|
|||||||
const char *name, unsigned int *count );
|
const char *name, unsigned int *count );
|
||||||
extern const char * fdt_string ( struct fdt *fdt, unsigned int offset,
|
extern const char * fdt_string ( struct fdt *fdt, unsigned int offset,
|
||||||
const char *name );
|
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,
|
extern int fdt_u64 ( struct fdt *fdt, unsigned int offset, const char *name,
|
||||||
uint64_t *value );
|
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,
|
extern int fdt_mac ( struct fdt *fdt, unsigned int offset,
|
||||||
struct net_device *netdev );
|
struct net_device *netdev );
|
||||||
extern int fdt_parse ( struct fdt *fdt, struct fdt_header *hdr,
|
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 */
|
/** Simplified QEMU sifive_u device tree blob */
|
||||||
static const uint8_t sifive_u[] = {
|
static const uint8_t sifive_u[] = {
|
||||||
0xd0, 0x0d, 0xfe, 0xed, 0x00, 0x00, 0x05, 0x43, 0x00, 0x00, 0x00, 0x38,
|
0xd0, 0x0d, 0xfe, 0xed, 0x00, 0x00, 0x05, 0x61, 0x00, 0x00, 0x00, 0x38,
|
||||||
0x00, 0x00, 0x04, 0x68, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x11,
|
0x00, 0x00, 0x04, 0x7c, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x11,
|
||||||
0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdb,
|
0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe5,
|
||||||
0x00, 0x00, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
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, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04,
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03,
|
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, 0x10, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x16,
|
||||||
0x00, 0x00, 0x00, 0x1b, 0x73, 0x69, 0x66, 0x69, 0x76, 0x65, 0x2c, 0x66,
|
0x00, 0x00, 0x00, 0x1b, 0x73, 0x69, 0x66, 0x69, 0x76, 0x65, 0x2c, 0x66,
|
||||||
0x75, 0x35, 0x34, 0x30, 0x2d, 0x63, 0x30, 0x30, 0x30, 0x2d, 0x67, 0x65,
|
0x75, 0x35, 0x34, 0x30, 0x2d, 0x63, 0x30, 0x30, 0x30, 0x2d, 0x67, 0x65,
|
||||||
0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x65, 0x74, 0x68, 0x65,
|
0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08,
|
||||||
0x72, 0x6e, 0x65, 0x74, 0x2d, 0x70, 0x68, 0x79, 0x40, 0x30, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0xdb, 0x00, 0x00, 0x00, 0x02, 0x54, 0x0b, 0xe4, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x69,
|
0x00, 0x00, 0x00, 0x01, 0x65, 0x74, 0x68, 0x65, 0x72, 0x6e, 0x65, 0x74,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02,
|
0x2d, 0x70, 0x68, 0x79, 0x40, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
|
||||||
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x09,
|
0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x23, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2d, 0x63, 0x65, 0x6c,
|
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02,
|
||||||
0x6c, 0x73, 0x00, 0x23, 0x73, 0x69, 0x7a, 0x65, 0x2d, 0x63, 0x65, 0x6c,
|
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x09, 0x23, 0x61, 0x64, 0x64,
|
||||||
0x6c, 0x73, 0x00, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62, 0x6c,
|
0x72, 0x65, 0x73, 0x73, 0x2d, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x00, 0x23,
|
||||||
0x65, 0x00, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x00, 0x73, 0x74, 0x64, 0x6f,
|
0x73, 0x69, 0x7a, 0x65, 0x2d, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x00, 0x63,
|
||||||
0x75, 0x74, 0x2d, 0x70, 0x61, 0x74, 0x68, 0x00, 0x73, 0x65, 0x72, 0x69,
|
0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62, 0x6c, 0x65, 0x00, 0x6d, 0x6f,
|
||||||
0x61, 0x6c, 0x30, 0x00, 0x65, 0x74, 0x68, 0x65, 0x72, 0x6e, 0x65, 0x74,
|
0x64, 0x65, 0x6c, 0x00, 0x73, 0x74, 0x64, 0x6f, 0x75, 0x74, 0x2d, 0x70,
|
||||||
0x30, 0x00, 0x74, 0x69, 0x6d, 0x65, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x66,
|
0x61, 0x74, 0x68, 0x00, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x30, 0x00,
|
||||||
0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x00, 0x64, 0x65, 0x76,
|
0x65, 0x74, 0x68, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x30, 0x00, 0x74, 0x69,
|
||||||
0x69, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x00, 0x72, 0x65, 0x67,
|
0x6d, 0x65, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x66, 0x72, 0x65, 0x71, 0x75,
|
||||||
0x00, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x00, 0x72, 0x69, 0x73, 0x63,
|
0x65, 0x6e, 0x63, 0x79, 0x00, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f,
|
||||||
0x76, 0x2c, 0x69, 0x73, 0x61, 0x00, 0x23, 0x69, 0x6e, 0x74, 0x65, 0x72,
|
0x74, 0x79, 0x70, 0x65, 0x00, 0x72, 0x65, 0x67, 0x00, 0x73, 0x74, 0x61,
|
||||||
0x72, 0x75, 0x70, 0x74, 0x2d, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x00, 0x69,
|
0x74, 0x75, 0x73, 0x00, 0x72, 0x69, 0x73, 0x63, 0x76, 0x2c, 0x69, 0x73,
|
||||||
0x6e, 0x74, 0x65, 0x72, 0x72, 0x75, 0x70, 0x74, 0x2d, 0x63, 0x6f, 0x6e,
|
0x61, 0x00, 0x23, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x72, 0x75, 0x70, 0x74,
|
||||||
0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x00, 0x72, 0x61, 0x6e, 0x67,
|
0x2d, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x00, 0x69, 0x6e, 0x74, 0x65, 0x72,
|
||||||
0x65, 0x73, 0x00, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2d, 0x6d, 0x61, 0x63,
|
0x72, 0x75, 0x70, 0x74, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c,
|
||||||
0x2d, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x00, 0x70, 0x68, 0x79,
|
0x6c, 0x65, 0x72, 0x00, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x00, 0x6c,
|
||||||
0x2d, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x00, 0x70, 0x68, 0x79, 0x2d,
|
0x6f, 0x63, 0x61, 0x6c, 0x2d, 0x6d, 0x61, 0x63, 0x2d, 0x61, 0x64, 0x64,
|
||||||
0x6d, 0x6f, 0x64, 0x65, 0x00, 0x72, 0x65, 0x67, 0x2d, 0x6e, 0x61, 0x6d,
|
0x72, 0x65, 0x73, 0x73, 0x00, 0x70, 0x68, 0x79, 0x2d, 0x68, 0x61, 0x6e,
|
||||||
0x65, 0x73, 0x00
|
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_header *hdr;
|
||||||
struct fdt fdt;
|
struct fdt fdt;
|
||||||
const char *string;
|
const char *string;
|
||||||
|
uint32_t u32;
|
||||||
uint64_t u64;
|
uint64_t u64;
|
||||||
unsigned int count;
|
unsigned int count;
|
||||||
unsigned int offset;
|
unsigned int offset;
|
||||||
@@ -194,11 +197,6 @@ static void fdt_test_exec ( void ) {
|
|||||||
&count ) ) == NULL );
|
&count ) ) == NULL );
|
||||||
ok ( count == 0 );
|
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 */
|
/* Verify path lookup */
|
||||||
ok ( fdt_path ( &fdt, "", &offset ) == 0 );
|
ok ( fdt_path ( &fdt, "", &offset ) == 0 );
|
||||||
ok ( 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, "/nonexistent", &offset ) != 0 );
|
||||||
ok ( fdt_path ( &fdt, "/cpus/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 */
|
/* Verify alias lookup */
|
||||||
ok ( fdt_alias ( &fdt, "serial0", &offset ) == 0 );
|
ok ( fdt_alias ( &fdt, "serial0", &offset ) == 0 );
|
||||||
ok ( ( string = fdt_string ( &fdt, offset, "compatible" ) ) != NULL );
|
ok ( ( string = fdt_string ( &fdt, offset, "compatible" ) ) != NULL );
|
||||||
|
|||||||
Reference in New Issue
Block a user