feat(firmware): share the FDT initrd block driver across device ports

This commit is contained in:
rponeawa committed 2026-10-25 02:56:06 +08:00
1 parent 0400f6b9d8
commit c952843598
6 files changed
+259 -2

No files matched your search

@@ -0,0 +1,222 @@
/** @file
Publish the FAT initrd from a Mu-Silicium FDT handoff as a read-only block device.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <Uefi.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/FdtLib.h>
#include <Library/HobLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Protocol/BlockIo.h>
#include <Protocol/DevicePath.h>
// Mu-Silicium SEC stores the incoming x0 value in this HOB as a UINT64.
STATIC CONST EFI_GUID mEntryArgHobGuid = {
0xDAEE82E6, 0x8090, 0x4E72, { 0xBF, 0xB9, 0x78, 0xC1, 0x3C, 0xD4, 0xE3, 0x59 }
};
STATIC
UINT64
ReadCells (
IN CONST VOID *Data,
IN UINT32 Cells
)
{
if (Cells == 2) {
return Fdt64ToCpu (ReadUnaligned64 (Data));
}
return Fdt32ToCpu (ReadUnaligned32 (Data));
}
#define RAM_BLOCK_SIZE 512
#pragma pack(1)
typedef struct {
VENDOR_DEVICE_PATH Vendor;
EFI_DEVICE_PATH_PROTOCOL End;
} RAM_BLOCK_DEVICE_PATH;
#pragma pack()
STATIC RAM_BLOCK_DEVICE_PATH mDevicePath = {
{
{ HARDWARE_DEVICE_PATH, HW_VENDOR_DP, { (UINT8)sizeof (VENDOR_DEVICE_PATH), (UINT8)(sizeof (VENDOR_DEVICE_PATH) >> 8) } },
{ 0xA9C6827C, 0x1BD8, 0x410C, { 0x88, 0x5A, 0xC4, 0x65, 0x00, 0xF7, 0xD8, 0x36 } }
},
{ END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 } }
};
STATIC UINT8 *mRamBase;
STATIC EFI_BLOCK_IO_MEDIA mMedia;
STATIC
EFI_STATUS
EFIAPI
RamBlockReset (
IN EFI_BLOCK_IO_PROTOCOL *This,
IN BOOLEAN ExtendedVerification
)
{
return EFI_SUCCESS;
}
STATIC
EFI_STATUS
EFIAPI
RamBlockRead (
IN EFI_BLOCK_IO_PROTOCOL *This,
IN UINT32 MediaId,
IN EFI_LBA Lba,
IN UINTN BufferSize,
OUT VOID *Buffer
)
{
if (Buffer == NULL) {
return EFI_INVALID_PARAMETER;
}
if (MediaId != mMedia.MediaId) {
return EFI_MEDIA_CHANGED;
}
if ((BufferSize % RAM_BLOCK_SIZE) != 0) {
return EFI_BAD_BUFFER_SIZE;
}
if ((Lba > mMedia.LastBlock) || ((BufferSize / RAM_BLOCK_SIZE) > (mMedia.LastBlock + 1 - Lba))) {
return EFI_INVALID_PARAMETER;
}
CopyMem (Buffer, mRamBase + Lba * RAM_BLOCK_SIZE, BufferSize);
return EFI_SUCCESS;
}
STATIC
EFI_STATUS
EFIAPI
RamBlockWrite (
IN EFI_BLOCK_IO_PROTOCOL *This,
IN UINT32 MediaId,
IN EFI_LBA Lba,
IN UINTN BufferSize,
IN VOID *Buffer
)
{
return EFI_WRITE_PROTECTED;
}
STATIC
EFI_STATUS
EFIAPI
RamBlockFlush (
IN EFI_BLOCK_IO_PROTOCOL *This
)
{
return EFI_SUCCESS;
}
STATIC EFI_BLOCK_IO_PROTOCOL mBlockIo = {
EFI_BLOCK_IO_PROTOCOL_REVISION,
&mMedia,
RamBlockReset,
RamBlockRead,
RamBlockWrite,
RamBlockFlush
};
STATIC
VOID
PublishInitrd (
IN CONST VOID *Fdt
)
{
EFI_STATUS Status;
INT32 Chosen;
CONST VOID *StartProp;
CONST VOID *EndProp;
INT32 StartLength;
INT32 EndLength;
UINT64 Start;
UINT64 End;
EFI_HANDLE Handle;
Chosen = FdtPathOffset (Fdt, "/chosen");
if (Chosen < 0) {
DEBUG ((DEBUG_ERROR, "UNIXNURAMDISK: no /chosen\n"));
return;
}
StartProp = FdtGetProp (Fdt, Chosen, "linux,initrd-start", &StartLength);
EndProp = FdtGetProp (Fdt, Chosen, "linux,initrd-end", &EndLength);
if ((StartProp == NULL) || (EndProp == NULL) ||
((StartLength != 4) && (StartLength != 8)) || ((EndLength != 4) && (EndLength != 8)))
{
DEBUG ((DEBUG_ERROR, "UNIXNURAMDISK: no initrd in /chosen\n"));
return;
}
Start = ReadCells (StartProp, StartLength / 4);
End = ReadCells (EndProp, EndLength / 4);
if ((End <= Start) || (((End - Start) % RAM_BLOCK_SIZE) != 0)) {
DEBUG ((DEBUG_ERROR, "UNIXNURAMDISK: initrd 0x%lx-0x%lx is not a whole number of sectors\n", Start, End));
return;
}
mRamBase = (UINT8 *)(UINTN)Start;
mMedia.MediaId = 1;
mMedia.RemovableMedia = FALSE;
mMedia.MediaPresent = TRUE;
mMedia.LogicalPartition = FALSE;
mMedia.ReadOnly = TRUE;
mMedia.WriteCaching = FALSE;
mMedia.BlockSize = RAM_BLOCK_SIZE;
mMedia.IoAlign = 1;
mMedia.LastBlock = (End - Start) / RAM_BLOCK_SIZE - 1;
Handle = NULL;
Status = gBS->InstallMultipleProtocolInterfaces (
&Handle,
&gEfiDevicePathProtocolGuid,
&mDevicePath,
&gEfiBlockIoProtocolGuid,
&mBlockIo,
NULL
);
DEBUG ((DEBUG_ERROR, "UNIXNURAMDISK: initrd block device 0x%lx size 0x%lx %r\n", Start, End - Start, Status));
}
EFI_STATUS
EFIAPI
UniXNURamDiskDxeEntry (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_HOB_GUID_TYPE *Hob;
UINT64 Dtb;
Hob = GetFirstGuidHob (&mEntryArgHobGuid);
if (Hob == NULL) {
DEBUG ((DEBUG_ERROR, "UNIXNURAMDISK: no entry argument HOB\n"));
return EFI_SUCCESS;
}
if (GET_GUID_HOB_DATA_SIZE (Hob) < sizeof (UINT64)) {
return EFI_COMPROMISED_DATA;
}
Dtb = ReadUnaligned64 ((CONST UINT64 *)GET_GUID_HOB_DATA (Hob));
if ((Dtb == 0) || ((Dtb & 3) != 0) || (FdtCheckHeader ((VOID *)(UINTN)Dtb) != 0)) {
DEBUG ((DEBUG_ERROR, "UNIXNURAMDISK: x0 0x%lx is not a device tree\n", Dtb));
return EFI_SUCCESS;
}
DEBUG ((DEBUG_ERROR, "UNIXNURAMDISK: device tree at 0x%lx, %u bytes\n", Dtb, (UINT32)FdtTotalSize ((VOID *)(UINTN)Dtb)));
PublishInitrd ((VOID *)(UINTN)Dtb);
return EFI_SUCCESS;
}
@@ -0,0 +1,29 @@
[Defines]
INF_VERSION = 0x0001001B
BASE_NAME = UniXNURamDiskDxe
FILE_GUID = 75CA63AD-FBAE-4A06-92A0-F937C671251D
MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.0
ENTRY_POINT = UniXNURamDiskDxeEntry
[Sources]
UniXNURamDiskDxe.c
[Packages]
MdePkg/MdePkg.dec
[LibraryClasses]
BaseLib
BaseMemoryLib
DebugLib
FdtLib
HobLib
UefiBootServicesTableLib
UefiDriverEntryPoint
[Protocols]
gEfiBlockIoProtocolGuid ## PRODUCES
gEfiDevicePathProtocolGuid ## PRODUCES
[Depex]
TRUE
+2
View File
@@ -24,6 +24,7 @@
BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
FdtLib|MdePkg/Library/BaseFdtLib/BaseFdtLib.inf
HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf
MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
@@ -52,6 +53,7 @@
[Components]
UniXNUPkg/Application/UniXNU/UniXNU.inf
UniXNUPkg/Driver/UniXNUDxe/UniXNUDxe.inf
UniXNUPkg/Driver/UniXNURamDiskDxe/UniXNURamDiskDxe.inf
UniXNUPkg/Test/HelloPayload/HelloPayload.inf
UniXNUPkg/Test/SampleDriver/SampleDriver.inf
UniXNUPkg/Test/XnuTest/XnuTest.inf
+1 -1
View File
@@ -88,7 +88,7 @@ build -p UniXNUPkg/UniXNUPkg.dsc -a "$ARCH" -b "$TARGET" -t "$TOOLCHAIN" -n "$JO
OUT=$BUILD_DIR/Build/Out/$ARCH-$TARGET
mkdir -p "$OUT"
BIN=$BUILD_DIR/Build/UniXNU/${TARGET}_$TOOLCHAIN/$ARCH
for m in UniXNU UniXNUDxe HelloPayload SampleDriver XnuTest; do
for m in UniXNU UniXNUDxe UniXNURamDiskDxe HelloPayload SampleDriver XnuTest; do
cp "$BIN/$m.efi" "$OUT/"
done
+2
View File
@@ -76,6 +76,8 @@ def build(ctx, uefi, fd, dtb, ramdisk=None, output=None):
raise Error(f'{mkbootimg} missing: --uefi must be a Mu-Silicium checkout')
for path, what in ((fd, 'firmware volume (--fd)'), (dtb, 'device tree (--dtb)')):
if not path or not Path(path).is_file():
if path == fd:
raise Error(f'firmware volume not found: {fd}; run ./unixnu build firmware --uefi {uefi}')
raise Error(f'{what} not found: {path}')
firmware = Path(fd).read_bytes()
if base is None or size is None:
+3 -1
View File
@@ -53,7 +53,7 @@ def parser():
b = sub.add_parser('build', parents=[c], help='build kernel, package and firmware')
b.add_argument('steps', nargs='*', choices=STEPS + OPTIONAL_STEPS + ('all', 'prelink'), default=['all'])
i = sub.add_parser('bootimg', parents=[c], help='pack the boot image from the firmware volume and a device tree')
i.add_argument('--fd', metavar='FILE', help='firmware volume (default: the build output under --uefi)')
i.add_argument('--fd', metavar='FILE', help='firmware volume with UniXNU, DarwinBoot and payload filesystem support (default: build firmware output under --uefi)')
i.add_argument('--dtb', metavar='FILE', help='compiled device tree; or UNIXNU_DTB')
i.add_argument('--ramdisk', metavar='FILE', help='ramdisk image, or none (default: the payload step output when present, else empty)')
i.add_argument('-o', '--output', metavar='FILE', help='output (default: out/<device>/boot/boot.img)')
@@ -171,6 +171,8 @@ def cmd_bootimg(ctx):
elif not ctx.args.ramdisk and payload.paths(ctx)[1].is_file():
ramdisk = payload.paths(ctx)[1]
log(f'ramdisk: {ramdisk} (use --ramdisk none for an empty one)')
if ramdisk is None:
log('ramdisk: empty; build payload or pass --ramdisk FILE to include configured boot entries')
bootimg.build(ctx, uefi, fd, dtb, ramdisk, expand(ctx.args.output) if ctx.args.output else None)