]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[fdt] Provide the ability to create a device tree for a booted OS
authorMichael Brown <mcb30@ipxe.org>
Fri, 28 Mar 2025 14:17:29 +0000 (14:17 +0000)
committerMichael Brown <mcb30@ipxe.org>
Fri, 28 Mar 2025 15:29:51 +0000 (15:29 +0000)
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>
src/core/fdt.c
src/include/ipxe/fdt.h

index 4fd2b76bfe4bbd026611ee2e67f96deabac19904..59692e1352827412ff4565116af46d54dd295a6a 100644 (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 );
 
index 2799e0d07f1eb766a4d595f93c4055896ea094ef..46025f02e995c24dea481000436bb35d0447d9d0 100644 (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 */