feat(firmware): share the FDT initrd block driver across device ports
This commit is contained in:
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
|
||||
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user