Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

3562 lines
98 KiB

/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
osloader.c
Abstract:
This module contains the code that implements the NT operating system
loader.
Author:
David N. Cutler (davec) 10-May-1991
Revision History:
--*/
#include "bldr.h"
#include "bldrint.h"
#include "ctype.h"
#include "stdlib.h"
#include "stdio.h"
#include "string.h"
#include "msg.h"
#include "cmp.h"
#include "ramdisk.h"
#include "cpyuchr.h"
#include "fat.h"
#include <netboot.h>
#include <ntverp.h>
#include <ntiodump.h>
#ifdef i386
#include "bldrx86.h"
#endif
#if defined(_IA64_)
#include "bldria64.h"
#endif
#include "blcache.h"
#include "vmode.h"
#include "ximagdef.h"
#define PAGEFILE_SYS ("\\pagefile.sys")
typedef PUCHAR PBYTE;
#if defined(_WIN64) && defined(_M_IA64)
#pragma section(".base", long, read, write)
__declspec(allocate(".base"))
extern
PVOID __ImageBase;
#else
extern
PVOID __ImageBase;
#endif
#if DBG
#define NtBuildNumber (VER_PRODUCTBUILD | 0xC0000000)
#else
#define NtBuildNumber (VER_PRODUCTBUILD | 0xF0000000)
#endif
//
// These are the paths we will search through during a LastKnownGood boot.
// Note that each LastKnownGood path must be of 8.3 form as the FastFat
// boot code currently doesn't support long file names (bletch).
//
// The temporary path exists only between SMSS's start and login. It contains
// everything that was saved as part of the last good boot. The working path
// contains all the backups from this boot, and is the path SetupApi saves
// things to.
//
#define LAST_KNOWN_GOOD_TEMPORARY_PATH "LastGood.Tmp"
#define LAST_KNOWN_GOOD_WORKING_PATH "LastGood"
//
// Long term work-item, make "system64" work on Win64.
//
#define SYSTEM_DIRECTORY_PATH "system32"
#ifdef ARCI386
TCHAR OutputBuffer[256];
char BreakInKey;
ULONG Count;
UCHAR OsLoaderVersion[] = "ARCx86 OS Loader V5.20\r\n";
WCHAR OsLoaderVersionW[] = L"ARCx86 OS Loader V5.20\r\n";
#else
UCHAR OsLoaderVersion[] = "OS Loader V5.20\r\n";
WCHAR OsLoaderVersionW[] = L"OS Loader V5.20\r\n";
#endif
#if defined(_IA64_)
UCHAR OsLoaderName[] = "ia64ldr.efi";
#else
UCHAR OsLoaderName[] = "osloader.exe";
#endif
CHAR KernelFileName[8+1+3+1]="ntoskrnl.exe";
CHAR HalFileName[8+1+3+1]="hal.dll";
CHAR KdFileName[8+1+3+1]="KDCOM.DLL";
BOOLEAN UseAlternateKdDll = FALSE;
#define KD_ALT_DLL_PREFIX_CHARS 2
#define KD_ALT_DLL_REPLACE_CHARS 6
//
// progress bar variables (defined in blload.c)
//
extern int BlNumFilesLoaded;
extern int BlMaxFilesToLoad;
extern BOOLEAN BlOutputDots;
extern BOOLEAN BlShowProgressBar;
extern ULONG BlStartTime;
BOOLEAN isOSCHOICE = FALSE;
#if defined(_X86_)
//
// XIP variables
//
BOOLEAN XIPEnabled;
BOOLEAN XIPBootFlag;
BOOLEAN XIPReadOnlyFlag;
PCHAR XIPLoadPath;
PFN_COUNT XIPPageCount;
PFN_COUNT XIPBasePage;
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
);
ARC_STATUS
BlpCheckVersion(
IN ULONG LoadDeviceId,
IN PCHAR ImagePath
);
#endif
//
// Define transfer entry of loaded image.
//
typedef
VOID
(*PTRANSFER_ROUTINE) (
PLOADER_PARAMETER_BLOCK LoaderBlock
);
PVOID
BlLoadDataFile(
IN ULONG DeviceId,
IN PCHAR LoadDevice,
IN PCHAR SystemPath,
IN PUNICODE_STRING Filename,
IN MEMORY_TYPE MemoryType,
OUT PULONG FileSize
);
ARC_STATUS
BlLoadTriageDump(
IN ULONG DriveId,
OUT PVOID * DumpHeader
);
VOID
putwS(
PUNICODE_STRING String
);
#if defined(_X86_)
BOOLEAN
BlAmd64RemapDram (
IN PCHAR LoaderOptions
);
#endif
#if defined(_IA64_)
VOID
BuildArcTree();
#endif // defined(_IA64_)
//
// Define local static data.
//
PCHAR ArcStatusCodeMessages[] = {
"operation was success",
"E2BIG",
"EACCES",
"EAGAIN",
"EBADF",
"EBUSY",
"EFAULT",
"EINVAL",
"EIO",
"EISDIR",
"EMFILE",
"EMLINK",
"ENAMETOOLONG",
"ENODEV",
"ENOENT",
"ENOEXEC",
"ENOMEM",
"ENOSPC",
"ENOTDIR",
"ENOTTY",
"ENXIO",
"EROFS",
};
//
// Diagnostic load messages
//
VOID
BlFatalError(
IN ULONG ClassMessage,
IN ULONG DetailMessage,
IN ULONG ActionMessage
);
VOID
BlBadFileMessage(
IN PCHAR BadFileName
);
//
// Define external static data.
//
BOOLEAN BlConsoleInitialized = FALSE;
ULONG BlConsoleOutDeviceId = ARC_CONSOLE_OUTPUT;
ULONG BlConsoleInDeviceId = ARC_CONSOLE_INPUT;
ULONG BlDcacheFillSize = 32;
BOOLEAN BlRebootSystem = FALSE;
ULONG BlVirtualBias = 0;
BOOLEAN BlUsePae = FALSE;
//++
//
// PULONG
// IndexByUlong(
// PVOID Pointer,
// ULONG Index
// )
//
// Routine Description:
//
// Return the address Index ULONGs into Pointer. That is,
// Index * sizeof (ULONG) bytes into Pointer.
//
// Arguments:
//
// Pointer - Start of region.
//
// Index - Number of ULONGs to index into.
//
// Return Value:
//
// PULONG representing the pointer described above.
//
//--
#define IndexByUlong(Pointer,Index) (&(((ULONG*) (Pointer)) [Index]))
//++
//
// PBYTE
// IndexByByte(
// PVOID Pointer,
// ULONG Index
// )
//
// Routine Description:
//
// Return the address Index BYTEs into Pointer. That is,
// Index * sizeof (BYTE) bytes into Pointer.
//
// Arguments:
//
// Pointer - Start of region.
//
// Index - Number of BYTEs to index into.
//
// Return Value:
//
// PBYTE representing the pointer described above.
//
//--
#define IndexByByte(Pointer, Index) (&(((UCHAR*) (Pointer)) [Index]))
ARC_STATUS
BlLoadTriageDump(
IN ULONG DriveId,
OUT PVOID * TriageDumpOut
)
/*++
Routine Description:
Load the triage dump, if it exists; return an error value otherwise.
Arguments:
DriveId - The device where we should check for the triage dump.
TriageDumpOut - Where the triage dump pointer is copied to on success.
Return Value:
ESUCCESS - If there was a triage dump and the dump information was
successfully copied into pTriageDump.
ARC_STATUS - Otherwise.
--*/
{
ARC_STATUS Status;
PMEMORY_DUMP MemoryDump = NULL;
ULONG PageFile = BL_INVALID_FILE_ID;
ULONG Count, actualBase;
PBYTE Buffer = NULL, NewBuffer = NULL;
//
// Fill in the TriageDump structure
//
Status = BlOpen (DriveId, PAGEFILE_SYS, ArcOpenReadOnly, &PageFile);
if (Status != ESUCCESS) {
goto _return;
}
//
// Allocate the buffer for the triage dump.
//
Buffer = (PBYTE) BlAllocateHeap (SECTOR_SIZE);
if (!Buffer) {
Status = ENOMEM;
goto _return;
}
//
// Read the first SECTOR_SIZE of the pagefile.
//
Status = BlRead (PageFile, Buffer, SECTOR_SIZE, &Count);
if (Status != ESUCCESS || Count != SECTOR_SIZE) {
Status = EINVAL;
goto _return;
}
MemoryDump = (PMEMORY_DUMP) Buffer;
if (MemoryDump->Header.ValidDump != DUMP_VALID_DUMP ||
MemoryDump->Header.Signature != DUMP_SIGNATURE ||
MemoryDump->Header.DumpType != DUMP_TYPE_TRIAGE) {
//
// Not a valid dump file.
//
Status = EINVAL;
goto _return;
}
Status = BlAllocateDescriptor (LoaderOsloaderHeap,0,BYTES_TO_PAGES(TRIAGE_DUMP_SIZE) ,&actualBase);
if (!actualBase || (Status != STATUS_SUCCESS)) {
Status = ENOMEM;
goto _return;
}
NewBuffer = (PBYTE)(KSEG0_BASE | (actualBase << PAGE_SHIFT));
//
// Read the first TRIAGE_DUMP_SIZE of the pagefile.
//
Status = BlReadAtOffset (PageFile, 0,TRIAGE_DUMP_SIZE,NewBuffer);
if (Status != ESUCCESS) {
Status = EINVAL;
goto _return;
}
MemoryDump = (PMEMORY_DUMP) NewBuffer;
//
// Does the dump have a valid signature.
//
if (MemoryDump->Triage.ValidOffset > (TRIAGE_DUMP_SIZE - sizeof (ULONG)) ||
*(ULONG *)IndexByByte (Buffer, MemoryDump->Triage.ValidOffset) != TRIAGE_DUMP_VALID) {
Status = EINVAL;
goto _return;
}
Status = ESUCCESS;
_return:
if (PageFile != BL_INVALID_FILE_ID) {
BlClose (PageFile);
PageFile = BL_INVALID_FILE_ID;
}
if (Status != ESUCCESS && Buffer) {
Buffer = NULL;
MemoryDump = NULL;
}
*TriageDumpOut = MemoryDump;
return Status;
}
ARC_STATUS
BlInitStdio (
IN ULONG Argc,
IN CHAR * FIRMWARE_PTR * FIRMWARE_PTR Argv
)
{
PCHAR ConsoleOutDevice;
PCHAR ConsoleInDevice;
ULONG Status;
if (BlConsoleInitialized) {
return ESUCCESS;
}
//
// initialize the progress bar
//
// BlShowProgressBar = TRUE;
if( BlIsTerminalConnected() ) {
BlShowProgressBar = TRUE;
DisplayLogoOnBoot = FALSE;
}
//
// Get the name of the console output device and open the device for
// write access.
//
ConsoleOutDevice = BlGetArgumentValue(Argc, Argv, "consoleout");
if ((ConsoleOutDevice == NULL) && !BlIsTerminalConnected()) {
return ENODEV;
}
Status = ArcOpen(ConsoleOutDevice, ArcOpenWriteOnly, &BlConsoleOutDeviceId);
if ((Status != ESUCCESS) && !BlIsTerminalConnected()) {
return Status;
}
//
// Get the name of the console input device and open the device for
// read access.
//
ConsoleInDevice = BlGetArgumentValue(Argc, Argv, "consolein");
if ((ConsoleInDevice == NULL) && !BlIsTerminalConnected()) {
return ENODEV;
}
Status = ArcOpen(ConsoleInDevice, ArcOpenReadOnly, &BlConsoleInDeviceId);
if ((Status != ESUCCESS) && !BlIsTerminalConnected()) {
return Status;
}
BlConsoleInitialized = TRUE;
return ESUCCESS;
}
int
Blatoi(
char *s
)
{
int digval = 0;
int num = 0;
char *n;
num = 0;
for (n=s; *n; n++) {
if (isdigit((int)(unsigned char)*n)) {
digval = *n - '0';
} else if (isxdigit((int)(unsigned char)*n)) {
digval = toupper(*n) - 'A' + 10;
} else {
digval = 0;
}
num = num * 16 + digval;
}
return num;
}
PCHAR
BlTranslateSignatureArcName(
IN PCHAR ArcNameIn
)
/*++
Routine Description:
This function's purpose is to translate a signature based arc
name to a scsi based arc name. The 2 different arc name syntaxes
are as follows:
scsi(28111684)disk(0)rdisk(0)partition(1)
scsi(1)disk(0)rdisk(0)partition(1)
Both of these arc names are really the same disk, the first uses
the disk's signature and the second uses the scsi bus number. This
function translates the signature arc name by interating thru all
of the scsi buses that the loaded scsi miniport supports. If it
finds a signature match then the arc name is changed to use the
correct scsi bus number. This problem occurs because the boot loader
only loads one scsi miniport and therefore only sees the buses
attached to it's devices. If you have a system with multiple
scsi adapters of differing type, like an adaptec and a symbios logic,
then there is a high probability that the boot loader will see the
buses in a different order than the nt executive will and the
system will not boot.
Arguments:
ArcNameIn - Supplies the signature based arc name
Return Value:
Success - Valid pointer to a scsi based arcname.
Failure - NULL pointer
--*/
{
#if defined(_X86_)
extern ULONG ScsiPortCount;
PCHAR s,p;
ULONG sigval;
ULONG Signature;
int found = -1;
ULONG i;
ARC_STATUS Status;
ULONG DriveId;
CHAR Buffer[2048+256];
CHAR ArcName[128];
PUCHAR Sector;
LARGE_INTEGER SeekValue;
ULONG Count;
PCONFIGURATION_COMPONENT target;
PCONFIGURATION_COMPONENT lun;
CHAR devicePath[117];
BOOLEAN gotPath;
USHORT mbrSig;
if (_strnicmp( ArcNameIn, "signature(", 10 ) != 0) {
//
// not a signature based name so leave
//
return NULL;
}
s = strchr( ArcNameIn, '(' );
p = strchr( ArcNameIn, ')' );
if (s == NULL || p == NULL) {
return NULL;
}
*p = 0;
sigval = Blatoi( s+1 );
*p = ')';
if (sigval == 0) {
return NULL;
}
Sector = ALIGN_BUFFER(Buffer);
for (i=0; i < ScsiPortCount; i++) {
target = ScsiGetFirstConfiguredTargetComponent(i);
while (target != NULL) {
lun = ScsiGetFirstConfiguredLunComponent(target);
while (lun != NULL) {
gotPath = ScsiGetDevicePath(i, target, lun, devicePath);
if (gotPath == FALSE) {
break;
}
sprintf(ArcName, "%spartition(0)", devicePath);
Status = ArcOpen( ArcName, ArcOpenReadOnly, &DriveId );
if (Status == ESUCCESS) {
SeekValue.QuadPart = 0;
Status = ArcSeek(DriveId, &SeekValue, SeekAbsolute);
if (Status == ESUCCESS) {
Status = ArcRead( DriveId, Sector, 512, &Count );
if (Status == ESUCCESS && Count == 512) {
mbrSig =
((PUSHORT)Sector)[BOOT_SIGNATURE_OFFSET];
Signature =
((PULONG)Sector)[PARTITION_TABLE_OFFSET/2-1];
if (mbrSig == BOOT_RECORD_SIGNATURE &&
Signature == sigval) {
found = i;
ArcClose(DriveId);
goto SigFound;
}
}
}
ArcClose(DriveId);
}
lun = ScsiGetNextConfiguredLunComponent(lun);
}
target = ScsiGetNextConfiguredTargetComponent(target);
}
}
SigFound:
if (found == -1) {
//
// the signature in the arcname is bogus
//
return NULL;
}
//
// if we get here then we have an arc name with a
// good signature in it, so now we can generate
// a good arc name
//
p = strstr(ArcNameIn, "partition(");
if (p == NULL) {
ASSERT(FALSE);
return NULL;
}
if ( sizeof(Buffer) < strlen(devicePath) + strlen(p) + 1 ) {
return NULL;
}
strcpy(Buffer, devicePath);
strcat(Buffer, p);
p = (PCHAR)BlAllocateHeap( strlen(Buffer) + 1 );
if (p) {
strcpy( p, Buffer );
}
return p;
#else
UNREFERENCED_PARAMETER(ArcNameIn);
return NULL;
#endif
}
#if defined(_X86_)
VOID FLUSH_TB();
VOID ENABLE_PSE();
#define _8kb ( 8*1024)
#define _32kb (32*1024)
#define _4mb (4*1024*1024)
#define _4mb_pages (_4mb >> PAGE_SHIFT)
ARC_STATUS
XipLargeRead(
ULONG FileId,
PFN_COUNT BasePage,
PFN_COUNT PageCount
)
/*++
Routine Description:
Initialize the XIP 'ROM' by reading from disk.
Arguments:
FileId - The file used to initialize for XIP.
BasePage - PFN of the first XIP Rom page.
PageCount - Number of XIP Rom pages.
Return Value:
ESUCCESS returned if all goes well.
--*/
{
PHARDWARE_PTE PDE_VA = (PHARDWARE_PTE)PDE_BASE;
ARC_STATUS status = ESUCCESS;
PHARDWARE_PTE pde;
HARDWARE_PTE zproto, proto;
PBYTE baseaddr, curraddr, copybuffer;
ULONG fileoffset;
ULONG count;
ULONG tcount;
ULONG paddingbytes;
int i, n;
copybuffer = NULL;
//
// Look for a zero PDE entry starting at entry 128 (address 512MB).
//
pde = PDE_VA + 128;
baseaddr = (PUCHAR)(128*_4mb);
for (i = 0; i < 32; i++) {
if (*(PULONG)pde == 0) {
break;
}
pde++;
baseaddr += _4mb;
}
if (i == 32) {
return ENOMEM;
}
//
// Have to enable 4MB pages in cr4 in order to use them in the PDE
//
ENABLE_PSE();
//
// Initialize the pte prototypes.
//
*(PULONG)&zproto = 0;
proto = zproto;
proto.Write = 1;
proto.LargePage = 1;
proto.Valid = 1;
//
//Use intermediate 8KB buffer and read in smaller chunks.
//
copybuffer = (PBYTE) BlAllocateHeap (TRIAGE_DUMP_SIZE);
if (!copybuffer) {
return ENOMEM;
}
//
// Map the XIP memory 4MB at a time.
// Read in the file 8KB at a time.
// Don't exceed the PageCount.
//
fileoffset = 0;
do {
//
// Reset the curraddr to the beginning of the buffer.
// Set the PFN in the 4MB pte and flush the TLB
//
curraddr = baseaddr;
proto.PageFrameNumber = BasePage;
*pde = proto;
FLUSH_TB();
//
// Adjust the BasePage and PageCount values for the next iteration
//
BasePage += _4mb_pages;
if (PageCount < _4mb_pages) {
PageCount = 0;
} else {
PageCount -= _4mb_pages;
}
//
// Read in the next 4MB in 8KB chunks.
//
n = _4mb / _8kb;
while (n--) {
status = BlRead(FileId, (PVOID)copybuffer, _8kb, &count);
//
// Just give up on an error.
//
if (status != ESUCCESS) {
goto done;
}
//
// If not the first read (or a short read)
// the copy is simple.
//
if (fileoffset > 0 || count < _8kb) {
RtlCopyMemory( (PVOID)curraddr, (PVOID)copybuffer, count );
curraddr += count;
fileoffset += count;
if (count < _8kb) {
goto done;
}
} else {
//
// Process boot sector. Need to pad out ReservedSectors
// to align clusters on a page boundary.
//
PPACKED_BOOT_SECTOR pboot;
BIOS_PARAMETER_BLOCK bios;
ULONG newReservedSectors;
pboot = (PPACKED_BOOT_SECTOR)copybuffer;
FatUnpackBios(&bios, &pboot->PackedBpb);
if (bios.BytesPerSector != SECTOR_SIZE
|| FatBytesPerCluster(&bios) != PAGE_SIZE) {
goto done;
}
//
// Compute how much paddint is required and update the ReservedSectors field.
//
paddingbytes = PAGE_SIZE - (FatFileAreaLbo(&bios) & (PAGE_SIZE-1));
if (paddingbytes < PAGE_SIZE) {
newReservedSectors = (FatReservedBytes(&bios) + paddingbytes) / SECTOR_SIZE;
pboot->PackedBpb.ReservedSectors[0] = (UCHAR) (newReservedSectors & 0xff);
pboot->PackedBpb.ReservedSectors[1] = (UCHAR) (newReservedSectors >> 8);
}
//
// Copy the boot block.
// Add padding.
// Copy the rest of the read buffer.
// Read in a short page to get us back on track.
//
RtlCopyMemory( (PVOID)curraddr, (PVOID)copybuffer, SECTOR_SIZE );
curraddr += SECTOR_SIZE;
RtlZeroMemory( (PVOID)curraddr, paddingbytes );
curraddr += paddingbytes;
RtlCopyMemory( (PVOID)curraddr, (PVOID) (copybuffer + SECTOR_SIZE), count - SECTOR_SIZE );
curraddr += (count - SECTOR_SIZE);
status = BlRead(FileId, (PVOID)copybuffer, count - paddingbytes, &tcount);
if (status != ESUCCESS || tcount != count - paddingbytes) {
goto done;
}
RtlCopyMemory( (PVOID)curraddr, (PVOID)copybuffer, count - paddingbytes );
curraddr += (count - paddingbytes);
fileoffset += (2*count - paddingbytes);;
//
// We decrement n again, since we have eaten up another 8KB of the 4MB mapping.
//
n--;
}
}
} while (PageCount);
done:
//
// Unmap the current 4MB chunk and flush the TB
//
*pde = zproto;
FLUSH_TB();
//
// Free the temporary copy buffer
//
if (copybuffer) {
;
}
return status;
}
#endif //_X86_
ARC_STATUS
BlOsLoader (
IN ULONG Argc,
IN CHAR * FIRMWARE_PTR * FIRMWARE_PTR Argv,
IN CHAR * FIRMWARE_PTR * FIRMWARE_PTR Envp
)
/*++
Routine Description:
This is the main routine that controls the loading of the NT operating
system on an ARC compliant system. It opens the system partition,
the boot partition, the console input device, and the console output
device. The NT operating system and all its DLLs are loaded and bound
together. Control is then transfered to the loaded system.
Arguments:
Argc - Supplies the number of arguments that were provided on the
command that invoked this program.
Argv - Supplies a pointer to a vector of pointers to null terminated
argument strings.
Envp - Supplies a pointer to a vector of pointers to null terminated
environment variables.
Return Value:
EBADF is returned if the specified OS image cannot be loaded.
--*/
{
ULONG CacheLineSize;
PCONFIGURATION_COMPONENT_DATA DataCache;
CHAR DeviceName[256];
CHAR DevicePrefix[256];
PCHAR DirectoryEnd;
CHAR KdDllName[256];
PCHAR FileName;
ULONG FileSize;
BOOLEAN KdDllLoadFailed;
PKLDR_DATA_TABLE_ENTRY KdDataTableEntry = NULL;
PKLDR_DATA_TABLE_ENTRY HalDataTableEntry;
PCHAR LoadDevice;
ULONG LoadDeviceId;
CHAR LoadDevicePath[256];
CHAR LoadDeviceLKG1Path[256];
CHAR LoadDeviceLKG2Path[256];
FULL_PATH_SET LoadDevicePathSet;
PCHAR SystemDevice;
ULONG SystemDeviceId;
CHAR SystemDevicePath[256];
FULL_PATH_SET SystemDevicePathSet;
CHAR KernelDirectoryPath[256];
FULL_PATH_SET KernelPathSet;
CHAR KernelPathName[256];
CHAR HalPathName[256];
PVOID HalBase;
PVOID KdDllBase;
#if defined(_ALPHA_) || defined(ARCI386) || defined(_IA64_)
PVOID LoaderBase;
PMEMORY_DESCRIPTOR ProgramDescriptor;
#endif
PVOID SystemBase;
ULONG Index;
ULONG Limit;
ULONG LinesPerBlock;
PCHAR LoadFileName;
PCHAR LoadOptions;
PCHAR OsLoader;
#if defined(_X86_)
PCHAR x86SystemPartition;
PCHAR userSpecifiedKernelName = NULL;
ULONG highestSystemPage;
BOOLEAN userSpecifiedPae;
BOOLEAN userSpecifiedNoPae;
#endif
#if defined(REMOTE_BOOT)
PCHAR SavedOsLoader;
PCHAR SavedLoadFileName;
#endif
ULONG i;
ARC_STATUS Status;
NTSTATUS NtStatus;
PKLDR_DATA_TABLE_ENTRY SystemDataTableEntry;
PTRANSFER_ROUTINE SystemEntry;
PIMAGE_NT_HEADERS NtHeaders;
PWSTR BootFileSystem;
CHAR BadFileName[128];
PBOOTFS_INFO FsInfo;
PCHAR TmpPchar;
BOOLEAN bDiskCacheInitialized = FALSE;
BOOLEAN ServerHive = FALSE;
#if defined(REMOTE_BOOT)
ULONGLONG NetRebootParameter;
CHAR OutputBuffer[256];
#endif // defined(REMOTE_BOOT)
BOOLEAN bLastKnownGood, bLastKnownGoodChosenLate;
#if defined(_X86_)
BOOLEAN safeBoot = FALSE;
#endif
PBOOT_DRIVER_NODE DriverNode = 0;
PBOOT_DRIVER_LIST_ENTRY DriverEntry = 0;
PLIST_ENTRY NextEntry = 0;
PLIST_ENTRY BootDriverListHead = 0;
UNICODE_STRING unicodeString;
CHAR Directory[256];
UNREFERENCED_PARAMETER( Envp );
#ifdef EFI
//
// set the EFI watchdog to 20 minutes.
// by default, it is set to 5 minutes by the efi boot manager
//
SetEFIWatchDog(EFI_WATCHDOG_TIMEOUT);
#elif defined(_X86_)
//
// set the x86 watchdog timer if it exists
//
SetX86WatchDog(X86_WATCHDOG_TIMEOUT);
#endif
// BlShowProgressBar = TRUE;
BlShowProgressBar = FALSE;
BlStartTime = ArcGetRelativeTime();
//
// Initialize the OS loader console input and output.
//
Status = BlInitStdio(Argc, Argv);
if (Status != ESUCCESS) {
return Status;
}
//
// Initialize the boot debugger for platforms that directly load the
// OS Loader.
//
// N.B. This must occur after the console input and output have been
// initialized so debug messages can be printed on the console
// output device.
//
#if defined(_ALPHA_) || defined(ARCI386) || defined(_IA64_)
//
// Locate the memory descriptor for the OS Loader.
//
ProgramDescriptor = NULL;
while ((ProgramDescriptor = ArcGetMemoryDescriptor(ProgramDescriptor)) != NULL) {
if (ProgramDescriptor->MemoryType == MemoryLoadedProgram) {
break;
}
}
//
// If the program memory descriptor was found, then compute the base
// address of the OS Loader for use by the debugger.
//
LoaderBase = &__ImageBase;
//
// Initialize traps and the boot debugger.
//
#if defined(ENABLE_LOADER_DEBUG)
#if defined(_ALPHA_)
BdInitializeTraps();
#endif
DBGTRACE( TEXT("About to BdInitDebugger. Base = %x\r\n"), LoaderBase );
BdInitDebugger((PCHAR)OsLoaderName, LoaderBase, ENABLE_LOADER_DEBUG);
DBGTRACE( TEXT("Back From BdInitDebugger.\r\n") );
#else
BdInitDebugger((PCHAR)OsLoaderName, 0, NULL);
#endif
#endif
#if defined(REMOTE_BOOT)
//
// Get any parameters from a reboot on a Net PC.
//
if (BlBootingFromNet) {
NetGetRebootParameters(&NetRebootParameter, NULL, NULL, NULL, NULL, NULL, TRUE);
}
#endif // defined(REMOTE_BOOT)
#if 0 && !defined(_IA64_)
//
// AJR bugbug -- do we really need to do this twice? we already call in SuMain()
//
// ChuckL -- Turned this code off because it screws up remote boot, which
// does some allocations before we get here.
//
//
// Initialize the memory descriptor list, the OS loader heap, and the
// OS loader parameter block.
//
Status = BlMemoryInitialize();
if (Status != ESUCCESS) {
BlFatalError(LOAD_HW_MEM_CLASS,
DIAG_BL_MEMORY_INIT,
LOAD_HW_MEM_ACT);
goto LoadFailed;
}
#endif
#if defined(_IA64_)
//
// Build required portion of ARC tree since we are not doing NTDETECT
// anymore for IA-64.
//
BuildArcTree();
#endif
#ifdef EFI
//
// Establish SMBIOS information in the loader block
//
SetupSMBiosInLoaderBlock();
#endif
//
// Compute the data cache fill size. This value is used to align
// I/O buffers in case the host system does not support coherent
// caches.
//
// If a combined secondary cache is present, then use the fill size
// for that cache. Otherwise, if a secondary data cache is present,
// then use the fill size for that cache. Otherwise, if a primary
// data cache is present, then use the fill size for that cache.
// Otherwise, use the default fill size.
//
DataCache = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
CacheClass,
SecondaryCache,
NULL);
if (DataCache == NULL) {
DataCache = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
CacheClass,
SecondaryDcache,
NULL);
if (DataCache == NULL) {
DataCache = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
CacheClass,
PrimaryDcache,
NULL);
}
}
if (DataCache != NULL) {
LinesPerBlock = DataCache->ComponentEntry.Key >> 24;
CacheLineSize = 1 << ((DataCache->ComponentEntry.Key >> 16) & 0xff);
BlDcacheFillSize = LinesPerBlock * CacheLineSize;
}
//
// Initialize the OS loader I/O system.
//
Status = BlIoInitialize();
if (Status != ESUCCESS) {
BlFatalError(LOAD_HW_DISK_CLASS,
DIAG_BL_IO_INIT,
LOAD_HW_DISK_ACT);
goto LoadFailed;
}
//
// Initialize the resource section.
//
Status = BlInitResources(Argv[0]);
if (Status != ESUCCESS) {
BlFatalError(LOAD_HW_DISK_CLASS,
DIAG_BL_IO_INIT,
LOAD_HW_DISK_ACT);
goto LoadFailed;
}
//
// Initialize the progress bar
//
BlSetProgBarCharacteristics(HIBER_UI_BAR_ELEMENT, BLDR_UI_BAR_BACKGROUND);
//
// Initialize the NT configuration tree.
//
BlLoaderBlock->ConfigurationRoot = NULL;
Status = BlConfigurationInitialize(NULL, NULL);
if (Status != ESUCCESS) {
BlFatalError(LOAD_HW_FW_CFG_CLASS,
DIAG_BL_CONFIG_INIT,
LOAD_HW_FW_CFG_ACT);
goto LoadFailed;
}
//
// Copy the osloadoptions argument into the LoaderBlock.
//
LoadOptions = BlGetArgumentValue(Argc, Argv, "osloadoptions");
#if defined(_X86_)
userSpecifiedPae = FALSE;
userSpecifiedNoPae = FALSE;
safeBoot = FALSE;
#endif
if (LoadOptions != NULL) {
FileSize = (ULONG)strlen(LoadOptions) + 1;
FileName = (PCHAR)BlAllocateHeap(FileSize);
strcpy(FileName, LoadOptions);
BlLoaderBlock->LoadOptions = FileName;
//
// Check for the SOS switch that forces the output of filenames during
// the boot instead of the progress dots.
//
if ((strstr(FileName, "SOS") != NULL) ||
(strstr(FileName, "sos") != NULL)) {
BlOutputDots = FALSE;
}
#ifdef EFI
GraphicsMode = FALSE;
#else
GraphicsMode = (BOOLEAN)(strstr(FileName, "BOOTLOGO") != NULL); // to display boot logo go to graphics mode
#endif
//
// Check for the 3gb user address space switch which causes the system
// to load at the alternate base address if it is relocatable.
//
#if defined(_X86_)
if (strstr(FileName, "SAFEBOOT") != NULL) {
safeBoot = TRUE;
}
if ((strstr(FileName, "3GB") != NULL) ||
(strstr(FileName, "3gb") != NULL)) {
BlVirtualBias = ALTERNATE_BASE - KSEG0_BASE;
}
if ((strstr(FileName, "PAE") != NULL) ||
(strstr(FileName, "pae") != NULL)) {
userSpecifiedPae = TRUE;
}
if ((strstr(FileName, "NOPAE") != NULL) ||
(strstr(FileName, "nopae") != NULL)) {
userSpecifiedNoPae = TRUE;
}
if (safeBoot != FALSE) {
//
// We're in safeboot mode. Override the user's desire to boot
// into PAE mode.
//
userSpecifiedPae = FALSE;
}
#endif
//
// Check for an alternate HAL specification.
//
FileName = strstr(BlLoaderBlock->LoadOptions, "HAL=");
if (FileName != NULL) {
FileName += strlen("HAL=");
for (i = 0; i < sizeof(HalFileName); i++) {
if (FileName[i] == ' ') {
HalFileName[i] = '\0';
break;
}
HalFileName[i] = FileName[i];
}
}
HalFileName[sizeof(HalFileName) - 1] = '\0';
//
// Check for an alternate kernel specification.
//
FileName = strstr(BlLoaderBlock->LoadOptions, "KERNEL=");
if (FileName != NULL) {
FileName += strlen("KERNEL=");
for (i = 0; i < sizeof(KernelFileName); i++) {
if (FileName[i] == ' ') {
KernelFileName[i] = '\0';
break;
}
KernelFileName[i] = FileName[i];
}
#if defined(_X86_)
userSpecifiedKernelName = KernelFileName;
#endif
}
#if defined(_X86_)
else {
userSpecifiedKernelName = NULL;
}
#endif
KernelFileName[sizeof(KernelFileName) - 1] = '\0';
//
// Check for an alternate Kernel Debugger DLL, i.e.,
// /debugport=1394 (kd1394.dll), /debugport=usb (kdusb.dll), etc...
//
FileName = strstr(BlLoaderBlock->LoadOptions, "DEBUGPORT=");
if (FileName == NULL) {
FileName = strstr(BlLoaderBlock->LoadOptions, "debugport=");
}
if (FileName != NULL) {
_strupr(FileName);
if (strstr(FileName, "COM") == NULL) {
UseAlternateKdDll = TRUE;
FileName += strlen("DEBUGPORT=");
for (i = 0; i < KD_ALT_DLL_REPLACE_CHARS; i++) {
if (FileName[i] == ' ') {
break;
}
KdFileName[KD_ALT_DLL_PREFIX_CHARS + i] = FileName[i];
}
KdFileName[KD_ALT_DLL_PREFIX_CHARS + i] = '\0';
strcat(KdFileName, ".DLL");
}
}
} else {
BlLoaderBlock->LoadOptions = NULL;
}
#if defined(_X86_)
if (LoadOptions != NULL) {
//
// Process XIP options
//
{
PCHAR XIPBootOption, XIPRomOption, XIPRamOption, XIPSizeOption;
PCHAR path, sizestr;
ULONG nmegs = 0;
PCHAR p, opts;
ULONG n;
opts = BlLoaderBlock->LoadOptions;
(XIPBootOption = strstr(opts, "XIPBOOT")) || (XIPBootOption = strstr(opts, "xipboot"));
(XIPRomOption = strstr(opts, "XIPROM=")) || (XIPRomOption = strstr(opts, "xiprom="));
(XIPRamOption = strstr(opts, "XIPRAM=")) || (XIPRamOption = strstr(opts, "xipram="));
(XIPSizeOption = strstr(opts, "XIPMEGS=")) || (XIPSizeOption = strstr(opts, "xipmegs="));
XIPEnabled = FALSE;
if (XIPRomOption || XIPRamOption) {
if (XIPRomOption && XIPRamOption) {
;
} else {
sizestr = XIPSizeOption? strchr(XIPSizeOption, '=') : NULL;
if (sizestr) {
sizestr++;
nmegs = 0;
while ('0' <= *sizestr && *sizestr <= '9') {
nmegs = 10*nmegs + (*sizestr - '0');
sizestr++;
}
}
path = strchr(XIPRomOption? XIPRomOption : XIPRamOption, '=');
if (nmegs && path) {
path++;
XIPBootFlag = XIPBootOption? TRUE : FALSE;
XIPPageCount = (1024*1024*nmegs) >> PAGE_SHIFT;
//
// strdup XIPLoadPath
//
for (p = path; *p; p++) {
if (*p == ' ') break;
if (*p == '/') break;
if (*p == '\n') break;
if (*p == '\r') break;
if (*p == '\t') break;
}
n = (p - path);
if (n > 1) {
XIPLoadPath = BlAllocateHeap(n+1);
if (XIPLoadPath) {
for (i = 0; i < n; i++) {
XIPLoadPath[i] = path[i];
}
XIPLoadPath[i] = '\0';
XIPEnabled = TRUE;
}
}
}
}
}
}
}
//
// Allocate the XIP pages.
//
if (XIPEnabled) {
ULONG OldBase;
ULONG OldLimit;
OldBase = BlUsableBase;
OldLimit = BlUsableLimit;
BlUsableBase = BL_XIPROM_RANGE_LOW;
BlUsableLimit = BL_XIPROM_RANGE_HIGH;
Status = BlAllocateAlignedDescriptor (LoaderXIPRom, 0, XIPPageCount, _4mb_pages, &XIPBasePage);
if (Status != ESUCCESS) {
XIPEnabled = FALSE;
}
BlUsableBase = OldBase;
BlUsableLimit = OldLimit;
}
#endif //_X86_
//
// Get the name of the OS loader (on i386 it's system32\NTLDR) and get
// the OS path (on i386 it's <SystemRoot> such as "\winnt").
//
OsLoader = BlGetArgumentValue(Argc, Argv, "osloader");
LoadFileName = BlGetArgumentValue(Argc, Argv, "osloadfilename");
//
// Check the load path to make sure it's valid.
//
if (LoadFileName == NULL) {
Status = ENOENT;
BlFatalError(LOAD_HW_FW_CFG_CLASS,
DIAG_BL_FW_GET_BOOT_DEVICE,
LOAD_HW_FW_CFG_ACT);
goto LoadFailed;
}
//
// Check the loader path to see if it's valid.
//
if (OsLoader == NULL) {
Status = ENOENT;
BlFatalError(LOAD_HW_FW_CFG_CLASS,
DIAG_BL_FIND_HAL_IMAGE,
LOAD_HW_FW_CFG_ACT);
goto LoadFailed;
}
#if defined(REMOTE_BOOT)
//
// If we're booting from the net, temporarily remove the server\share
// from the front of the OsLoader and LoadFileName strings so that TFTP
// works.
//
if (BlBootingFromNet) {
NetServerShare = OsLoader; // Required for Client Side Cache.
SavedOsLoader = OsLoader; // save OsLoader pointer
OsLoader++; // skip leading "\"
OsLoader = strchr(OsLoader,'\\'); // find server\share separator
if (OsLoader != NULL) {
OsLoader++; // skip server\share separator
OsLoader = strchr(OsLoader,'\\'); // find share\path separator
}
if (OsLoader == NULL) { // very bad if no \ found
OsLoader = SavedOsLoader;
goto LoadFailed;
}
SavedLoadFileName = LoadFileName; // save LoadFileName pointer
LoadFileName++; // skip leading "\"
LoadFileName = strchr(LoadFileName,'\\'); // find server\share separator
if (LoadFileName != NULL) {
LoadFileName++; // skip server\share separator
LoadFileName = strchr(LoadFileName,'\\'); // find share\path separator
}
if (LoadFileName == NULL) { // very bad if no \ found
LoadFileName = SavedLoadFileName;
OsLoader = SavedOsLoader;
goto LoadFailed;
}
}
#endif // defined(REMOTE_BOOT)
//
// Try to make sure disk caching is initialized. Failure in
// initializing the disk cache should not keep us from booting, so
// Status is not set.
//
if (BlDiskCacheInitialize() == ESUCCESS) {
bDiskCacheInitialized = TRUE;
}
//
// Get the NTFT drive signatures to allow the kernel to create the
// correct ARC name <=> NT name mappings.
//
BlGetArcDiskInformation(FALSE);
//
// Display the Configuration prompt for breakin at this point, but don't
// check for key downstrokes. This gives the user a little more reaction
// time.
//
BlStartConfigPrompt();
//
// Determine if we are going to do a last known good boot.
//
// ISSUE-2000/03/29-ADRIAO: LastKnownGood enhancements
// Note that last known kernel/hal support requires that we know we're
// going into a lkg boot prior to initializing the loader. On an x86 system
// with only one boot.ini option we will not present the user the lkg option
// until *after* we've loaded the kernel, hal, registry, and kd-dlls. If we
// decide to support last known kernel/hal, we'd probably have to do
// something similar to what 9x does (ie look for a depressed CTRL key at
// the earliest point in boot.)
//
bLastKnownGood = (BOOLEAN)(LoadOptions && (strstr(LoadOptions, "LASTKNOWNGOOD") != NULL));
//
// Put together everything we need to describe the loader device. This is
// where the OS is loaded from (ie some \winnt installation). The alias
// for this path is \SystemRoot.
//
LoadDevice = BlGetArgumentValue(Argc, Argv, "osloadpartition");
if (LoadDevice == NULL) {
Status = ENODEV;
BlFatalError(LOAD_HW_FW_CFG_CLASS,
DIAG_BL_FW_GET_BOOT_DEVICE,
LOAD_HW_FW_CFG_ACT);
goto LoadFailed;
}
//
// Initialize the Ramdisk if it is specified in LoadOptions
//
Status = RamdiskInitialize( LoadOptions, FALSE );
if (Status != ESUCCESS) {
// BlFatalError called inside RamdiskInitialize
goto LoadFailed;
}
//
// Translate it's signature based arc name
//
TmpPchar = BlTranslateSignatureArcName( LoadDevice );
if (TmpPchar) {
LoadDevice = TmpPchar;
}
//
// Open the load device
//
Status = ArcOpen(LoadDevice, ArcOpenReadWrite, &LoadDeviceId);
if (Status != ESUCCESS) {
BlFatalError(LOAD_HW_DISK_CLASS,
DIAG_BL_OPEN_BOOT_DEVICE,
LOAD_HW_DISK_ACT);
goto LoadFailed;
}
#if defined(_X86_)
//
// Check for the special SDIBOOT flag, which tells us to boot from an
// SDI image in the root of the boot partition.
//
if ( BlLoaderBlock->LoadOptions != NULL ) {
TmpPchar = strstr( BlLoaderBlock->LoadOptions, "SDIBOOT=" );
if ( TmpPchar != NULL ) {
TmpPchar = strchr( TmpPchar, '=' ) + 1;
RamdiskSdiBoot( TmpPchar );
}
}
#endif
if (GraphicsMode) {
HW_CURSOR(0x80000000,0x12);
VgaEnableVideo();
LoadBootLogoBitmap (LoadDeviceId, LoadFileName);
if (DisplayLogoOnBoot) {
PrepareGfxProgressBar();
BlUpdateBootStatus();
}
}
//
// Initiate filesystem metadata caching on the load device.
//
// NOTE: From here on access the LoadDevice only through the LoadDeviceId.
// This way, your access will be faster because it is cached. Otherwise if
// you make writes, you will have cache consistency issues.
//
if (bDiskCacheInitialized) {
BlDiskCacheStartCachingOnDevice(LoadDeviceId);
}
//
// Build the load device path set. We keep multiple paths so that we can
// fall back to a last known driver set during a last known good boot.
//
strcpy(LoadDevicePath, LoadFileName);
strcat(LoadDevicePath, "\\");
strcpy(LoadDeviceLKG1Path, LoadDevicePath);
strcat(LoadDeviceLKG1Path, LAST_KNOWN_GOOD_TEMPORARY_PATH "\\" );
strcpy(LoadDeviceLKG2Path, LoadDevicePath);
strcat(LoadDeviceLKG2Path, LAST_KNOWN_GOOD_WORKING_PATH "\\" );
#if defined(_X86_)
//
// Read in the XIP image
//
if (XIPEnabled) {
ULONG FileId;
//
// Read in the imagefile
//
Status = BlOpen(LoadDeviceId, XIPLoadPath, ArcOpenReadOnly, &FileId);
if (Status == ESUCCESS) {
Status = XipLargeRead(FileId, XIPBasePage, XIPPageCount);
(void) BlClose(FileId);
}
if (Status != ESUCCESS) {
XIPEnabled = FALSE;
}
}
#endif //_X86_
i = 0;
if (bLastKnownGood) {
//
// Add the last known good paths as if we are in a LastKnownGood boot.
//
LoadDevicePathSet.Source[i].DeviceId = LoadDeviceId;
LoadDevicePathSet.Source[i].DeviceName = LoadDevice;
LoadDevicePathSet.Source[i].DirectoryPath = LoadDeviceLKG1Path;
i++;
LoadDevicePathSet.Source[i].DeviceId = LoadDeviceId;
LoadDevicePathSet.Source[i].DeviceName = LoadDevice;
LoadDevicePathSet.Source[i].DirectoryPath = LoadDeviceLKG2Path;
i++;
}
LoadDevicePathSet.Source[i].DeviceId = LoadDeviceId;
LoadDevicePathSet.Source[i].DeviceName = LoadDevice;
LoadDevicePathSet.Source[i].DirectoryPath = LoadDevicePath;
//
// The load path sources are all relative to \SystemRoot.
//
LoadDevicePathSet.AliasName = "\\SystemRoot";
LoadDevicePathSet.PathOffset[0] = '\0';
LoadDevicePathSet.PathCount = ++i;
//
// While here, form the kernel path set. This is the same as the boot path
// set except that it's off of system32/64. Note also that we don't add in
// the LKG path today.
//
KernelPathSet.PathCount = 1;
KernelPathSet.AliasName = "\\SystemRoot";
strcpy(KernelPathSet.PathOffset, SYSTEM_DIRECTORY_PATH "\\" );
KernelPathSet.Source[0].DeviceId = LoadDeviceId;
KernelPathSet.Source[0].DeviceName = LoadDevice;
KernelPathSet.Source[0].DirectoryPath = LoadDevicePath;
//
// While here, form the fully qualified kernel path.
//
strcpy(KernelDirectoryPath, LoadFileName);
strcat(KernelDirectoryPath, "\\" SYSTEM_DIRECTORY_PATH "\\" );
//
// Now put together everything we need to describe the system device. This
// is where we get the hal and pal from. There is no alias for this path
// (ie no equivalent to \SystemRoot.)
//
SystemDevice = BlGetArgumentValue(Argc, Argv, "systempartition");
if (SystemDevice == NULL) {
Status = ENODEV;
BlFatalError(LOAD_HW_FW_CFG_CLASS,
DIAG_BL_FW_GET_SYSTEM_DEVICE,
LOAD_HW_FW_CFG_ACT);
goto LoadFailed;
}
//
// Translate it's signature based arc name
//
TmpPchar = BlTranslateSignatureArcName( SystemDevice );
if (TmpPchar) {
SystemDevice = TmpPchar;
}
//
// Open the system device. If SystemDevice path and LoadDevice
// path are the same [as on all x86 I have seen so far], do not
// open the device under another device id so we can use disk
// caching. Otherwise there may be a cache consistency issue.
//
if (!_stricmp(LoadDevice, SystemDevice)) {
SystemDeviceId = LoadDeviceId;
} else {
Status = ArcOpen(SystemDevice, ArcOpenReadWrite, &SystemDeviceId);
if (Status != ESUCCESS) {
BlFatalError(LOAD_HW_FW_CFG_CLASS,
DIAG_BL_FW_OPEN_SYSTEM_DEVICE,
LOAD_HW_FW_CFG_ACT);
goto LoadFailed;
}
}
//
// Initiate filesystem metadata caching on the system device.
//
// NOTE: From here on access the SystemDevice only through the
// SystemDeviceId. This way, your access will be faster because it is
// cached. Otherwise if you make writes, you will have cache consistency
// issues.
//
if (bDiskCacheInitialized) {
if (SystemDeviceId != LoadDeviceId) {
BlDiskCacheStartCachingOnDevice(SystemDeviceId);
}
}
//
// Get the path name of the OS loader file and isolate the directory
// path so it can be used to load the HAL DLL.
//
// Note well: We actually don't use this path to load the hal anymore
// -- we rely on the kernel path to load the hal as they are at the same
// location
// -- we do use this path for identifying the system partition, so do not
// remove code related to systemdevicepath unless you know what you're
// doing.
//
FileName = OsLoader;
DirectoryEnd = strrchr(FileName, '\\');
FileName = strchr(FileName, '\\');
SystemDevicePath[0] = 0;
if (DirectoryEnd != NULL) {
Limit = (ULONG)((ULONG_PTR)DirectoryEnd - (ULONG_PTR)FileName + 1);
for (Index = 0; Index < Limit; Index += 1) {
SystemDevicePath[Index] = *FileName++;
}
SystemDevicePath[Index] = 0;
}
//
// Describe our hal paths.
//
// ISSUE-2000/03/29-ADRIAO: LastKnownGood enhancements
// On x86 we'd like to support LKG for hals way into the future. Ideally
// we'd get them from \Winnt\LastGood\System32. Unfortunately, we get back
// \Winnt\System32 from the Arc, making it kinda hard to splice in our
// LKG path.
//
// ISSUE-2000/03/29-ADRIAO: Existant namespace polution
// We need to come up with an Alias for the Hal path so that it can
// properly be inserted into the image namespace. Either that or we should
// consider lying and saying it comes from \SystemRoot. Note that on x86
// we probably *would* want it to say it was from \SystemRoot in case it
// brings in its own DLL's!
//
SystemDevicePathSet.PathCount = 1;
SystemDevicePathSet.AliasName = NULL;
SystemDevicePathSet.PathOffset[0] = '\0';
SystemDevicePathSet.Source[0].DeviceId = SystemDeviceId;
SystemDevicePathSet.Source[0].DeviceName = SystemDevice;
SystemDevicePathSet.Source[0].DirectoryPath = SystemDevicePath;
//
// Handle triage dump (if present).
//
Status = BlLoadTriageDump (LoadDeviceId,
&BlLoaderBlock->Extension->TriageDumpBlock);
if (Status != ESUCCESS) {
BlLoaderBlock->Extension->TriageDumpBlock = NULL;
}
//
// Handle hibernation image (if present)
//
#if defined(i386) || defined(_IA64_)
Status = BlHiberRestore(LoadDeviceId, NULL);
if (Status != ESUCCESS) {
Status = ESUCCESS;
// proceed with the boot.
// goto LoadFailed;
}
#endif
//
// Initialize the logging system. Note that we dump to the system device
// and not the load device.
//
BlLogInitialize(SystemDeviceId);
#if defined(REMOTE_BOOT)
//
// If booting from the net, check for any of the following:
// - The client-side disk is incorrect for this NetPC.
// - The client-side cache is stale.
//
if (BlBootingFromNet) {
BlLoaderBlock->SetupLoaderBlock = BlAllocateHeap(sizeof(SETUP_LOADER_BLOCK));
if (BlLoaderBlock->SetupLoaderBlock == NULL) {
Status = ENOMEM;
BlFatalError(LOAD_HW_MEM_CLASS,
DIAG_BL_MEMORY_INIT,
LOAD_HW_MEM_ACT);
goto LoadFailed;
}
//
// ISSUE-1998/07/13-JVert (John Vert)
// Code below is ifdef'd out because net boot is no longer
// in the product. BlCheckMachineReplacement ends up calling
// SlDetectHAL, which now requires access to txtsetup.sif
// in order to see if an ACPI machine has a known "good" BIOS.
// Since there is no txtsetup.sif during a normal boot there
// is no point in getting all the INF processing logic into
// NTLDR.
// ISSUE-1998/07/16-ChuckL (Chuck Lenzmeier)
// This means that if we ever reenable full remote boot, as
// opposed to just remote install, and we want to be able to
// do machine replacement, we're going to have to figure out
// how to make SlDetectHAL work outside of textmode setup.
//
strncpy(OutputBuffer, LoadFileName + 1, 256);
TmpPchar = strchr(OutputBuffer, '\\');
TmpPchar++;
TmpPchar = strchr(TmpPchar, '\\');
TmpPchar++;
strcpy(TmpPchar, "startrom.com");
BlCheckMachineReplacement(SystemDevice, SystemDeviceId, NetRebootParameter, OutputBuffer);
} else
#endif // defined(REMOTE_BOOT)
{
BlLoaderBlock->SetupLoaderBlock = NULL;
}
//
// See if we're redirecting.
//
if( LoaderRedirectionInformation.PortAddress ) {
//
// Yes, we are redirecting right now. Use these settings.
//
BlLoaderBlock->Extension->HeadlessLoaderBlock = BlAllocateHeap(sizeof(HEADLESS_LOADER_BLOCK));
RtlCopyMemory( BlLoaderBlock->Extension->HeadlessLoaderBlock,
&LoaderRedirectionInformation,
sizeof(HEADLESS_LOADER_BLOCK) );
} else {
BlLoaderBlock->Extension->HeadlessLoaderBlock = NULL;
}
//
// Generate the full path name for the HAL DLL image and load it into
// memory.
//
strcpy(HalPathName, KernelDirectoryPath);
strcat(HalPathName, HalFileName);
//
// Prepare for building the full path name of the kernel
//
strcpy(KernelPathName, KernelDirectoryPath);
#if defined(_X86_)
BlAmd64RemapDram( LoadOptions );
//
// If Amd64 long mode is detected, the following call will set
// the global BlAmd64UseLongMode to TRUE, AND will append
// KernelFileName to KernelPathName.
//
Status = BlAmd64CheckForLongMode( LoadDeviceId,
KernelPathName,
KernelFileName );
if (Status != ESUCCESS) {
Status = ENODEV;
BlFatalError(LOAD_SW_MIS_FILE_CLASS,
DIAG_BL_LOAD_SYSTEM_IMAGE,
LOAD_SW_FILE_REINST_ACT);
goto LoadFailed;
}
if (BlAmd64UseLongMode == FALSE) {
//
// On X86, there are two kernel images: one compiled for PAE mode,
// and one not. Call a routine that decides what to load.
//
// Upon successful return, KernelPathName contains the full path of
// the kernel image.
//
Status = Blx86CheckForPaeKernel( userSpecifiedPae,
userSpecifiedNoPae,
userSpecifiedKernelName,
HalPathName,
LoadDeviceId,
SystemDeviceId,
&highestSystemPage,
&BlUsePae,
KernelPathName
);
if (Status != ESUCCESS) {
//
// A valid kernel compatible with this processor could not be
// located. This is fatal.
//
BlFatalError(LOAD_SW_MIS_FILE_CLASS,
(Status == EBADF)
? DIAG_BL_LOAD_HAL_IMAGE
: DIAG_BL_LOAD_SYSTEM_IMAGE,
LOAD_SW_FILE_REINST_ACT);
goto LoadFailed;
}
}
#else
//
// Generate the full pathname of ntoskrnl.exe
//
// "\winnt\system32\ntoskrnl.exe"
//
strcat(KernelPathName, KernelFileName);
#endif
//
// Set allocatable range to the kernel-specific range
//
BlUsableBase = BL_KERNEL_RANGE_LOW;
BlUsableLimit = BL_KERNEL_RANGE_HIGH;
//
// Initialize the progress bar
//
if( BlIsTerminalConnected() ) {
BlOutputStartupMsg(BL_MSG_STARTING_WINDOWS);
BlOutputTrailerMsg(BL_ADVANCED_BOOT_MESSAGE);
}
#if defined (_X86_)
if (BlAmd64UseLongMode == FALSE) {
BlpCheckVersion(LoadDeviceId,KernelPathName);
}
#endif
//
// Load the kernel image into memory.
//
BlOutputLoadMessage(LoadDevice, KernelPathName, NULL);
#ifdef i386
retrykernel:
#endif
Status = BlLoadImage(LoadDeviceId,
LoaderSystemCode,
KernelPathName,
TARGET_IMAGE,
&SystemBase);
#ifdef i386
//
// If the kernel didn't fit in the preferred range, reset the range to
// all of memory and try again.
//
if ((Status == ENOMEM) &&
((BlUsableBase != BL_DRIVER_RANGE_LOW) ||
(BlUsableLimit != BL_DRIVER_RANGE_HIGH))) {
BlUsableBase = BL_DRIVER_RANGE_LOW;
BlUsableLimit = BL_DRIVER_RANGE_HIGH;
goto retrykernel;
}
#endif
if (Status != ESUCCESS) {
BlFatalError(LOAD_SW_MIS_FILE_CLASS,
DIAG_BL_LOAD_SYSTEM_IMAGE,
LOAD_SW_FILE_REINST_ACT);
goto LoadFailed;
}
BlUpdateBootStatus();
//
// Whatever filesystem was used to load the kernel image is the
// one that needs to be loaded along with the boot drivers.
//
#if defined(REMOTE_BOOT)
if (BlBootingFromNet) {
//
// For a remote boot, the boot file system is always NTFS.
//
BootFileSystem = L"ntfs";
} else
#endif // defined(REMOTE_BOOT)
{
FsInfo = BlGetFsInfo(LoadDeviceId);
if (FsInfo != NULL) {
BootFileSystem = FsInfo->DriverName;
} else {
BlFatalError(LOAD_SW_MIS_FILE_CLASS,
DIAG_BL_LOAD_SYSTEM_IMAGE,
LOAD_SW_FILE_REINST_ACT);
goto LoadFailed;
}
}
//
// Load the HAL DLL image into memory.
//
BlOutputLoadMessage(LoadDevice, HalPathName, NULL);
#ifdef i386
retryhal:
#endif
Status = BlLoadImage(LoadDeviceId,
LoaderHalCode,
HalPathName,
TARGET_IMAGE,
&HalBase);
#ifdef i386
//
// If the HAL didn't fit in the preferred range, reset the range to
// all of memory and try again.
//
if ((Status == ENOMEM) &&
((BlUsableBase != BL_DRIVER_RANGE_LOW) ||
(BlUsableLimit != BL_DRIVER_RANGE_HIGH))) {
BlUsableBase = BL_DRIVER_RANGE_LOW;
BlUsableLimit = BL_DRIVER_RANGE_HIGH;
goto retryhal;
}
#endif
if (Status != ESUCCESS) {
BlFatalError(LOAD_SW_MIS_FILE_CLASS,
DIAG_BL_LOAD_HAL_IMAGE,
LOAD_SW_FILE_REINST_ACT);
goto LoadFailed;
}
BlUpdateBootStatus();
//
// Load the Kernel Debugger DLL image into memory.
//
KdDllLoadFailed = FALSE;
strcpy(&KdDllName[0], KernelDirectoryPath);
strcat(&KdDllName[0], KdFileName);
BlOutputLoadMessage(LoadDevice, &KdDllName[0], NULL);
Status = BlLoadImage(LoadDeviceId,
LoaderSystemCode,
&KdDllName[0],
TARGET_IMAGE,
&KdDllBase);
if ((Status != ESUCCESS) && (UseAlternateKdDll == TRUE)) {
UseAlternateKdDll = FALSE;
strcpy(&KdDllName[0], KernelDirectoryPath);
strcat(&KdDllName[0], "kdcom.dll");
BlOutputLoadMessage(LoadDevice, &KdDllName[0], NULL);
Status = BlLoadImage(LoadDeviceId,
LoaderSystemCode,
&KdDllName[0],
TARGET_IMAGE,
&KdDllBase);
}
//
// Don't bugcheck if KDCOM.DLL is not present, we may be trying to dual-
// boot an older OS. If we really do require KDCOM.DLL, we will fail to
// scan the import table for the system image, and bugcheck with kernel
// needed DLLs to load
//
if (Status != ESUCCESS) {
KdDllLoadFailed = TRUE;
}
BlUpdateBootStatus();
//
// Set allocatable range to the driver-specific range
//
BlUsableBase = BL_DRIVER_RANGE_LOW;
BlUsableLimit = BL_DRIVER_RANGE_HIGH;
//
// Generate a loader data entry for the system image.
//
Status = BlAllocateDataTableEntry("ntoskrnl.exe",
KernelPathName,
SystemBase,
&SystemDataTableEntry);
if (Status != ESUCCESS) {
BlFatalError(LOAD_SW_INT_ERR_CLASS,
DIAG_BL_LOAD_SYSTEM_IMAGE,
LOAD_SW_INT_ERR_ACT);
goto LoadFailed;
}
//
// Generate a loader data entry for the HAL DLL.
//
Status = BlAllocateDataTableEntry("hal.dll",
HalPathName,
HalBase,
&HalDataTableEntry);
if (Status != ESUCCESS) {
BlFatalError(LOAD_SW_INT_ERR_CLASS,
DIAG_BL_LOAD_HAL_IMAGE,
LOAD_SW_INT_ERR_ACT);
goto LoadFailed;
}
//
// Generate a loader data entry for the Kernel Debugger DLL.
//
if (!KdDllLoadFailed) {
Status = BlAllocateDataTableEntry("kdcom.dll",
KdDllName,
KdDllBase,
&KdDataTableEntry);
if (Status != ESUCCESS) {
BlFatalError(LOAD_SW_INT_ERR_CLASS,
DIAG_BL_LOAD_SYSTEM_DLLS,
LOAD_SW_INT_ERR_ACT);
goto LoadFailed;
}
}
//
// Scan the import table for the system image and load all referenced
// DLLs.
//
Status = BlScanImportDescriptorTable(&KernelPathSet,
SystemDataTableEntry,
LoaderSystemCode);
if (Status != ESUCCESS) {
BlFatalError(LOAD_SW_INT_ERR_CLASS,
DIAG_BL_LOAD_SYSTEM_DLLS,
LOAD_SW_INT_ERR_ACT);
goto LoadFailed;
}
//
// Scan the import table for the HAL DLL and load all referenced DLLs.
//
Status = BlScanImportDescriptorTable(&KernelPathSet,
HalDataTableEntry,
LoaderHalCode);
if (Status != ESUCCESS) {
BlFatalError(LOAD_SW_INT_ERR_CLASS,
DIAG_BL_LOAD_HAL_DLLS,
LOAD_SW_INT_ERR_ACT);
goto LoadFailed;
}
//
// Scan the import table for the Kernel Debugger DLL and load all
// referenced DLLs.
//
if (!KdDllLoadFailed) {
Status = BlScanImportDescriptorTable(&KernelPathSet,
KdDataTableEntry,
LoaderSystemCode);
if (Status != ESUCCESS) {
BlFatalError(LOAD_SW_INT_ERR_CLASS,
DIAG_BL_LOAD_SYSTEM_DLLS,
LOAD_SW_INT_ERR_ACT);
goto LoadFailed;
}
}
//
// Relocate the system entry point and set system specific information.
//
NtHeaders = RtlImageNtHeader(SystemBase);
SystemEntry = (PTRANSFER_ROUTINE)((ULONG_PTR)SystemBase +
NtHeaders->OptionalHeader.AddressOfEntryPoint);
#if defined(_IA64_)
BlLoaderBlock->u.Ia64.KernelVirtualBase = (ULONG_PTR)SystemBase;
BlLoaderBlock->u.Ia64.KernelPhysicalBase = (ULONG_PTR)SystemBase & 0x7fffffff;
#endif
//
// Allocate a structure for NLS data which will be loaded and filled
// by BlLoadAndScanSystemHive.
//
BlLoaderBlock->NlsData = BlAllocateHeap(sizeof(NLS_DATA_BLOCK));
if (BlLoaderBlock->NlsData == NULL) {
Status = ENOMEM;
BlFatalError(LOAD_HW_MEM_CLASS,
DIAG_BL_LOAD_SYSTEM_HIVE,
LOAD_HW_MEM_ACT);
goto LoadFailed;
}
#if defined(REMOTE_BOOT)
//
// If booting from the net, we use the SetupLoaderBlock to pass
// information. BlLoadAndScanSystemHive fills in the netboot card
// fields if present in the registry.
//
if (BlBootingFromNet) {
BlLoaderBlock->SetupLoaderBlock->NetbootCardInfo = BlAllocateHeap(sizeof(NET_CARD_INFO));
if ( BlLoaderBlock->SetupLoaderBlock->NetbootCardInfo == NULL ) {
Status = ENOMEM;
BlFatalError(LOAD_HW_MEM_CLASS,
DIAG_BL_MEMORY_INIT,
LOAD_HW_MEM_ACT);
goto LoadFailed;
}
BlLoaderBlock->SetupLoaderBlock->NetbootCardInfoLength = sizeof(NET_CARD_INFO);
}
#endif // defined(REMOTE_BOOT)
//
// Load the SYSTEM hive.
//
//
bLastKnownGoodChosenLate = bLastKnownGood;
Status = BlLoadAndScanSystemHive(LoadDeviceId,
LoadDevice,
LoadFileName,
BootFileSystem,
&bLastKnownGoodChosenLate,
&ServerHive,
BadFileName);
if (Status != ESUCCESS) {
if (BlRebootSystem != FALSE) {
Status = ESUCCESS;
} else {
BlBadFileMessage(BadFileName);
}
goto LoadFailed;
}
if (bLastKnownGoodChosenLate) {
//
// The user may have selected last known good boot after the kernel and
// friends were loaded. Update the boot path list here as neccessary.
//
if (!bLastKnownGood) {
ASSERT((LoadDevicePathSet.PathCount < MAX_PATH_SOURCES) &&
(LoadDevicePathSet.PathCount == 1));
//
// Move the current boot path to the end of our last good array.
//
LoadDevicePathSet.Source[2] = LoadDevicePathSet.Source[0];
//
// Add the last known good paths as if we are in a LastKnownGood boot.
//
LoadDevicePathSet.Source[0].DeviceId = LoadDeviceId;
LoadDevicePathSet.Source[0].DeviceName = LoadDevice;
LoadDevicePathSet.Source[0].DirectoryPath = LoadDeviceLKG1Path;
LoadDevicePathSet.Source[1].DeviceId = LoadDeviceId;
LoadDevicePathSet.Source[1].DeviceName = LoadDevice;
LoadDevicePathSet.Source[1].DirectoryPath = LoadDeviceLKG2Path;
LoadDevicePathSet.PathCount = 3;
bLastKnownGood = TRUE;
}
} else {
//
// The user might have changed his mind and deselected LKG. If so undo
// the path work here.
//
if (bLastKnownGood) {
ASSERT((LoadDevicePathSet.PathCount < MAX_PATH_SOURCES) &&
(LoadDevicePathSet.PathCount == 3));
//
// Move the current boot path to the end of our last good array.
//
LoadDevicePathSet.Source[0] = LoadDevicePathSet.Source[2];
LoadDevicePathSet.PathCount = 1;
bLastKnownGood = FALSE;
}
}
//
// Count the number of drivers we need to load
//
BlMaxFilesToLoad = BlNumFilesLoaded;
BootDriverListHead = &(BlLoaderBlock->BootDriverListHead);
NextEntry = BootDriverListHead->Flink ;
while (NextEntry != BootDriverListHead) {
DriverNode = CONTAINING_RECORD(NextEntry,
BOOT_DRIVER_NODE,
ListEntry.Link);
DriverEntry = &DriverNode->ListEntry;
NextEntry = DriverEntry->Link.Flink;
BlMaxFilesToLoad++;
}
//
// Rescale the progress bar
//
BlRedrawProgressBar();
//
// Insert the headless driver onto the boot driver list if this is supposed to be a
// headless boot.
//
// The SAC is only availabe on server products, so we need to check the
// product type.
//
if ((BlLoaderBlock->Extension->HeadlessLoaderBlock != NULL) && ServerHive) {
BlAddToBootDriverList(
&BlLoaderBlock->BootDriverListHead,
L"sacdrv.sys", // Driver name
L"sacdrv", // Service
L"SAC", // Group
1, // Tag
NormalError, // ErrorControl
TRUE // Insert at head of list
);
}
#if defined(REMOTE_BOOT)
//
// If booting from the net, then save the IP address and subnet mask,
// and determine which net card driver we need to load. This may involve
// doing an exchange with the server if the registry is not set up
// correctly.
//
if (BlBootingFromNet && NetworkBootRom) {
NET_CARD_INFO tempNetCardInfo;
PSETUP_LOADER_BLOCK setupLoaderBlock = BlLoaderBlock->SetupLoaderBlock;
//
// Pass DHCP information to OS for use by TCP/IP
//
setupLoaderBlock->IpAddress = NetLocalIpAddress;
setupLoaderBlock->SubnetMask = NetLocalSubnetMask;
setupLoaderBlock->DefaultRouter = NetGatewayIpAddress;
setupLoaderBlock->ServerIpAddress = NetServerIpAddress;
//
// Get information about the net card from the ROM.
//
NtStatus = NetQueryCardInfo(
&tempNetCardInfo
);
if (NtStatus != STATUS_SUCCESS) {
Status = ENOMEM;
BlFatalError(LOAD_HW_MEM_CLASS,
DIAG_BL_MEMORY_INIT,
LOAD_HW_MEM_ACT);
goto LoadFailed;
}
//
// If the net card info is the same as the one that BlLoadAndScanSystemHive
// stored in the setup loader block, and it also read something into
// the hardware ID and driver name parameters, then we are fine,
// otherwise we need to do an exchange with the server to get
// the information.
//
// If we don't do an exchange with the server, then NetbootCardRegistry
// will stay NULL, which will be OK because even if the card has
// moved to a different slot, the registry params still go in the
// same place.
//
if ((memcmp(
&tempNetCardInfo,
setupLoaderBlock->NetbootCardInfo,
sizeof(NET_CARD_INFO)) != 0) ||
(setupLoaderBlock->NetbootCardHardwareId[0] == L'\0') ||
(setupLoaderBlock->NetbootCardDriverName[0] == L'\0') ||
(setupLoaderBlock->NetbootCardServiceName[0] == L'\0')) {
//
// This call may allocate setupLoaderBlock->NetbootCardRegistry
//
//
// If we ever do go back to remote boot land, we'll have
// to fill the second parameter with the server setup path of the
// flat NT image. It doesn't look like we conveniently have it
// here so we might have to store it in the setup loader block
// so that we can pass it in here. We'll postpone this work
// until we do the full remote install work. The path should be
// set to \srv\reminst\setup\english\images\cd1911.
//
NtStatus = NetQueryDriverInfo(
&tempNetCardInfo,
NULL,
SavedLoadFileName,
setupLoaderBlock->NetbootCardHardwareId,
sizeof(setupLoaderBlock->NetbootCardHardwareId),
setupLoaderBlock->NetbootCardDriverName,
NULL, // don't need NetbootCardDriverName in ANSI
sizeof(setupLoaderBlock->NetbootCardDriverName),
setupLoaderBlock->NetbootCardServiceName,
sizeof(setupLoaderBlock->NetbootCardServiceName),
&setupLoaderBlock->NetbootCardRegistry,
&setupLoaderBlock->NetbootCardRegistryLength);
if (NtStatus != STATUS_SUCCESS) {
Status = ENOMEM;
BlFatalError(LOAD_HW_MEM_CLASS,
DIAG_BL_MEMORY_INIT,
LOAD_HW_MEM_ACT);
goto LoadFailed;
}
//
// if we detected a new card, then remember to pin it later.
//
if (setupLoaderBlock->NetbootCardRegistry != NULL) {
setupLoaderBlock->Flags |= SETUPBLK_FLAGS_PIN_NET_DRIVER;
}
}
//
// Add an entry to the BootDriverList for the netboot card,
// because it will either not have a registry entry or else
// will have one with Start set to 3.
//
// NOTE: This routine does NOT resort the list.
//
BlAddToBootDriverList(
&BlLoaderBlock->BootDriverListHead,
setupLoaderBlock->NetbootCardDriverName,
setupLoaderBlock->NetbootCardServiceName,
L"NDIS", // Group
1, // Tag
NormalError, // ErrorControl
FALSE // Insert at Tail of list
);
RtlMoveMemory(
setupLoaderBlock->NetbootCardInfo,
&tempNetCardInfo,
sizeof(NET_CARD_INFO)
);
}
#endif // defined(REMOTE_BOOT)
//
// Load boot drivers
//
Status = BlLoadBootDrivers(&LoadDevicePathSet,
&BlLoaderBlock->BootDriverListHead,
BadFileName);
if (Status != ESUCCESS) {
if (BlRebootSystem != FALSE) {
Status = ESUCCESS;
} else {
BlBadFileMessage(BadFileName);
}
goto LoadFailed;
}
//
// Load the blocked driver database.
//
RtlInitUnicodeString(&unicodeString, L"drvmain.sdb");
strcpy(Directory, LoadFileName);
strcat(Directory, "\\AppPatch\\");
//
// Let the kernel deal with failure to load this driver database.
//
BlLoaderBlock->Extension->DrvDBImage = NULL;
BlLoaderBlock->Extension->DrvDBSize = 0;
BlLoadDrvDB( LoadDeviceId,
LoadDevice,
Directory,
&unicodeString,
&BlLoaderBlock->Extension->DrvDBImage,
&BlLoaderBlock->Extension->DrvDBSize,
BadFileName);
#if defined(REMOTE_BOOT)
if (BlBootingFromNet) {
ARC_STATUS ArcStatus;
ULONG FileId;
//
// Exchange with the server to set up for the future IPSEC conversation
// we will have. Whether IPSEC is enabled is determined in BlLoadAndScanSystemHives.
//
if ((BlLoaderBlock->SetupLoaderBlock->Flags & SETUPBLK_FLAGS_IPSEC_ENABLED) != 0) {
BlLoaderBlock->SetupLoaderBlock->IpsecInboundSpi = 0x11111111;
NetPrepareIpsec(
BlLoaderBlock->SetupLoaderBlock->IpsecInboundSpi,
&BlLoaderBlock->SetupLoaderBlock->IpsecSessionKey,
&BlLoaderBlock->SetupLoaderBlock->IpsecOutboundSpi
);
}
//
// Indicate whether the CSC needs to be repinned or disabled.
//
if ( NetBootRepin ) {
BlLoaderBlock->SetupLoaderBlock->Flags |= SETUPBLK_FLAGS_REPIN;
}
if ( !NetBootCSC ) {
BlLoaderBlock->SetupLoaderBlock->Flags |= SETUPBLK_FLAGS_DISABLE_CSC;
}
//
// Restore the server\share at the front of the OsLoader and
// LoadFileName strings.
//
OsLoader = SavedOsLoader;
LoadFileName = SavedLoadFileName;
//
// Read the secret off the disk, if there is one, and store it
// in the loader block.
//
ArcStatus = BlOpenRawDisk(&FileId);
if (ArcStatus == ESUCCESS) {
BlLoaderBlock->SetupLoaderBlock->NetBootSecret = BlAllocateHeap(sizeof(RI_SECRET));
if (BlLoaderBlock->SetupLoaderBlock->NetBootSecret == NULL) {
Status = ENOMEM;
BlFatalError(LOAD_HW_MEM_CLASS,
DIAG_BL_MEMORY_INIT,
LOAD_HW_MEM_ACT);
goto LoadFailed;
}
ArcStatus = BlReadSecret(
FileId,
(PRI_SECRET)(BlLoaderBlock->SetupLoaderBlock->NetBootSecret));
if (Status != ESUCCESS) {
BlFatalError(LOAD_HW_MEM_CLASS,
DIAG_BL_MEMORY_INIT,
LOAD_HW_MEM_ACT);
goto LoadFailed;
}
ArcStatus = BlCloseRawDisk(FileId);
//
// By now we have TFTPed some files so this will be TRUE if it
// is ever going to be.
//
BlLoaderBlock->SetupLoaderBlock->NetBootUsePassword2 = NetBootTftpUsedPassword2;
}
}
#endif // defined(REMOTE_BOOT)
//
// Generate the ARC boot device name and NT path name.
//
Status = BlGenerateDeviceNames(LoadDevice, DeviceName, &DevicePrefix[0]);
if (Status != ESUCCESS) {
BlFatalError(LOAD_HW_FW_CFG_CLASS,
DIAG_BL_ARC_BOOT_DEV_NAME,
LOAD_HW_FW_CFG_ACT);
goto LoadFailed;
}
FileSize = (ULONG)strlen(DeviceName) + 1;
FileName = (PCHAR)BlAllocateHeap(FileSize);
strcpy(FileName, DeviceName);
BlLoaderBlock->ArcBootDeviceName = FileName;
FileSize = (ULONG)strlen(LoadFileName) + 2;
FileName = (PCHAR)BlAllocateHeap( FileSize);
strcpy(FileName, LoadFileName);
strcat(FileName, "\\");
BlLoaderBlock->NtBootPathName = FileName;
//
// Generate the ARC HAL device name and NT path name.
//
// On the x86, the systempartition variable lies, and instead points to
// the location of the hal. Therefore, the variable, 'X86SystemPartition'
// is defined for the real system partition.
//
#if defined(_X86_)
x86SystemPartition = BlGetArgumentValue(Argc, Argv, "x86systempartition");
strcpy(&DeviceName[0], x86SystemPartition);
#else
Status = BlGenerateDeviceNames(SystemDevice, &DeviceName[0], &DevicePrefix[0]);
if (Status != ESUCCESS) {
BlFatalError(LOAD_HW_FW_CFG_CLASS,
DIAG_BL_ARC_BOOT_DEV_NAME,
LOAD_HW_FW_CFG_ACT);
goto LoadFailed;
}
#endif
FileSize = (ULONG)strlen(DeviceName) + 1;
FileName = (PCHAR)BlAllocateHeap(FileSize);
strcpy(FileName, DeviceName);
BlLoaderBlock->ArcHalDeviceName = FileName;
//
// On the x86, this structure is unfortunately named. What we really need
// here is the osloader path. What we actually have is a path to the HAL.
// Since this path is always at the root of the partition, hardcode it here.
//
#if defined(_X86_)
FileName = (PCHAR)BlAllocateHeap(2);
FileName[0] = '\\';
FileName[1] = '\0';
#else
FileSize = (ULONG)strlen(&SystemDevicePath[0]) + 1;
FileName = (PCHAR)BlAllocateHeap(FileSize);
strcpy(FileName, &SystemDevicePath[0]);
#endif
BlLoaderBlock->NtHalPathName = FileName;
//
// Close the open handles & stop caching on closed devices.
//
ArcClose(LoadDeviceId);
if (bDiskCacheInitialized) {
BlDiskCacheStopCachingOnDevice(LoadDeviceId);
}
//
// Close the system device only if it is different from the
// LoadDevice.
//
if (SystemDeviceId != LoadDeviceId) {
ArcClose(SystemDeviceId);
if (bDiskCacheInitialized) {
BlDiskCacheStopCachingOnDevice(SystemDeviceId);
}
}
//
// Bump the progress bar all the way to 100% as this is our last chance
// before we jump into the kernel.
//
BlUpdateProgressBar(100);
if ( BlBootingFromNet ) {
//
// If booting from Network, we should save the network information
// in the network loader block for use by the kernel.
//
BlLoaderBlock->Extension->NetworkLoaderBlock = BlAllocateHeap(sizeof(NETWORK_LOADER_BLOCK));
if (BlLoaderBlock->Extension->NetworkLoaderBlock == NULL) {
Status = ENOMEM;
BlFatalError(LOAD_HW_MEM_CLASS,
DIAG_BL_MEMORY_INIT,
LOAD_HW_MEM_ACT);
goto LoadFailed;
}
memset( BlLoaderBlock->Extension->NetworkLoaderBlock, 0, sizeof(NETWORK_LOADER_BLOCK) );
//
// Pass DHCP information to OS for use by TCP/IP
//
NtStatus = NetFillNetworkLoaderBlock(BlLoaderBlock->Extension->NetworkLoaderBlock);
if (NtStatus != STATUS_SUCCESS) {
Status = NtStatus;
BlFatalError(LOAD_HW_MEM_CLASS,
DIAG_BL_MEMORY_INIT,
LOAD_HW_MEM_ACT);
goto LoadFailed;
}
//
// Close down the remote boot network file system.
//
// NOTE: If BlBootingFromNet, don't do anything after this point
// that would cause access to the boot ROM.
//
NetTerminate();
}
#if defined(_X86_)
//
// Write out the boot status flags to disk so we can determine if the
// OS fails to boot.
//
BlWriteBootStatusFlags(LoadDeviceId, (PUCHAR)LoadFileName, FALSE, FALSE);
#endif
#if defined(_X86_)
//
// Close down the arc emulator's i/o system if we initialized it.
// This cannot be done after BlSetupForNt becase that routine will
// unmap the miniport code the arc emulator may need to shutdown.
//
AETerminateIo();
#endif
//
// Execute the architecture specific setup code.
//
Status = BlSetupForNt(BlLoaderBlock);
if (Status != ESUCCESS) {
BlFatalError(LOAD_SW_INT_ERR_CLASS,
DIAG_BL_SETUP_FOR_NT,
LOAD_SW_INT_ERR_ACT);
goto LoadFailed;
}
//
// Transfer control to loaded image.
//
BlTransferToKernel(SystemEntry, BlLoaderBlock);
//
// Any return from the system is an error.
//
Status = EBADF;
BlFatalError(LOAD_SW_BAD_FILE_CLASS,
DIAG_BL_KERNEL_INIT_XFER,
LOAD_SW_FILE_REINST_ACT);
//
// The load failed.
//
LoadFailed:
//
// We do not know if the devices we are caching will be
// closed/reopened etc beyond this function. To be safe,
// uninitialize the disk caching.
//
if (bDiskCacheInitialized) {
BlDiskCacheUninitialize();
}
return Status;
}
VOID
BlOutputLoadMessage (
IN PCHAR DeviceName,
IN PCHAR FileName,
IN PTCHAR FileDescription OPTIONAL
)
/*++
Routine Description:
This routine outputs a loading message to the console output device.
Arguments:
DeviceName - Supplies a pointer to a zero terminated device name.
FileName - Supplies a pointer to a zero terminated file name.
FileDescription - Friendly name of the file in question.
Return Value:
None.
--*/
{
ULONG Count;
CHAR OutputBuffer[256];
#ifdef UNICODE
TCHAR OutputBufferUnicode[256];
ANSI_STRING aString;
UNICODE_STRING uString;
#endif
PTCHAR p;
UNREFERENCED_PARAMETER(FileDescription);
if(!DisplayLogoOnBoot) {
//
// Proceed only if no logo is displayed.
///////////////////////////////////////////////
//
// Construct and output loading file message.
//
if (!BlOutputDots) {
strcpy(&OutputBuffer[0], " ");
if (DeviceName)
strcat(&OutputBuffer[0], DeviceName);
if (FileName)
strcat(&OutputBuffer[0], FileName);
strcat(&OutputBuffer[0], "\r\n");
BlLog((LOG_LOGFILE,OutputBuffer));
#ifdef UNICODE
p = OutputBufferUnicode;
uString.Buffer = OutputBufferUnicode;
uString.MaximumLength = sizeof(OutputBufferUnicode);
RtlInitAnsiString(&aString, OutputBuffer );
RtlAnsiStringToUnicodeString( &uString, &aString, FALSE );
#else
p = OutputBuffer;
#endif
ArcWrite(BlConsoleOutDeviceId,
p,
(ULONG)_tcslen(p)*sizeof(TCHAR),
&Count);
}
}
return;
}
ARC_STATUS
BlLoadAndScanSystemHive(
IN ULONG DeviceId,
IN PCHAR DeviceName,
IN PCHAR DirectoryPath,
IN PWSTR BootFileSystem,
IN OUT BOOLEAN *LastKnownGoodBoot,
OUT BOOLEAN *ServerHive,
OUT PCHAR BadFileName
)
/*++
Routine Description:
This function loads the system hive into memory, verifies its
consistency, scans it for the list of boot drivers, and loads
the resulting list of drivers.
If the system hive cannot be loaded or is not a valid hive, it
is rejected and the system.alt hive is used. If this is invalid,
the boot must fail.
Arguments:
DeviceId - Supplies the file id of the device the system tree is on.
DeviceName - Supplies the name of the device the system tree is on.
DirectoryPath - Supplies a pointer to the zero-terminated directory path
of the root of the NT system32 directory.
HiveName - Supplies the name of the SYSTEM hive
LastKnownGoodBoot - On input, LastKnownGood indicates whether LKG has been
selected. This value is updated to TRUE if the user
chooses LKG via the profile configuration menu.
ServerHive - Return TRUE if this is a server hive, else FALSE.
BadFileName - Returns the file required for booting that was corrupt
or missing. This will not be filled in if ESUCCESS is returned.
Return Value:
ESUCCESS - System hive valid and all necessary boot drivers successfully
loaded.
!ESUCCESS - System hive corrupt or critical boot drivers not present.
LastKnownGoodBoot receives FALSE, BadFileName contains name
of corrupted/missing file.
--*/
{
ARC_STATUS Status;
PTCHAR FailReason;
CHAR Directory[256];
CHAR FontDirectory[256];
UNICODE_STRING AnsiCodepage;
UNICODE_STRING OemCodepage;
UNICODE_STRING OemHalFont;
UNICODE_STRING LanguageTable;
BOOLEAN RestartSetup;
BOOLEAN LogPresent;
#ifdef _WANT_MACHINE_IDENTIFICATION
UNICODE_STRING unicodeString;
#endif
if (sizeof(Directory) < strlen(DirectoryPath) + sizeof("\\system32\\config\\")) {
return ENOMEM;
}
strcpy(Directory,DirectoryPath);
strcat(Directory,"\\system32\\config\\");
Status = BlLoadAndInitSystemHive(DeviceId,
DeviceName,
Directory,
"system",
FALSE,
&RestartSetup,
&LogPresent);
if(Status != ESUCCESS) {
if( !LogPresent ) {
//
// Bogus hive, try system.alt only if no log is present.
//
Status = BlLoadAndInitSystemHive(DeviceId,
DeviceName,
Directory,
"system.alt",
TRUE,
&RestartSetup,
&LogPresent);
}
if(Status != ESUCCESS) {
strcpy(BadFileName,DirectoryPath);
strcat(BadFileName,"\\SYSTEM32\\CONFIG\\SYSTEM");
goto HiveScanFailed;
}
}
if(RestartSetup) {
//
// Need to restart setup.
//
Status = BlLoadAndInitSystemHive(DeviceId,
DeviceName,
Directory,
"system.sav",
TRUE,
&RestartSetup,
&LogPresent);
if(Status != ESUCCESS) {
strcpy(BadFileName,DirectoryPath);
strcat(BadFileName,"\\SYSTEM32\\CONFIG\\SYSTEM.SAV");
goto HiveScanFailed;
}
}
//
// Hive is there, it's valid, go compute the driver list and NLS
// filenames. Note that if this fails, there is no point in switching
// to system.alt, since it will always be the same as system.
//
FailReason = BlScanRegistry(BootFileSystem,
LastKnownGoodBoot,
&BlLoaderBlock->BootDriverListHead,
&AnsiCodepage,
&OemCodepage,
&LanguageTable,
&OemHalFont,
#ifdef _WANT_MACHINE_IDENTIFICATION
&unicodeString,
#endif
BlLoaderBlock->SetupLoaderBlock,
ServerHive);
if (FailReason != NULL) {
Status = EBADF;
strcpy(BadFileName,Directory);
strcat(BadFileName,"SYSTEM");
goto HiveScanFailed;
}
strcpy(Directory,DirectoryPath);
strcat(Directory,"\\system32\\");
//
// Load NLS data tables.
//
Status = BlLoadNLSData(DeviceId,
DeviceName,
Directory,
&AnsiCodepage,
&OemCodepage,
&LanguageTable,
BadFileName);
if (Status != ESUCCESS) {
goto HiveScanFailed;
}
//
// Load the OEM font file to be used by the HAL for possible frame
// buffer displays.
//
#ifdef i386
if (OemHalFont.Buffer == NULL) {
goto oktoskipfont;
}
#endif
//
// On newer systems fonts are in the FONTS directory.
// On older systems fonts are in the SYSTEM directory.
//
strcpy(FontDirectory, DirectoryPath);
strcat(FontDirectory, "\\FONTS\\");
Status = BlLoadOemHalFont(DeviceId,
DeviceName,
FontDirectory,
&OemHalFont,
BadFileName);
if(Status != ESUCCESS) {
strcpy(FontDirectory, DirectoryPath);
strcat(FontDirectory, "\\SYSTEM\\");
Status = BlLoadOemHalFont(DeviceId,
DeviceName,
FontDirectory,
&OemHalFont,
BadFileName);
}
if (Status != ESUCCESS) {
#ifndef i386
goto HiveScanFailed;
#endif
}
#ifdef i386
oktoskipfont:
#endif
if (BlLoaderBlock->Extension && BlLoaderBlock->Extension->Size >= sizeof(LOADER_PARAMETER_EXTENSION)) {
ULONG majorVersion;
ULONG minorVersion;
CHAR versionBuffer[64];
PCHAR major;
PCHAR minor;
major = strcpy(versionBuffer, VER_PRODUCTVERSION_STR);
minor = strchr(major, '.');
*minor++ = '\0';
majorVersion = atoi(major);
minorVersion = atoi(minor);
if ( BlLoaderBlock->Extension->MajorVersion > majorVersion ||
(BlLoaderBlock->Extension->MajorVersion == majorVersion &&
BlLoaderBlock->Extension->MinorVersion >= minorVersion)) {
#ifdef i386
#ifdef _WANT_MACHINE_IDENTIFICATION
if (unicodeString.Length) {
//
// For x86 machines, read in the inf into memory for processing
// by the kernel.
//
strcpy(Directory,DirectoryPath);
strcat(Directory,"\\inf\\");
//
// Fail to boot if there is any error in loading this
// critical inf.
//
Status = BlLoadBiosinfoInf( DeviceId,
DeviceName,
Directory,
&unicodeString,
&BlLoaderBlock->Extension->InfFileImage,
&BlLoaderBlock->Extension->InfFileSize,
BadFileName);
if (Status != ESUCCESS) {
goto HiveScanFailed;
}
}
#endif
#endif
}
}
HiveScanFailed:
if (Status != ESUCCESS) {
*LastKnownGoodBoot = FALSE;
}
return(Status);
}
VOID
BlBadFileMessage(
IN PCHAR BadFileName
)
/*++
Routine Description:
This function displays the error message for a missing or incorrect
critical file.
Arguments:
BadFileName - Supplies the name of the file that is missing or
corrupt.
Return Value:
None.
--*/
{
ULONG Count;
PTCHAR Text;
PTSTR pBadFileName;
#ifdef UNICODE
WCHAR BadFileNameW[128];
ANSI_STRING aString;
UNICODE_STRING uString;
pBadFileName = BadFileNameW;
uString.Buffer = BadFileNameW;
uString.MaximumLength = sizeof(BadFileNameW);
RtlInitAnsiString(&aString, BadFileName);
RtlAnsiStringToUnicodeString( &uString, &aString, FALSE );
#else
pBadFileName = BadFileName;
#endif
ArcWrite(BlConsoleOutDeviceId,
TEXT("\r\n"),
(ULONG)_tcslen(TEXT("\r\n"))*sizeof(TCHAR),
&Count);
//
// Remove any remains from the last known good message.
//
BlClearToEndOfScreen();
Text = BlFindMessage(LOAD_SW_MIS_FILE_CLASS);
if (Text != NULL) {
ArcWrite(BlConsoleOutDeviceId,
Text,
(ULONG)_tcslen(Text)*sizeof(TCHAR),
&Count);
}
ArcWrite(BlConsoleOutDeviceId,
pBadFileName,
(ULONG)_tcslen(pBadFileName)*sizeof(TCHAR),
&Count);
ArcWrite(BlConsoleOutDeviceId,
TEXT("\r\n\r\n"),
(ULONG)_tcslen(TEXT("\r\n\r\n"))*sizeof(TCHAR),
&Count);
Text = BlFindMessage(LOAD_SW_FILE_REST_ACT);
if (Text != NULL) {
ArcWrite(BlConsoleOutDeviceId,
Text,
(ULONG)_tcslen(Text)*sizeof(TCHAR),
&Count);
}
}
VOID
BlClearToEndOfScreen(
VOID
);
VOID
BlFatalError(
IN ULONG ClassMessage,
IN ULONG DetailMessage,
IN ULONG ActionMessage
)
/*++
Routine Description:
This function looks up messages to display at a error condition.
It attempts to locate the string in the resource section of the
osloader. If that fails, it prints a numerical error code.
The only time it should print a numerical error code is if the
resource section could not be located. This will only happen
on ARC machines where boot fails before the osloader.exe file
can be opened.
Arguments:
ClassMessage - General message that describes the class of
problem.
DetailMessage - Detailed description of what caused problem
ActionMessage - Message that describes a course of action
for user to take.
Return Value:
none
--*/
{
PTCHAR Text;
TCHAR Buffer[40];
ULONG Count;
ArcWrite(BlConsoleOutDeviceId,
TEXT("\r\n"),
(ULONG)_tcslen(TEXT("\r\n"))*sizeof(TCHAR),
&Count);
//
// Remove any remains from the last known good message.
//
BlClearToEndOfScreen();
Text = BlFindMessage(ClassMessage);
if (Text == NULL) {
_stprintf(Buffer,TEXT("%08lx\r\n"),ClassMessage);
Text = Buffer;
}
ArcWrite(BlConsoleOutDeviceId,
Text,
(ULONG)_tcslen(Text)*sizeof(TCHAR),
&Count);
Text = BlFindMessage(DetailMessage);
if (Text == NULL) {
_stprintf(Buffer,TEXT("%08lx\r\n"),DetailMessage);
Text = Buffer;
}
ArcWrite(BlConsoleOutDeviceId,
Text,
(ULONG)_tcslen(Text)*sizeof(TCHAR),
&Count);
Text = BlFindMessage(ActionMessage);
if (Text == NULL) {
_stprintf(Buffer,TEXT("%08lx\r\n"),ActionMessage);
Text = Buffer;
}
ArcWrite(BlConsoleOutDeviceId,
Text,
(ULONG)_tcslen(Text)*sizeof(TCHAR),
&Count);
#if defined(ENABLE_LOADER_DEBUG) || DBG
#if (defined(_X86_) || defined(_ALPHA_) || defined(_IA64_)) && !defined(ARCI386) // everything but ARCI386
if(BdDebuggerEnabled) {
DbgBreakPoint();
}
#endif
#endif
return;
}