mirror of
https://github.com/reactos/reactos.git
synced 2024-06-01 02:01:57 +00:00
e5517176b8
Also document a little bit the RootDevice field in the boot sector; add SAL2 annotations.
560 lines
18 KiB
C
560 lines
18 KiB
C
/*
|
|
* FreeLoader
|
|
* Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*/
|
|
|
|
/*
|
|
* 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)
|
|
|
|
/* INCLUDES *******************************************************************/
|
|
|
|
#include <freeldr.h>
|
|
|
|
#include <debug.h>
|
|
DBG_DEFAULT_CHANNEL(LINUX);
|
|
|
|
/* GLOBALS ********************************************************************/
|
|
|
|
#define LINUX_READ_CHUNK_SIZE 0x20000 // Read 128k at a time
|
|
|
|
PLINUX_BOOTSECTOR LinuxBootSector = NULL;
|
|
PLINUX_SETUPSECTOR LinuxSetupSector = NULL;
|
|
ULONG SetupSectorSize = 0;
|
|
BOOLEAN NewStyleLinuxKernel = FALSE;
|
|
ULONG LinuxKernelSize = 0;
|
|
ULONG LinuxInitrdSize = 0;
|
|
PCSTR LinuxKernelName = NULL;
|
|
PCSTR LinuxInitrdName = NULL;
|
|
PSTR LinuxCommandLine = NULL;
|
|
ULONG LinuxCommandLineSize = 0;
|
|
PVOID LinuxKernelLoadAddress = NULL;
|
|
PVOID LinuxInitrdLoadAddress = NULL;
|
|
CHAR LinuxBootDescription[80];
|
|
|
|
/* FUNCTIONS ******************************************************************/
|
|
|
|
static BOOLEAN LinuxReadBootSector(ULONG LinuxKernelFile);
|
|
static BOOLEAN LinuxReadSetupSector(ULONG LinuxKernelFile);
|
|
static BOOLEAN LinuxReadKernel(ULONG LinuxKernelFile);
|
|
static BOOLEAN LinuxCheckKernelVersion(VOID);
|
|
static BOOLEAN LinuxReadInitrd(ULONG LinuxInitrdFile);
|
|
|
|
static VOID
|
|
RemoveQuotes(
|
|
IN OUT PSTR QuotedString)
|
|
{
|
|
PCHAR p;
|
|
PSTR Start;
|
|
SIZE_T Size;
|
|
|
|
/* Skip spaces up to " */
|
|
p = QuotedString;
|
|
while (*p == ' ' || *p == '\t' || *p == '"')
|
|
++p;
|
|
Start = p;
|
|
|
|
/* Go up to next " */
|
|
while (*p != ANSI_NULL && *p != '"')
|
|
++p;
|
|
/* NULL-terminate */
|
|
*p = ANSI_NULL;
|
|
|
|
/* Move the NULL-terminated string back into 'QuotedString' in place */
|
|
Size = (strlen(Start) + 1) * sizeof(CHAR);
|
|
memmove(QuotedString, Start, Size);
|
|
}
|
|
|
|
ARC_STATUS
|
|
LoadAndBootLinux(
|
|
_In_ ULONG Argc,
|
|
_In_ PCHAR Argv[],
|
|
_In_ PCHAR Envp[])
|
|
{
|
|
ARC_STATUS Status;
|
|
PCSTR Description;
|
|
PCSTR ArgValue;
|
|
PCSTR BootPath;
|
|
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);
|
|
else
|
|
strcpy(LinuxBootDescription, "Loading Linux...");
|
|
|
|
UiDrawBackdrop();
|
|
UiDrawStatusText(LinuxBootDescription);
|
|
UiDrawProgressBarCenter(LinuxBootDescription);
|
|
|
|
/* Find all the message box settings and run them */
|
|
UiShowMessageBoxesInArgv(Argc, Argv);
|
|
|
|
/*
|
|
* Check whether we have a "BootPath" value (takes precedence
|
|
* over both "BootDrive" and "BootPartition").
|
|
*/
|
|
BootPath = GetArgumentValue(Argc, Argv, "BootPath");
|
|
if (!BootPath || !*BootPath)
|
|
{
|
|
/* We don't have one, check whether we use "BootDrive" and "BootPartition" */
|
|
|
|
/* Retrieve the boot drive (optional, fall back to using default path otherwise) */
|
|
ArgValue = GetArgumentValue(Argc, Argv, "BootDrive");
|
|
if (ArgValue && *ArgValue)
|
|
{
|
|
UCHAR DriveNumber = DriveMapGetBiosDriveNumber(ArgValue);
|
|
|
|
/* Retrieve the boot partition (not optional and cannot be zero) */
|
|
ULONG PartitionNumber = 0;
|
|
ArgValue = GetArgumentValue(Argc, Argv, "BootPartition");
|
|
if (ArgValue && *ArgValue)
|
|
PartitionNumber = atoi(ArgValue);
|
|
if (PartitionNumber == 0)
|
|
{
|
|
UiMessageBox("Boot partition cannot be 0!");
|
|
goto LinuxBootFailed;
|
|
// return EINVAL;
|
|
}
|
|
|
|
/* Construct the corresponding ARC path */
|
|
ConstructArcPath(ArcPath, "", DriveNumber, PartitionNumber);
|
|
*strrchr(ArcPath, '\\') = ANSI_NULL; // Trim the trailing path separator.
|
|
|
|
BootPath = ArcPath;
|
|
}
|
|
else
|
|
{
|
|
/* Fall back to using the system partition as default path */
|
|
BootPath = GetArgumentValue(Argc, Argv, "SystemPartition");
|
|
}
|
|
}
|
|
|
|
/* Get the kernel name */
|
|
LinuxKernelName = GetArgumentValue(Argc, Argv, "Kernel");
|
|
if (!LinuxKernelName || !*LinuxKernelName)
|
|
{
|
|
UiMessageBox("Linux kernel filename not specified for selected OS!");
|
|
goto LinuxBootFailed;
|
|
}
|
|
|
|
/* Get the initrd name (optional) */
|
|
LinuxInitrdName = GetArgumentValue(Argc, Argv, "Initrd");
|
|
|
|
/* Get the command line (optional) */
|
|
LinuxCommandLineSize = 0;
|
|
LinuxCommandLine = GetArgumentValue(Argc, Argv, "CommandLine");
|
|
if (LinuxCommandLine && *LinuxCommandLine)
|
|
{
|
|
RemoveQuotes(LinuxCommandLine);
|
|
LinuxCommandLineSize = (ULONG)strlen(LinuxCommandLine) + 1;
|
|
LinuxCommandLineSize = min(LinuxCommandLineSize, 260);
|
|
}
|
|
|
|
/* Open the kernel */
|
|
Status = FsOpenFile(LinuxKernelName, BootPath, OpenReadOnly, &LinuxKernel);
|
|
if (Status != ESUCCESS)
|
|
{
|
|
UiMessageBox("Linux kernel '%s' not found.", LinuxKernelName);
|
|
goto LinuxBootFailed;
|
|
}
|
|
|
|
/* Open the initrd file image (if necessary) */
|
|
if (LinuxInitrdName)
|
|
{
|
|
Status = FsOpenFile(LinuxInitrdName, BootPath, OpenReadOnly, &LinuxInitrdFile);
|
|
if (Status != ESUCCESS)
|
|
{
|
|
UiMessageBox("Linux initrd image '%s' not found.", LinuxInitrdName);
|
|
goto LinuxBootFailed;
|
|
}
|
|
}
|
|
|
|
/* Load the boot sector */
|
|
if (!LinuxReadBootSector(LinuxKernel))
|
|
goto LinuxBootFailed;
|
|
|
|
/* Load the setup sector */
|
|
if (!LinuxReadSetupSector(LinuxKernel))
|
|
goto LinuxBootFailed;
|
|
|
|
/* Calc kernel size */
|
|
Status = ArcGetFileInformation(LinuxKernel, &FileInfo);
|
|
if (Status != ESUCCESS || FileInfo.EndingAddress.HighPart != 0)
|
|
LinuxKernelSize = 0;
|
|
else
|
|
LinuxKernelSize = FileInfo.EndingAddress.LowPart - (512 + SetupSectorSize);
|
|
|
|
/* Get the initrd file image (if necessary) */
|
|
LinuxInitrdSize = 0;
|
|
if (LinuxInitrdName)
|
|
{
|
|
Status = ArcGetFileInformation(LinuxInitrdFile, &FileInfo);
|
|
if (Status != ESUCCESS || FileInfo.EndingAddress.HighPart != 0)
|
|
LinuxInitrdSize = 0;
|
|
else
|
|
LinuxInitrdSize = FileInfo.EndingAddress.LowPart;
|
|
}
|
|
|
|
/* Load the kernel */
|
|
if (!LinuxReadKernel(LinuxKernel))
|
|
goto LinuxBootFailed;
|
|
|
|
/* Load the initrd (if necessary) */
|
|
if (LinuxInitrdName)
|
|
{
|
|
if (!LinuxReadInitrd(LinuxInitrdFile))
|
|
goto LinuxBootFailed;
|
|
}
|
|
|
|
/*
|
|
* 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)
|
|
{
|
|
LinuxSetupSector->CommandLinePointer = 0x99000;
|
|
}
|
|
else
|
|
{
|
|
LinuxBootSector->CommandLineMagic = LINUX_COMMAND_LINE_MAGIC;
|
|
LinuxBootSector->CommandLineOffset = 0x9000;
|
|
}
|
|
|
|
if (NewStyleLinuxKernel)
|
|
LinuxSetupSector->TypeOfLoader = LINUX_LOADER_TYPE_FREELOADER;
|
|
else
|
|
LinuxSetupSector->LoadFlags = 0;
|
|
|
|
RtlCopyMemory((PVOID)0x90000, LinuxBootSector, 512);
|
|
RtlCopyMemory((PVOID)0x90200, LinuxSetupSector, SetupSectorSize);
|
|
RtlCopyMemory((PVOID)0x99000,
|
|
LinuxCommandLine ? LinuxCommandLine : "",
|
|
LinuxCommandLine ? LinuxCommandLineSize : sizeof(ANSI_NULL));
|
|
|
|
UiUnInitialize("Booting Linux...");
|
|
IniCleanup();
|
|
|
|
BootLinuxKernel(LinuxKernelSize, LinuxKernelLoadAddress,
|
|
(LinuxSetupSector->LoadFlags & LINUX_FLAG_LOAD_HIGH)
|
|
? (PVOID)LINUX_KERNEL_LOAD_ADDRESS /* == 0x100000 */
|
|
: (PVOID)0x10000);
|
|
/* Must not return! */
|
|
return ESUCCESS;
|
|
|
|
LinuxBootFailed:
|
|
|
|
if (LinuxKernel)
|
|
ArcClose(LinuxKernel);
|
|
|
|
if (LinuxInitrdFile)
|
|
ArcClose(LinuxInitrdFile);
|
|
|
|
if (LinuxBootSector != NULL)
|
|
MmFreeMemory(LinuxBootSector);
|
|
|
|
if (LinuxSetupSector != NULL)
|
|
MmFreeMemory(LinuxSetupSector);
|
|
|
|
if (LinuxKernelLoadAddress != NULL)
|
|
MmFreeMemory(LinuxKernelLoadAddress);
|
|
|
|
if (LinuxInitrdLoadAddress != NULL)
|
|
MmFreeMemory(LinuxInitrdLoadAddress);
|
|
|
|
LinuxBootSector = NULL;
|
|
LinuxSetupSector = NULL;
|
|
SetupSectorSize = 0;
|
|
NewStyleLinuxKernel = FALSE;
|
|
LinuxKernelSize = 0;
|
|
LinuxInitrdSize = 0;
|
|
LinuxKernelName = NULL;
|
|
LinuxInitrdName = NULL;
|
|
LinuxCommandLine = NULL;
|
|
LinuxCommandLineSize = 0;
|
|
LinuxKernelLoadAddress = NULL;
|
|
LinuxInitrdLoadAddress = NULL;
|
|
*LinuxBootDescription = ANSI_NULL;
|
|
|
|
return ENOEXEC;
|
|
}
|
|
|
|
static BOOLEAN LinuxReadBootSector(ULONG LinuxKernelFile)
|
|
{
|
|
LARGE_INTEGER Position;
|
|
|
|
/* Allocate memory for boot sector */
|
|
LinuxBootSector = MmAllocateMemoryWithType(512, LoaderSystemCode);
|
|
if (LinuxBootSector == NULL)
|
|
return FALSE;
|
|
|
|
/* Load the linux boot sector */
|
|
Position.QuadPart = 0;
|
|
if (ArcSeek(LinuxKernelFile, &Position, SeekAbsolute) != ESUCCESS)
|
|
return FALSE;
|
|
if (ArcRead(LinuxKernelFile, LinuxBootSector, 512, NULL) != ESUCCESS)
|
|
return FALSE;
|
|
|
|
/* Check for validity */
|
|
if (LinuxBootSector->BootFlag != LINUX_BOOT_SECTOR_MAGIC)
|
|
{
|
|
UiMessageBox("Invalid boot sector magic (0xaa55)");
|
|
return FALSE;
|
|
}
|
|
|
|
// DbgDumpBuffer(DPRINT_LINUX, LinuxBootSector, 512);
|
|
|
|
TRACE("SetupSectors: %d\n" , LinuxBootSector->SetupSectors);
|
|
TRACE("RootFlags: 0x%x\n", LinuxBootSector->RootFlags);
|
|
TRACE("SystemSize: 0x%x\n", LinuxBootSector->SystemSize);
|
|
TRACE("SwapDevice: 0x%x\n", LinuxBootSector->SwapDevice);
|
|
TRACE("RamSize: 0x%x\n", LinuxBootSector->RamSize);
|
|
TRACE("VideoMode: 0x%x\n", LinuxBootSector->VideoMode);
|
|
TRACE("RootDevice: 0x%x\n", LinuxBootSector->RootDevice);
|
|
TRACE("BootFlag: 0x%x\n", LinuxBootSector->BootFlag);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOLEAN LinuxReadSetupSector(ULONG LinuxKernelFile)
|
|
{
|
|
LARGE_INTEGER Position;
|
|
UCHAR TempLinuxSetupSector[512];
|
|
|
|
/* Load the first linux setup sector */
|
|
Position.QuadPart = 512;
|
|
if (ArcSeek(LinuxKernelFile, &Position, SeekAbsolute) != ESUCCESS)
|
|
return FALSE;
|
|
if (ArcRead(LinuxKernelFile, TempLinuxSetupSector, 512, NULL) != ESUCCESS)
|
|
return FALSE;
|
|
|
|
/* Check the kernel version */
|
|
LinuxSetupSector = (PLINUX_SETUPSECTOR)TempLinuxSetupSector;
|
|
if (!LinuxCheckKernelVersion())
|
|
return FALSE;
|
|
|
|
if (NewStyleLinuxKernel)
|
|
SetupSectorSize = 512 * LinuxBootSector->SetupSectors;
|
|
else
|
|
SetupSectorSize = 512 * 4; // Always 4 setup sectors
|
|
|
|
/* Allocate memory for setup sectors */
|
|
LinuxSetupSector = MmAllocateMemoryWithType(SetupSectorSize, LoaderSystemCode);
|
|
if (LinuxSetupSector == NULL)
|
|
return FALSE;
|
|
|
|
/* Copy over first setup sector */
|
|
RtlCopyMemory(LinuxSetupSector, TempLinuxSetupSector, 512);
|
|
|
|
/* Load the rest of the linux setup sectors */
|
|
Position.QuadPart = 1024;
|
|
if (ArcSeek(LinuxKernelFile, &Position, SeekAbsolute) != ESUCCESS)
|
|
return FALSE;
|
|
if (ArcRead(LinuxKernelFile, (PVOID)((ULONG_PTR)LinuxSetupSector + 512), SetupSectorSize - 512, NULL) != ESUCCESS)
|
|
return FALSE;
|
|
|
|
// DbgDumpBuffer(DPRINT_LINUX, LinuxSetupSector, SetupSectorSize);
|
|
|
|
TRACE("SetupHeaderSignature: 0x%x (HdrS)\n", LinuxSetupSector->SetupHeaderSignature);
|
|
TRACE("Version: 0x%x\n", LinuxSetupSector->Version);
|
|
TRACE("RealModeSwitch: 0x%x\n", LinuxSetupSector->RealModeSwitch);
|
|
TRACE("SetupSeg: 0x%x\n", LinuxSetupSector->SetupSeg);
|
|
TRACE("StartSystemSeg: 0x%x\n", LinuxSetupSector->StartSystemSeg);
|
|
TRACE("KernelVersion: 0x%x\n", LinuxSetupSector->KernelVersion);
|
|
TRACE("TypeOfLoader: 0x%x\n", LinuxSetupSector->TypeOfLoader);
|
|
TRACE("LoadFlags: 0x%x\n", LinuxSetupSector->LoadFlags);
|
|
TRACE("SetupMoveSize: 0x%x\n", LinuxSetupSector->SetupMoveSize);
|
|
TRACE("Code32Start: 0x%x\n", LinuxSetupSector->Code32Start);
|
|
TRACE("RamdiskAddress: 0x%x\n", LinuxSetupSector->RamdiskAddress);
|
|
TRACE("RamdiskSize: 0x%x\n", LinuxSetupSector->RamdiskSize);
|
|
TRACE("BootSectKludgeOffset: 0x%x\n", LinuxSetupSector->BootSectKludgeOffset);
|
|
TRACE("BootSectKludgeSegment: 0x%x\n", LinuxSetupSector->BootSectKludgeSegment);
|
|
TRACE("HeapEnd: 0x%x\n", LinuxSetupSector->HeapEnd);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOLEAN LinuxReadKernel(ULONG LinuxKernelFile)
|
|
{
|
|
PVOID LoadAddress;
|
|
LARGE_INTEGER Position;
|
|
ULONG BytesLoaded;
|
|
CHAR StatusText[260];
|
|
|
|
RtlStringCbPrintfA(StatusText, sizeof(StatusText), "Loading %s", LinuxKernelName);
|
|
UiDrawStatusText(StatusText);
|
|
|
|
/* Try to allocate memory for the Linux kernel; if it fails, allocate somewhere else */
|
|
LinuxKernelLoadAddress = MmAllocateMemoryAtAddress(LinuxKernelSize, (PVOID)LINUX_KERNEL_LOAD_ADDRESS, LoaderSystemCode);
|
|
if (LinuxKernelLoadAddress != (PVOID)LINUX_KERNEL_LOAD_ADDRESS)
|
|
{
|
|
/* It's OK, let's allocate again somewhere else */
|
|
LinuxKernelLoadAddress = MmAllocateMemoryWithType(LinuxKernelSize, LoaderSystemCode);
|
|
if (LinuxKernelLoadAddress == NULL)
|
|
{
|
|
TRACE("Failed to allocate 0x%lx bytes for the kernel image.\n", LinuxKernelSize);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
LoadAddress = LinuxKernelLoadAddress;
|
|
|
|
/* Load the linux kernel at 0x100000 (1mb) */
|
|
Position.QuadPart = 512 + SetupSectorSize;
|
|
if (ArcSeek(LinuxKernelFile, &Position, SeekAbsolute) != ESUCCESS)
|
|
return FALSE;
|
|
for (BytesLoaded = 0; BytesLoaded < LinuxKernelSize; )
|
|
{
|
|
if (ArcRead(LinuxKernelFile, LoadAddress, LINUX_READ_CHUNK_SIZE, NULL) != ESUCCESS)
|
|
return FALSE;
|
|
|
|
BytesLoaded += LINUX_READ_CHUNK_SIZE;
|
|
LoadAddress = (PVOID)((ULONG_PTR)LoadAddress + LINUX_READ_CHUNK_SIZE);
|
|
|
|
UiUpdateProgressBar(BytesLoaded * 100 / (LinuxKernelSize + LinuxInitrdSize), NULL);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOLEAN LinuxCheckKernelVersion(VOID)
|
|
{
|
|
/* Just assume old kernel until we find otherwise */
|
|
NewStyleLinuxKernel = FALSE;
|
|
|
|
/* Check for new style setup header */
|
|
if (LinuxSetupSector->SetupHeaderSignature != LINUX_SETUP_HEADER_ID)
|
|
{
|
|
NewStyleLinuxKernel = FALSE;
|
|
}
|
|
/* Check for version below 2.0 */
|
|
else if (LinuxSetupSector->Version < 0x0200)
|
|
{
|
|
NewStyleLinuxKernel = FALSE;
|
|
}
|
|
/* Check for version 2.0 */
|
|
else if (LinuxSetupSector->Version == 0x0200)
|
|
{
|
|
NewStyleLinuxKernel = TRUE;
|
|
}
|
|
/* Check for version 2.01+ */
|
|
else if (LinuxSetupSector->Version >= 0x0201)
|
|
{
|
|
NewStyleLinuxKernel = TRUE;
|
|
LinuxSetupSector->HeapEnd = 0x9000;
|
|
LinuxSetupSector->LoadFlags |= LINUX_FLAG_CAN_USE_HEAP;
|
|
}
|
|
|
|
if ((NewStyleLinuxKernel == FALSE) && (LinuxInitrdName))
|
|
{
|
|
UiMessageBox("Error: Cannot load a ramdisk (initrd) with an old kernel image.");
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOLEAN LinuxReadInitrd(ULONG LinuxInitrdFile)
|
|
{
|
|
ULONG BytesLoaded;
|
|
CHAR StatusText[260];
|
|
|
|
RtlStringCbPrintfA(StatusText, sizeof(StatusText), "Loading %s", LinuxInitrdName);
|
|
UiDrawStatusText(StatusText);
|
|
|
|
/* Allocate memory for the ramdisk, below 4GB */
|
|
// LinuxInitrdLoadAddress = MmAllocateMemory(LinuxInitrdSize);
|
|
/* Try to align it at the next MB boundary after the kernel */
|
|
// LinuxInitrdLoadAddress = MmAllocateMemoryAtAddress(LinuxInitrdSize, (PVOID)ROUND_UP((LINUX_KERNEL_LOAD_ADDRESS + LinuxKernelSize), 0x100000));
|
|
if (LinuxSetupSector->Version <= 0x0202)
|
|
{
|
|
#ifdef _M_AMD64
|
|
C_ASSERT(LINUX_MAX_INITRD_ADDRESS < 0x100000000);
|
|
#endif
|
|
LinuxInitrdLoadAddress = MmAllocateHighestMemoryBelowAddress(LinuxInitrdSize, (PVOID)LINUX_MAX_INITRD_ADDRESS, LoaderSystemCode);
|
|
}
|
|
else
|
|
{
|
|
LinuxInitrdLoadAddress = MmAllocateHighestMemoryBelowAddress(LinuxInitrdSize, UlongToPtr(LinuxSetupSector->InitrdAddressMax), LoaderSystemCode);
|
|
}
|
|
if (LinuxInitrdLoadAddress == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
#ifdef _M_AMD64
|
|
ASSERT((ULONG_PTR)LinuxInitrdLoadAddress < 0x100000000);
|
|
#endif
|
|
|
|
/* Set the information in the setup struct */
|
|
LinuxSetupSector->RamdiskAddress = PtrToUlong(LinuxInitrdLoadAddress);
|
|
LinuxSetupSector->RamdiskSize = LinuxInitrdSize;
|
|
|
|
TRACE("RamdiskAddress: 0x%x\n", LinuxSetupSector->RamdiskAddress);
|
|
TRACE("RamdiskSize: 0x%x\n", LinuxSetupSector->RamdiskSize);
|
|
|
|
if (LinuxSetupSector->Version >= 0x0203)
|
|
{
|
|
TRACE("InitrdAddressMax: 0x%x\n", LinuxSetupSector->InitrdAddressMax);
|
|
}
|
|
|
|
/* Load the ramdisk */
|
|
for (BytesLoaded = 0; BytesLoaded < LinuxInitrdSize; )
|
|
{
|
|
if (ArcRead(LinuxInitrdFile, LinuxInitrdLoadAddress, LINUX_READ_CHUNK_SIZE, NULL) != ESUCCESS)
|
|
return FALSE;
|
|
|
|
BytesLoaded += LINUX_READ_CHUNK_SIZE;
|
|
LinuxInitrdLoadAddress = (PVOID)((ULONG_PTR)LinuxInitrdLoadAddress + LINUX_READ_CHUNK_SIZE);
|
|
|
|
UiUpdateProgressBar((BytesLoaded + LinuxKernelSize) * 100 / (LinuxInitrdSize + LinuxKernelSize), NULL);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
#endif /* _M_IX86 || _M_AMD64 */
|