[fdt] Provide the ability to create a device tree for a booted OS

Provide fdt_create() to create a device tree to be passed to a booted
operating system.  The device tree will be created from the FDT image
(if present), falling back to the system device tree (if present).

Signed-off-by: Michael Brown <mcb30@ipxe.org>
pull/1437/head
Michael Brown 2025-03-28 14:17:29 +00:00
parent 666929e311
commit 761f43ce12
2 changed files with 81 additions and 0 deletions

View File

@ -29,6 +29,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <byteswap.h>
#include <ipxe/netdevice.h>
#include <ipxe/image.h>
#include <ipxe/umalloc.h>
#include <ipxe/fdt.h>
/** @file
@ -540,6 +541,84 @@ int fdt_parse ( struct fdt *fdt, struct fdt_header *hdr, size_t max_len ) {
return -EINVAL;
}
/**
* Parse device tree image
*
* @v fdt Device tree
* @v image Image
* @ret rc Return status code
*/
static int fdt_parse_image ( struct fdt *fdt, struct image *image ) {
int rc;
/* Parse image */
if ( ( rc = fdt_parse ( fdt, user_to_virt ( image->data, 0 ),
image->len ) ) != 0 ) {
DBGC ( fdt, "FDT image \"%s\" is invalid: %s\n",
image->name, strerror ( rc ) );
return rc;
}
DBGC ( fdt, "FDT image is \"%s\"\n", image->name );
return 0;
}
/**
* Create device tree
*
* @v hdr Device tree header to fill in (may be set to NULL)
* @ret rc Return status code
*/
int fdt_create ( struct fdt_header **hdr ) {
struct image *image;
struct fdt fdt;
void *copy;
int rc;
/* Use system FDT as the base by default */
memcpy ( &fdt, &sysfdt, sizeof ( fdt ) );
/* If an FDT image exists, use this instead */
image = find_image_tag ( &fdt_image );
if ( image && ( ( rc = fdt_parse_image ( &fdt, image ) ) != 0 ) )
goto err_image;
/* Exit successfully if we have no base FDT */
if ( ! fdt.len ) {
DBGC ( &fdt, "FDT has no base tree\n" );
goto no_fdt;
}
/* Create modifiable copy */
copy = user_to_virt ( umalloc ( fdt.len ), 0 );
if ( ! copy ) {
rc = -ENOMEM;
goto err_alloc;
}
memcpy ( copy, fdt.raw, fdt.len );
fdt.raw = copy;
no_fdt:
*hdr = fdt.raw;
return 0;
ufree ( virt_to_user ( fdt.raw ) );
err_alloc:
err_image:
return rc;
}
/**
* Remove device tree
*
* @v hdr Device tree header, or NULL
*/
void fdt_remove ( struct fdt_header *hdr ) {
/* Free modifiable copy */
ufree ( virt_to_user ( hdr ) );
}
/* Drag in objects via fdt_traverse() */
REQUIRING_SYMBOL ( fdt_traverse );

View File

@ -109,5 +109,7 @@ 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,
size_t max_len );
extern int fdt_create ( struct fdt_header **hdr );
extern void fdt_remove ( struct fdt_header *hdr );
#endif /* _IPXE_FDT_H */