1348 lines
36 KiB
C
1348 lines
36 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1992 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
initx86.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
Does any x86-specific initialization, then starts the common ARC osloader
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
John Vert (jvert) 4-Nov-1993
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
#include "bldrx86.h"
|
|||
|
#include "acpitabl.h"
|
|||
|
#include "msg.h"
|
|||
|
#include "bootstatus.h"
|
|||
|
|
|||
|
#include <string.h>
|
|||
|
#include <stdlib.h>
|
|||
|
#include <stdio.h>
|
|||
|
#include <netboot.h>
|
|||
|
#include <ramdisk.h>
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
BlpPaeSupported(
|
|||
|
VOID
|
|||
|
);
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
BlpChipsetPaeSupported(
|
|||
|
VOID
|
|||
|
);
|
|||
|
|
|||
|
ARC_STATUS
|
|||
|
Blx86GetImageProperties(
|
|||
|
IN ULONG LoadDeviceId,
|
|||
|
IN PCHAR ImagePath,
|
|||
|
OUT PBOOLEAN IsPae,
|
|||
|
OUT PBOOLEAN SupportsHotPlugMemory
|
|||
|
);
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
Blx86IsKernelCompatible(
|
|||
|
IN ULONG LoadDeviceId,
|
|||
|
IN PCHAR ImagePath,
|
|||
|
IN BOOLEAN ProcessorSupportsPae,
|
|||
|
IN OUT PBOOLEAN UsePae
|
|||
|
);
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
Blx86NeedPaeForHotPlugMemory(
|
|||
|
VOID
|
|||
|
);
|
|||
|
|
|||
|
UCHAR BootPartitionName[80];
|
|||
|
UCHAR KernelBootDevice[80];
|
|||
|
UCHAR OsLoadFilename[100];
|
|||
|
UCHAR OsLoaderFilename[100];
|
|||
|
UCHAR SystemPartition[100];
|
|||
|
UCHAR OsLoadPartition[100];
|
|||
|
UCHAR OsLoadOptions[100];
|
|||
|
UCHAR ConsoleInputName[50];
|
|||
|
UCHAR MyBuffer[SECTOR_SIZE+32];
|
|||
|
UCHAR ConsoleOutputName[50];
|
|||
|
UCHAR X86SystemPartition[sizeof("x86systempartition=") + sizeof(BootPartitionName)];
|
|||
|
|
|||
|
extern BOOLEAN ForceLastKnownGood;
|
|||
|
extern ULONG BlHighestPage;
|
|||
|
extern PHARDWARE_PTE PDE;
|
|||
|
|
|||
|
extern ULONG BootFlags;
|
|||
|
|
|||
|
extern PDESCRIPTION_HEADER
|
|||
|
BlFindACPITable(
|
|||
|
IN PCHAR TableName,
|
|||
|
IN ULONG TableLength
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
BlStartup(
|
|||
|
IN PCHAR PartitionName
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Does x86-specific initialization, particularly presenting the boot.ini
|
|||
|
menu and running NTDETECT, then calls to the common osloader.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
PartitionName - Supplies the ARC name of the partition (or floppy) that
|
|||
|
setupldr was loaded from.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Does not return
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ULONG Argc = 0;
|
|||
|
PUCHAR Argv[10];
|
|||
|
ARC_STATUS Status;
|
|||
|
ULONG BootFileId;
|
|||
|
PCHAR BootFile = NULL;
|
|||
|
ULONG Read;
|
|||
|
PCHAR p,q;
|
|||
|
ULONG i;
|
|||
|
ULONG DriveId;
|
|||
|
ULONG FileSize;
|
|||
|
ULONG Count;
|
|||
|
LARGE_INTEGER SeekPosition;
|
|||
|
PCHAR LoadOptions = NULL;
|
|||
|
BOOLEAN UseTimeOut=TRUE;
|
|||
|
BOOLEAN AlreadyInitialized = FALSE;
|
|||
|
extern BOOLEAN FwDescriptorsValid;
|
|||
|
PCHAR BadLinkName = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// If this is an SDI boot, initialize the ramdisk "driver" now.
|
|||
|
//
|
|||
|
// NB. PartitionName is the name of the device from which the loader
|
|||
|
// was loaded. It is NOT the name of the device from which the OS will
|
|||
|
// be loaded. If we're doing a straight ramdisk boot, this will NOT be
|
|||
|
// ramdisk(0) -- it will be net(0) or a physical disk name. Only if
|
|||
|
// we're doing a real SDI boot will this be ramdisk(0). (See
|
|||
|
// NtProcessStartup() in boot\lib\i386\entry.c.)
|
|||
|
//
|
|||
|
|
|||
|
if ( strcmp(PartitionName,"ramdisk(0)") == 0 ) {
|
|||
|
RamdiskInitialize( NULL, TRUE );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Open the boot partition so we can load boot drivers off it.
|
|||
|
//
|
|||
|
Status = ArcOpen(PartitionName, ArcOpenReadWrite, &DriveId);
|
|||
|
if (Status != ESUCCESS) {
|
|||
|
BlPrint(TEXT("Couldn't open drive %s\n"),PartitionName);
|
|||
|
BlPrint(BlFindMessage(BL_DRIVE_ERROR),PartitionName);
|
|||
|
goto BootFailed;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Initialize dbcs font and display support.
|
|||
|
//
|
|||
|
TextGrInitialize(DriveId, NULL);
|
|||
|
|
|||
|
//
|
|||
|
// Initialize ARC StdIo functionality
|
|||
|
//
|
|||
|
|
|||
|
strcpy(ConsoleInputName,"consolein=multi(0)key(0)keyboard(0)");
|
|||
|
strcpy(ConsoleOutputName,"consoleout=multi(0)video(0)monitor(0)");
|
|||
|
Argv[0]=ConsoleInputName;
|
|||
|
Argv[1]=ConsoleOutputName;
|
|||
|
BlInitStdio (2, Argv);
|
|||
|
|
|||
|
//
|
|||
|
// Announce the loader
|
|||
|
//
|
|||
|
//BlPrint(OsLoaderVersion);
|
|||
|
|
|||
|
//
|
|||
|
// Check ntldr partition for hiberation image
|
|||
|
//
|
|||
|
|
|||
|
BlHiberRestore(DriveId, &BadLinkName);
|
|||
|
|
|||
|
//
|
|||
|
// Re-open the boot partition as a temporary work around
|
|||
|
// for NTFS caching bug.
|
|||
|
//
|
|||
|
ArcClose(DriveId);
|
|||
|
|
|||
|
Status = ArcOpen(PartitionName, ArcOpenReadWrite, &DriveId);
|
|||
|
|
|||
|
if (Status != ESUCCESS) {
|
|||
|
BlPrint(TEXT("Couldn't open drive %s\n"),PartitionName);
|
|||
|
BlPrint(BlFindMessage(BL_DRIVE_ERROR),PartitionName);
|
|||
|
goto BootFailed;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// It is possible that the link file points to the hiber file on a scsi
|
|||
|
// disk. In that case, we need to load NTBOOTDD.SYS in order to access the
|
|||
|
// hiber file and try again.
|
|||
|
//
|
|||
|
if ((BadLinkName != NULL) &&
|
|||
|
((_strnicmp(BadLinkName,"scsi(",5)==0) || (_strnicmp(BadLinkName,"signature(",10)==0))) {
|
|||
|
ULONG HiberDrive;
|
|||
|
|
|||
|
//
|
|||
|
// Before loading NTBOOTDD we must load NTDETECT as that figures
|
|||
|
// out the PCI buses
|
|||
|
//
|
|||
|
if (BlDetectHardware(DriveId, "/fastdetect")) {
|
|||
|
if (AEInitializeIo(DriveId) == ESUCCESS) {
|
|||
|
AlreadyInitialized = TRUE;
|
|||
|
|
|||
|
//
|
|||
|
// Now that NTBOOTDD.SYS is loaded, we can try again.
|
|||
|
//
|
|||
|
Status = ArcOpen(BadLinkName, ArcOpenReadWrite, &HiberDrive);
|
|||
|
if (Status == ESUCCESS) {
|
|||
|
BlHiberRestore(HiberDrive, NULL);
|
|||
|
ArcClose(HiberDrive);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
do {
|
|||
|
|
|||
|
if (BlBootingFromNet) {
|
|||
|
PCHAR BootIniPath;
|
|||
|
|
|||
|
//
|
|||
|
// If we are booting from the network and
|
|||
|
// NetBootIniContents has been specified, we
|
|||
|
// will just its contents for boot.ini
|
|||
|
//
|
|||
|
if (NetBootIniContents[0] != '\0') {
|
|||
|
BootFile = NetBootIniContents;
|
|||
|
} else {
|
|||
|
//
|
|||
|
// NetBootIniContents is empty, therefore
|
|||
|
// we need to open the boot.ini file from the
|
|||
|
// network. The acutal file to open is either
|
|||
|
// specificied in NetBootIniPath or is the
|
|||
|
// default of NetBootPath\boot.ini
|
|||
|
//
|
|||
|
if (NetBootIniPath[0] != '\0') {
|
|||
|
BootIniPath = NetBootIniPath;
|
|||
|
} else {
|
|||
|
strcpy(MyBuffer, NetBootPath);
|
|||
|
strcat(MyBuffer, "boot.ini");
|
|||
|
BootIniPath = MyBuffer;
|
|||
|
}
|
|||
|
Status = BlOpen( DriveId,
|
|||
|
BootIniPath,
|
|||
|
ArcOpenReadOnly,
|
|||
|
&BootFileId );
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
Status = BlOpen( DriveId,
|
|||
|
"\\boot.ini",
|
|||
|
ArcOpenReadOnly,
|
|||
|
&BootFileId );
|
|||
|
}
|
|||
|
|
|||
|
if (BootFile == NULL) {
|
|||
|
|
|||
|
BootFile = MyBuffer;
|
|||
|
RtlZeroMemory(MyBuffer, SECTOR_SIZE+32);
|
|||
|
|
|||
|
if (Status != ESUCCESS) {
|
|||
|
BootFile[0]='\0';
|
|||
|
} else {
|
|||
|
//
|
|||
|
// Determine the length of the boot.ini file by reading to the end of
|
|||
|
// file.
|
|||
|
//
|
|||
|
|
|||
|
FileSize = 0;
|
|||
|
do {
|
|||
|
Status = BlRead(BootFileId, BootFile, SECTOR_SIZE, &Count);
|
|||
|
if (Status != ESUCCESS) {
|
|||
|
BlClose(BootFileId);
|
|||
|
BlPrint(BlFindMessage(BL_READ_ERROR),Status);
|
|||
|
BootFile[0] = '\0';
|
|||
|
FileSize = 0;
|
|||
|
Count = 0;
|
|||
|
goto BootFailed;
|
|||
|
}
|
|||
|
|
|||
|
FileSize += Count;
|
|||
|
} while (Count != 0);
|
|||
|
|
|||
|
if (FileSize >= SECTOR_SIZE) {
|
|||
|
|
|||
|
//
|
|||
|
// We need to allocate a bigger buffer, since the boot.ini file
|
|||
|
// is bigger than one sector.
|
|||
|
//
|
|||
|
|
|||
|
BootFile=FwAllocateHeap(FileSize);
|
|||
|
}
|
|||
|
|
|||
|
if (BootFile == NULL) {
|
|||
|
BlPrint(BlFindMessage(BL_READ_ERROR),ENOMEM);
|
|||
|
BootFile = MyBuffer;
|
|||
|
BootFile[0] = '\0';
|
|||
|
goto BootFailed;
|
|||
|
} else {
|
|||
|
|
|||
|
SeekPosition.QuadPart = 0;
|
|||
|
Status = BlSeek(BootFileId,
|
|||
|
&SeekPosition,
|
|||
|
SeekAbsolute);
|
|||
|
if (Status != ESUCCESS) {
|
|||
|
BlPrint(BlFindMessage(BL_READ_ERROR),Status);
|
|||
|
BootFile = MyBuffer;
|
|||
|
BootFile[0] = '\0';
|
|||
|
goto BootFailed;
|
|||
|
} else {
|
|||
|
Status = BlRead( BootFileId,
|
|||
|
BootFile,
|
|||
|
FileSize,
|
|||
|
&Read );
|
|||
|
|
|||
|
SeekPosition.QuadPart = 0;
|
|||
|
Status = BlSeek(BootFileId,
|
|||
|
&SeekPosition,
|
|||
|
SeekAbsolute);
|
|||
|
if (Status != ESUCCESS) {
|
|||
|
BlPrint(BlFindMessage(BL_READ_ERROR),Status);
|
|||
|
BootFile = MyBuffer;
|
|||
|
BootFile[0] = '\0';
|
|||
|
goto BootFailed;
|
|||
|
} else {
|
|||
|
BootFile[Read]='\0';
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Find Ctrl-Z, if it exists
|
|||
|
//
|
|||
|
|
|||
|
p=BootFile;
|
|||
|
while ((*p!='\0') && (*p!=26)) {
|
|||
|
++p;
|
|||
|
}
|
|||
|
if (*p != '\0') {
|
|||
|
*p='\0';
|
|||
|
}
|
|||
|
BlClose(BootFileId);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
MdShutoffFloppy();
|
|||
|
|
|||
|
ARC_DISPLAY_CLEAR();
|
|||
|
|
|||
|
// We require a boot.ini file when booting from the network
|
|||
|
if (BlBootingFromNet && *BootFile == '\0') {
|
|||
|
BlPrint(BlFindMessage(BL_READ_ERROR),Status);
|
|||
|
goto BootFailed;
|
|||
|
}
|
|||
|
|
|||
|
p=BlSelectKernel(DriveId,BootFile, &LoadOptions, UseTimeOut);
|
|||
|
if ( p == NULL ) {
|
|||
|
BlPrint(BlFindMessage(BL_INVALID_BOOT_INI_FATAL));
|
|||
|
goto BootFailed;
|
|||
|
}
|
|||
|
|
|||
|
#if defined(REMOTE_BOOT)
|
|||
|
//
|
|||
|
// We may have loaded boot.ini from the hard drive but if the selection was
|
|||
|
// for a remote boot installation then we need to load the rest from the net.
|
|||
|
//
|
|||
|
|
|||
|
if((DriveId != NET_DEVICE_ID) &&
|
|||
|
(!_strnicmp(p,"net(",4))) {
|
|||
|
BlPrint("\nWarning:Booting from CSC without access to server\n");
|
|||
|
strcpy(BootPartitionName,"net(0)");
|
|||
|
BlBootingFromNet = TRUE;
|
|||
|
NetworkBootRom = FALSE;
|
|||
|
|
|||
|
//
|
|||
|
// p points to something like: "net(0)\COLINW3\IMirror\Clients\cwintel\BootDrive\WINNT"
|
|||
|
// NetBootPath needs to contain "\Clients\cwintel\"
|
|||
|
// ServerShare is used inside lib\netboot.c to find the correct file if CSC
|
|||
|
// is used.
|
|||
|
//
|
|||
|
|
|||
|
q = strchr(p+sizeof("net(0)"), '\\');
|
|||
|
q = strchr(q+1, '\\');
|
|||
|
strcpy(NetBootPath,q);
|
|||
|
q = strrchr( NetBootPath, '\\' );
|
|||
|
q[1] = '\0';
|
|||
|
}
|
|||
|
#endif // defined(REMOTE_BOOT)
|
|||
|
|
|||
|
if (!AlreadyInitialized) {
|
|||
|
|
|||
|
// BlPrint(BlFindMessage(BL_NTDETECT_MSG));
|
|||
|
if (!BlDetectHardware(DriveId, LoadOptions)) {
|
|||
|
BlPrint(BlFindMessage(BL_NTDETECT_FAILURE));
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
ARC_DISPLAY_CLEAR();
|
|||
|
|
|||
|
//
|
|||
|
// Initialize SCSI boot driver, if necessary.
|
|||
|
//
|
|||
|
if (_strnicmp(p,"scsi(",5)==0 || _strnicmp(p,"signature(",10)==0) {
|
|||
|
AEInitializeIo(DriveId);
|
|||
|
}
|
|||
|
|
|||
|
ArcClose(DriveId);
|
|||
|
//
|
|||
|
// Indicate that fw memory descriptors cannot be changed from
|
|||
|
// now on.
|
|||
|
//
|
|||
|
FwDescriptorsValid = FALSE;
|
|||
|
} else {
|
|||
|
ARC_DISPLAY_CLEAR();
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Set AlreadyInitialized Flag to TRUE to indicate that ntdetect
|
|||
|
// routines have been run.
|
|||
|
//
|
|||
|
|
|||
|
AlreadyInitialized = TRUE;
|
|||
|
|
|||
|
//
|
|||
|
// Only time out the boot menu the first time through the boot.
|
|||
|
// For all subsequent reboots, the menu will stay up.
|
|||
|
//
|
|||
|
UseTimeOut=FALSE;
|
|||
|
|
|||
|
i=0;
|
|||
|
while (*p !='\\') {
|
|||
|
KernelBootDevice[i] = *p;
|
|||
|
i++;
|
|||
|
p++;
|
|||
|
}
|
|||
|
KernelBootDevice[i] = '\0';
|
|||
|
|
|||
|
//
|
|||
|
// If the user hasn't chosen an advanced boot mode then we will present
|
|||
|
// them with the menu and select our default.
|
|||
|
//
|
|||
|
|
|||
|
if(BlGetAdvancedBootOption() == -1) {
|
|||
|
PVOID dataHandle;
|
|||
|
ULONG abmDefault;
|
|||
|
BSD_LAST_BOOT_STATUS LastBootStatus = BsdLastBootGood;
|
|||
|
|
|||
|
//
|
|||
|
// Open the boot status data.
|
|||
|
//
|
|||
|
|
|||
|
Status = BlLockBootStatusData(0, KernelBootDevice, p, &dataHandle);
|
|||
|
|
|||
|
if(Status == ESUCCESS) {
|
|||
|
|
|||
|
//
|
|||
|
// Check the status of the last boot. This will return both the
|
|||
|
// status and the advanced boot mode we should enter (based on the
|
|||
|
// status and the "enable auto advanced boot" flag.
|
|||
|
//
|
|||
|
|
|||
|
abmDefault = BlGetLastBootStatus(dataHandle, &LastBootStatus);
|
|||
|
|
|||
|
if(LastBootStatus == BsdLastBootFailed) {
|
|||
|
|
|||
|
//
|
|||
|
// If we should attempt an ABM mode then present the user with
|
|||
|
// the menu.
|
|||
|
//
|
|||
|
|
|||
|
if(abmDefault != -1) {
|
|||
|
ULONG menuTitle;
|
|||
|
UCHAR timeout;
|
|||
|
|
|||
|
if(LastBootStatus == BsdLastBootFailed) {
|
|||
|
menuTitle = BL_ADVANCEDBOOT_AUTOLKG_TITLE;
|
|||
|
} else if(LastBootStatus == BsdLastBootNotShutdown) {
|
|||
|
menuTitle = BL_ADVANCEDBOOT_AUTOSAFE_TITLE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Read the timeout value.
|
|||
|
//
|
|||
|
|
|||
|
Status = BlGetSetBootStatusData(dataHandle,
|
|||
|
TRUE,
|
|||
|
RtlBsdItemAabTimeout,
|
|||
|
&timeout,
|
|||
|
sizeof(UCHAR),
|
|||
|
NULL);
|
|||
|
|
|||
|
if(Status != ESUCCESS) {
|
|||
|
timeout = 30;
|
|||
|
}
|
|||
|
|
|||
|
abmDefault = BlDoAdvancedBoot(menuTitle,
|
|||
|
-1,
|
|||
|
TRUE,
|
|||
|
timeout);
|
|||
|
}
|
|||
|
|
|||
|
BlAutoAdvancedBoot(&LoadOptions,
|
|||
|
LastBootStatus,
|
|||
|
abmDefault);
|
|||
|
}
|
|||
|
|
|||
|
BlUnlockBootStatusData(dataHandle);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// We are fooling the OS Loader here. It only uses the osloader= variable
|
|||
|
// to determine where to load HAL.DLL from. Since x86 systems have no
|
|||
|
// "system partition" we want to load HAL.DLL from \nt\system\HAL.DLL.
|
|||
|
// So we pass that it as the osloader path.
|
|||
|
//
|
|||
|
|
|||
|
strcpy(OsLoaderFilename,"osloader=");
|
|||
|
strcat(OsLoaderFilename,p);
|
|||
|
strcat(OsLoaderFilename,"\\System32\\NTLDR");
|
|||
|
|
|||
|
strcpy(SystemPartition,"systempartition=");
|
|||
|
strcat(SystemPartition,KernelBootDevice);
|
|||
|
|
|||
|
strcpy(OsLoadPartition,"osloadpartition=");
|
|||
|
strcat(OsLoadPartition,KernelBootDevice);
|
|||
|
|
|||
|
strcpy(OsLoadFilename, "osloadfilename=");
|
|||
|
strcat(OsLoadFilename, p);
|
|||
|
|
|||
|
strcpy(OsLoadOptions,"osloadoptions=");
|
|||
|
if (LoadOptions) {
|
|||
|
strcat(OsLoadOptions,LoadOptions);
|
|||
|
}
|
|||
|
|
|||
|
strcpy(ConsoleInputName,"consolein=multi(0)key(0)keyboard(0)");
|
|||
|
|
|||
|
strcpy(ConsoleOutputName,"consoleout=multi(0)video(0)monitor(0)");
|
|||
|
|
|||
|
strcpy(X86SystemPartition,"x86systempartition=");
|
|||
|
strcat(X86SystemPartition,PartitionName);
|
|||
|
|
|||
|
Argv[Argc++]="load";
|
|||
|
|
|||
|
Argv[Argc++]=OsLoaderFilename;
|
|||
|
Argv[Argc++]=SystemPartition;
|
|||
|
Argv[Argc++]=OsLoadFilename;
|
|||
|
Argv[Argc++]=OsLoadPartition;
|
|||
|
Argv[Argc++]=OsLoadOptions;
|
|||
|
Argv[Argc++]=X86SystemPartition;
|
|||
|
|
|||
|
Status = BlOsLoader( Argc, Argv, NULL );
|
|||
|
|
|||
|
BootFailed:
|
|||
|
ForceLastKnownGood = FALSE;
|
|||
|
if (Status != ESUCCESS) {
|
|||
|
|
|||
|
#if defined(ENABLE_LOADER_DEBUG)
|
|||
|
DbgBreakPoint();
|
|||
|
#endif
|
|||
|
|
|||
|
if (BootFlags & BOOTFLAG_REBOOT_ON_FAILURE) {
|
|||
|
ULONG StartTime = ArcGetRelativeTime();
|
|||
|
BlPrint(TEXT("\nRebooting in 5 seconds...\n"));
|
|||
|
while ( ArcGetRelativeTime() - StartTime < 5) {}
|
|||
|
ArcRestart();
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Boot failed, wait for reboot
|
|||
|
//
|
|||
|
while (TRUE) {
|
|||
|
while (!BlGetKey()); // BOOT FAILED!
|
|||
|
if (BlTerminalHandleLoaderFailure()) {
|
|||
|
ArcRestart();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
//
|
|||
|
// Need to reopen the drive
|
|||
|
//
|
|||
|
Status = ArcOpen(BootPartitionName, ArcOpenReadOnly, &DriveId);
|
|||
|
if (Status != ESUCCESS) {
|
|||
|
BlPrint(BlFindMessage(BL_DRIVE_ERROR),BootPartitionName);
|
|||
|
goto BootFailed;
|
|||
|
}
|
|||
|
}
|
|||
|
} while (TRUE);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
DoApmAttemptReconnect(
|
|||
|
VOID
|
|||
|
)
|
|||
|
{
|
|||
|
APM_ATTEMPT_RECONNECT();
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
Blx86NeedPaeForHotPlugMemory(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Determine whether any hot plug memory described in the SRAT table
|
|||
|
extends beyond the 4gb mark and thus implies a need for PAE.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE: Machine supports hot plug memory beyond the 4gb mark, PAE should be
|
|||
|
turned on if possible.
|
|||
|
|
|||
|
FALSE: Machine doesn't support hot plug memory beyond the 4gb mark.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PACPI_SRAT SratTable;
|
|||
|
PACPI_SRAT_ENTRY SratEntry;
|
|||
|
PACPI_SRAT_ENTRY SratEnd;
|
|||
|
|
|||
|
SratTable = (PACPI_SRAT) BlFindACPITable("SRAT", sizeof(ACPI_SRAT));
|
|||
|
if (SratTable == NULL) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
SratTable = (PACPI_SRAT) BlFindACPITable("SRAT", SratTable->Header.Length);
|
|||
|
if (SratTable == NULL) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
SratEnd = (PACPI_SRAT_ENTRY)(((PUCHAR)SratTable) +
|
|||
|
SratTable->Header.Length);
|
|||
|
for (SratEntry = (PACPI_SRAT_ENTRY)(SratTable + 1);
|
|||
|
SratEntry < SratEnd;
|
|||
|
SratEntry = (PACPI_SRAT_ENTRY)(((PUCHAR) SratEntry) + SratEntry->Length)) {
|
|||
|
if (SratEntry->Type != SratMemory) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
if (SratEntry->MemoryAffinity.Flags.HotPlug &&
|
|||
|
SratEntry->MemoryAffinity.Flags.Enabled) {
|
|||
|
ULONGLONG Extent;
|
|||
|
|
|||
|
//
|
|||
|
// Check if hot plug region ends beyond the 4gb mark.
|
|||
|
//
|
|||
|
|
|||
|
Extent = SratEntry->MemoryAffinity.Base.QuadPart +
|
|||
|
SratEntry->MemoryAffinity.Length;
|
|||
|
if (Extent > 0x100000000) {
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
ARC_STATUS
|
|||
|
Blx86CheckForPaeKernel(
|
|||
|
IN BOOLEAN UserSpecifiedPae,
|
|||
|
IN BOOLEAN UserSpecifiedNoPae,
|
|||
|
IN PCHAR UserSpecifiedKernelImage,
|
|||
|
IN PCHAR HalImagePath,
|
|||
|
IN ULONG LoadDeviceId,
|
|||
|
IN ULONG SystemDeviceId,
|
|||
|
OUT PULONG HighestSystemPage,
|
|||
|
OUT PBOOLEAN UsePaeMode,
|
|||
|
IN OUT PCHAR KernelPath
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
There are two kernels: one, ntkrnlpa.exe, is compiled for PAE mode.
|
|||
|
The other, ntoskrnl.exe, is not.
|
|||
|
|
|||
|
This routine is responsible for deciding which one to load.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
UserSpecifiedPae - Indicates whether the user requested PAE mode
|
|||
|
via the /PAE loader switch.
|
|||
|
|
|||
|
UserSpecifiedNoPae - Indicates whether the user requrested non-PAE mode
|
|||
|
via the /NOPAE loader switch.
|
|||
|
|
|||
|
UserSpecifiedKernelImage - Points to the user-specified kernel image name,
|
|||
|
indicated via the /KERNEL= switch, or NULL if none was specified.
|
|||
|
|
|||
|
HalImagePath - Points to the hal image that will be used.
|
|||
|
|
|||
|
LoadDeviceId - The ARC device handle of the kernel load device.
|
|||
|
|
|||
|
SystemDeviceId - The ARC device handle of the system device.
|
|||
|
|
|||
|
HighestSystemPage - Out parameter returning the highest physical
|
|||
|
page found in the system.
|
|||
|
|
|||
|
UsePaeMode - Indicates whether the kernel should be loaded in PAE mode.
|
|||
|
|
|||
|
KernelPath - On input, the directory path of the kernel images. Upon
|
|||
|
successful return, this will contain the full kernel image path.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
ESUCCESS : A compatible kernel has been located, and its path resides in
|
|||
|
the output buffer pointed to by KernelPath.
|
|||
|
|
|||
|
EINVAL: A compatible kernel could not be located. This will be a fatal
|
|||
|
condition.
|
|||
|
|
|||
|
EBADF: hal is corrupt or missing. This will be a fatal condition.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
BOOLEAN foundMemoryAbove4G;
|
|||
|
BOOLEAN usePae;
|
|||
|
BOOLEAN processorSupportsPae;
|
|||
|
BOOLEAN halSupportsPae;
|
|||
|
BOOLEAN osSupportsHotPlugMemory;
|
|||
|
BOOLEAN havePaeKernel;
|
|||
|
BOOLEAN compatibleKernel;
|
|||
|
ULONG lastPage;
|
|||
|
PLIST_ENTRY link;
|
|||
|
PLIST_ENTRY listHead;
|
|||
|
PMEMORY_ALLOCATION_DESCRIPTOR descriptor;
|
|||
|
PCHAR kernelImageNamePae;
|
|||
|
PCHAR kernelImageNameNoPae;
|
|||
|
PCHAR kernelImageName;
|
|||
|
PCHAR kernelImageNameTarget;
|
|||
|
ARC_STATUS status;
|
|||
|
ULONG highestSystemPage;
|
|||
|
ULONG pagesAbove4Gig;
|
|||
|
|
|||
|
kernelImageNameNoPae = "ntoskrnl.exe";
|
|||
|
kernelImageNamePae = "ntkrnlpa.exe";
|
|||
|
kernelImageNameTarget = KernelPath + strlen( KernelPath );
|
|||
|
|
|||
|
//
|
|||
|
// Determine the highest physical page. Also, count the number of pages
|
|||
|
// at or above the 4G mark.
|
|||
|
//
|
|||
|
|
|||
|
highestSystemPage = 0;
|
|||
|
pagesAbove4Gig = 0;
|
|||
|
listHead = &BlLoaderBlock->MemoryDescriptorListHead;
|
|||
|
link = listHead->Flink;
|
|||
|
while (link != listHead) {
|
|||
|
|
|||
|
descriptor = CONTAINING_RECORD(link,
|
|||
|
MEMORY_ALLOCATION_DESCRIPTOR,
|
|||
|
ListEntry);
|
|||
|
|
|||
|
lastPage = descriptor->BasePage + descriptor->PageCount - 1;
|
|||
|
if (lastPage > highestSystemPage) {
|
|||
|
|
|||
|
//
|
|||
|
// We have a new highest system page, record it.
|
|||
|
//
|
|||
|
|
|||
|
highestSystemPage = lastPage;
|
|||
|
}
|
|||
|
|
|||
|
if (lastPage >= (1024 * 1024)) {
|
|||
|
|
|||
|
//
|
|||
|
// This descriptor includes one or more pages at or above
|
|||
|
// the 4G mark.
|
|||
|
//
|
|||
|
|
|||
|
if (descriptor->BasePage >= (1024 * 1024)) {
|
|||
|
|
|||
|
//
|
|||
|
// All of the pages in this descriptor lie at or above 4G.
|
|||
|
//
|
|||
|
|
|||
|
pagesAbove4Gig += descriptor->PageCount;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Only some of the pages in this descriptor lie at or above
|
|||
|
// 4G.
|
|||
|
//
|
|||
|
|
|||
|
pagesAbove4Gig += lastPage - (1024 * 1024) + 1;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
link = link->Flink;
|
|||
|
}
|
|||
|
*HighestSystemPage = highestSystemPage;
|
|||
|
|
|||
|
//
|
|||
|
// Record whether there is a non-trivial amount of memory above 4G on this
|
|||
|
// machine. Note that most machines with "exactly" 4G of ram actually move
|
|||
|
// a small amount of ram to above the 4G mark.
|
|||
|
//
|
|||
|
// Because running a PAE kernel inflicts a performance hit, we would rather
|
|||
|
// ignore some amount of memory x rather than move into PAE mode to use it.
|
|||
|
//
|
|||
|
// Right now, x is set to 64MB, or 16384 pages.
|
|||
|
//
|
|||
|
|
|||
|
if (pagesAbove4Gig > 16384) {
|
|||
|
foundMemoryAbove4G = TRUE;
|
|||
|
} else {
|
|||
|
foundMemoryAbove4G = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Find out if this processor can handle PAE mode.
|
|||
|
//
|
|||
|
|
|||
|
processorSupportsPae = BlpPaeSupported();
|
|||
|
|
|||
|
//
|
|||
|
// Find out whether this chipset supports PAE
|
|||
|
//
|
|||
|
if (!BlpChipsetPaeSupported()) {
|
|||
|
processorSupportsPae = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Start out with a pae flag based on whether memory above 4G was located
|
|||
|
// or whether a /PAE switch was passed on the command line.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// It used to be the case that we would default to PAE mode if memory
|
|||
|
// above 4G physical was found in the machine. The decision was made
|
|||
|
// to NEVER default to PAE mode, rather to use PAE only when the
|
|||
|
// user specifically asks for it.
|
|||
|
//
|
|||
|
// If we revert back to the previous way of doing things, uncomment the
|
|||
|
// following line and remove the subsequent one.
|
|||
|
//
|
|||
|
// if (foundMemoryAbove4G || UserSpecifiedPae) {
|
|||
|
//
|
|||
|
|
|||
|
if (UserSpecifiedPae) {
|
|||
|
usePae = TRUE;
|
|||
|
} else {
|
|||
|
usePae = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Determine whether the HAL image can support PAE mode and
|
|||
|
// whether the underlying OS supports hot plug memory.
|
|||
|
//
|
|||
|
|
|||
|
status = Blx86GetImageProperties( SystemDeviceId,
|
|||
|
HalImagePath,
|
|||
|
&halSupportsPae,
|
|||
|
&osSupportsHotPlugMemory );
|
|||
|
if (status != ESUCCESS) {
|
|||
|
|
|||
|
//
|
|||
|
// Apparently the HAL image supplied is invalid.
|
|||
|
//
|
|||
|
return(EBADF);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If machine has the ability for memory to be hot plugged over
|
|||
|
// the 4gb mark, then this is interpreted as a user request for
|
|||
|
// PAE support. This request will be ignored if not supported by
|
|||
|
// the underlying hardware or operating system.
|
|||
|
//
|
|||
|
|
|||
|
if (osSupportsHotPlugMemory && Blx86NeedPaeForHotPlugMemory()) {
|
|||
|
usePae = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
if (halSupportsPae == FALSE) {
|
|||
|
|
|||
|
//
|
|||
|
// The HAL cannot support operation in PAE mode. Override
|
|||
|
// processorSupportsPae to FALSE in this case, meaning that we must
|
|||
|
// not under any circumstances try to use PAE mode.
|
|||
|
//
|
|||
|
|
|||
|
processorSupportsPae = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If the processor doesn't handle PAE mode or if the user specified
|
|||
|
// a /NOPAE switch on the loader command line, then disable PAE mode.
|
|||
|
//
|
|||
|
|
|||
|
if (processorSupportsPae == FALSE || UserSpecifiedNoPae) {
|
|||
|
|
|||
|
usePae = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Choose the image name based on the data accumulated thus far.
|
|||
|
//
|
|||
|
|
|||
|
if (UserSpecifiedKernelImage != NULL) {
|
|||
|
kernelImageName = UserSpecifiedKernelImage;
|
|||
|
} else if (usePae != FALSE) {
|
|||
|
kernelImageName = kernelImageNamePae;
|
|||
|
} else {
|
|||
|
kernelImageName = kernelImageNameNoPae;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Build the path for this kernel and determine its suitability.
|
|||
|
//
|
|||
|
|
|||
|
strcpy( kernelImageNameTarget, kernelImageName );
|
|||
|
compatibleKernel = Blx86IsKernelCompatible( LoadDeviceId,
|
|||
|
KernelPath,
|
|||
|
processorSupportsPae,
|
|||
|
&usePae );
|
|||
|
if (compatibleKernel == FALSE) {
|
|||
|
|
|||
|
//
|
|||
|
// This kernel is not compatible or does not exist. If the failed
|
|||
|
// kernel was user-specified, fall back to the default, non-PAE
|
|||
|
// kernel and see if that is compatible.
|
|||
|
//
|
|||
|
|
|||
|
if (UserSpecifiedKernelImage != NULL) {
|
|||
|
|
|||
|
kernelImageName = kernelImageNameNoPae;
|
|||
|
strcpy( kernelImageNameTarget, kernelImageName );
|
|||
|
compatibleKernel = Blx86IsKernelCompatible( LoadDeviceId,
|
|||
|
KernelPath,
|
|||
|
processorSupportsPae,
|
|||
|
&usePae );
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (compatibleKernel == FALSE) {
|
|||
|
|
|||
|
//
|
|||
|
// At this point we have tried one of the default kernel image names,
|
|||
|
// as well as any user-specified kernel image name. There remains
|
|||
|
// one final default image name that hasn't been tried. Determine
|
|||
|
// which one that is and try it.
|
|||
|
//
|
|||
|
|
|||
|
if (kernelImageName == kernelImageNameNoPae) {
|
|||
|
kernelImageName = kernelImageNamePae;
|
|||
|
} else {
|
|||
|
kernelImageName = kernelImageNameNoPae;
|
|||
|
}
|
|||
|
|
|||
|
strcpy( kernelImageNameTarget, kernelImageName );
|
|||
|
compatibleKernel = Blx86IsKernelCompatible( LoadDeviceId,
|
|||
|
KernelPath,
|
|||
|
processorSupportsPae,
|
|||
|
&usePae );
|
|||
|
}
|
|||
|
|
|||
|
if (compatibleKernel != FALSE) {
|
|||
|
|
|||
|
*UsePaeMode = usePae;
|
|||
|
status = ESUCCESS;
|
|||
|
} else {
|
|||
|
status = EINVAL;
|
|||
|
}
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
Blx86IsKernelCompatible(
|
|||
|
IN ULONG LoadDeviceId,
|
|||
|
IN PCHAR ImagePath,
|
|||
|
IN BOOLEAN ProcessorSupportsPae,
|
|||
|
OUT PBOOLEAN UsePae
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine examines the supplied kernel image and determines whether
|
|||
|
it is valid and compatible with the current processor and, if so, whether
|
|||
|
PAE mode should be enabled.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
LoadDeviceId - The ARC device handle of the kernel load device.
|
|||
|
|
|||
|
ImagePath - Pointer to a buffer containing the full path of the
|
|||
|
kernel to check.
|
|||
|
|
|||
|
ProcessorSupportsPae - TRUE if the current processor supports PAE
|
|||
|
mode, FALSE otherwise.
|
|||
|
|
|||
|
UsePae - Upon successful return, indicates whether the kernel is PAE
|
|||
|
enabled.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE: The supplied kernel image is compatible with the current processor,
|
|||
|
and *UsePae has been updated as appropriate.
|
|||
|
|
|||
|
FALSE: The supplied kernel image is invalid or is not compatible with the
|
|||
|
current processor.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
BOOLEAN isPaeKernel;
|
|||
|
BOOLEAN supportsHotPlugMemory;
|
|||
|
ARC_STATUS status;
|
|||
|
|
|||
|
status = Blx86GetImageProperties( LoadDeviceId,
|
|||
|
ImagePath,
|
|||
|
&isPaeKernel,
|
|||
|
&supportsHotPlugMemory );
|
|||
|
if (status != ESUCCESS) {
|
|||
|
|
|||
|
//
|
|||
|
// This kernel is invalid or does not exist. Therefore, it is
|
|||
|
// not compatible.
|
|||
|
//
|
|||
|
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
if (isPaeKernel == FALSE) {
|
|||
|
|
|||
|
//
|
|||
|
// This is a non-PAE kernel. All supported processors can run in
|
|||
|
// non-PAE mode. Indicate that PAE mode should not be used and that
|
|||
|
// this kernel is compatible.
|
|||
|
//
|
|||
|
|
|||
|
*UsePae = FALSE;
|
|||
|
return TRUE;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// This is a PAE kernel.
|
|||
|
//
|
|||
|
|
|||
|
if (ProcessorSupportsPae == FALSE) {
|
|||
|
|
|||
|
//
|
|||
|
// This is a PAE kernel but the processor will not run in that
|
|||
|
// mode. Indicate that this kernel is not compatible.
|
|||
|
//
|
|||
|
|
|||
|
return FALSE;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// This is a PAE kernel and a PAE processor. Indicate that PAE
|
|||
|
// mode should be used and that this kernel is compatible.
|
|||
|
//
|
|||
|
|
|||
|
*UsePae = TRUE;
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
ARC_STATUS
|
|||
|
Blx86GetImageProperties(
|
|||
|
IN ULONG LoadDeviceId,
|
|||
|
IN PCHAR ImagePath,
|
|||
|
OUT PBOOLEAN IsPae,
|
|||
|
OUT PBOOLEAN SupportsHotPlugMemory
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine examines the supplied image and determines whether
|
|||
|
it is valid and, if so, whether it is PAE compatible by examining
|
|||
|
the IMAGE_FILE_LARGE_ADDRESS_AWARE bit.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
LoadDeviceId - The ARC device handle of the image device.
|
|||
|
|
|||
|
ImagePath - Pointer to a buffer containing the full path of the
|
|||
|
kernel to check.
|
|||
|
|
|||
|
IsPae - Upon successful return, indicates whether the image is PAE
|
|||
|
compatible.
|
|||
|
|
|||
|
SupportsHotPlugMemory - Upon successful return, indicates whether the
|
|||
|
image indicates an OS that supports hot plug memory.
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
ESUCCESS - The supplied kernel image is valid, and *IsPae has been updated
|
|||
|
according to the image header.
|
|||
|
|
|||
|
Otherwise, the Arc status of the failed operation is returned.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
CHAR localBufferSpace[ SECTOR_SIZE * 2 + SECTOR_SIZE - 1 ];
|
|||
|
PCHAR localBuffer;
|
|||
|
ARC_STATUS status;
|
|||
|
ULONG fileId;
|
|||
|
PIMAGE_NT_HEADERS ntHeaders;
|
|||
|
USHORT imageCharacteristics;
|
|||
|
ULONG bytesRead;
|
|||
|
|
|||
|
//
|
|||
|
// File I/O here must be sector-aligned.
|
|||
|
//
|
|||
|
|
|||
|
localBuffer = (PCHAR)
|
|||
|
(((ULONG)localBufferSpace + SECTOR_SIZE - 1) & ~(SECTOR_SIZE - 1));
|
|||
|
|
|||
|
//
|
|||
|
// Read in the PE image header.
|
|||
|
//
|
|||
|
|
|||
|
status = BlOpen( LoadDeviceId, ImagePath, ArcOpenReadOnly, &fileId );
|
|||
|
if (status != ESUCCESS) {
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
status = BlRead( fileId, localBuffer, SECTOR_SIZE * 2, &bytesRead );
|
|||
|
BlClose( fileId );
|
|||
|
|
|||
|
if (bytesRead != SECTOR_SIZE * 2) {
|
|||
|
status = EBADF;
|
|||
|
}
|
|||
|
|
|||
|
if (status != ESUCCESS) {
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If the file header has the IMAGE_FILE_LARGE_ADDRESS_AWARE
|
|||
|
// characteristic set then this is a PAE image.
|
|||
|
//
|
|||
|
|
|||
|
ntHeaders = RtlImageNtHeader( localBuffer );
|
|||
|
if (ntHeaders == NULL) {
|
|||
|
return EBADF;
|
|||
|
}
|
|||
|
|
|||
|
imageCharacteristics = ntHeaders->FileHeader.Characteristics;
|
|||
|
if ((imageCharacteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE) != 0) {
|
|||
|
|
|||
|
//
|
|||
|
// This is a PAE image.
|
|||
|
//
|
|||
|
|
|||
|
*IsPae = TRUE;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// This is not a PAE image.
|
|||
|
//
|
|||
|
|
|||
|
*IsPae = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Hot Plug Memory is only supported post 5.0
|
|||
|
//
|
|||
|
if (ntHeaders->OptionalHeader.MajorOperatingSystemVersion > 5 ||
|
|||
|
((ntHeaders->OptionalHeader.MajorOperatingSystemVersion == 5) &&
|
|||
|
(ntHeaders->OptionalHeader.MinorOperatingSystemVersion > 0 ))) {
|
|||
|
*SupportsHotPlugMemory = TRUE;
|
|||
|
} else {
|
|||
|
*SupportsHotPlugMemory = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
return ESUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
BlpChipsetPaeSupported(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Scans PCI space to see if the current chipset is supported for PAE mode.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE - PAE is supported
|
|||
|
|
|||
|
FALSE - PAE is not supported
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ULONG DevVenId=0;
|
|||
|
ULONG i;
|
|||
|
|
|||
|
typedef struct _PCIDEVICE {
|
|||
|
ULONG Bus;
|
|||
|
ULONG Device;
|
|||
|
ULONG DevVen;
|
|||
|
} PCIDEVICE, *PPCIDEVICE;
|
|||
|
|
|||
|
PCIDEVICE BadChipsets[] = {
|
|||
|
{0, 0, 0x1a208086}, // MCH
|
|||
|
{0, 0, 0x1a218086}, // MCH
|
|||
|
{0, 0, 0x1a228086}, // MCH
|
|||
|
{0, 30, 0x24188086}, // ICH
|
|||
|
{0, 30, 0x24288086} // ICH
|
|||
|
};
|
|||
|
|
|||
|
|
|||
|
for (i=0; i<sizeof(BadChipsets)/sizeof(PCIDEVICE); i++) {
|
|||
|
HalGetBusData(PCIConfiguration,
|
|||
|
BadChipsets[i].Bus,
|
|||
|
BadChipsets[i].Device,
|
|||
|
&DevVenId,
|
|||
|
sizeof(DevVenId));
|
|||
|
if (DevVenId == BadChipsets[i].DevVen) {
|
|||
|
return(FALSE);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return(TRUE);
|
|||
|
}
|
|||
|
|
|||
|
ARC_STATUS
|
|||
|
BlpCheckVersion(
|
|||
|
IN ULONG LoadDeviceId,
|
|||
|
IN PCHAR ImagePath
|
|||
|
)
|
|||
|
{
|
|||
|
CHAR localBufferSpace[ SECTOR_SIZE * 2 + SECTOR_SIZE - 1 ];
|
|||
|
PCHAR localBuffer;
|
|||
|
ARC_STATUS status;
|
|||
|
ULONG fileId;
|
|||
|
PIMAGE_NT_HEADERS ntHeaders;
|
|||
|
USHORT imageCharacteristics;
|
|||
|
ULONG bytesRead;
|
|||
|
ULONG i,j,Count;
|
|||
|
HARDWARE_PTE_X86 nullpte;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// File I/O here must be sector-aligned.
|
|||
|
//
|
|||
|
|
|||
|
localBuffer = (PCHAR)
|
|||
|
(((ULONG)localBufferSpace + SECTOR_SIZE - 1) & ~(SECTOR_SIZE - 1));
|
|||
|
|
|||
|
//
|
|||
|
// Read in the PE image header.
|
|||
|
//
|
|||
|
|
|||
|
status = BlOpen( LoadDeviceId, ImagePath, ArcOpenReadOnly, &fileId );
|
|||
|
if (status != ESUCCESS) {
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
status = BlRead( fileId, localBuffer, SECTOR_SIZE * 2, &bytesRead );
|
|||
|
BlClose( fileId );
|
|||
|
|
|||
|
if (bytesRead != SECTOR_SIZE * 2) {
|
|||
|
status = EBADF;
|
|||
|
}
|
|||
|
|
|||
|
if (status != ESUCCESS) {
|
|||
|
return status;
|
|||
|
}
|
|||
|
ntHeaders = RtlImageNtHeader( localBuffer );
|
|||
|
if (ntHeaders == NULL) {
|
|||
|
return EBADF;
|
|||
|
}
|
|||
|
//
|
|||
|
// Setup the mm remapping checks for post 5.0 or pre 5.0
|
|||
|
//
|
|||
|
if (ntHeaders->OptionalHeader.MajorOperatingSystemVersion < 5 ||
|
|||
|
((ntHeaders->OptionalHeader.MajorOperatingSystemVersion == 5) &&
|
|||
|
(ntHeaders->OptionalHeader.MinorOperatingSystemVersion == 0 ))) {
|
|||
|
|
|||
|
|
|||
|
BlOldKernel=TRUE;
|
|||
|
BlKernelChecked=TRUE;
|
|||
|
BlHighestPage = ((16*1024*1024) >> PAGE_SHIFT) - 40;
|
|||
|
|
|||
|
//
|
|||
|
// Virtual was moved up for the dynamic load case. It was 64MB off
|
|||
|
// in 5.0 and prior
|
|||
|
//
|
|||
|
RtlZeroMemory (&nullpte,sizeof (HARDWARE_PTE_X86));
|
|||
|
|
|||
|
if (BlVirtualBias != 0 ) {
|
|||
|
|
|||
|
BlVirtualBias = OLD_ALTERNATE-KSEG0_BASE;
|
|||
|
|
|||
|
//
|
|||
|
// PDE entries represent 4MB. Zap the new ones.
|
|||
|
//
|
|||
|
i=(OLD_ALTERNATE) >> 22L;
|
|||
|
j=(ALTERNATE_BASE)>> 22L;
|
|||
|
|
|||
|
for (Count = 0; Count < 4;Count++){
|
|||
|
PDE[i++]= PDE[j++];
|
|||
|
}
|
|||
|
for (Count = 0; Count < 12; Count++) {
|
|||
|
PDE[i++]= nullpte;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return (ESUCCESS);
|
|||
|
}
|