[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:
Michael Brown
2025-04-15 20:14:03 +01:00
parent 2c406ec0b1
commit 99322fd3b3
3 changed files with 140 additions and 51 deletions

View File

@@ -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;
}