/*++ 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 #include #include #include #include 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; iOptionalHeader.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); }