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
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;
|
|
}
|