From e5517176b8ccbff31076e3a2214f7cc4ab7597c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herm=C3=A8s=20B=C3=A9lusca-Ma=C3=AFto?= Date: Sat, 13 Apr 2024 11:54:06 +0200 Subject: [PATCH] [FREELDR] linuxboot: It doesn't need the BIOS boot drive number and partition. Also document a little bit the RootDevice field in the boot sector; add SAL2 annotations. --- boot/freeldr/freeldr/arch/amd64/linux.S | 33 +++------------ boot/freeldr/freeldr/arch/i386/linux.S | 32 +++----------- boot/freeldr/freeldr/include/linux.h | 17 ++++---- boot/freeldr/freeldr/linuxboot.c | 56 +++++++++++++++---------- 4 files changed, 51 insertions(+), 87 deletions(-) diff --git a/boot/freeldr/freeldr/arch/amd64/linux.S b/boot/freeldr/freeldr/arch/amd64/linux.S index 55d623bbb79..a2ab714e436 100644 --- a/boot/freeldr/freeldr/arch/amd64/linux.S +++ b/boot/freeldr/freeldr/arch/amd64/linux.S @@ -23,8 +23,6 @@ EXTERN DiskStopFloppyMotor:PROC EXTERN Relocator16Boot:PROC -EXTERN FrldrBootDrive:BYTE -EXTERN FrldrBootPartition:DWORD .code64 @@ -32,12 +30,11 @@ Regs: .space REGS_SIZE /* - * VOID __cdecl BootLinuxKernel( - * IN ULONG KernelSize, - * IN PVOID KernelCurrentLoadAddress, - * IN PVOID KernelTargetLoadAddress, - * IN UCHAR DriveNumber, - * IN ULONG PartitionNumber); + * VOID __cdecl + * BootLinuxKernel( + * _In_ ULONG KernelSize, + * _In_ PVOID KernelCurrentLoadAddress, + * _In_ PVOID KernelTargetLoadAddress); */ PUBLIC BootLinuxKernel BootLinuxKernel: @@ -47,7 +44,6 @@ BootLinuxKernel: mov dword ptr [r11 + 8], ecx mov qword ptr [r11 + 16], rdx mov qword ptr [r11 + 24], r8 - mov byte ptr [r11 + 32], r9b /* Save non-volatile registers */ push rsi @@ -67,25 +63,6 @@ BootLinuxKernel: mov word ptr [Regs + REGS_FS], ax mov word ptr [Regs + REGS_GS], ax - /* Set the boot drive */ - xor edx, edx - mov dl, byte ptr [r11 + 32] - test dl, dl - jnz set_part - mov dl, byte ptr /*ds:*/[FrldrBootDrive] - - /* Set the boot partition */ -set_part: - mov eax, dword ptr [r11 + 40] - test eax, eax - jnz continue - mov eax, dword ptr /*ds:*/[FrldrBootPartition] -continue: - /* Store the 1-byte truncated partition number in DH */ - mov dh, al - - mov dword ptr [Regs + REGS_EDX], edx - /* * Relocate the kernel image to its final destination (can be as low as 0x10000). * The reason we can overwrite low memory is because this code executes diff --git a/boot/freeldr/freeldr/arch/i386/linux.S b/boot/freeldr/freeldr/arch/i386/linux.S index cc18346a17e..66682f3a98e 100644 --- a/boot/freeldr/freeldr/arch/i386/linux.S +++ b/boot/freeldr/freeldr/arch/i386/linux.S @@ -23,8 +23,6 @@ EXTERN _DiskStopFloppyMotor:PROC EXTERN _Relocator16Boot:PROC -EXTERN _FrldrBootDrive:BYTE -EXTERN _FrldrBootPartition:DWORD .code32 @@ -32,12 +30,11 @@ Regs: .space REGS_SIZE /* - * VOID __cdecl BootLinuxKernel( - * IN ULONG KernelSize, - * IN PVOID KernelCurrentLoadAddress, - * IN PVOID KernelTargetLoadAddress, - * IN UCHAR DriveNumber, - * IN ULONG PartitionNumber); + * VOID __cdecl + * BootLinuxKernel( + * _In_ ULONG KernelSize, + * _In_ PVOID KernelCurrentLoadAddress, + * _In_ PVOID KernelTargetLoadAddress); */ PUBLIC _BootLinuxKernel _BootLinuxKernel: @@ -52,25 +49,6 @@ _BootLinuxKernel: mov word ptr [Regs + REGS_FS], ax mov word ptr [Regs + REGS_GS], ax - /* Set the boot drive */ - xor edx, edx - mov dl, byte ptr [esp + 16] - test dl, dl - jnz set_part - mov dl, byte ptr ds:[_FrldrBootDrive] - - /* Set the boot partition */ -set_part: - mov eax, dword ptr [esp + 20] - test eax, eax - jnz continue - mov eax, dword ptr ds:[_FrldrBootPartition] -continue: - /* Store the 1-byte truncated partition number in DH */ - mov dh, al - - mov dword ptr [Regs + REGS_EDX], edx - /* * Relocate the kernel image to its final destination (can be as low as 0x10000). * The reason we can overwrite low memory is because this code executes diff --git a/boot/freeldr/freeldr/include/linux.h b/boot/freeldr/freeldr/include/linux.h index 6bb92d946c7..f7591db7410 100644 --- a/boot/freeldr/freeldr/include/linux.h +++ b/boot/freeldr/freeldr/include/linux.h @@ -129,18 +129,17 @@ typedef struct #include // Implemented in linux.S -VOID __cdecl BootLinuxKernel( - IN ULONG KernelSize, - IN PVOID KernelCurrentLoadAddress, - IN PVOID KernelTargetLoadAddress, - IN UCHAR DriveNumber, - IN ULONG PartitionNumber); +VOID __cdecl +BootLinuxKernel( + _In_ ULONG KernelSize, + _In_ PVOID KernelCurrentLoadAddress, + _In_ PVOID KernelTargetLoadAddress); ARC_STATUS LoadAndBootLinux( - IN ULONG Argc, - IN PCHAR Argv[], - IN PCHAR Envp[]); + _In_ ULONG Argc, + _In_ PCHAR Argv[], + _In_ PCHAR Envp[]); #endif /* _M_IX86 || _M_AMD64 */ diff --git a/boot/freeldr/freeldr/linuxboot.c b/boot/freeldr/freeldr/linuxboot.c index 5375aafe796..e7f81d699d8 100644 --- a/boot/freeldr/freeldr/linuxboot.c +++ b/boot/freeldr/freeldr/linuxboot.c @@ -20,6 +20,7 @@ /* * The x86 Linux Boot Protocol is explained at: * https://www.kernel.org/doc/Documentation/x86/boot.txt + * https://www.linux.it/~rubini/docs/boot/boot.html */ #if defined(_M_IX86) || defined(_M_AMD64) @@ -84,21 +85,29 @@ RemoveQuotes( ARC_STATUS LoadAndBootLinux( - IN ULONG Argc, - IN PCHAR Argv[], - IN PCHAR Envp[]) + _In_ ULONG Argc, + _In_ PCHAR Argv[], + _In_ PCHAR Envp[]) { ARC_STATUS Status; PCSTR Description; PCSTR ArgValue; PCSTR BootPath; - UCHAR DriveNumber = 0; - ULONG PartitionNumber = 0; ULONG LinuxKernel = 0; ULONG LinuxInitrdFile = 0; FILEINFORMATION FileInfo; CHAR ArcPath[MAX_PATH]; +#if DBG + /* Ensure the boot type is the one expected */ + ArgValue = GetArgumentValue(Argc, Argv, "BootType"); + if (!ArgValue || !*ArgValue || _stricmp(ArgValue, "Linux") != 0) + { + ERR("Unexpected boot type '%s', aborting\n", ArgValue ? ArgValue : "n/a"); + return EINVAL; + } +#endif + Description = GetArgumentValue(Argc, Argv, "LoadIdentifier"); if (Description && *Description) RtlStringCbPrintfA(LinuxBootDescription, sizeof(LinuxBootDescription), "Loading %s...", Description); @@ -125,10 +134,10 @@ LoadAndBootLinux( ArgValue = GetArgumentValue(Argc, Argv, "BootDrive"); if (ArgValue && *ArgValue) { - DriveNumber = DriveMapGetBiosDriveNumber(ArgValue); + UCHAR DriveNumber = DriveMapGetBiosDriveNumber(ArgValue); /* Retrieve the boot partition (not optional and cannot be zero) */ - PartitionNumber = 0; + ULONG PartitionNumber = 0; ArgValue = GetArgumentValue(Argc, Argv, "BootPartition"); if (ArgValue && *ArgValue) PartitionNumber = atoi(ArgValue); @@ -152,17 +161,6 @@ LoadAndBootLinux( } } - /* If we haven't retrieved the BIOS drive and partition numbers above, do it now */ - if (PartitionNumber == 0) - { - /* Retrieve the BIOS drive and partition numbers */ - if (!DissectArcPath(BootPath, NULL, &DriveNumber, &PartitionNumber)) - { - /* This is not a fatal failure, but just an inconvenience: display a message */ - TRACE("DissectArcPath(%s) failed to retrieve BIOS drive and partition numbers.\n", BootPath); - } - } - /* Get the kernel name */ LinuxKernelName = GetArgumentValue(Argc, Argv, "Kernel"); if (!LinuxKernelName || !*LinuxKernelName) @@ -240,9 +238,22 @@ LoadAndBootLinux( goto LinuxBootFailed; } - // If the default root device is set to FLOPPY (0000h), change to /dev/fd0 (0200h) - if (LinuxBootSector->RootDevice == 0x0000) - LinuxBootSector->RootDevice = 0x0200; + /* + * If the default root device is set to FLOPPY (0000h), change to /dev/fd0 (0200h). + * For a list of majors, see + * https://github.com/torvalds/linux/blob/master/include/uapi/linux/major.h + * For some examples of (decoded) root devices values, see + * https://github.com/torvalds/linux/blob/cc89c63e2/include/linux/root_dev.h + * + * NOTE: The RootDevice field is deprecated since commits + * https://github.com/torvalds/linux/commit/079f85e62 + * https://github.com/torvalds/linux/commit/7448e8e5d + */ +#define NODEV 0 +#define FLOPPY_MAJOR 2 +#define makedev(maj, min) (((maj) << 8) | (min)) + if (LinuxBootSector->RootDevice == NODEV) + LinuxBootSector->RootDevice = makedev(FLOPPY_MAJOR, 0); if (LinuxSetupSector->Version >= 0x0202) { @@ -271,8 +282,7 @@ LoadAndBootLinux( BootLinuxKernel(LinuxKernelSize, LinuxKernelLoadAddress, (LinuxSetupSector->LoadFlags & LINUX_FLAG_LOAD_HIGH) ? (PVOID)LINUX_KERNEL_LOAD_ADDRESS /* == 0x100000 */ - : (PVOID)0x10000, - DriveNumber, PartitionNumber); + : (PVOID)0x10000); /* Must not return! */ return ESUCCESS;