[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.
This commit is contained in:
Hermès Bélusca-Maïto 2024-04-13 11:54:06 +02:00
parent c25a0e1919
commit e5517176b8
No known key found for this signature in database
GPG key ID: 3B2539C65E7B93D0
4 changed files with 51 additions and 87 deletions

View file

@ -23,8 +23,6 @@
EXTERN DiskStopFloppyMotor:PROC EXTERN DiskStopFloppyMotor:PROC
EXTERN Relocator16Boot:PROC EXTERN Relocator16Boot:PROC
EXTERN FrldrBootDrive:BYTE
EXTERN FrldrBootPartition:DWORD
.code64 .code64
@ -32,12 +30,11 @@ Regs:
.space REGS_SIZE .space REGS_SIZE
/* /*
* VOID __cdecl BootLinuxKernel( * VOID __cdecl
* IN ULONG KernelSize<ecx>, * BootLinuxKernel(
* IN PVOID KernelCurrentLoadAddress<rdx>, * _In_ ULONG KernelSize<ecx>,
* IN PVOID KernelTargetLoadAddress<r8>, * _In_ PVOID KernelCurrentLoadAddress<rdx>,
* IN UCHAR DriveNumber<r9b>, * _In_ PVOID KernelTargetLoadAddress<r8>);
* IN ULONG PartitionNumber<rsp+40>);
*/ */
PUBLIC BootLinuxKernel PUBLIC BootLinuxKernel
BootLinuxKernel: BootLinuxKernel:
@ -47,7 +44,6 @@ BootLinuxKernel:
mov dword ptr [r11 + 8], ecx mov dword ptr [r11 + 8], ecx
mov qword ptr [r11 + 16], rdx mov qword ptr [r11 + 16], rdx
mov qword ptr [r11 + 24], r8 mov qword ptr [r11 + 24], r8
mov byte ptr [r11 + 32], r9b
/* Save non-volatile registers */ /* Save non-volatile registers */
push rsi push rsi
@ -67,25 +63,6 @@ BootLinuxKernel:
mov word ptr [Regs + REGS_FS], ax mov word ptr [Regs + REGS_FS], ax
mov word ptr [Regs + REGS_GS], 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). * 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 * The reason we can overwrite low memory is because this code executes

View file

@ -23,8 +23,6 @@
EXTERN _DiskStopFloppyMotor:PROC EXTERN _DiskStopFloppyMotor:PROC
EXTERN _Relocator16Boot:PROC EXTERN _Relocator16Boot:PROC
EXTERN _FrldrBootDrive:BYTE
EXTERN _FrldrBootPartition:DWORD
.code32 .code32
@ -32,12 +30,11 @@ Regs:
.space REGS_SIZE .space REGS_SIZE
/* /*
* VOID __cdecl BootLinuxKernel( * VOID __cdecl
* IN ULONG KernelSize, * BootLinuxKernel(
* IN PVOID KernelCurrentLoadAddress, * _In_ ULONG KernelSize,
* IN PVOID KernelTargetLoadAddress, * _In_ PVOID KernelCurrentLoadAddress,
* IN UCHAR DriveNumber, * _In_ PVOID KernelTargetLoadAddress);
* IN ULONG PartitionNumber);
*/ */
PUBLIC _BootLinuxKernel PUBLIC _BootLinuxKernel
_BootLinuxKernel: _BootLinuxKernel:
@ -52,25 +49,6 @@ _BootLinuxKernel:
mov word ptr [Regs + REGS_FS], ax mov word ptr [Regs + REGS_FS], ax
mov word ptr [Regs + REGS_GS], 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). * 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 * The reason we can overwrite low memory is because this code executes

View file

@ -129,18 +129,17 @@ typedef struct
#include <poppack.h> #include <poppack.h>
// Implemented in linux.S // Implemented in linux.S
VOID __cdecl BootLinuxKernel( VOID __cdecl
IN ULONG KernelSize, BootLinuxKernel(
IN PVOID KernelCurrentLoadAddress, _In_ ULONG KernelSize,
IN PVOID KernelTargetLoadAddress, _In_ PVOID KernelCurrentLoadAddress,
IN UCHAR DriveNumber, _In_ PVOID KernelTargetLoadAddress);
IN ULONG PartitionNumber);
ARC_STATUS ARC_STATUS
LoadAndBootLinux( LoadAndBootLinux(
IN ULONG Argc, _In_ ULONG Argc,
IN PCHAR Argv[], _In_ PCHAR Argv[],
IN PCHAR Envp[]); _In_ PCHAR Envp[]);
#endif /* _M_IX86 || _M_AMD64 */ #endif /* _M_IX86 || _M_AMD64 */

View file

@ -20,6 +20,7 @@
/* /*
* The x86 Linux Boot Protocol is explained at: * The x86 Linux Boot Protocol is explained at:
* https://www.kernel.org/doc/Documentation/x86/boot.txt * 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) #if defined(_M_IX86) || defined(_M_AMD64)
@ -84,21 +85,29 @@ RemoveQuotes(
ARC_STATUS ARC_STATUS
LoadAndBootLinux( LoadAndBootLinux(
IN ULONG Argc, _In_ ULONG Argc,
IN PCHAR Argv[], _In_ PCHAR Argv[],
IN PCHAR Envp[]) _In_ PCHAR Envp[])
{ {
ARC_STATUS Status; ARC_STATUS Status;
PCSTR Description; PCSTR Description;
PCSTR ArgValue; PCSTR ArgValue;
PCSTR BootPath; PCSTR BootPath;
UCHAR DriveNumber = 0;
ULONG PartitionNumber = 0;
ULONG LinuxKernel = 0; ULONG LinuxKernel = 0;
ULONG LinuxInitrdFile = 0; ULONG LinuxInitrdFile = 0;
FILEINFORMATION FileInfo; FILEINFORMATION FileInfo;
CHAR ArcPath[MAX_PATH]; 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"); Description = GetArgumentValue(Argc, Argv, "LoadIdentifier");
if (Description && *Description) if (Description && *Description)
RtlStringCbPrintfA(LinuxBootDescription, sizeof(LinuxBootDescription), "Loading %s...", Description); RtlStringCbPrintfA(LinuxBootDescription, sizeof(LinuxBootDescription), "Loading %s...", Description);
@ -125,10 +134,10 @@ LoadAndBootLinux(
ArgValue = GetArgumentValue(Argc, Argv, "BootDrive"); ArgValue = GetArgumentValue(Argc, Argv, "BootDrive");
if (ArgValue && *ArgValue) if (ArgValue && *ArgValue)
{ {
DriveNumber = DriveMapGetBiosDriveNumber(ArgValue); UCHAR DriveNumber = DriveMapGetBiosDriveNumber(ArgValue);
/* Retrieve the boot partition (not optional and cannot be zero) */ /* Retrieve the boot partition (not optional and cannot be zero) */
PartitionNumber = 0; ULONG PartitionNumber = 0;
ArgValue = GetArgumentValue(Argc, Argv, "BootPartition"); ArgValue = GetArgumentValue(Argc, Argv, "BootPartition");
if (ArgValue && *ArgValue) if (ArgValue && *ArgValue)
PartitionNumber = atoi(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 */ /* Get the kernel name */
LinuxKernelName = GetArgumentValue(Argc, Argv, "Kernel"); LinuxKernelName = GetArgumentValue(Argc, Argv, "Kernel");
if (!LinuxKernelName || !*LinuxKernelName) if (!LinuxKernelName || !*LinuxKernelName)
@ -240,9 +238,22 @@ LoadAndBootLinux(
goto LinuxBootFailed; goto LinuxBootFailed;
} }
// If the default root device is set to FLOPPY (0000h), change to /dev/fd0 (0200h) /*
if (LinuxBootSector->RootDevice == 0x0000) * If the default root device is set to FLOPPY (0000h), change to /dev/fd0 (0200h).
LinuxBootSector->RootDevice = 0x0200; * 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) if (LinuxSetupSector->Version >= 0x0202)
{ {
@ -271,8 +282,7 @@ LoadAndBootLinux(
BootLinuxKernel(LinuxKernelSize, LinuxKernelLoadAddress, BootLinuxKernel(LinuxKernelSize, LinuxKernelLoadAddress,
(LinuxSetupSector->LoadFlags & LINUX_FLAG_LOAD_HIGH) (LinuxSetupSector->LoadFlags & LINUX_FLAG_LOAD_HIGH)
? (PVOID)LINUX_KERNEL_LOAD_ADDRESS /* == 0x100000 */ ? (PVOID)LINUX_KERNEL_LOAD_ADDRESS /* == 0x100000 */
: (PVOID)0x10000, : (PVOID)0x10000);
DriveNumber, PartitionNumber);
/* Must not return! */ /* Must not return! */
return ESUCCESS; return ESUCCESS;