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.
7183 lines
218 KiB
7183 lines
218 KiB
/*++
|
|
|
|
Copyright (c) 1992 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
setup.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the code that implements the NT setup loader
|
|
|
|
Author:
|
|
|
|
John Vert (jvert) 6-Oct-1993
|
|
|
|
Environment:
|
|
|
|
ARC Environment
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <setupbat.h>
|
|
#include "setupldr.h"
|
|
#include "stdio.h"
|
|
#include "string.h"
|
|
#include "stdlib.h"
|
|
#include <dockinfo.h>
|
|
#include <netboot.h>
|
|
#include <ramdisk.h>
|
|
#include "acpitabl.h"
|
|
|
|
#ifdef i386
|
|
#include <bldrx86.h>
|
|
#endif
|
|
|
|
#if defined(_IA64_)
|
|
#include "bldria64.h"
|
|
#endif
|
|
|
|
#if defined(EFI)
|
|
#include "bootefi.h"
|
|
#endif
|
|
|
|
#if defined(_IA64_)
|
|
UCHAR OsLoaderName[] = "setupldr.efi";
|
|
#else
|
|
UCHAR OsLoaderName[] = "setupldr.exe";
|
|
#endif
|
|
|
|
#if defined(_WIN64) && defined(_M_IA64)
|
|
#pragma section(".base", long, read, write)
|
|
__declspec(allocate(".base"))
|
|
extern
|
|
PVOID __ImageBase;
|
|
#else
|
|
extern
|
|
PVOID __ImageBase;
|
|
#endif
|
|
|
|
|
|
#define BlDiagLoadMessage(x,y,z)
|
|
|
|
#define DRIVER_DATABASE_FILENAME L"drvmain.sdb"
|
|
#define KERNEL_UP_IMAGE_FILENAME LEGACY_KERNEL_NAME
|
|
#define KERNEL_MP_IMAGE_FILENAME MP_KERNEL_NAME
|
|
CHAR KernelImage[13];
|
|
BOOLEAN UseCommandConsole = FALSE;
|
|
BOOLEAN g_RollbackEnabled = FALSE;
|
|
BOOLEAN TryASRViaNetwork = FALSE;
|
|
|
|
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
|
|
|
|
#if defined(_X86_) && !defined(ALLOW_386)
|
|
//
|
|
// Disallow installation on a 386 or any processor which
|
|
// does not support CPUID and CMPXCHG8B instructions.
|
|
//
|
|
extern BOOLEAN BlIs386(VOID);
|
|
extern ULONG BlGetFeatureBits(VOID);
|
|
#endif
|
|
|
|
#define DBG_OUT(x)
|
|
|
|
/*
|
|
//
|
|
// For debugging purposes
|
|
// Example:
|
|
//
|
|
// DBG_OUT("Testing")
|
|
//
|
|
#define DBG_OUT(x) { \
|
|
if (x) { \
|
|
BlPositionCursor(5, 10); \
|
|
BlPrint(" "); \
|
|
BlPositionCursor(5, 10); \
|
|
BlPrint(x); \
|
|
while (!SlGetChar()); \
|
|
} \
|
|
}
|
|
|
|
//
|
|
// For debugging purposes
|
|
// Example:
|
|
//
|
|
// DebugOutput("Calling SlDetectScsi(). Line = %d. %s\n",__LINE__,"")
|
|
//
|
|
//
|
|
#define DebugOutput(X,Y,Z) { \
|
|
if (ARC_CONSOLE_OUTPUT) { \
|
|
CHAR _b[128]; \
|
|
ULONG _c; \
|
|
sprintf(&_b[0], X, Y, Z); \
|
|
ArcWrite(ARC_CONSOLE_OUTPUT, &_b[0], strlen(&_b[0]), &_c); \
|
|
SlGetChar(); \
|
|
} \
|
|
}
|
|
*/
|
|
|
|
//
|
|
// Define external static data.
|
|
//
|
|
|
|
ULONG BlConsoleOutDeviceId = ARC_CONSOLE_OUTPUT;
|
|
ULONG BlConsoleInDeviceId = ARC_CONSOLE_INPUT;
|
|
|
|
//
|
|
// Global string constants.
|
|
//
|
|
PCHAR FilesSectionName = "SourceDisksFiles";
|
|
PCHAR MediaSectionName = "SourceDisksNames";
|
|
|
|
#if defined(_AXP64_)
|
|
PCHAR PlatformExtension = ".axp64";
|
|
#elif defined(_ALPHA_)
|
|
PCHAR PlatformExtension = ".alpha";
|
|
#elif defined(_IA64_)
|
|
PCHAR PlatformExtension = ".ia64";
|
|
#elif defined(_X86_)
|
|
#define PlatformExtension (BlAmd64Setup(NULL) ? ".amd64" : ".x86")
|
|
#endif
|
|
|
|
//
|
|
// Global data
|
|
//
|
|
|
|
ULONG BlDcacheFillSize = 32;
|
|
ULONG BlVirtualBias = 0;
|
|
|
|
//
|
|
// Global setupldr control values
|
|
//
|
|
MEDIA_TYPE BootMedia;
|
|
MEDIA_TYPE InstallMedia;
|
|
PCHAR BootDevice;
|
|
ULONG BootDeviceId;
|
|
BOOLEAN BootDeviceIdValid = FALSE;
|
|
PCHAR BootPath;
|
|
ULONG BootDriveNumber;
|
|
ULONG InstallDriveNumber;
|
|
PCHAR HalName;
|
|
PCHAR HalDescription;
|
|
PCHAR AnsiCpName;
|
|
PCHAR OemHalFontName;
|
|
UNICODE_STRING AnsiCodepage;
|
|
UNICODE_STRING OemCodepage;
|
|
UNICODE_STRING UnicodeCaseTable;
|
|
UNICODE_STRING OemHalFont;
|
|
|
|
#ifdef _WANT_MACHINE_IDENTIFICATION
|
|
UNICODE_STRING BiosInfo;
|
|
#endif
|
|
|
|
BOOLEAN LoadScsiMiniports;
|
|
BOOLEAN LoadDiskClass;
|
|
BOOLEAN LoadCdfs;
|
|
BOOLEAN FixedBootMedia = FALSE;
|
|
BOOLEAN FloppyBoot = FALSE;
|
|
|
|
PVOID InfFile;
|
|
PVOID WinntSifHandle;
|
|
PVOID MigrateInfHandle;
|
|
ULONG BootFontImageLength = 0;
|
|
PVOID UnsupDriversInfHandle;
|
|
BOOLEAN IgnoreMissingFiles;
|
|
BOOLEAN BlUsePae;
|
|
BOOLEAN UseRegularBackground = TRUE;
|
|
BOOLEAN IsUpgrade = FALSE;
|
|
|
|
//
|
|
// OEM related variables
|
|
//
|
|
POEM_SOURCE_DEVICE OemSourceDevices = NULL;
|
|
POEM_SOURCE_DEVICE DefaultOemSourceDevice = NULL;
|
|
POEM_SOURCE_DEVICE AutoLoadOemHalDevice = NULL;
|
|
BOOLEAN AutoLoadOemScsi = FALSE;
|
|
|
|
//
|
|
// Pre-install stuff
|
|
//
|
|
|
|
PCHAR OemTag = "OEM";
|
|
PTCHAR _TOemTag = TEXT("OEM");
|
|
BOOLEAN PreInstall = FALSE;
|
|
PTCHAR ComputerType = NULL;
|
|
BOOLEAN OemHal = FALSE;
|
|
PPREINSTALL_DRIVER_INFO PreinstallDriverList = NULL;
|
|
POEM_SOURCE_DEVICE PreInstallOemSourceDevice = NULL;
|
|
PCHAR PreInstallSourcePath = NULL;
|
|
|
|
//
|
|
// Dynamic update variables
|
|
//
|
|
static BOOLEAN DynamicUpdate = FALSE;
|
|
static PCSTR DynamicUpdateRootDir = NULL;
|
|
static POEM_SOURCE_DEVICE DynamicUpdateSourceDevice = NULL;
|
|
|
|
//
|
|
// WinPE (aka MiniNT) global variables
|
|
//
|
|
BOOLEAN WinPEBoot = FALSE;
|
|
BOOLEAN WinPEAutoBoot = FALSE;
|
|
|
|
PCTSTR StartupMsg = NULL;
|
|
|
|
//
|
|
// Is used by HALACPI.DLL
|
|
//
|
|
BOOLEAN DisableACPI = FALSE;
|
|
|
|
BOOLEAN isOSCHOICE = FALSE;
|
|
|
|
//
|
|
// Primarily used by floppy boot support to key track
|
|
// of the last disk read
|
|
//
|
|
PCHAR LastDiskTag = NULL;
|
|
|
|
//
|
|
// TRUE if user pressed F8
|
|
//
|
|
BOOLEAN EnableDebugger = FALSE;
|
|
|
|
//
|
|
// TRUE if user presses F4.
|
|
//
|
|
BOOLEAN DisableVirtualOemDevices = FALSE;
|
|
|
|
#if defined(ELTORITO)
|
|
extern BOOLEAN ElToritoCDBoot;
|
|
#endif
|
|
|
|
//
|
|
// Define transfer entry of loaded image.
|
|
//
|
|
|
|
typedef
|
|
VOID
|
|
(*PTRANSFER_ROUTINE) (
|
|
PLOADER_PARAMETER_BLOCK LoaderBlock
|
|
);
|
|
|
|
#if defined(_IA64_)
|
|
|
|
VOID
|
|
BuildArcTree();
|
|
|
|
#endif
|
|
|
|
//
|
|
// Local function prototypes
|
|
//
|
|
VOID
|
|
SlGetSetupValuesBeforePrompt(
|
|
IN PSETUP_LOADER_BLOCK SetupBlock
|
|
);
|
|
|
|
VOID
|
|
SlGetSetupValuesAfterPrompt(
|
|
IN PSETUP_LOADER_BLOCK SetupBlock
|
|
);
|
|
|
|
ARC_STATUS
|
|
SlLoadDriver(
|
|
IN PTCHAR DriverDescription,
|
|
IN PCHAR DriverName,
|
|
IN ULONG DriverFlags,
|
|
IN BOOLEAN InsertIntoDriverList,
|
|
IN BOOLEAN MigratedDriver,
|
|
IN PCHAR ServiceName OPTIONAL
|
|
);
|
|
|
|
ARC_STATUS
|
|
SlLoadOemDriver(
|
|
IN PCHAR ExportDriver OPTIONAL,
|
|
IN PCHAR DriverName,
|
|
IN PVOID BaseAddress,
|
|
IN PTCHAR LoadMessage
|
|
);
|
|
|
|
PBOOT_DRIVER_LIST_ENTRY
|
|
SlpCreateDriverEntry(
|
|
IN PCHAR DriverName,
|
|
IN PCHAR ServiceName OPTIONAL
|
|
);
|
|
|
|
|
|
ARC_STATUS
|
|
SlDetectMigratedScsiDrivers(
|
|
IN PVOID Inf
|
|
);
|
|
|
|
ARC_STATUS
|
|
SlGetMigratedHardwareIds(
|
|
IN PSETUP_LOADER_BLOCK SetupBlock,
|
|
IN PVOID Inf
|
|
);
|
|
|
|
BOOLEAN
|
|
SlpIsDiskVacant(
|
|
IN PARC_DISK_SIGNATURE DiskSignature
|
|
);
|
|
|
|
ARC_STATUS
|
|
SlpStampFTSignature(
|
|
IN PARC_DISK_SIGNATURE DiskSignature,
|
|
IN BOOLEAN GenerateNewSignature
|
|
);
|
|
|
|
VOID
|
|
SlpMarkDisks(
|
|
IN BOOLEAN Reboot
|
|
);
|
|
|
|
|
|
VOID
|
|
SlCheckOemKeypress(
|
|
IN ULONG WaitTime
|
|
);
|
|
|
|
VOID
|
|
SlCheckASRKeypress(
|
|
VOID
|
|
);
|
|
|
|
ARC_STATUS
|
|
SlLoadPnpDriversSection(
|
|
IN PVOID Inf,
|
|
IN PCHAR SectionName,
|
|
IN OUT PDETECTED_DEVICE* DetectedDeviceList OPTIONAL
|
|
);
|
|
|
|
BOOLEAN
|
|
SlIsUpgrade(
|
|
IN PVOID SifHandle
|
|
);
|
|
|
|
BOOLEAN
|
|
SlIsCdBootUpgrade(
|
|
IN PCHAR InstallDirectory,
|
|
IN PCHAR SetupFileName,
|
|
IN ULONG MaxDisksToScan,
|
|
IN ULONG MaxPartitionsPerDisk,
|
|
OUT PCHAR SetupDevice
|
|
);
|
|
|
|
ARC_STATUS
|
|
SlLoadBootFontFile(
|
|
IN PSETUP_LOADER_BLOCK SetupLoaderBlock,
|
|
IN ULONG DiskId,
|
|
IN ULONG BootFontImageLength
|
|
);
|
|
|
|
//
|
|
// Dynamic update function prototypes
|
|
//
|
|
BOOLEAN
|
|
SlpIsDynamicUpdate(
|
|
IN PVOID InfHandle,
|
|
OUT PCSTR *DynamicUpdateRootDir
|
|
);
|
|
|
|
BOOLEAN
|
|
SlModifyOsLoadOptions(
|
|
IN OUT PSTR* LoadOptions,
|
|
IN PCSTR OptionsToAdd OPTIONAL,
|
|
IN PCSTR OptionsToRemove OPTIONAL
|
|
);
|
|
|
|
BOOLEAN
|
|
SlIsVirtualOemDeviceDisabled(
|
|
IN PVOID SifHandle,
|
|
IN PPREINSTALL_DRIVER_INFO PreinstallDriverList
|
|
);
|
|
|
|
VOID
|
|
SlDisableVirtualOemDevices(
|
|
IN POEM_SOURCE_DEVICE OemDeviceList
|
|
);
|
|
|
|
ARC_STATUS
|
|
SlInit(
|
|
IN ULONG Argc,
|
|
IN CHAR * FIRMWARE_PTR * FIRMWARE_PTR Argv,
|
|
IN CHAR * FIRMWARE_PTR * FIRMWARE_PTR Envp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The main startup routine for the NT Setup Loader. This is the entrypoint
|
|
called by the ARC firmware.
|
|
|
|
If successful, this routine will never return, it will start NT directly.
|
|
|
|
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:
|
|
|
|
ARC_STATUS if unsuccessful.
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// if we use too much stack space the heap and stack can overlap and we can run into corruption problems
|
|
// without any "stack overflow" exceptions; making large strings static helps prevent this
|
|
//
|
|
|
|
PCONFIGURATION_COMPONENT_DATA DataCache;
|
|
ARC_STATUS Status;
|
|
ULONG LinesPerBlock;
|
|
ULONG CacheLineSize;
|
|
static CHAR SetupDevice[128];
|
|
static CHAR SetupDirectory[128];
|
|
static CHAR BadFileName[128];
|
|
static CHAR CanonicalName[128];
|
|
static CHAR HalDirectoryPath[256];
|
|
static CHAR KernelDirectoryPath[256];
|
|
PCHAR NetSetupServerShare = NULL;
|
|
PCHAR NetSetupPath = NULL;
|
|
PCHAR p;
|
|
ULONG ErrorLine=0;
|
|
ULONG DontCare;
|
|
PVOID SystemBase;
|
|
PVOID HalBase;
|
|
PVOID VideoBase;
|
|
PCHAR FileName;
|
|
PVOID KdDllBase;
|
|
static CHAR KdDllName[256];
|
|
ULONG i;
|
|
PKLDR_DATA_TABLE_ENTRY SystemDataTableEntry;
|
|
PKLDR_DATA_TABLE_ENTRY HalDataTableEntry;
|
|
PKLDR_DATA_TABLE_ENTRY KdDataTableEntry;
|
|
PTRANSFER_ROUTINE SystemEntry;
|
|
PIMAGE_NT_HEADERS NtHeaders;
|
|
PBOOT_DRIVER_LIST_ENTRY DriverEntry;
|
|
PSETUP_LOADER_BLOCK SetupBlock;
|
|
PDETECTED_DEVICE ScsiDevice;
|
|
PCHAR VideoFileName;
|
|
PTCHAR VideoDescription;
|
|
POEMSCSIINFO OemScsiInfo = NULL;
|
|
PCHAR OemVideoName;
|
|
PVOID OemInfHandle = NULL;
|
|
BOOLEAN LoadedAVideoDriver = FALSE;
|
|
static CHAR NetbootCardDriverName[24];
|
|
static CHAR NetbootUser[64];
|
|
static CHAR NetbootDomain[64];
|
|
static CHAR NetbootPassword[64];
|
|
static CHAR NetbootAdministratorPassword[OSC_ADMIN_PASSWORD_LEN];
|
|
static CHAR NetbootSifFile[128];
|
|
DOCKING_STATION_INFO dockInfo = { 0, 0, 0, FW_DOCKINFO_DOCK_STATE_UNKNOWN };
|
|
PCONFIGURATION_COMPONENT_DATA dockInfoData;
|
|
extern ULONG BlProgressBarShowTimeOut;
|
|
extern ULONG BlDisableProgressBar;
|
|
#if defined (_X86_)
|
|
extern BOOLEAN AllowGraphicsReset;
|
|
#endif
|
|
ULONG OemKeypressTimeout = 5; //secs
|
|
|
|
#if defined(REMOTE_BOOT)
|
|
BOOLEAN RemoteBootEnableIpsec = FALSE;
|
|
#endif // defined(REMOTE_BOOT)
|
|
#if defined(_X86_) || defined(_IA64_)
|
|
BOOLEAN Win9xUnsupHdc = FALSE;
|
|
#endif
|
|
static FULL_PATH_SET PathSet;
|
|
UNICODE_STRING DrvMainSdb;
|
|
|
|
#if DBG
|
|
ULONG StartTime = 0;
|
|
#endif
|
|
|
|
#if defined(_ALPHA_) || defined(ARCI386) || defined(_IA64_)
|
|
PVOID LoaderBase;
|
|
#endif
|
|
|
|
UNREFERENCED_PARAMETER( Envp );
|
|
|
|
//
|
|
// Disable progress bar, by default.
|
|
//
|
|
BlDisableProgressBar = TRUE;
|
|
|
|
|
|
#ifdef EFI
|
|
//
|
|
// set the efi watchdog timer to 20 minutes. the boot manager sets it to 5, but
|
|
// setupldr could take longer than this, especially if installing over the
|
|
// network
|
|
//
|
|
SetEFIWatchDog(EFI_WATCHDOG_TIMEOUT);
|
|
#endif
|
|
|
|
#if defined (_X86_)
|
|
//
|
|
// Do not allow display to be reset at the end of setupldr.
|
|
// this would leave the screen blank for ~30 seconds, until
|
|
// textmode setup reinitializes the display
|
|
//
|
|
AllowGraphicsReset = FALSE;
|
|
#endif
|
|
|
|
//
|
|
// 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_)
|
|
|
|
LoaderBase = &__ImageBase;
|
|
|
|
//
|
|
// Initialize traps and the boot debugger.
|
|
//
|
|
|
|
#if defined(ENABLE_LOADER_DEBUG)
|
|
|
|
#if defined(_ALPHA_)
|
|
|
|
BdInitializeTraps();
|
|
|
|
#endif
|
|
|
|
BdInitDebugger((PCHAR)OsLoaderName, LoaderBase, ENABLE_LOADER_DEBUG);
|
|
|
|
#else
|
|
|
|
BdInitDebugger((PCHAR)OsLoaderName, 0, NULL);
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#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) {
|
|
BlDiagLoadMessage(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.
|
|
//
|
|
BuildArcTree();
|
|
#endif
|
|
|
|
#ifdef EFI
|
|
//
|
|
// Establish SMBIOS information in the loader block
|
|
//
|
|
SetupSMBiosInLoaderBlock();
|
|
#endif
|
|
|
|
|
|
|
|
SetupBlock = BlAllocateHeap(sizeof(SETUP_LOADER_BLOCK));
|
|
if (SetupBlock==NULL) {
|
|
SlNoMemoryError();
|
|
Status = ENOMEM;
|
|
goto LoadFailed;
|
|
}
|
|
BlLoaderBlock->SetupLoaderBlock = SetupBlock;
|
|
SetupBlock->ScsiDevices = NULL;
|
|
SetupBlock->BootBusExtenders = NULL;
|
|
SetupBlock->BusExtenders = NULL;
|
|
SetupBlock->InputDevicesSupport = NULL;
|
|
SetupBlock->Flags |= SETUPBLK_FLAGS_IS_TEXTMODE;
|
|
|
|
SetupBlock->ScalarValues.SetupFromCdRom = FALSE;
|
|
SetupBlock->ScalarValues.SetupOperation = SetupOperationSetup;
|
|
SetupBlock->ScalarValues.LoadedScsi = 0;
|
|
SetupBlock->ScalarValues.LoadedCdRomDrivers = 0;
|
|
SetupBlock->ScalarValues.LoadedDiskDrivers = 0;
|
|
SetupBlock->ScalarValues.LoadedFloppyDrivers = 0;
|
|
SetupBlock->ScalarValues.LoadedFileSystems = 0;
|
|
|
|
//
|
|
// Initialize the NT configuration tree.
|
|
//
|
|
|
|
BlLoaderBlock->ConfigurationRoot = NULL;
|
|
|
|
|
|
Status = BlConfigurationInitialize(NULL, NULL);
|
|
if (Status != ESUCCESS) {
|
|
BlDiagLoadMessage(LOAD_HW_FW_CFG_CLASS,
|
|
DIAG_BL_CONFIG_INIT,
|
|
LOAD_HW_FW_CFG_ACT);
|
|
goto LoadFailed;
|
|
}
|
|
|
|
//
|
|
// 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) {
|
|
BlDiagLoadMessage(LOAD_HW_DISK_CLASS,
|
|
DIAG_BL_IO_INIT,
|
|
LOAD_HW_DISK_ACT);
|
|
goto LoadFailed;
|
|
}
|
|
|
|
#if DBG
|
|
StartTime = ArcGetRelativeTime();
|
|
#endif
|
|
|
|
SlPositionCursor(5,3);
|
|
|
|
#if !defined(_IA64_)
|
|
//
|
|
// Initialize the message resources
|
|
//
|
|
Status = BlInitResources(Argv[0]);
|
|
if (Status != ESUCCESS) {
|
|
// if this fails, then we can't print out any messages,
|
|
// so we just exit.
|
|
return(Status);
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// If there is an ImageType parameter, this is a command console or rollback.
|
|
//
|
|
p = BlGetArgumentValue(Argc, Argv, "ImageType");
|
|
if (p) {
|
|
if (!strcmp (p, "cmdcons")) {
|
|
UseCommandConsole = TRUE;
|
|
} else if (!strcmp (p, "rollback")) {
|
|
g_RollbackEnabled = TRUE;
|
|
}
|
|
}
|
|
|
|
#ifdef FORCE_CD_BOOT
|
|
g_RollbackEnabled = FALSE;
|
|
#endif
|
|
|
|
|
|
//
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Initialize the display and announce ourselves
|
|
//
|
|
SlInitDisplay();
|
|
|
|
#if defined(_X86_) && !defined(ALLOW_386)
|
|
//
|
|
// Disallow installation on a 386 or any processor which
|
|
// does not support CPUID and CMPXCHG8B instructions.
|
|
//
|
|
{
|
|
if(BlIs386()) {
|
|
SlFatalError(SL_TEXT_REQUIRES_486);
|
|
}
|
|
|
|
//
|
|
// CMPXCHG8B is required on Whistler and above. This
|
|
// implies a requirement for CPUID which is used to
|
|
// determine the presence of CMPXCHG8B.
|
|
//
|
|
|
|
if ((BlGetFeatureBits() & 0x100) == 0) {
|
|
SlFatalError(SL_TEXT_REQUIRED_FEATURES_MISSING);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef _IA64_
|
|
//
|
|
// Is this automated WinPE boot?
|
|
//
|
|
p = BlGetArgumentValue(Argc, Argv, "systempartition");
|
|
|
|
if (p && SlIsWinPEAutoBoot(p)) {
|
|
WinPEAutoBoot = TRUE;
|
|
|
|
//
|
|
// get the WinPE device & directory
|
|
//
|
|
if (ESUCCESS != SlGetWinPEStartupParams(SetupDevice, SetupDirectory)) {
|
|
SlFriendlyError(
|
|
Status,
|
|
"SETUPLDR:Cannot find WinPE installation",
|
|
__LINE__,
|
|
__FILE__
|
|
);
|
|
|
|
goto LoadFailed;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (!WinPEAutoBoot) {
|
|
//
|
|
// If this is a winnt setup, then we want to behave as if
|
|
// we were started from the location specified by the
|
|
// OSLOADPARTITION and OSLOADFILENAME nv-ram variables.
|
|
//
|
|
p = BlGetArgumentValue(Argc,Argv,"osloadoptions");
|
|
|
|
if(p && !_stricmp(p,"winnt32")) {
|
|
|
|
p = BlGetArgumentValue(Argc,Argv,"osloadpartition");
|
|
if(!p) {
|
|
SlError(100);
|
|
goto LoadFailed;
|
|
}
|
|
|
|
Status = BlGenerateDeviceNames(p,SetupDevice,NULL);
|
|
if (Status != ESUCCESS) {
|
|
SlError(110);
|
|
goto LoadFailed;
|
|
}
|
|
|
|
p = BlGetArgumentValue(Argc,Argv,"osloadfilename");
|
|
if(!p || !(*p)) {
|
|
SlError(120);
|
|
goto LoadFailed;
|
|
}
|
|
|
|
strcpy(SetupDirectory,p);
|
|
|
|
//
|
|
// Make sure directory is terminated with a \.
|
|
//
|
|
if(SetupDirectory[strlen(SetupDirectory)-1] != '\\') {
|
|
strcat(SetupDirectory,"\\");
|
|
}
|
|
} else {
|
|
//
|
|
// extract device name from our startup path
|
|
//
|
|
p=strrchr(Argv[0],')');
|
|
if (p==NULL) {
|
|
SlError(0);
|
|
goto LoadFailed;
|
|
}
|
|
|
|
strncpy(SetupDevice, Argv[0], (int)(p-Argv[0]+1));
|
|
SetupDevice[p-Argv[0]+1] = '\0';
|
|
|
|
Status = BlGenerateDeviceNames(SetupDevice,CanonicalName,NULL);
|
|
if (Status != ESUCCESS) {
|
|
SlFriendlyError(
|
|
Status,
|
|
SetupDevice,
|
|
__LINE__,
|
|
__FILE__
|
|
);
|
|
goto LoadFailed;
|
|
}
|
|
strcpy(SetupDevice,CanonicalName);
|
|
|
|
//
|
|
// If this is a remote boot, load winnt.sif. If we were passed
|
|
// a path through the soft reboot use that, if not then look
|
|
// in the same place that the loader was loaded from. Once we
|
|
// have read winnt.sif we get the SetupSourceDevice path.
|
|
//
|
|
if (BlBootingFromNet) {
|
|
|
|
NetGetRebootParameters(
|
|
NULL,
|
|
NULL,
|
|
(PUCHAR) NetbootSifFile,
|
|
(PUCHAR) NetbootUser,
|
|
(PUCHAR) NetbootDomain,
|
|
(PUCHAR) NetbootPassword,
|
|
(PUCHAR) NetbootAdministratorPassword,
|
|
TRUE);
|
|
|
|
if (NetbootSifFile[0] != '\0') {
|
|
strcpy(BadFileName, NetbootSifFile);
|
|
} else {
|
|
strcpy(BadFileName,NetBootPath);
|
|
strcat(BadFileName,WINNT_SIF_FILE_A);
|
|
}
|
|
|
|
|
|
if (NetbootAdministratorPassword[0] != '\0') {
|
|
//
|
|
// It's possible that the string contained in NetbootAdministratorPassword
|
|
// may not be terminated. Just block copy the entire 64-bytes into the loader
|
|
// block, then we'll treat the data carefully in setupdd.sys when we read it
|
|
// back out.
|
|
//
|
|
RtlMoveMemory(BlLoaderBlock->SetupLoaderBlock->NetBootAdministratorPassword,
|
|
NetbootAdministratorPassword,
|
|
OSC_ADMIN_PASSWORD_LEN );
|
|
}
|
|
|
|
|
|
BlLoaderBlock->SetupLoaderBlock->WinntSifFile = NULL;
|
|
BlLoaderBlock->SetupLoaderBlock->WinntSifFileLength = 0;
|
|
Status = SlInitIniFile(SetupDevice,
|
|
0,
|
|
BadFileName,
|
|
&WinntSifHandle,
|
|
&BlLoaderBlock->SetupLoaderBlock->WinntSifFile,
|
|
&BlLoaderBlock->SetupLoaderBlock->WinntSifFileLength,
|
|
&DontCare);
|
|
if(Status != ESUCCESS) {
|
|
if (NetbootSifFile[0] != '\0') {
|
|
SlFatalError(
|
|
SL_BAD_INF_FILE,
|
|
SlCopyStringAT(NetbootSifFile),
|
|
Status);
|
|
} else {
|
|
SlFatalError(
|
|
SL_BAD_INF_FILE,
|
|
WINNT_SIF_FILE,
|
|
Status);
|
|
}
|
|
goto LoadFailed;
|
|
}
|
|
|
|
//
|
|
// Get the SetupSourceDevice parameter from winnt.sif.
|
|
//
|
|
// SetupSourceDevice is of the form "\Device\LanmanRedirector\server\share\setup\nt5".
|
|
//
|
|
|
|
NetSetupServerShare = SlGetSectionKeyIndex(WinntSifHandle,
|
|
"SetupData",
|
|
"SetupSourceDevice",
|
|
0);
|
|
|
|
#if DBG
|
|
if (((ULONG)strlen(NetSetupServerShare) + 1) > sizeof(SetupBlock->NetBootIMirrorFilePath)) {
|
|
DbgPrint("The UNC name is too long!\n");
|
|
goto LoadFailed;
|
|
}
|
|
#endif
|
|
|
|
strcpy((PCHAR)SetupBlock->NetBootIMirrorFilePath, NetSetupServerShare);
|
|
|
|
if(NetSetupServerShare != NULL) {
|
|
// must start with '\'
|
|
if (*NetSetupServerShare != '\\') {
|
|
NetSetupServerShare = NULL;
|
|
} else {
|
|
// skip to '\' after Device
|
|
NetSetupServerShare = strchr(NetSetupServerShare+1,'\\');
|
|
if (NetSetupServerShare != NULL) {
|
|
// skip to '\' after LanmanRedirector (before server)
|
|
NetSetupServerShare = strchr(NetSetupServerShare+1,'\\');
|
|
if (NetSetupServerShare != NULL) {
|
|
// skip to '\' after server
|
|
NetSetupPath = strchr(NetSetupServerShare+1,'\\');
|
|
if (NetSetupPath != NULL) {
|
|
// skip to '\' after share (path part)
|
|
NetSetupPath = strchr(NetSetupPath+1,'\\');
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if ((NetSetupServerShare == NULL) || (NetSetupPath == NULL)) {
|
|
SlFatalError(SL_INF_ENTRY_MISSING,TEXT("SetupSourceDevice"),TEXT("SetupData"));
|
|
|
|
goto LoadFailed;
|
|
}
|
|
*NetSetupPath = 0; // terminate server\share part
|
|
NetSetupPath++; // remainder is path part
|
|
|
|
//
|
|
// If the TargetNtPartition parameter exists in winnt.sif, then
|
|
// the target is remote, and this is a remote boot setup. Otherwise,
|
|
// this is a remote installation setup.
|
|
//
|
|
|
|
if (SlGetSectionKeyIndex(WinntSifHandle,
|
|
"SetupData",
|
|
"TargetNtPartition",
|
|
0) == NULL) {
|
|
PCHAR pTmp, pTmp2;
|
|
|
|
pTmp = SlGetSectionKeyIndex(WinntSifHandle,
|
|
"OSChooser",
|
|
"ImageType",
|
|
0);
|
|
|
|
if (pTmp != NULL) {
|
|
|
|
pTmp2 = pTmp;
|
|
while (*pTmp != '\0') {
|
|
*pTmp = (UCHAR)toupper(*pTmp);
|
|
pTmp++;
|
|
}
|
|
|
|
if (!strcmp(pTmp2, "SYSPREP")) {
|
|
|
|
pTmp = SlGetSectionKeyIndex(WinntSifHandle,
|
|
"SetupData",
|
|
"SysPrepDevice",
|
|
0);
|
|
|
|
if (pTmp != NULL) {
|
|
strcpy((PCHAR)SetupBlock->NetBootIMirrorFilePath, pTmp);
|
|
} else {
|
|
memset(SetupBlock->NetBootIMirrorFilePath,
|
|
0x0,
|
|
sizeof(SetupBlock->NetBootIMirrorFilePath)
|
|
);
|
|
}
|
|
SetupBlock->Flags |= SETUPBLK_FLAGS_SYSPREP_INSTALL;
|
|
} else {
|
|
SetupBlock->Flags |= SETUPBLK_FLAGS_REMOTE_INSTALL;
|
|
}
|
|
} else {
|
|
SetupBlock->Flags |= SETUPBLK_FLAGS_REMOTE_INSTALL;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// extract directory from our startup path.
|
|
//
|
|
if (BlBootingFromNet) {
|
|
strcpy(SetupDirectory, "\\");
|
|
strcat(SetupDirectory, NetSetupPath);
|
|
} else if (UseCommandConsole) {
|
|
strcpy(SetupDirectory,"\\cmdcons");
|
|
} else if(*(p+1) != '\\') {
|
|
//
|
|
// directory must begin at root
|
|
//
|
|
strcpy(SetupDirectory, "\\");
|
|
} else {
|
|
*SetupDirectory = '\0';
|
|
}
|
|
strcat(SetupDirectory, p+1);
|
|
p=strrchr(SetupDirectory, '\\');
|
|
*(p+1) = '\0';
|
|
}
|
|
}
|
|
|
|
#ifndef _IA64_
|
|
BlAmd64Setup(SetupDevice);
|
|
#endif
|
|
|
|
#if defined(ELTORITO)
|
|
if (ElToritoCDBoot && !WinPEAutoBoot) {
|
|
//
|
|
// Use the i386 directory for setup files when we boot from an El Torito CD
|
|
//
|
|
PCHAR SetupDirectoryOnDisk = "\\$WIN_NT$.~BT";
|
|
CHAR SetupBootDevice[128] = {0};
|
|
ULONG MaxDisksToScan = 1; // on x86 only the first disk
|
|
ULONG MaxPartitionsToScan = 4; // on x86 check only primary partitions
|
|
BOOLEAN CheckUpgrades = TRUE;
|
|
|
|
#if defined(_IA64_)
|
|
strcat(SetupDirectory, "ia64\\");
|
|
|
|
/*
|
|
//
|
|
// Values for IA64 installation, currently not used
|
|
//
|
|
SetupDirectoryOnDisk = "\\$WIN_NT$.~LS\\ia64";
|
|
MaxDisksToScan = 4; // NOTE : arbitrary limit
|
|
MaxPartitionsToScan = 4; // NOTE : arbitrary limit
|
|
*/
|
|
|
|
CheckUpgrades = FALSE; // NOTE : Currently disabled on IA64
|
|
#else
|
|
strcat(SetupDirectory, BlAmd64Setup(NULL) ? "AMD64\\" : "I386\\" );
|
|
#endif
|
|
|
|
|
|
//
|
|
// If WinPE boot then disable check for CD boot upgrade
|
|
// NOTE: We check for the presence of system32\\drivers directory
|
|
// rather than relying on /minint flag in txtsetup.sif since we
|
|
// have not yet loaded txtsetup.sif file
|
|
//
|
|
if (CheckUpgrades) {
|
|
CHAR DriversDir[128];
|
|
ARC_STATUS DirStatus;
|
|
ULONG DeviceId, DirId;
|
|
|
|
strcat(DriversDir, SetupDirectory);
|
|
strcat(DriversDir, "system32\\drivers");
|
|
|
|
DirStatus = ArcOpen(SetupDevice, ArcOpenReadOnly, &DeviceId);
|
|
|
|
if (ESUCCESS == DirStatus) {
|
|
DirStatus = BlOpen(DeviceId, DriversDir, ArcOpenDirectory, &DirId);
|
|
|
|
if (ESUCCESS == DirStatus) {
|
|
CheckUpgrades = FALSE; // looks like a WinPE boot
|
|
BlClose(DirId);
|
|
}
|
|
|
|
ArcClose(DeviceId);
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Figure out if user was already trying to upgrade
|
|
// using winnt32.exe. If user confirms he is
|
|
// wants to continue upgrading then switch to
|
|
// harddisk
|
|
//
|
|
if (CheckUpgrades &&
|
|
SlIsCdBootUpgrade(SetupDirectoryOnDisk,
|
|
WINNT_SIF_FILE_A,
|
|
MaxDisksToScan,
|
|
MaxPartitionsToScan,
|
|
SetupBootDevice)) {
|
|
strcpy(SetupDevice, SetupBootDevice);
|
|
strcpy(SetupDirectory, SetupDirectoryOnDisk);
|
|
strcat(SetupDirectory, "\\");
|
|
ElToritoCDBoot = FALSE;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Turn on ability to load compressed files.
|
|
//
|
|
|
|
DecompEnableDecompression(TRUE);
|
|
|
|
#if defined(EFI)
|
|
//
|
|
// Now that all variables are set and we can load compressed files, load the fpswa.efi driver from the setup dir
|
|
//
|
|
BlLoadEFIImage(SetupDevice, SetupDirectory, "fpswa.efi", TRUE, NULL);
|
|
#endif
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// On x86, the files loaded from now on are on boot floppy #1
|
|
// HALs may be on floppy #1 or floppy #2
|
|
//
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
strcpy(KernelDirectoryPath, SetupDirectory);
|
|
strcat(KernelDirectoryPath, "txtsetup.sif");
|
|
|
|
BlLoaderBlock->SetupLoaderBlock->IniFile = NULL;
|
|
|
|
Status = SlInitIniFile(SetupDevice,
|
|
0,
|
|
KernelDirectoryPath,
|
|
&InfFile,
|
|
&BlLoaderBlock->SetupLoaderBlock->IniFile,
|
|
&BlLoaderBlock->SetupLoaderBlock->IniFileLength,
|
|
&ErrorLine);
|
|
if (Status != ESUCCESS) {
|
|
|
|
//
|
|
// See if we can get the txtsetup.sif out of the WinPE boot
|
|
// directory.
|
|
//
|
|
if( (strcmp( SetupDirectory, "\\") == 0) &&
|
|
(!ElToritoCDBoot) &&
|
|
(!BlBootingFromNet) ) {
|
|
//
|
|
// We're not booting off CD and we're not booting off the
|
|
// net and we're about to fail because we didn't find \txtsetup.sif
|
|
// Try in the MiniNT directory...
|
|
//
|
|
Status = SlInitIniFile(SetupDevice,
|
|
0,
|
|
"\\minint\\txtsetup.sif",
|
|
&InfFile,
|
|
&BlLoaderBlock->SetupLoaderBlock->IniFile,
|
|
&BlLoaderBlock->SetupLoaderBlock->IniFileLength,
|
|
&ErrorLine);
|
|
}
|
|
|
|
if( Status != ESUCCESS ) {
|
|
SlFatalError(SL_BAD_INF_FILE,
|
|
TEXT("txtsetup.sif"),
|
|
Status);
|
|
|
|
goto LoadFailed;
|
|
}
|
|
}
|
|
|
|
SlGetSetupValuesBeforePrompt(SetupBlock);
|
|
|
|
//
|
|
// Find out if we are starting the MiniNT boot or rollback
|
|
// (mutually exclusive options)
|
|
//
|
|
if (BlLoaderBlock->LoadOptions) {
|
|
CHAR Option[256];
|
|
PCHAR NextOption = strchr(BlLoaderBlock->LoadOptions, '/');
|
|
PCHAR OptionEnd = NULL;
|
|
|
|
|
|
while (NextOption) {
|
|
OptionEnd = strchr(NextOption, ' ');
|
|
|
|
if (OptionEnd) {
|
|
strncpy(Option, NextOption, OptionEnd - NextOption);
|
|
Option[OptionEnd - NextOption] = 0;
|
|
} else {
|
|
strcpy(Option, NextOption);
|
|
}
|
|
|
|
if (!_stricmp(Option, "/minint")) {
|
|
WinPEBoot = TRUE;
|
|
}
|
|
|
|
//
|
|
// Pick up any headless settings in the boot options.
|
|
//
|
|
if (!_strnicmp(Option,"/redirect=",10)) {
|
|
PCHAR pOption = strchr(Option,'=');
|
|
if( pOption != NULL ) {
|
|
pOption++;
|
|
|
|
if (_strnicmp(pOption,"com",3) == 0) {
|
|
pOption +=3;
|
|
LoaderRedirectionInformation.PortNumber = atoi(pOption);
|
|
|
|
} else if (_strnicmp(pOption, "usebiossettings", 15) == 0) {
|
|
|
|
BlRetrieveBIOSRedirectionInformation();
|
|
|
|
} else {
|
|
|
|
//
|
|
// See if they gave us a hardcoded address.
|
|
//
|
|
LoaderRedirectionInformation.PortAddress = (PUCHAR)ULongToPtr(strtoul(pOption,NULL,16));
|
|
|
|
if( LoaderRedirectionInformation.PortAddress != (PUCHAR)NULL ) {
|
|
LoaderRedirectionInformation.PortNumber = 3;
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!_strnicmp(Option,"/redirectbaudrate=",18)) {
|
|
PCHAR pOption = strchr(Option,'=');
|
|
if( pOption != NULL ) {
|
|
pOption++;
|
|
|
|
if( _strnicmp(pOption,"115200",6) == 0 ) {
|
|
LoaderRedirectionInformation.BaudRate = BD_115200;
|
|
} else if( _strnicmp(pOption,"57600",5) == 0 ) {
|
|
LoaderRedirectionInformation.BaudRate = BD_57600;
|
|
} else if( _strnicmp(pOption,"19200",5) == 0 ) {
|
|
LoaderRedirectionInformation.BaudRate = BD_19200;
|
|
} else {
|
|
LoaderRedirectionInformation.BaudRate = BD_9600;
|
|
}
|
|
}
|
|
}
|
|
|
|
NextOption++;
|
|
NextOption = strchr(NextOption, '/');
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Fix up the setup directory path to include system32 also
|
|
// if this is a MiniNT boot
|
|
//
|
|
if (WinPEBoot) {
|
|
strcat(SetupDirectory, "system32\\");
|
|
|
|
//
|
|
// find out if a different load message has been specified
|
|
//
|
|
#ifdef UNICODE
|
|
StartupMsg = SlGetIniValueW(InfFile,
|
|
#else
|
|
StartupMsg = (PCTSTR)SlGetIniValue(InfFile,
|
|
#endif
|
|
"setupdata",
|
|
"loaderprompt",
|
|
NULL);
|
|
|
|
//
|
|
// Reduce the OEM key press time out
|
|
//
|
|
OemKeypressTimeout = 2; // secs
|
|
}
|
|
|
|
//
|
|
// Now we know everything we should load, compute the ARC name to load
|
|
// from and start loading things.
|
|
//
|
|
if (BootDevice==NULL) {
|
|
//
|
|
// No device was explicitly specified, so use whatever device
|
|
// setupldr was started from.
|
|
//
|
|
|
|
BootDevice = SlCopyStringA(SetupDevice);
|
|
}
|
|
|
|
Status = ArcOpen(BootDevice, ArcOpenReadOnly, &BootDeviceId);
|
|
|
|
if (Status != ESUCCESS) {
|
|
SlFatalError(SL_IO_ERROR,SlCopyStringAT(BootDevice));
|
|
goto LoadFailed;
|
|
} else {
|
|
BootDeviceIdValid = TRUE;
|
|
}
|
|
|
|
#ifdef _X86_
|
|
//
|
|
// Load the bootfont.bin into memory
|
|
//
|
|
SlLoadBootFontFile(BlLoaderBlock->SetupLoaderBlock,
|
|
BootDeviceId,
|
|
BootFontImageLength);
|
|
#endif // _X86_
|
|
|
|
_strlwr(BootDevice);
|
|
FixedBootMedia = (BOOLEAN)(strstr(BootDevice,")rdisk(") != NULL);
|
|
FloppyBoot = (BOOLEAN)(strstr(BootDevice, ")fdisk(") != NULL);
|
|
|
|
//
|
|
// If we are booting from fixed media, we better load disk class drivers.
|
|
//
|
|
if(FixedBootMedia) {
|
|
LoadDiskClass = TRUE;
|
|
}
|
|
|
|
if(!BlGetPathMnemonicKey(BootDevice,"disk",&DontCare)
|
|
&& !BlGetPathMnemonicKey(BootDevice,"fdisk",&BootDriveNumber))
|
|
{
|
|
//
|
|
// boot was from floppy, canonicalize the ARC name.
|
|
//
|
|
BlLoaderBlock->ArcBootDeviceName = BlAllocateHeap(80);
|
|
sprintf(BlLoaderBlock->ArcBootDeviceName, "multi(0)disk(0)fdisk(%d)",BootDriveNumber);
|
|
} else {
|
|
BlLoaderBlock->ArcBootDeviceName = BootDevice;
|
|
}
|
|
if (BootPath==NULL) {
|
|
//
|
|
// No explicit boot path given, default to the directory setupldr was started
|
|
// from.
|
|
//
|
|
#if defined(_X86_)
|
|
//
|
|
// Increadibly nauseating hack:
|
|
//
|
|
// If we are booting from hard drive on x86, we will assume this is
|
|
// the 'floppyless' winnt/winnt32 scenario, in which case the actual
|
|
// boot path is \$win_nt$.~bt.
|
|
//
|
|
// This lets us avoid having winnt and winnt32 attempt to modify
|
|
// the BootPath value in the [SetupData] section of txtsetup.sif.
|
|
//
|
|
// Enable booting WINPE from an LS-120 media.
|
|
//
|
|
if((FixedBootMedia)||(WinPEBoot && FloppyBoot)) {
|
|
|
|
CHAR SetupPath[256];
|
|
|
|
if( WinPEBoot ) {
|
|
strcpy(SetupPath, "\\minint\\system32\\");
|
|
} else if( UseCommandConsole ) {
|
|
strcpy(SetupPath, "\\CMDCONS\\");
|
|
} else {
|
|
strcpy(SetupPath, "\\$WIN_NT$.~BT\\");
|
|
}
|
|
BootPath = SlCopyStringA(SetupPath);
|
|
} else
|
|
#endif
|
|
BootPath = SlCopyStringA(SetupDirectory);
|
|
}
|
|
|
|
//
|
|
// Load the WinPE inf, if present.
|
|
//
|
|
if (WinPEBoot) {
|
|
CHAR FullPath[128];
|
|
|
|
strcpy(FullPath, BootPath);
|
|
strcat(FullPath, WINPE_OEM_FILENAME_A);
|
|
|
|
Status = SlInitIniFile(NULL,
|
|
BootDeviceId,
|
|
FullPath,
|
|
&OemInfHandle,
|
|
NULL,
|
|
0,
|
|
&ErrorLine);
|
|
|
|
if (Status != ESUCCESS) {
|
|
OemInfHandle = NULL;
|
|
Status = ESUCCESS;
|
|
}
|
|
}
|
|
|
|
#ifdef _WANT_MACHINE_IDENTIFICATION
|
|
|
|
BlLoaderBlock->Extension->InfFileImage = NULL;
|
|
BlLoaderBlock->Extension->InfFileSize = 0;
|
|
if (BiosInfo.Buffer) {
|
|
|
|
if (Status == ESUCCESS) {
|
|
|
|
Status = BlLoadBiosinfoInf( BootDeviceId,
|
|
BlFindMessage(SL_BIOSINFO_NAME),
|
|
BootPath,
|
|
&BiosInfo,
|
|
&BlLoaderBlock->Extension->InfFileImage,
|
|
&BlLoaderBlock->Extension->InfFileSize,
|
|
BadFileName);
|
|
}
|
|
|
|
|
|
if (Status != ESUCCESS) {
|
|
SlFatalError(SL_FILE_LOAD_FAILED, SlCopyStringAT(BadFileName), Status);
|
|
goto LoadFailed;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
//
|
|
// Let the kernel deal with failure to load this driver database.
|
|
//
|
|
|
|
BlLoaderBlock->Extension->DrvDBImage = NULL;
|
|
BlLoaderBlock->Extension->DrvDBSize = 0;
|
|
DrvMainSdb.Buffer = DRIVER_DATABASE_FILENAME;
|
|
DrvMainSdb.MaximumLength = sizeof(DRIVER_DATABASE_FILENAME); // MaxLength is size of buffer
|
|
DrvMainSdb.Length = sizeof(DRIVER_DATABASE_FILENAME) - sizeof(WCHAR); // Length does not include \0
|
|
BlLoadDrvDB( BootDeviceId,
|
|
NULL, // BlFindMessage(SL_DRVMAINSDB_NAME),
|
|
BootPath,
|
|
&DrvMainSdb,
|
|
&BlLoaderBlock->Extension->DrvDBImage,
|
|
&BlLoaderBlock->Extension->DrvDBSize,
|
|
BadFileName);
|
|
|
|
//
|
|
// Attempt to load winnt.sif from the path where we are
|
|
// loading setup files. Borrow the BadFileName buffer
|
|
// for temporary use.
|
|
//
|
|
if (!BlBootingFromNet) {
|
|
CHAR FloppyName[80];
|
|
ULONG FloppyId;
|
|
BOOLEAN FloppyUsed = FALSE;
|
|
|
|
if (SlpFindFloppy(0,FloppyName)) {
|
|
Status = ArcOpen(FloppyName,ArcOpenReadOnly,&FloppyId);
|
|
|
|
if (Status == ESUCCESS) {
|
|
strcpy(BadFileName,"\\");
|
|
strcat(BadFileName,WINNT_SIF_FILE_A);
|
|
BlLoaderBlock->SetupLoaderBlock->WinntSifFile = NULL;
|
|
BlLoaderBlock->SetupLoaderBlock->WinntSifFileLength = 0;
|
|
Status = SlInitIniFile(
|
|
NULL,
|
|
FloppyId,
|
|
BadFileName,
|
|
&WinntSifHandle,
|
|
&BlLoaderBlock->SetupLoaderBlock->WinntSifFile,
|
|
&BlLoaderBlock->SetupLoaderBlock->WinntSifFileLength,
|
|
&DontCare
|
|
);
|
|
if (Status == ESUCCESS) {
|
|
FloppyUsed = TRUE;
|
|
}
|
|
|
|
ArcClose(FloppyId);
|
|
}
|
|
}
|
|
|
|
if (!FloppyUsed) {
|
|
strcpy(BadFileName,BootPath);
|
|
strcat(BadFileName,WINNT_SIF_FILE_A);
|
|
BlLoaderBlock->SetupLoaderBlock->WinntSifFile = NULL;
|
|
BlLoaderBlock->SetupLoaderBlock->WinntSifFileLength = 0;
|
|
Status = SlInitIniFile(
|
|
NULL,
|
|
BootDeviceId,
|
|
BadFileName,
|
|
&WinntSifHandle,
|
|
&BlLoaderBlock->SetupLoaderBlock->WinntSifFile,
|
|
&BlLoaderBlock->SetupLoaderBlock->WinntSifFileLength,
|
|
&DontCare
|
|
);
|
|
}
|
|
|
|
}
|
|
|
|
IsUpgrade = SlIsUpgrade(WinntSifHandle);
|
|
UseRegularBackground = (UseCommandConsole || IsUpgrade || WinPEBoot);
|
|
|
|
//
|
|
// If the BIOS told us to redirect, we'd be doing it right now. However,
|
|
// the user may have told us some specific settings. If that's the case,
|
|
// override anything we're doing now with the settings from the user.
|
|
//
|
|
|
|
if( WinntSifHandle ) {
|
|
|
|
p = SlGetSectionKeyIndex(WinntSifHandle, WINNT_DATA_A, WINNT_U_HEADLESS_REDIRECT_A, 0);
|
|
|
|
if (p != NULL) {
|
|
|
|
if (!_strnicmp(p, "com", 3)) {
|
|
|
|
LoaderRedirectionInformation.PortNumber = (UCHAR)atoi( (PCHAR)(p+3) );
|
|
|
|
//
|
|
// See if they want to give us a baudrate.
|
|
//
|
|
p = SlGetSectionKeyIndex( WinntSifHandle, WINNT_DATA_A, WINNT_U_HEADLESS_REDIRECTBAUDRATE_A, 0 );
|
|
if( p ) {
|
|
|
|
if( _strnicmp(p,"115200",6) == 0 ) {
|
|
LoaderRedirectionInformation.BaudRate = BD_115200;
|
|
} else if( _strnicmp(p,"57600",5) == 0 ) {
|
|
LoaderRedirectionInformation.BaudRate = BD_57600;
|
|
} else if( _strnicmp(p,"19200",5) == 0 ) {
|
|
LoaderRedirectionInformation.BaudRate = BD_19200;
|
|
} else {
|
|
LoaderRedirectionInformation.BaudRate = BD_9600;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
} else if( !_stricmp(p, "usebiossettings" ) ) {
|
|
|
|
|
|
//
|
|
// Now we get to dig up all the information from the
|
|
// ACPI table.
|
|
//
|
|
BlRetrieveBIOSRedirectionInformation();
|
|
|
|
} else if( !_stricmp(p, "noncomport" ) ) {
|
|
|
|
//
|
|
// It's something other than serial. Go load a file off the floppy
|
|
// and get the driver from there.
|
|
//
|
|
|
|
//
|
|
// Currently not implemented.
|
|
//
|
|
RtlZeroMemory( &LoaderRedirectionInformation, sizeof(HEADLESS_LOADER_BLOCK) );
|
|
|
|
} else {
|
|
|
|
//
|
|
// See if they gave us a hardcoded address.
|
|
//
|
|
LoaderRedirectionInformation.PortAddress = (PUCHAR)ULongToPtr(strtoul(p,NULL,16));
|
|
|
|
if( LoaderRedirectionInformation.PortAddress != (PUCHAR)NULL ) {
|
|
LoaderRedirectionInformation.PortNumber = 3;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// If we found any headless redirection settings, go initialize
|
|
// the port now.
|
|
//
|
|
if( (LoaderRedirectionInformation.PortNumber) || (LoaderRedirectionInformation.PortAddress) ) {
|
|
|
|
//
|
|
// Yes, we are redirecting right now. Use these settings.
|
|
//
|
|
BlInitializeHeadlessPort();
|
|
SlClearDisplay();
|
|
|
|
|
|
if( BlLoaderBlock->Extension->HeadlessLoaderBlock == NULL ) {
|
|
BlLoaderBlock->Extension->HeadlessLoaderBlock = BlAllocateHeap(sizeof(HEADLESS_LOADER_BLOCK));
|
|
if (BlLoaderBlock->Extension->HeadlessLoaderBlock == NULL) {
|
|
SlNoMemoryError();
|
|
goto LoadFailed;
|
|
}
|
|
}
|
|
|
|
RtlCopyMemory( BlLoaderBlock->Extension->HeadlessLoaderBlock,
|
|
&LoaderRedirectionInformation,
|
|
sizeof(HEADLESS_LOADER_BLOCK) );
|
|
|
|
} else {
|
|
|
|
BlLoaderBlock->Extension->HeadlessLoaderBlock = NULL;
|
|
|
|
}
|
|
|
|
if (UseRegularBackground) {
|
|
extern BOOLEAN BlOutputDots;
|
|
extern int BlMaxFilesToLoad;
|
|
|
|
SlSetCurrentAttribute(DEFATT);
|
|
SlSetStatusAttribute(DEFATT);
|
|
SlClearDisplay();
|
|
SlPositionCursor(0,0);
|
|
|
|
if (UseCommandConsole) {
|
|
SlPrint(BlFindMessage(SL_CMDCONS_MSG));
|
|
}
|
|
|
|
BlOutputDots = TRUE;
|
|
|
|
//
|
|
// To reset BlShowProgress bar correctly
|
|
//
|
|
BlDisableProgressBar = FALSE;
|
|
BlProgressBarShowTimeOut = 0;
|
|
|
|
//
|
|
// Note : We can compute the real number of drivers to be loaded
|
|
// from various INF sections and manually counting all the
|
|
// different SlLoadDriver(...) calls. But the code/effort required
|
|
// to do this is not worth the feature, since we just want to
|
|
// replace the old "..." with progress bar to make the recovery
|
|
// console starting look similar to windows starting. So we make
|
|
// an assumption here about the maximum files to be loaded.
|
|
//
|
|
BlMaxFilesToLoad = 80;
|
|
|
|
BlSetProgBarCharacteristics(SL_CMDCONS_PROGBAR_FRONT,
|
|
SL_CMDCONS_PROGBAR_BACK);
|
|
|
|
if (WinPEBoot) {
|
|
StartupMsg ? BlOutputStartupMsgStr(StartupMsg) :
|
|
BlOutputStartupMsg(SL_SETUP_STARTING_WINPE);
|
|
} else if (UseCommandConsole) {
|
|
BlOutputStartupMsg(SL_CMDCONS_STARTING);
|
|
} else if (g_RollbackEnabled) {
|
|
BlOutputStartupMsg(SL_ROLLBACK_STARTING);
|
|
} else if (IsUpgrade) {
|
|
BlOutputStartupMsg(SL_SETUP_STARTING);
|
|
}
|
|
} else {
|
|
SlSetCurrentAttribute(DEFATT);
|
|
SlSetStatusAttribute(DEFSTATTR);
|
|
SlClearDisplay();
|
|
SlWriteHeaderText(SL_WELCOME_HEADER);
|
|
SlClearClientArea();
|
|
}
|
|
|
|
//
|
|
// Figure out all the OEM drivers source devices
|
|
//
|
|
RamdiskInitialize(BlLoaderBlock->LoadOptions, FALSE);
|
|
SlInitOemSourceDevices(&OemSourceDevices, &DefaultOemSourceDevice);
|
|
|
|
//
|
|
// If we found at least one valid OEM source device with proper
|
|
// txtsetup.oem and no default driver then bump up the timeout to
|
|
// 20 secs
|
|
//
|
|
|
|
if (OemSourceDevices) {
|
|
POEM_SOURCE_DEVICE CurrDevice = OemSourceDevices;
|
|
|
|
while(CurrDevice) {
|
|
if (SL_OEM_SOURCE_MEDIA_TYPE(CurrDevice,
|
|
SL_OEM_SOURCE_MEDIA_HAS_DRIVERS) &&
|
|
!SL_OEM_SOURCE_MEDIA_TYPE(CurrDevice,
|
|
SL_OEM_SOURCE_MEDIA_HAS_DEFAULT)) {
|
|
OemKeypressTimeout = 20;
|
|
|
|
break;
|
|
}
|
|
|
|
CurrDevice = CurrDevice->Next;
|
|
}
|
|
}
|
|
|
|
//
|
|
// We need to check to see if the user pressed any keys to force OEM HAL,
|
|
// OEM SCSI, or both. Do this before getting the settings in the sif file,
|
|
// so that we won't try to detect the machine if OEM HAL is needed.
|
|
//
|
|
|
|
SlCheckOemKeypress(OemKeypressTimeout);
|
|
|
|
{
|
|
PCSTR szOptionsToAdd = NULL;
|
|
CHAR szOptionsToRemove[sizeof("/noguiboot/nodebug")];
|
|
szOptionsToRemove[0] = 0;
|
|
|
|
//
|
|
// If F8 was pressed, add the debug options
|
|
//
|
|
if(EnableDebugger) {
|
|
if(InfFile != NULL) {
|
|
szOptionsToAdd = SlGetSectionKeyIndex(InfFile, "SetupData", "SetupDebugOptions", 0);
|
|
}
|
|
|
|
if(NULL == szOptionsToAdd) {
|
|
szOptionsToAdd = "/debug";
|
|
}
|
|
|
|
strcat(szOptionsToRemove, "/nodebug");
|
|
}
|
|
|
|
//
|
|
// remove the /noguiboot option so what we show the logo
|
|
// and switch the video adapter into graphics mode
|
|
// early on during initialization
|
|
//
|
|
if (IsUpgrade) {
|
|
strcat(szOptionsToRemove, "/noguiboot");
|
|
}
|
|
|
|
if(szOptionsToAdd != NULL || szOptionsToRemove[0] != 0) {
|
|
SlModifyOsLoadOptions(&BlLoaderBlock->LoadOptions, szOptionsToAdd, szOptionsToRemove);
|
|
}
|
|
}
|
|
|
|
|
|
#if defined(_X86_) || defined(_IA64_)
|
|
//
|
|
// We need to check to see if the user pressed any keys to force loading,
|
|
// an ASR pnp repair disk. Only do this if the user didn't select
|
|
// anything in the SlCheckOemKeypress function.
|
|
//
|
|
if(!UseCommandConsole && !WinPEBoot && !IsUpgrade && !BlBootingFromNet) {
|
|
|
|
PCHAR pTmp;
|
|
|
|
pTmp = SlGetSectionKeyIndex(InfFile,
|
|
"SetupData",
|
|
"DisableAsr",
|
|
0);
|
|
|
|
if ((pTmp == NULL) || (atoi(pTmp) == 0)) {
|
|
|
|
SlCheckASRKeypress();
|
|
}
|
|
}
|
|
|
|
if (BlBootingFromNet && TryASRViaNetwork) {
|
|
PVOID ASRPNPSifHandle = NULL;
|
|
ULONG c;
|
|
PCHAR FileNameFromSif;
|
|
|
|
FileNameFromSif = SlGetIniValue(
|
|
WinntSifHandle,
|
|
"OSChooser",
|
|
"ASRFile",
|
|
"generic.sif" );
|
|
|
|
Status = SlInitIniFile( SetupDevice,
|
|
0,
|
|
FileNameFromSif,
|
|
&ASRPNPSifHandle,
|
|
&BlLoaderBlock->SetupLoaderBlock->ASRPnPSifFile,
|
|
&BlLoaderBlock->SetupLoaderBlock->ASRPnPSifFileLength,
|
|
&c );
|
|
|
|
if(Status != ESUCCESS) {
|
|
SlFatalError(SL_BAD_INF_FILE,SlCopyStringAT(FileNameFromSif),Status);
|
|
goto LoadFailed;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
SlGetSetupValuesAfterPrompt(SetupBlock);
|
|
|
|
//
|
|
// Are there any dyamic update boot drivers which we need
|
|
// to process
|
|
//
|
|
DynamicUpdate = SlpIsDynamicUpdate(WinntSifHandle, &DynamicUpdateRootDir);
|
|
|
|
//
|
|
// Add the dynamic update source device as OEM source device since it could
|
|
// have F6
|
|
//
|
|
if (DynamicUpdate) {
|
|
DynamicUpdateSourceDevice = BlAllocateHeap(sizeof(OEM_SOURCE_DEVICE));
|
|
|
|
if (DynamicUpdateSourceDevice) {
|
|
memset(DynamicUpdateSourceDevice, 0, sizeof(OEM_SOURCE_DEVICE));
|
|
|
|
strcpy(DynamicUpdateSourceDevice->ArcDeviceName,
|
|
BootDevice);
|
|
|
|
DynamicUpdateSourceDevice->DriverDir = DynamicUpdateRootDir;
|
|
|
|
SL_OEM_SET_SOURCE_DEVICE_TYPE(DynamicUpdateSourceDevice,
|
|
(SL_OEM_SOURCE_DEVICE_TYPE_LOCAL |
|
|
SL_OEM_SOURCE_DEVICE_TYPE_FIXED |
|
|
SL_OEM_SOURCE_DEVICE_TYPE_DYN_UPDATE));
|
|
|
|
SL_OEM_SET_SOURCE_MEDIA_TYPE(DynamicUpdateSourceDevice,
|
|
(SL_OEM_SOURCE_MEDIA_PRESENT |
|
|
SL_OEM_SOURCE_MEDIA_HAS_DRIVERS |
|
|
SL_OEM_SOURCE_MEDIA_HAS_MSD |
|
|
SL_OEM_SOURCE_MEDIA_HAS_DEFAULT));
|
|
|
|
SL_OEM_SET_SOURCE_DEVICE_STATE(DynamicUpdateSourceDevice,
|
|
SL_OEM_SOURCE_DEVICE_NOT_PROCESSED);
|
|
|
|
DynamicUpdateSourceDevice->DeviceId = BootDeviceId;
|
|
|
|
//
|
|
// Insert it at the head of the linked list
|
|
//
|
|
DynamicUpdateSourceDevice->Next = OemSourceDevices;
|
|
OemSourceDevices = DynamicUpdateSourceDevice;
|
|
}
|
|
}
|
|
|
|
if (BlBootingFromNet || (Status == ESUCCESS)) {
|
|
|
|
|
|
//
|
|
// Find out if this is a pre-install, by looking at OemPreinstall key
|
|
// in [unattended] section of winnt.sif
|
|
//
|
|
p = SlGetSectionKeyIndex(WinntSifHandle,WINNT_UNATTENDED_A,WINNT_U_OEMPREINSTALL_A,0);
|
|
if(p && !_stricmp(p,"yes")) {
|
|
PreInstall = TRUE;
|
|
}
|
|
|
|
//
|
|
// If this is a pre-install, find out which hal to load, by looking
|
|
// at ComputerType key in [unattended] section of winnt.sif.
|
|
//
|
|
if( PreInstall && !DynamicUpdate) {
|
|
#ifdef UNICODE
|
|
ComputerType = (PTCHAR)SlGetSectionKeyIndexW(
|
|
#else
|
|
ComputerType = (PTCHAR)SlGetSectionKeyIndex(
|
|
#endif
|
|
WinntSifHandle,
|
|
WINNT_UNATTENDED_A,
|
|
WINNT_U_COMPUTERTYPE_A,
|
|
0);
|
|
if(ComputerType) {
|
|
//
|
|
// If the hal to load is an OEM one, then set OemHal to TRUE
|
|
//
|
|
p = SlGetSectionKeyIndex(WinntSifHandle,WINNT_UNATTENDED_A,WINNT_U_COMPUTERTYPE_A,1);
|
|
if(p && !_stricmp(p, OemTag)) {
|
|
OemHal = TRUE;
|
|
} else {
|
|
OemHal = FALSE;
|
|
}
|
|
//
|
|
// In the pre-install mode, don't let the user specify
|
|
// an OEM hal, if one was specified in unattend.txt
|
|
//
|
|
PromptOemHal = FALSE;
|
|
}
|
|
|
|
//
|
|
// Find out which SCSI drivers to load, by looking at
|
|
// [MassStorageDrivers] in winnt.sif
|
|
//
|
|
if( SpSearchINFSection( WinntSifHandle, WINNT_OEMSCSIDRIVERS_A ) ) {
|
|
PPREINSTALL_DRIVER_INFO TempDriverInfo;
|
|
PTSTR pOem;
|
|
#ifdef UNICODE
|
|
CHAR DriverDescriptionA[100];
|
|
PCHAR pDriverDescriptionA;
|
|
UNICODE_STRING uString;
|
|
ANSI_STRING aString;
|
|
#endif
|
|
|
|
PreinstallDriverList = NULL;
|
|
for( i = 0;
|
|
#ifdef UNICODE
|
|
((pOem = SlGetKeyNameW(
|
|
#else
|
|
((pOem = SlGetKeyName(
|
|
#endif
|
|
WinntSifHandle,
|
|
WINNT_OEMSCSIDRIVERS_A,
|
|
i )) != NULL);
|
|
i++ ) {
|
|
TempDriverInfo = BlAllocateHeap(sizeof(PREINSTALL_DRIVER_INFO));
|
|
if (TempDriverInfo==NULL) {
|
|
SlNoMemoryError();
|
|
goto LoadFailed;
|
|
}
|
|
TempDriverInfo->DriverDescription = pOem;
|
|
#ifdef UNICODE
|
|
RtlInitUnicodeString( &uString, TempDriverInfo->DriverDescription);
|
|
|
|
|
|
//
|
|
// use the static buffer if possible
|
|
//
|
|
pDriverDescriptionA = DriverDescriptionA;
|
|
aString.MaximumLength = sizeof(DriverDescriptionA);
|
|
|
|
//
|
|
// if more memory is needed for the driver description
|
|
// allocate it
|
|
//
|
|
if (aString.MaximumLength < uString.Length/2 + 1 ) {
|
|
pDriverDescriptionA = BlAllocateHeap(uString.Length/2 + 1);
|
|
if (pDriverDescriptionA == NULL) {
|
|
SlNoMemoryError();
|
|
goto LoadFailed;
|
|
}
|
|
aString.MaximumLength = uString.Length/2 + 1;
|
|
}
|
|
|
|
aString.Buffer = pDriverDescriptionA;
|
|
|
|
Status = RtlUnicodeStringToAnsiString( &aString, &uString, FALSE );
|
|
pOem = (Status != ESUCCESS) ? NULL : SlGetIniValueW( WinntSifHandle,
|
|
WINNT_OEMSCSIDRIVERS_A,
|
|
pDriverDescriptionA,
|
|
NULL );
|
|
#else
|
|
pOem = SlGetIniValue(
|
|
WinntSifHandle,
|
|
WINNT_OEMSCSIDRIVERS_A,
|
|
TempDriverInfo->DriverDescription,
|
|
NULL );
|
|
#endif
|
|
TempDriverInfo->OemDriver = (pOem && !_tcsicmp(pOem, _TOemTag))? TRUE : FALSE;
|
|
TempDriverInfo->Next = PreinstallDriverList;
|
|
PreinstallDriverList = TempDriverInfo;
|
|
}
|
|
if( PreinstallDriverList != NULL ) {
|
|
//
|
|
// In the pre-install mode, don't let the user specify
|
|
// an OEM scsi, if at least one was specified in unattend.txt
|
|
//
|
|
PromptOemScsi = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
p = SlGetSectionKeyIndex(WinntSifHandle,WINNT_SETUPPARAMS_A,WINNT_S_SKIPMISSING_A,0);
|
|
if(p && (*p != '0')) {
|
|
IgnoreMissingFiles = TRUE;
|
|
}
|
|
|
|
#if defined(_X86_) || defined(_IA64_)
|
|
//
|
|
// Find out if this is a Win9x upgrade
|
|
//
|
|
Win9xUnsupHdc = FALSE;
|
|
p = SlGetSectionKeyIndex(WinntSifHandle,WINNT_DATA_A,WINNT_D_WIN95UPGRADE_A,0);
|
|
if(p && !_stricmp(p, WINNT_A_YES_A)) {
|
|
//
|
|
// If it is an Win9x upgrade, find out if winnt32 found an unsupported
|
|
// hard disk controller.
|
|
//
|
|
p = SlGetSectionKeyIndex(WinntSifHandle,WINNT_DATA_A,WINNT_D_WIN95UNSUPHDC_A,0);
|
|
if(p && (*p != '0')) {
|
|
Win9xUnsupHdc = TRUE;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// At this point, we know that we wre able to read winnt.sif.
|
|
// So attempt to read migrate.inf. Borrow the BadFileName buffer
|
|
// for temporary use.
|
|
//
|
|
|
|
strcpy(BadFileName,BootPath);
|
|
strcat(BadFileName,WINNT_MIGRATE_INF_FILE_A);
|
|
if( SlInitIniFile(NULL,
|
|
BootDeviceId,
|
|
BadFileName,
|
|
&MigrateInfHandle,
|
|
&BlLoaderBlock->SetupLoaderBlock->MigrateInfFile,
|
|
&BlLoaderBlock->SetupLoaderBlock->MigrateInfFileLength,
|
|
&DontCare) != ESUCCESS ) {
|
|
MigrateInfHandle = NULL;
|
|
BlLoaderBlock->SetupLoaderBlock->MigrateInfFile = NULL;
|
|
BlLoaderBlock->SetupLoaderBlock->MigrateInfFileLength = 0;
|
|
}
|
|
//
|
|
// Attempt also to read unsupdrv.inf. Borrow the BadFileName buffer
|
|
// for temporary use.
|
|
//
|
|
|
|
strcpy(BadFileName,BootPath);
|
|
strcat(BadFileName,WINNT_UNSUPDRV_INF_FILE_A);
|
|
if( SlInitIniFile(NULL,
|
|
BootDeviceId,
|
|
BadFileName,
|
|
&UnsupDriversInfHandle,
|
|
&BlLoaderBlock->SetupLoaderBlock->UnsupDriversInfFile,
|
|
&BlLoaderBlock->SetupLoaderBlock->UnsupDriversInfFileLength,
|
|
&DontCare) != ESUCCESS ) {
|
|
UnsupDriversInfHandle = NULL;
|
|
BlLoaderBlock->SetupLoaderBlock->UnsupDriversInfFile = NULL;
|
|
BlLoaderBlock->SetupLoaderBlock->UnsupDriversInfFileLength = 0;
|
|
}
|
|
SlGetMigratedHardwareIds(SetupBlock, UnsupDriversInfHandle);
|
|
|
|
} else {
|
|
WinntSifHandle = NULL;
|
|
//
|
|
// If winnt.sif doesn't exist, then we don't bother to read migrate.inf and unsupdrv.inf,
|
|
// since we are booting from the retail boot floppies or the CD, and in this
|
|
// case there is no migrate.inf or unsupdrv.inf.
|
|
//
|
|
MigrateInfHandle = NULL;
|
|
BlLoaderBlock->SetupLoaderBlock->MigrateInfFile = NULL;
|
|
BlLoaderBlock->SetupLoaderBlock->MigrateInfFileLength = 0;
|
|
|
|
UnsupDriversInfHandle = NULL;
|
|
BlLoaderBlock->SetupLoaderBlock->UnsupDriversInfFile = NULL;
|
|
BlLoaderBlock->SetupLoaderBlock->UnsupDriversInfFileLength = 0;
|
|
}
|
|
|
|
//
|
|
// Store the boot path in the loader block.
|
|
//
|
|
|
|
if (UseCommandConsole) {
|
|
SetupBlock->Flags |= SETUPBLK_FLAGS_CONSOLE;
|
|
}
|
|
|
|
if (g_RollbackEnabled) {
|
|
SetupBlock->Flags |= SETUPBLK_FLAGS_ROLLBACK;
|
|
}
|
|
|
|
if ( !BlBootingFromNet ) {
|
|
|
|
BlLoaderBlock->NtBootPathName = BootPath;
|
|
|
|
} else {
|
|
|
|
ANSI_STRING aString;
|
|
UNICODE_STRING uString;
|
|
ULONG length;
|
|
#if defined(REMOTE_BOOT)
|
|
PCHAR TempEnableIpsec;
|
|
#endif // defined(REMOTE_BOOT)
|
|
|
|
SetupBlock->Flags |= SETUPBLK_FLAGS_IS_REMOTE_BOOT;
|
|
|
|
BlLoaderBlock->NtBootPathName =
|
|
BlAllocateHeap( (ULONG)strlen(NetSetupServerShare) + (ULONG)strlen(BootPath) + 1 );
|
|
if ( BlLoaderBlock->NtBootPathName == NULL ) {
|
|
SlNoMemoryError();
|
|
goto LoadFailed;
|
|
}
|
|
strcpy( BlLoaderBlock->NtBootPathName, NetSetupServerShare );
|
|
strcat( BlLoaderBlock->NtBootPathName, BootPath );
|
|
|
|
//
|
|
// NetSetupServerShare is of the form \server\IMirror. NetBootPath
|
|
// is of the form Clients\machine\ (note trailing \). We need to
|
|
// insert a \ between the two and add BootDrive to yield
|
|
// \server\IMirror\Clients\machine\BootDrive.
|
|
//
|
|
|
|
length = (ULONG)strlen(NetSetupServerShare) +
|
|
sizeof(CHAR) + // '\'
|
|
(ULONG)strlen(NetBootPath) +
|
|
sizeof("BootDrive"); // sizeof includes the \0
|
|
SetupBlock->MachineDirectoryPath = BlAllocateHeap( length );
|
|
if ( SetupBlock->MachineDirectoryPath == NULL ) {
|
|
SlNoMemoryError();
|
|
goto LoadFailed;
|
|
}
|
|
strcpy( SetupBlock->MachineDirectoryPath, NetSetupServerShare );
|
|
SetupBlock->MachineDirectoryPath[strlen(NetSetupServerShare)] = '\\';
|
|
SetupBlock->MachineDirectoryPath[strlen(NetSetupServerShare) + 1] = 0;
|
|
strcat(SetupBlock->MachineDirectoryPath, NetBootPath);
|
|
strcat(SetupBlock->MachineDirectoryPath, "BootDrive");
|
|
|
|
//
|
|
// Save the path to the SIF file so it can be deleted later.
|
|
//
|
|
if (((SetupBlock->Flags & (SETUPBLK_FLAGS_REMOTE_INSTALL|SETUPBLK_FLAGS_SYSPREP_INSTALL)) != 0) &&
|
|
(NetbootSifFile[0] != '\0')) {
|
|
length = (ULONG)strlen(NetSetupServerShare) +
|
|
sizeof(CHAR) + // '\'
|
|
(ULONG)strlen(NetbootSifFile) +
|
|
sizeof(CHAR); // '\0'
|
|
|
|
SetupBlock->NetBootSifPath = BlAllocateHeap( length );
|
|
if ( SetupBlock->NetBootSifPath == NULL ) {
|
|
SlNoMemoryError();
|
|
goto LoadFailed;
|
|
}
|
|
strcpy( SetupBlock->NetBootSifPath, NetSetupServerShare );
|
|
SetupBlock->NetBootSifPath[strlen(NetSetupServerShare)] = '\\';
|
|
SetupBlock->NetBootSifPath[strlen(NetSetupServerShare) + 1] = 0;
|
|
strcat(SetupBlock->NetBootSifPath, NetbootSifFile);
|
|
}
|
|
|
|
//
|
|
// NetSetupServerShare was read from winnt.sif and we replaced
|
|
// the '\' at the end with a NULL -- put this back for when
|
|
// winnt.sif is re-parsed by the kernel (the only modification
|
|
// that the kernel parser can really accept is replacing a
|
|
// final " with a NULL, which SlInitIniFile does).
|
|
//
|
|
|
|
NetSetupServerShare[strlen(NetSetupServerShare)] = '\\';
|
|
|
|
//
|
|
// Get the computer name from winnt.sif.
|
|
//
|
|
p = SlGetSectionKeyIndex(WinntSifHandle,WINNT_USERDATA_A,WINNT_US_COMPNAME_A,0);
|
|
if(!p || (*p == 0)) {
|
|
SlFatalError(SL_INF_ENTRY_MISSING,WINNT_US_COMPNAME,WINNT_USERDATA);
|
|
goto LoadFailed;
|
|
}
|
|
|
|
RtlInitString( &aString, p );
|
|
uString.Buffer = SetupBlock->ComputerName;
|
|
uString.MaximumLength = 64 * sizeof(WCHAR);
|
|
RtlAnsiStringToUnicodeString( &uString, &aString, FALSE );
|
|
|
|
//
|
|
// Save these from the global variables.
|
|
//
|
|
|
|
#ifdef EFI
|
|
//
|
|
// Convert these back to Network Order.
|
|
//
|
|
SetupBlock->IpAddress = RtlUlongByteSwap(NetLocalIpAddress);
|
|
SetupBlock->SubnetMask = RtlUlongByteSwap(NetLocalSubnetMask);
|
|
SetupBlock->DefaultRouter = RtlUlongByteSwap(NetGatewayIpAddress);
|
|
SetupBlock->ServerIpAddress = RtlUlongByteSwap(NetServerIpAddress);
|
|
#else
|
|
SetupBlock->IpAddress = NetLocalIpAddress;
|
|
SetupBlock->SubnetMask = NetLocalSubnetMask;
|
|
SetupBlock->DefaultRouter = NetGatewayIpAddress;
|
|
SetupBlock->ServerIpAddress = NetServerIpAddress;
|
|
#endif
|
|
|
|
//
|
|
// Get information about the net card and do an exchange with the
|
|
// server to get information we need to load it properly.
|
|
//
|
|
|
|
SetupBlock->NetbootCardInfo = BlAllocateHeap(sizeof(NET_CARD_INFO));
|
|
if ( SetupBlock->NetbootCardInfo == NULL ) {
|
|
SlNoMemoryError();
|
|
goto LoadFailed;
|
|
}
|
|
SetupBlock->NetbootCardInfoLength = sizeof(NET_CARD_INFO);
|
|
|
|
Status = NetQueryCardInfo(
|
|
(PNET_CARD_INFO)SetupBlock->NetbootCardInfo
|
|
);
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
SlFatalError(SL_NETBOOT_CARD_ERROR);
|
|
goto LoadFailed;
|
|
}
|
|
|
|
//
|
|
// This call may allocate SetupBlock->NetbootCardRegistry
|
|
//
|
|
|
|
Status = NetQueryDriverInfo(
|
|
(PNET_CARD_INFO)SetupBlock->NetbootCardInfo,
|
|
NetSetupServerShare,
|
|
NULL,
|
|
SetupBlock->NetbootCardHardwareId,
|
|
sizeof(SetupBlock->NetbootCardHardwareId),
|
|
SetupBlock->NetbootCardDriverName,
|
|
NetbootCardDriverName,
|
|
sizeof(SetupBlock->NetbootCardDriverName),
|
|
SetupBlock->NetbootCardServiceName,
|
|
sizeof(SetupBlock->NetbootCardServiceName),
|
|
&SetupBlock->NetbootCardRegistry,
|
|
&SetupBlock->NetbootCardRegistryLength);
|
|
|
|
if (Status == STATUS_INSUFFICIENT_RESOURCES) {
|
|
SlNoMemoryError();
|
|
goto LoadFailed;
|
|
} else if (Status != STATUS_SUCCESS) {
|
|
SlFatalError(SL_NETBOOT_SERVER_ERROR);
|
|
goto LoadFailed;
|
|
}
|
|
|
|
#if 0
|
|
DbgPrint("HardwareID is <%ws>, DriverName is <%ws>, Service <%ws>\n",
|
|
SetupBlock->NetbootCardHardwareId,
|
|
SetupBlock->NetbootCardDriverName,
|
|
SetupBlock->NetbootCardServiceName);
|
|
DbgPrint("NetbootCardRegistry at %lx, length %d\n",
|
|
SetupBlock->NetbootCardRegistry,
|
|
SetupBlock->NetbootCardRegistryLength);
|
|
DbgBreakPoint();
|
|
#endif
|
|
|
|
#if defined(REMOTE_BOOT)
|
|
//
|
|
// See if we should enable remote boot security (IPSEC).
|
|
//
|
|
|
|
TempEnableIpsec = SlGetSectionKeyIndex(WinntSifHandle,
|
|
"RemoteBoot",
|
|
"EnableIpSecurity",
|
|
0);
|
|
if ((TempEnableIpsec != NULL) &&
|
|
((TempEnableIpsec[0] == 'Y') ||
|
|
(TempEnableIpsec[0] == 'y'))) {
|
|
|
|
RemoteBootEnableIpsec = TRUE;
|
|
}
|
|
|
|
if ((SetupBlock->Flags & (SETUPBLK_FLAGS_REMOTE_INSTALL |
|
|
SETUPBLK_FLAGS_SYSPREP_INSTALL)) == 0) {
|
|
|
|
ARC_STATUS ArcStatus;
|
|
ULONG FileId;
|
|
|
|
//
|
|
// Read the secret off the disk, if there is one, and store it
|
|
// in the loader block.
|
|
//
|
|
|
|
ArcStatus = BlOpenRawDisk(&FileId);
|
|
|
|
if (ArcStatus == ESUCCESS) {
|
|
|
|
SetupBlock->NetBootSecret = BlAllocateHeap(sizeof(RI_SECRET));
|
|
if (SetupBlock->NetBootSecret == NULL) {
|
|
SlNoMemoryError();
|
|
BlCloseRawDisk(FileId);
|
|
goto LoadFailed;
|
|
}
|
|
|
|
ArcStatus = BlReadSecret(FileId, (PRI_SECRET)(SetupBlock->NetBootSecret));
|
|
if (ArcStatus != ESUCCESS) {
|
|
SlNoMemoryError();
|
|
BlCloseRawDisk(FileId);
|
|
goto LoadFailed;
|
|
}
|
|
|
|
ArcStatus = BlCloseRawDisk(FileId);
|
|
|
|
//
|
|
// By now we have TFTPed some files so this will be TRUE if it
|
|
// is ever going to be.
|
|
//
|
|
|
|
SetupBlock->NetBootUsePassword2 = NetBootTftpUsedPassword2;
|
|
}
|
|
|
|
} else
|
|
#endif // defined(REMOTE_BOOT)
|
|
{
|
|
|
|
//
|
|
// Construct a secret to pass to the redirector, based on what
|
|
// was passed to use across the reboot. For the moment only
|
|
// user/domain/password matters.
|
|
//
|
|
|
|
WCHAR UnicodePassword[64];
|
|
UNICODE_STRING TmpNtPassword;
|
|
CHAR LmOwfPassword[LM_OWF_PASSWORD_SIZE];
|
|
CHAR NtOwfPassword[NT_OWF_PASSWORD_SIZE];
|
|
CHAR GarbageSid[RI_SECRET_SID_SIZE];
|
|
|
|
SetupBlock->NetBootSecret = BlAllocateHeap(sizeof(RI_SECRET));
|
|
if (SetupBlock->NetBootSecret == NULL) {
|
|
SlNoMemoryError();
|
|
goto LoadFailed;
|
|
}
|
|
|
|
//
|
|
// Do a quick conversion of the password to Unicode.
|
|
//
|
|
|
|
TmpNtPassword.Length = (USHORT)strlen(NetbootPassword) * sizeof(WCHAR);
|
|
TmpNtPassword.MaximumLength = sizeof(UnicodePassword);
|
|
TmpNtPassword.Buffer = UnicodePassword;
|
|
|
|
for (i = 0; i < sizeof(NetbootPassword); i++) {
|
|
UnicodePassword[i] = (WCHAR)(NetbootPassword[i]);
|
|
}
|
|
|
|
BlOwfPassword((PUCHAR) NetbootPassword,
|
|
&TmpNtPassword,
|
|
(PUCHAR) LmOwfPassword,
|
|
(PUCHAR) NtOwfPassword);
|
|
|
|
BlInitializeSecret(
|
|
(PUCHAR) NetbootDomain,
|
|
(PUCHAR) NetbootUser,
|
|
(PUCHAR) LmOwfPassword,
|
|
(PUCHAR) NtOwfPassword,
|
|
#if defined(REMOTE_BOOT)
|
|
NULL, // no password2
|
|
NULL, // no password2
|
|
#endif // defined(REMOTE_BOOT)
|
|
(PUCHAR) GarbageSid,
|
|
SetupBlock->NetBootSecret);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Initialize the debugging system.
|
|
//
|
|
|
|
BlLogInitialize(BootDeviceId);
|
|
|
|
//
|
|
// Do PPC-specific initialization.
|
|
//
|
|
|
|
#if defined(_PPC_)
|
|
|
|
Status = BlPpcInitialize();
|
|
if (Status != ESUCCESS) {
|
|
goto LoadFailed;
|
|
}
|
|
|
|
#endif // defined(_PPC_)
|
|
|
|
//
|
|
// Check for an alternate Kernel Debugger DLL, i.e.,
|
|
// /debugport=1394 (kd1394.dll), /debugport=usb (kdusb.dll), etc...
|
|
//
|
|
|
|
FileName = NULL;
|
|
|
|
if (BlLoaderBlock->LoadOptions != NULL) {
|
|
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");
|
|
}
|
|
}
|
|
|
|
//
|
|
// If this is a preinstall case then add another
|
|
// OEM source device
|
|
//
|
|
|
|
if (PreInstall || WinPEBoot) {
|
|
PreInstallOemSourceDevice = BlAllocateHeap(sizeof(OEM_SOURCE_DEVICE));
|
|
PreInstallSourcePath = BlAllocateHeap(256);
|
|
|
|
if (PreInstallOemSourceDevice && PreInstallSourcePath) {
|
|
strcpy(PreInstallOemSourceDevice->ArcDeviceName,
|
|
BootDevice);
|
|
|
|
strcpy(PreInstallSourcePath, BootPath);
|
|
strcat(PreInstallSourcePath, WINNT_OEM_DIR_A);
|
|
|
|
PreInstallOemSourceDevice->DriverDir = PreInstallSourcePath;
|
|
|
|
SL_OEM_SET_SOURCE_DEVICE_TYPE(PreInstallOemSourceDevice,
|
|
(SL_OEM_SOURCE_DEVICE_TYPE_LOCAL |
|
|
SL_OEM_SOURCE_DEVICE_TYPE_FIXED |
|
|
SL_OEM_SOURCE_DEVICE_TYPE_PREINSTALL));
|
|
|
|
//
|
|
// Mark the device as containing preinstall drivers only if they
|
|
// specified any F6 mass storage drivers
|
|
//
|
|
if (!WinPEBoot && PreinstallDriverList) {
|
|
SL_OEM_SET_SOURCE_MEDIA_TYPE(PreInstallOemSourceDevice,
|
|
(SL_OEM_SOURCE_MEDIA_PRESENT |
|
|
SL_OEM_SOURCE_MEDIA_HAS_DRIVERS |
|
|
SL_OEM_SOURCE_MEDIA_HAS_MSD |
|
|
SL_OEM_SOURCE_MEDIA_HAS_DEFAULT));
|
|
}
|
|
|
|
SL_OEM_SET_SOURCE_DEVICE_STATE(PreInstallOemSourceDevice,
|
|
SL_OEM_SOURCE_DEVICE_NOT_PROCESSED);
|
|
|
|
PreInstallOemSourceDevice->DeviceId = BootDeviceId;
|
|
|
|
//
|
|
// Insert it at the head of the linked list
|
|
//
|
|
PreInstallOemSourceDevice->Next = OemSourceDevices;
|
|
OemSourceDevices = PreInstallOemSourceDevice;
|
|
} else {
|
|
SlNoMemoryError();
|
|
goto LoadFailed;
|
|
}
|
|
}
|
|
|
|
if (!BlBootingFromNet) {
|
|
//
|
|
// Figure out if there are any OEM hal/drivers which need to
|
|
// be autoloaded.
|
|
// NOTE: We skip the dynamic update OEM source device since it's
|
|
// drivers will be autoloaded later.
|
|
//
|
|
POEM_SOURCE_DEVICE CurrDevice = OemSourceDevices;
|
|
|
|
while (CurrDevice && !(AutoLoadOemHalDevice && AutoLoadOemScsi)) {
|
|
if ((SL_OEM_SOURCE_MEDIA_TYPE(CurrDevice,
|
|
SL_OEM_SOURCE_MEDIA_HAS_DRIVERS) &&
|
|
SL_OEM_SOURCE_MEDIA_TYPE(CurrDevice,
|
|
SL_OEM_SOURCE_MEDIA_HAS_DEFAULT)) &&
|
|
!SL_OEM_SOURCE_DEVICE_TYPE(CurrDevice,
|
|
SL_OEM_SOURCE_DEVICE_TYPE_DYN_UPDATE)) {
|
|
|
|
if (!AutoLoadOemHalDevice &&
|
|
SL_OEM_SOURCE_MEDIA_TYPE(CurrDevice, SL_OEM_SOURCE_MEDIA_HAS_HAL)) {
|
|
AutoLoadOemHalDevice = CurrDevice;
|
|
}
|
|
|
|
if (!AutoLoadOemScsi &&
|
|
SL_OEM_SOURCE_MEDIA_TYPE(CurrDevice, SL_OEM_SOURCE_MEDIA_HAS_MSD)) {
|
|
AutoLoadOemScsi = TRUE;
|
|
}
|
|
}
|
|
|
|
CurrDevice = CurrDevice->Next;
|
|
}
|
|
|
|
//
|
|
// Set allocatable range to the kernel-specific range
|
|
//
|
|
BlUsableBase = BL_KERNEL_RANGE_LOW;
|
|
BlUsableLimit = BL_KERNEL_RANGE_HIGH;
|
|
|
|
//
|
|
// Load the kernel.
|
|
//
|
|
|
|
SlGetDisk(KERNEL_MP_IMAGE_FILENAME);
|
|
strcpy(KernelDirectoryPath, BootPath);
|
|
strcat(KernelDirectoryPath, KERNEL_MP_IMAGE_FILENAME);
|
|
|
|
//
|
|
// If AMD64 long mode is detected, the following call will set the
|
|
// global BlAmd64UseLongMode to TRUE.
|
|
//
|
|
|
|
#if defined(_X86_)
|
|
|
|
BlAmd64CheckForLongMode(BootDeviceId, KernelDirectoryPath, "");
|
|
|
|
#endif
|
|
|
|
strcpy(KernelImage, KERNEL_MP_IMAGE_FILENAME);
|
|
|
|
#ifdef i386
|
|
retrykernel:
|
|
#endif
|
|
|
|
BlOutputLoadMessage(BootDevice, KernelDirectoryPath, BlFindMessage(SL_KERNEL_NAME));
|
|
Status = BlLoadImage(BootDeviceId,
|
|
LoaderSystemCode,
|
|
KernelDirectoryPath,
|
|
TARGET_IMAGE,
|
|
&SystemBase);
|
|
|
|
//
|
|
// If the kernel didn't fit in the preferred range, reset the range to
|
|
// all of memory and try again.
|
|
//
|
|
|
|
#ifdef i386
|
|
|
|
if ((Status == ENOMEM) &&
|
|
((BlUsableBase != 0) ||
|
|
(BlUsableLimit != _16MB))) {
|
|
BlUsableBase = 0;
|
|
BlUsableLimit = _16MB;
|
|
|
|
goto retrykernel;
|
|
}
|
|
|
|
#endif
|
|
|
|
if (Status != ESUCCESS) {
|
|
SlFatalError(SL_FILE_LOAD_FAILED,
|
|
SlCopyStringAT(KernelDirectoryPath),
|
|
Status);
|
|
|
|
goto LoadFailed;
|
|
}
|
|
|
|
BlUpdateBootStatus();
|
|
|
|
//
|
|
// Load the HAL.
|
|
//
|
|
|
|
strcpy(HalDirectoryPath, BootPath);
|
|
if (PromptOemHal || (PreInstall && (ComputerType != NULL))) {
|
|
if(PreInstall && OemHal) {
|
|
//
|
|
// This is a pre-install and an OEM hal was specified
|
|
//
|
|
strcat( HalDirectoryPath,
|
|
#if defined(_X86_) || defined(_IA64_)
|
|
WINNT_OEM_DIR_A
|
|
#else
|
|
WINNT_OEM_TEXTMODE_DIR_A
|
|
#endif
|
|
);
|
|
strcat( HalDirectoryPath, "\\" );
|
|
}
|
|
|
|
SlPromptOemHal((PreInstall ? PreInstallOemSourceDevice : DefaultOemSourceDevice),
|
|
(BOOLEAN) (!PreInstall || (ComputerType == NULL)),
|
|
&HalBase,
|
|
&HalName);
|
|
|
|
strcat(HalDirectoryPath,HalName);
|
|
|
|
//
|
|
// Reset the last disk tag for floopy boot
|
|
//
|
|
if (FloppyBoot) {
|
|
LastDiskTag = NULL;
|
|
}
|
|
} else {
|
|
if (AutoLoadOemHalDevice) {
|
|
SlPromptOemHal(AutoLoadOemHalDevice,
|
|
FALSE,
|
|
&HalBase,
|
|
&HalName);
|
|
} else {
|
|
//
|
|
// Note that on x86, the HAL may be on floppy #1 or floppy #2
|
|
//
|
|
strcat(HalDirectoryPath,HalName);
|
|
SlGetDisk(HalName);
|
|
BlOutputLoadMessage(BootDevice, HalDirectoryPath, BlFindMessage(SL_HAL_NAME));
|
|
|
|
#ifdef i386
|
|
retryhal:
|
|
#endif
|
|
Status = BlLoadImage(BootDeviceId,
|
|
LoaderHalCode,
|
|
HalDirectoryPath,
|
|
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 != 0) ||
|
|
(BlUsableLimit != _16MB))) {
|
|
BlUsableBase = 0;
|
|
BlUsableLimit = _16MB;
|
|
|
|
goto retryhal;
|
|
}
|
|
#endif
|
|
if (Status != ESUCCESS) {
|
|
SlFatalError(SL_FILE_LOAD_FAILED,
|
|
SlCopyStringAT(HalDirectoryPath),
|
|
Status);
|
|
|
|
goto LoadFailed;
|
|
}
|
|
}
|
|
|
|
BlUpdateBootStatus();
|
|
}
|
|
|
|
//
|
|
// Set allocatable range to the driver-specific range
|
|
//
|
|
BlUsableBase = BL_DRIVER_RANGE_LOW;
|
|
BlUsableLimit = BL_DRIVER_RANGE_HIGH;
|
|
|
|
} else {
|
|
|
|
#if !defined(_IA64_)
|
|
//
|
|
// don't need these variables for ia64
|
|
//
|
|
PCHAR id;
|
|
ULONG idLength;
|
|
#endif
|
|
|
|
//
|
|
// This is a remote boot setup. Load the HAL first, so that we
|
|
// can determine whether to load the UP or MP kernel.
|
|
//
|
|
// Note that we cannot load the HAL first on local boots
|
|
// because that would break floppy boot, where the kernel
|
|
// is on floppy #1 and the HALs are on floppy #2.
|
|
//
|
|
|
|
|
|
//
|
|
// Set allocatable range to the kernel-specific range
|
|
//
|
|
BlUsableBase = BL_KERNEL_RANGE_LOW;
|
|
BlUsableLimit = BL_KERNEL_RANGE_HIGH;
|
|
|
|
|
|
#if defined(_IA64_)
|
|
|
|
//
|
|
// ===============
|
|
// Load the kernel for IA64 systems.
|
|
//
|
|
// On IA64, load the kernel first, then hal. This helps ensure
|
|
// the kernel will go at 48Mb.
|
|
// ===============
|
|
//
|
|
|
|
strcpy( KernelImage, KERNEL_MP_IMAGE_FILENAME );
|
|
SlGetDisk(KernelImage);
|
|
strcpy(KernelDirectoryPath, BootPath);
|
|
strcat(KernelDirectoryPath,KernelImage);
|
|
BlOutputLoadMessage(BootDevice, KernelDirectoryPath, BlFindMessage(SL_KERNEL_NAME));
|
|
Status = BlLoadImage(BootDeviceId,
|
|
LoaderSystemCode,
|
|
KernelDirectoryPath,
|
|
TARGET_IMAGE,
|
|
&SystemBase);
|
|
if (Status != ESUCCESS) {
|
|
SlFatalError(SL_FILE_LOAD_FAILED,SlCopyStringAT(KernelDirectoryPath),Status);
|
|
goto LoadFailed;
|
|
}
|
|
|
|
BlUpdateBootStatus();
|
|
|
|
|
|
#endif
|
|
|
|
|
|
//
|
|
// ===============
|
|
// Load the hal.
|
|
// ===============
|
|
//
|
|
|
|
|
|
strcpy(HalDirectoryPath, BootPath);
|
|
|
|
if (PromptOemHal || (PreInstall && (ComputerType != NULL))) {
|
|
if(PreInstall && OemHal) {
|
|
//
|
|
// This is a pre-install and an OEM hal was specified
|
|
//
|
|
strcat( HalDirectoryPath,
|
|
#if defined(_X86_) || defined(_IA64_)
|
|
WINNT_OEM_DIR_A
|
|
#else
|
|
WINNT_OEM_TEXTMODE_DIR_A
|
|
#endif
|
|
);
|
|
strcat( HalDirectoryPath, "\\" );
|
|
}
|
|
|
|
SlPromptOemHal((PreInstall ? PreInstallOemSourceDevice : DefaultOemSourceDevice),
|
|
(BOOLEAN) (!PreInstall || (ComputerType == NULL)),
|
|
&HalBase,
|
|
&HalName);
|
|
|
|
strcat(HalDirectoryPath,HalName);
|
|
|
|
//
|
|
// Reset the last disk tag for floopy boot
|
|
//
|
|
if (FloppyBoot) {
|
|
LastDiskTag = NULL;
|
|
}
|
|
} else {
|
|
strcat(HalDirectoryPath,HalName);
|
|
BlOutputLoadMessage(BootDevice, HalDirectoryPath, BlFindMessage(SL_HAL_NAME));
|
|
#ifdef i386
|
|
netbootretryhal:
|
|
#endif
|
|
Status = BlLoadImage(BootDeviceId,
|
|
LoaderHalCode,
|
|
HalDirectoryPath,
|
|
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 != 0) ||
|
|
(BlUsableLimit != _16MB))) {
|
|
BlUsableBase = 0;
|
|
BlUsableLimit = _16MB;
|
|
|
|
goto netbootretryhal;
|
|
}
|
|
#endif
|
|
if (Status != ESUCCESS) {
|
|
SlFatalError(SL_FILE_LOAD_FAILED,SlCopyStringAT(HalDirectoryPath),Status);
|
|
goto LoadFailed;
|
|
}
|
|
|
|
BlUpdateBootStatus();
|
|
}
|
|
|
|
|
|
#if !defined(_IA64_)
|
|
|
|
//
|
|
// ===============
|
|
// Load the kernel for non-IA64 systems.
|
|
//
|
|
// Load the kernel, loading ntoskrnl.exe or ntkrnlmp.exe based on
|
|
// whether the HAL is UP or MP. This is important for remote boot
|
|
// because the networking code's spin lock usage pattern requires
|
|
// the kernel and HAL to be matched.
|
|
//
|
|
// If the computer ID string ends in "_mp", load the MP kernel.
|
|
// Otherwise, load the UP kernel. The code is modeled after similar
|
|
// code in setup\textmode\kernel\sphw.c\SpInstallingMp().
|
|
//
|
|
// ===============
|
|
//
|
|
|
|
id = SetupBlock->ComputerDevice.IdString;
|
|
idLength = strlen(id);
|
|
|
|
//
|
|
// load ntkrnlmp always in MiniNT network boot
|
|
//
|
|
if (WinPEBoot || ((idLength >= 3) && (_stricmp(id+idLength-3,"_mp") == 0))) {
|
|
strcpy(KernelImage,KERNEL_MP_IMAGE_FILENAME);
|
|
} else {
|
|
strcpy(KernelImage,KERNEL_UP_IMAGE_FILENAME);
|
|
}
|
|
|
|
|
|
#if defined(REMOTE_BOOT)
|
|
#if DBG
|
|
if ((strlen(id) + 1) > sizeof(SetupBlock->NetBootHalName)) {
|
|
DbgPrint("The KERNEL name is too long!\n");
|
|
goto LoadFailed;
|
|
}
|
|
#endif
|
|
|
|
strcpy(SetupBlock->NetBootHalName, id);
|
|
#endif // defined(REMOTE_BOOT)
|
|
|
|
SlGetDisk(KernelImage);
|
|
|
|
strcpy(KernelDirectoryPath, BootPath);
|
|
strcat(KernelDirectoryPath,KernelImage);
|
|
BlOutputLoadMessage(BootDevice, KernelDirectoryPath, BlFindMessage(SL_KERNEL_NAME));
|
|
#ifdef i386
|
|
netbootretrykernel:
|
|
#endif
|
|
Status = BlLoadImage(BootDeviceId,
|
|
LoaderSystemCode,
|
|
KernelDirectoryPath,
|
|
TARGET_IMAGE,
|
|
&SystemBase);
|
|
if (Status != ESUCCESS) {
|
|
#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) {
|
|
if (BlUsableBase == BL_KERNEL_RANGE_LOW &&
|
|
BlUsableLimit == BL_KERNEL_RANGE_HIGH) {
|
|
//
|
|
// first we try all of memory below 16MB
|
|
//
|
|
BlUsableBase = 0;
|
|
BlUsableLimit = _16MB;
|
|
goto netbootretrykernel;
|
|
} else if (BlUsableBase == 0 &&
|
|
BlUsableLimit == _16MB) {
|
|
//
|
|
// then we try all of memory above 16MB
|
|
//
|
|
BlUsableBase = _16MB;
|
|
BlUsableLimit = BL_DRIVER_RANGE_HIGH;
|
|
goto netbootretrykernel;
|
|
}
|
|
}
|
|
#endif
|
|
SlFatalError(SL_FILE_LOAD_FAILED,SlCopyStringAT(KernelDirectoryPath),Status);
|
|
goto LoadFailed;
|
|
}
|
|
|
|
BlUpdateBootStatus();
|
|
|
|
|
|
#endif // if !defined(_IA64_)
|
|
|
|
//
|
|
// Set allocatable range to the driver-specific range
|
|
//
|
|
BlUsableBase = BL_DRIVER_RANGE_LOW;
|
|
BlUsableLimit = BL_DRIVER_RANGE_HIGH;
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Load Kernel Debugger DLL
|
|
//
|
|
|
|
strcpy(KdDllName, BootPath);
|
|
strcat(KdDllName, KdFileName);
|
|
SlGetDisk(KdFileName);
|
|
BlOutputLoadMessage(BootDevice, KdDllName, BlFindMessage(SL_KDDLL_NAME));
|
|
Status = BlLoadImage(BootDeviceId,
|
|
LoaderHalCode,
|
|
KdDllName,
|
|
TARGET_IMAGE,
|
|
&KdDllBase);
|
|
|
|
if ((Status != ESUCCESS) && (UseAlternateKdDll == TRUE)) {
|
|
UseAlternateKdDll = FALSE;
|
|
|
|
strcpy(KdDllName, BootPath);
|
|
strcpy(KdFileName, "KDCOM.DLL");
|
|
strcat(KdDllName, KdFileName);
|
|
|
|
Status = BlLoadImage(BootDeviceId,
|
|
LoaderHalCode,
|
|
KdDllName,
|
|
TARGET_IMAGE,
|
|
&KdDllBase);
|
|
}
|
|
|
|
if (Status != ESUCCESS) {
|
|
SlFatalError(SL_FILE_LOAD_FAILED, SlCopyStringAT(KdDllName), Status);
|
|
goto LoadFailed;
|
|
}
|
|
|
|
//
|
|
// Generate a loader data entry for the system image.
|
|
//
|
|
|
|
Status = BlAllocateDataTableEntry("ntoskrnl.exe",
|
|
KernelDirectoryPath,
|
|
SystemBase,
|
|
&SystemDataTableEntry);
|
|
|
|
if (Status != ESUCCESS) {
|
|
SlFatalError(SL_FILE_LOAD_FAILED,SlCopyStringAT(KernelDirectoryPath),Status);
|
|
goto LoadFailed;
|
|
}
|
|
|
|
//
|
|
// Generate a loader data entry for the HAL DLL.
|
|
//
|
|
|
|
Status = BlAllocateDataTableEntry("hal.dll",
|
|
HalDirectoryPath,
|
|
HalBase,
|
|
&HalDataTableEntry);
|
|
|
|
if (Status != ESUCCESS) {
|
|
SlFatalError(SL_FILE_LOAD_FAILED,SlCopyStringAT(HalDirectoryPath),Status);
|
|
goto LoadFailed;
|
|
}
|
|
|
|
//
|
|
// Generate a loader data entry for the Kernel Debugger DLL.
|
|
//
|
|
|
|
Status = BlAllocateDataTableEntry("kdcom.dll",
|
|
KdDllName,
|
|
KdDllBase,
|
|
&KdDataTableEntry);
|
|
|
|
if (Status != ESUCCESS) {
|
|
SlFatalError(SL_FILE_LOAD_FAILED, SlCopyStringAT(KdDllName), Status);
|
|
goto LoadFailed;
|
|
}
|
|
|
|
PathSet.PathCount = 1;
|
|
PathSet.AliasName = "\\SystemRoot";
|
|
PathSet.PathOffset[0] = '\0';
|
|
PathSet.Source[0].DeviceId = BootDeviceId;
|
|
PathSet.Source[0].DeviceName = BootDevice;
|
|
PathSet.Source[0].DirectoryPath = BootPath;
|
|
|
|
Status = BlScanImportDescriptorTable(&PathSet,
|
|
SystemDataTableEntry,
|
|
LoaderSystemCode
|
|
);
|
|
|
|
if (Status != ESUCCESS) {
|
|
SlFatalError(SL_FILE_LOAD_FAILED,SlCopyStringAT(KernelImage),Status);
|
|
}
|
|
|
|
//
|
|
// Scan the import table for the HAL DLL and load all referenced DLLs.
|
|
//
|
|
|
|
Status = BlScanImportDescriptorTable(&PathSet,
|
|
HalDataTableEntry,
|
|
LoaderHalCode);
|
|
|
|
if (Status != ESUCCESS) {
|
|
SlFatalError(SL_FILE_LOAD_FAILED,SlCopyStringAT("hal.dll"),Status);
|
|
goto LoadFailed;
|
|
}
|
|
|
|
//
|
|
// Scan the import table for the Kernel Debugger DLL and load all
|
|
// referenced DLLs.
|
|
//
|
|
|
|
Status = BlScanImportDescriptorTable(&PathSet,
|
|
KdDataTableEntry,
|
|
LoaderSystemCode);
|
|
|
|
|
|
if (Status != ESUCCESS) {
|
|
SlFatalError(SL_FILE_LOAD_FAILED, SlCopyStringAT(KdFileName), Status);
|
|
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
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// On x86, the files loaded from now on are on boot floppy #2
|
|
//
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
// Load registry's SYSTEM hive
|
|
//
|
|
|
|
SlGetDisk("SETUPREG.HIV");
|
|
Status = BlLoadSystemHive(BootDeviceId,
|
|
NULL, // BlFindMessage(SL_HIVE_NAME), UNREFERENCED_PARAMETER
|
|
BootPath,
|
|
"SETUPREG.HIV");
|
|
|
|
if (Status != ESUCCESS) {
|
|
SlFatalError(SL_FILE_LOAD_FAILED,SlCopyStringAT("SETUPREG.HIV"),Status);
|
|
goto LoadFailed;
|
|
}
|
|
|
|
//
|
|
// Pull the Docking information from the hardware tree.
|
|
//
|
|
|
|
dockInfoData = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
|
|
PeripheralClass,
|
|
DockingInformation,
|
|
NULL);
|
|
|
|
if (NULL == dockInfoData) {
|
|
BlLoaderBlock->Extension->Profile.Status = HW_PROFILE_STATUS_SUCCESS;
|
|
BlLoaderBlock->Extension->Profile.DockingState = HW_PROFILE_DOCKSTATE_UNKNOWN;
|
|
BlLoaderBlock->Extension->Profile.Capabilities = 0;
|
|
BlLoaderBlock->Extension->Profile.DockID = 0;
|
|
BlLoaderBlock->Extension->Profile.SerialNumber = 0;
|
|
|
|
} else if (sizeof (dockInfo) <=
|
|
dockInfoData->ComponentEntry.ConfigurationDataLength) {
|
|
|
|
RtlCopyMemory (
|
|
&dockInfo,
|
|
(PUCHAR) (dockInfoData->ConfigurationData) + sizeof(CM_PARTIAL_RESOURCE_LIST),
|
|
sizeof (dockInfo));
|
|
|
|
BlLoaderBlock->Extension->Profile.Status = HW_PROFILE_STATUS_FAILURE;
|
|
|
|
switch (dockInfo.ReturnCode) {
|
|
case FW_DOCKINFO_SUCCESS:
|
|
BlLoaderBlock->Extension->Profile.Status = HW_PROFILE_STATUS_SUCCESS;
|
|
BlLoaderBlock->Extension->Profile.DockingState = HW_PROFILE_DOCKSTATE_DOCKED;
|
|
BlLoaderBlock->Extension->Profile.Capabilities = dockInfo.Capabilities;
|
|
BlLoaderBlock->Extension->Profile.DockID = dockInfo.DockID;
|
|
BlLoaderBlock->Extension->Profile.SerialNumber = dockInfo.SerialNumber;
|
|
break;
|
|
|
|
case FW_DOCKINFO_SYSTEM_NOT_DOCKED:
|
|
BlLoaderBlock->Extension->Profile.Status = HW_PROFILE_STATUS_SUCCESS;
|
|
BlLoaderBlock->Extension->Profile.DockingState = HW_PROFILE_DOCKSTATE_UNDOCKED;
|
|
BlLoaderBlock->Extension->Profile.Capabilities = dockInfo.Capabilities;
|
|
BlLoaderBlock->Extension->Profile.DockID = dockInfo.DockID;
|
|
BlLoaderBlock->Extension->Profile.SerialNumber = dockInfo.SerialNumber;
|
|
break;
|
|
|
|
case FW_DOCKINFO_DOCK_STATE_UNKNOWN:
|
|
BlLoaderBlock->Extension->Profile.Status = HW_PROFILE_STATUS_SUCCESS;
|
|
BlLoaderBlock->Extension->Profile.DockingState = HW_PROFILE_DOCKSTATE_UNKNOWN;
|
|
BlLoaderBlock->Extension->Profile.Capabilities = dockInfo.Capabilities;
|
|
BlLoaderBlock->Extension->Profile.DockID = dockInfo.DockID;
|
|
BlLoaderBlock->Extension->Profile.SerialNumber = dockInfo.SerialNumber;
|
|
break;
|
|
|
|
case FW_DOCKINFO_FUNCTION_NOT_SUPPORTED:
|
|
case FW_DOCKINFO_BIOS_NOT_CALLED:
|
|
BlLoaderBlock->Extension->Profile.Status = HW_PROFILE_STATUS_SUCCESS;
|
|
default:
|
|
BlLoaderBlock->Extension->Profile.DockingState = HW_PROFILE_DOCKSTATE_UNSUPPORTED;
|
|
BlLoaderBlock->Extension->Profile.Capabilities = dockInfo.Capabilities;
|
|
BlLoaderBlock->Extension->Profile.DockID = dockInfo.DockID;
|
|
BlLoaderBlock->Extension->Profile.SerialNumber = dockInfo.SerialNumber;
|
|
break;
|
|
}
|
|
|
|
} else {
|
|
BlLoaderBlock->Extension->Profile.Status = HW_PROFILE_STATUS_SUCCESS;
|
|
BlLoaderBlock->Extension->Profile.Capabilities = 0;
|
|
BlLoaderBlock->Extension->Profile.DockID = 0;
|
|
BlLoaderBlock->Extension->Profile.SerialNumber = 0;
|
|
}
|
|
|
|
if (BlLoaderBlock->Extension->Profile.Status == HW_PROFILE_STATUS_SUCCESS) {
|
|
//
|
|
// We don't match profiles in textmode setup so just pretend that we did.
|
|
//
|
|
BlLoaderBlock->Extension->Profile.Status = HW_PROFILE_STATUS_TRUE_MATCH;
|
|
}
|
|
|
|
//
|
|
// Allocate structure for NLS data.
|
|
//
|
|
|
|
BlLoaderBlock->NlsData = BlAllocateHeap(sizeof(NLS_DATA_BLOCK));
|
|
if (BlLoaderBlock->NlsData == NULL) {
|
|
Status = ENOMEM;
|
|
SlNoMemoryError();
|
|
goto LoadFailed;
|
|
}
|
|
|
|
//
|
|
// Load the OEM font
|
|
//
|
|
|
|
SlGetDisk(OemHalFontName);
|
|
Status = BlLoadOemHalFont(BootDeviceId,
|
|
NULL, // BlFindMessage(SL_OEM_FONT_NAME), UNREFERENCED_PARAMETER
|
|
BootPath,
|
|
&OemHalFont,
|
|
BadFileName);
|
|
|
|
if(Status != ESUCCESS) {
|
|
SlFatalError(SL_FILE_LOAD_FAILED, SlCopyStringAT(BadFileName), Status);
|
|
goto LoadFailed;
|
|
}
|
|
|
|
//
|
|
// Load the NLS data.
|
|
//
|
|
// For now, we ensure that the disk containing the ansi
|
|
// codepage file is in the drive and hope that the rest of the
|
|
// nls files (oem codepage, unicode table) are on the same disk.
|
|
//
|
|
|
|
SlGetDisk(AnsiCpName);
|
|
Status = BlLoadNLSData(BootDeviceId,
|
|
NULL, // BlFindMessage(SL_NLS_NAME), UNREFERENCED_PARAMETER
|
|
BootPath,
|
|
&AnsiCodepage,
|
|
&OemCodepage,
|
|
&UnicodeCaseTable,
|
|
BadFileName);
|
|
|
|
if(Status != ESUCCESS) {
|
|
SlFatalError(SL_FILE_LOAD_FAILED, SlCopyStringAT(BadFileName), Status);
|
|
goto LoadFailed;
|
|
}
|
|
|
|
//
|
|
// Load the system drivers we will need here
|
|
//
|
|
|
|
InitializeListHead(&BlLoaderBlock->BootDriverListHead);
|
|
|
|
//
|
|
// Load setupdd.sys next. Setupdd.sys needs to be loaded before any other
|
|
// driver, because it will need to prep the rest of the system.
|
|
//
|
|
Status = SlLoadDriver(BlFindMessage(SL_SETUP_NAME),
|
|
"setupdd.sys",
|
|
0,
|
|
TRUE,
|
|
FALSE,
|
|
NULL
|
|
);
|
|
|
|
if (Status != ESUCCESS) {
|
|
SlFatalError(SL_FILE_LOAD_FAILED,SlCopyStringAT("setupdd.sys"),Status);
|
|
goto LoadFailed;
|
|
}
|
|
|
|
//
|
|
// Fill in its registry key -- setupdd fills these in for all the other
|
|
// drivers (unless we do it here), but we have to do it here for setupdd
|
|
// itself.
|
|
//
|
|
|
|
DriverEntry = (PBOOT_DRIVER_LIST_ENTRY)(BlLoaderBlock->BootDriverListHead.Flink);
|
|
DriverEntry->RegistryPath.Buffer = BlAllocateHeap(256);
|
|
if (DriverEntry->RegistryPath.Buffer == NULL) {
|
|
SlNoMemoryError();
|
|
goto LoadFailed;
|
|
}
|
|
|
|
DriverEntry->RegistryPath.Length = 0;
|
|
DriverEntry->RegistryPath.MaximumLength = 256;
|
|
RtlAppendUnicodeToString(&DriverEntry->RegistryPath,
|
|
L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\setupdd");
|
|
|
|
#if 0
|
|
#ifdef i386
|
|
//
|
|
// Note that if pciide.sys, intelide.sys and pciidex.sys are on the same
|
|
// boot floppy (x86 only), then we don't need to load pciidex.sys.
|
|
// The driver will be automatically loaded when pciide.sys or intelide.sys
|
|
// (both listed on [BusExtenders.Load] is loaded.
|
|
//
|
|
Status = SlLoadDriver(BlFindMessage(SL_PCI_IDE_EXTENSIONS_NAME),
|
|
"PCIIDEX.SYS",
|
|
0,
|
|
FALSE,
|
|
FALSE,
|
|
NULL
|
|
);
|
|
#endif
|
|
#endif
|
|
|
|
//
|
|
// Load boot bus extenders.
|
|
// It has to be done before scsiport.sys
|
|
//
|
|
|
|
Status = SlLoadPnpDriversSection( InfFile,
|
|
"BootBusExtenders",
|
|
&(SetupBlock->BootBusExtenders) );
|
|
if (Status!=ESUCCESS) {
|
|
goto LoadFailed;
|
|
}
|
|
|
|
//
|
|
// Load bus extenders.
|
|
// It has to be done before scsiport.sys
|
|
//
|
|
|
|
Status = SlLoadPnpDriversSection( InfFile,
|
|
"BusExtenders",
|
|
&(SetupBlock->BusExtenders) );
|
|
if (Status!=ESUCCESS) {
|
|
goto LoadFailed;
|
|
}
|
|
|
|
//
|
|
// Load input device related drivers.
|
|
//
|
|
|
|
Status = SlLoadPnpDriversSection( InfFile,
|
|
"InputDevicesSupport",
|
|
&(SetupBlock->InputDevicesSupport) );
|
|
if (Status!=ESUCCESS) {
|
|
goto LoadFailed;
|
|
}
|
|
|
|
//
|
|
// Detect video
|
|
//
|
|
|
|
SlDetectVideo(SetupBlock);
|
|
|
|
//
|
|
// On x86, the video type is always set to VGA in i386\x86dtect.c.
|
|
// On non-x86, the video type is either recognized, in which case
|
|
// we don't unconditionally need vga.sys (the Display.Load section
|
|
// tells us what to load), or it's not recognized,
|
|
// in which case we will prompt the user for an oem disk.
|
|
// If there is no display controller node at all, then PromptOemDisk
|
|
// will be false and there will be no video device. In this case
|
|
// we load vga.sys.
|
|
//
|
|
|
|
if (SetupBlock->VideoDevice.IdString != NULL) {
|
|
VideoFileName = SlGetSectionKeyIndex(InfFile,
|
|
"Display.Load",
|
|
SetupBlock->VideoDevice.IdString,
|
|
SIF_FILENAME_INDEX);
|
|
if (VideoFileName != NULL) {
|
|
#ifdef ARCI386
|
|
VideoDescription = SlGetIniValue(InfFile,
|
|
"Display",
|
|
SetupBlock->VideoDevice.IdString,
|
|
BlFindMessage(SL_VIDEO_NAME));
|
|
#else
|
|
//
|
|
// With the new video detection mechanism, the description
|
|
// for the video driver is likely to be something like
|
|
// "Windows NT Compatible" which looks funny when displayed
|
|
// in the status bar.
|
|
//
|
|
VideoDescription = BlFindMessage(SL_VIDEO_NAME);
|
|
#endif
|
|
if (!WinPEBoot) {
|
|
Status = SlLoadDriver(VideoDescription,
|
|
VideoFileName,
|
|
0,
|
|
TRUE,
|
|
FALSE,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
if (Status == ESUCCESS) {
|
|
SetupBlock->VideoDevice.BaseDllName = SlCopyStringA(VideoFileName);
|
|
|
|
} else {
|
|
SlFriendlyError(
|
|
Status,
|
|
VideoFileName,
|
|
__LINE__,
|
|
__FILE__
|
|
);
|
|
goto LoadFailed;
|
|
}
|
|
|
|
LoadedAVideoDriver = TRUE;
|
|
}
|
|
} else if (PromptOemVideo) {
|
|
|
|
SlPromptOemVideo(DefaultOemSourceDevice,
|
|
TRUE,
|
|
&VideoBase,
|
|
&OemVideoName);
|
|
|
|
Status = SlLoadOemDriver(
|
|
"VIDEOPRT.SYS",
|
|
OemVideoName,
|
|
VideoBase,
|
|
BlFindMessage(SL_VIDEO_NAME)
|
|
);
|
|
|
|
if(Status==ESUCCESS) {
|
|
|
|
LoadedAVideoDriver = TRUE;
|
|
SetupBlock->VideoDevice.BaseDllName = SlCopyStringA(OemVideoName);
|
|
}
|
|
|
|
//
|
|
// Reset the last disk tag for floopy boot
|
|
//
|
|
if (FloppyBoot) {
|
|
LastDiskTag = NULL;
|
|
}
|
|
}
|
|
|
|
if(!LoadedAVideoDriver) {
|
|
Status = SlLoadDriver(BlFindMessage(SL_VIDEO_NAME),
|
|
VGA_DRIVER_FILENAME,
|
|
0,
|
|
TRUE,
|
|
FALSE,
|
|
NULL
|
|
);
|
|
if(Status == ESUCCESS) {
|
|
SetupBlock->VideoDevice.BaseDllName = SlCopyStringA(VGA_DRIVER_FILENAME);
|
|
} else {
|
|
SlFriendlyError(
|
|
Status,
|
|
VGA_DRIVER_FILENAME,
|
|
__LINE__,
|
|
__FILE__
|
|
);
|
|
goto LoadFailed;
|
|
}
|
|
}
|
|
|
|
if(SetupBlock->VideoDevice.IdString == NULL) {
|
|
SetupBlock->VideoDevice.IdString = SlCopyStringA(VIDEO_DEVICE_NAME);
|
|
}
|
|
|
|
//
|
|
// Load keyboard drivers.
|
|
//
|
|
|
|
Status = SlLoadPnpDriversSection( InfFile,
|
|
"Keyboard",
|
|
&(SetupBlock->KeyboardDevices) );
|
|
if (Status!=ESUCCESS) {
|
|
goto LoadFailed;
|
|
}
|
|
|
|
|
|
Status = SlLoadDriver(BlFindMessage(SL_KBD_NAME),
|
|
"kbdclass.sys",
|
|
0,
|
|
TRUE,
|
|
FALSE,
|
|
NULL
|
|
);
|
|
if(Status != ESUCCESS) {
|
|
SlFriendlyError(
|
|
Status,
|
|
"kbdclass.sys",
|
|
__LINE__,
|
|
__FILE__
|
|
);
|
|
goto LoadFailed;
|
|
}
|
|
|
|
//
|
|
// We would need mouse support also in minint environment
|
|
//
|
|
|
|
if (WinPEBoot) {
|
|
Status = SlLoadSection(InfFile,
|
|
"MouseDrivers",
|
|
FALSE,
|
|
TRUE,
|
|
NULL);
|
|
|
|
if(Status != ESUCCESS) {
|
|
SlFriendlyError(
|
|
Status,
|
|
"MouseDrivers",
|
|
__LINE__,
|
|
__FILE__
|
|
);
|
|
|
|
goto LoadFailed;
|
|
}
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// On x86, the files loaded from now on are on boot floppy #3
|
|
//
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
// Load scsiport.sys next, so it'll always be around for any scsi miniports we may load
|
|
//
|
|
|
|
Status = SlLoadDriver(BlFindMessage(SL_SCSIPORT_NAME),
|
|
"SCSIPORT.SYS",
|
|
0,
|
|
FALSE,
|
|
FALSE,
|
|
NULL
|
|
);
|
|
|
|
|
|
//
|
|
// Detect scsi
|
|
//
|
|
// (If the user wants to select their own SCSI devices, we won't
|
|
// do any detection)
|
|
//
|
|
|
|
if(!PromptOemScsi && (PreinstallDriverList == NULL) ) {
|
|
SlDetectScsi(SetupBlock);
|
|
#if defined(_X86_) || defined(_IA64_)
|
|
if( Win9xUnsupHdc ) {
|
|
//
|
|
// If this is a Win9x upgrade and winnt32 detected an unsupported
|
|
// SCSI controller, then the user needs to be prompted for an OEM SCSI driver
|
|
//
|
|
PromptOemScsi = TRUE;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#if defined(ELTORITO) && !defined(ARCI386)
|
|
//
|
|
// If this is an El Torito CD-ROM install, then we want to load all SCSI miniports
|
|
// and disk class drivers.
|
|
// BUT we do not want to load all the disk class drivers for an ARC
|
|
// machine which knows what drivers it wants to install from its tree
|
|
//
|
|
if(ElToritoCDBoot) {
|
|
LoadScsiMiniports = TRUE;
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// If the LoadScsi flag is set, enumerate all the known SCSI miniports and load each
|
|
// one.
|
|
//
|
|
if(LoadScsiMiniports && (PreinstallDriverList == NULL)) {
|
|
if (WinPEBoot && OemInfHandle) {
|
|
Status = SlLoadWinPESection(PreInstallOemSourceDevice,
|
|
OemInfHandle,
|
|
WINNT_OEMSCSIDRIVERS_A,
|
|
InfFile,
|
|
"Scsi",
|
|
TRUE,
|
|
&OemScsiInfo,
|
|
&BlLoaderBlock->SetupLoaderBlock->HardwareIdDatabase);
|
|
} else {
|
|
Status = SlLoadSection(InfFile,"Scsi",TRUE, TRUE, NULL);
|
|
}
|
|
|
|
if (Status!=ESUCCESS) {
|
|
goto LoadFailed;
|
|
}
|
|
|
|
SetupBlock->ScalarValues.LoadedScsi = 1;
|
|
}
|
|
|
|
//
|
|
// Pick the the dynamic update boot drivers, if any
|
|
//
|
|
|
|
if (DynamicUpdate) {
|
|
SlLoadOemScsiDriversUnattended(DynamicUpdateSourceDevice,
|
|
WinntSifHandle,
|
|
WINNT_SETUPPARAMS_A,
|
|
WINNT_SP_DYNUPDTBOOTDRIVERROOT_A,
|
|
WINNT_SP_DYNUPDTBOOTDRIVERS_A,
|
|
&OemScsiInfo,
|
|
&BlLoaderBlock->SetupLoaderBlock->HardwareIdDatabase);
|
|
}
|
|
|
|
//
|
|
// Allow the user to pick an OEM SCSI driver here
|
|
//
|
|
|
|
if (PromptOemScsi || (PreinstallDriverList != NULL)) {
|
|
POEMSCSIINFO DynUpdtScsiInfo = OemScsiInfo;
|
|
|
|
SlPromptOemScsi(((PreinstallDriverList == NULL) ?
|
|
DefaultOemSourceDevice : PreInstallOemSourceDevice),
|
|
(BOOLEAN) (!PreInstall || (PreinstallDriverList == NULL)),
|
|
&OemScsiInfo);
|
|
|
|
//
|
|
// Mark the default OEM source device as processed,
|
|
// if the user manually pressed F6
|
|
//
|
|
if (PromptOemScsi && DefaultOemSourceDevice) {
|
|
SL_OEM_SET_SOURCE_DEVICE_STATE(DefaultOemSourceDevice,
|
|
SL_OEM_SOURCE_DEVICE_PROCESSED);
|
|
}
|
|
|
|
//
|
|
// Reset the last disk tag for floopy boot
|
|
//
|
|
if (FloppyBoot) {
|
|
LastDiskTag = NULL;
|
|
}
|
|
|
|
//
|
|
// Merge the dynamic update SCSI driver list with oem SCSI
|
|
// driver list
|
|
//
|
|
if (DynUpdtScsiInfo) {
|
|
if (OemScsiInfo) {
|
|
POEMSCSIINFO CurrNode = DynUpdtScsiInfo;
|
|
|
|
while (CurrNode && CurrNode->Next) {
|
|
CurrNode = CurrNode->Next;
|
|
}
|
|
|
|
if (CurrNode) {
|
|
CurrNode->Next = OemScsiInfo;
|
|
OemScsiInfo = DynUpdtScsiInfo;
|
|
}
|
|
} else {
|
|
OemScsiInfo = DynUpdtScsiInfo;
|
|
}
|
|
}
|
|
|
|
// Cleanup here needed for all installation - ARCI386
|
|
if (UseRegularBackground) {
|
|
SlClearDisplay();
|
|
|
|
if (WinPEBoot) {
|
|
StartupMsg ? BlOutputStartupMsgStr(StartupMsg) :
|
|
BlOutputStartupMsg(SL_SETUP_STARTING_WINPE);
|
|
} else {
|
|
if (UseCommandConsole) {
|
|
BlOutputStartupMsg(SL_CMDCONS_STARTING);
|
|
} else if (g_RollbackEnabled) {
|
|
BlOutputStartupMsg(SL_ROLLBACK_STARTING);
|
|
} else {
|
|
BlOutputStartupMsg(SL_SETUP_STARTING);
|
|
}
|
|
}
|
|
|
|
BlRedrawProgressBar();
|
|
} else {
|
|
SlClearClientArea();
|
|
SlWriteStatusText(TEXT(""));
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we found any valid txtsetup.oem with valid default MSD
|
|
// in any OEM source device which is not yet processed, then
|
|
// go and autoload the drivers from these devices.
|
|
//
|
|
|
|
if (OemSourceDevices && AutoLoadOemScsi) {
|
|
POEMSCSIINFO DeviceOemScsiInfo = NULL;
|
|
POEMSCSIINFO LastOemScsiNode = NULL;
|
|
|
|
//
|
|
// Determine if we need to disable the Virtual OEM devices.
|
|
// Disable OEM virtual Devices if we have been instructed by F4 in
|
|
// attended install, using the DisableOemVirtualDevices key in the unattend
|
|
// file or if Preinstall.
|
|
//
|
|
if (SlIsVirtualOemDeviceDisabled(WinntSifHandle,
|
|
PreinstallDriverList)) {
|
|
SlDisableVirtualOemDevices(OemSourceDevices);
|
|
}
|
|
SlLoadOemScsiDriversFromOemSources(OemSourceDevices,
|
|
&BlLoaderBlock->SetupLoaderBlock->HardwareIdDatabase,
|
|
&DeviceOemScsiInfo);
|
|
|
|
//
|
|
// Merge the full OEM source device list with the
|
|
// global OEM scsi information
|
|
//
|
|
if (DeviceOemScsiInfo) {
|
|
if (OemScsiInfo) {
|
|
LastOemScsiNode = OemScsiInfo;
|
|
|
|
while (LastOemScsiNode->Next) {
|
|
LastOemScsiNode = LastOemScsiNode->Next;
|
|
}
|
|
|
|
LastOemScsiNode->Next = DeviceOemScsiInfo;
|
|
} else {
|
|
OemScsiInfo = DeviceOemScsiInfo;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Load all the disk images for the virtual devices
|
|
// into memory
|
|
//
|
|
|
|
if (OemSourceDevices) {
|
|
Status = SlInitVirtualOemSourceDevices(BlLoaderBlock->SetupLoaderBlock,
|
|
OemSourceDevices);
|
|
|
|
if (Status != ESUCCESS) {
|
|
SlFatalError(SL_OEM_FILE_LOAD_FAILED);
|
|
|
|
goto LoadFailed;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Add unsupported SCSI drivers, if any, to the list
|
|
//
|
|
|
|
if( UnsupDriversInfHandle != NULL ) {
|
|
Status = SlDetectMigratedScsiDrivers( UnsupDriversInfHandle );
|
|
if (Status!=ESUCCESS) {
|
|
goto LoadFailed;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Walk the list of detected SCSI miniports and load each one.
|
|
//
|
|
|
|
ScsiDevice = SetupBlock->ScsiDevices;
|
|
while (ScsiDevice != NULL) {
|
|
|
|
if(ScsiDevice->ThirdPartyOptionSelected) {
|
|
|
|
if(!OemScsiInfo) {
|
|
SlError(500);
|
|
goto LoadFailed;
|
|
}
|
|
|
|
Status = SlLoadOemDriver(
|
|
NULL,
|
|
OemScsiInfo->ScsiName,
|
|
OemScsiInfo->ScsiBase,
|
|
BlFindMessage(SL_SCSIPORT_NAME)
|
|
);
|
|
OemScsiInfo = OemScsiInfo->Next;
|
|
} else if(ScsiDevice->MigratedDriver) {
|
|
Status = SlLoadDriver(ScsiDevice->Description,
|
|
ScsiDevice->BaseDllName,
|
|
0,
|
|
TRUE,
|
|
TRUE,
|
|
ScsiDevice->IdString
|
|
);
|
|
if( Status != ESUCCESS ) {
|
|
// DebugOutput("Status = %d %s \n",Status,"");
|
|
}
|
|
} else {
|
|
Status = SlLoadDriver(ScsiDevice->Description,
|
|
ScsiDevice->BaseDllName,
|
|
0,
|
|
TRUE,
|
|
FALSE,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
if((Status == ESUCCESS)
|
|
|| ((Status == ENOENT) && IgnoreMissingFiles && !ScsiDevice->ThirdPartyOptionSelected)) {
|
|
|
|
SetupBlock->ScalarValues.LoadedScsi = 1;
|
|
|
|
} else {
|
|
SlFriendlyError(
|
|
Status,
|
|
ScsiDevice->BaseDllName,
|
|
__LINE__,
|
|
__FILE__
|
|
);
|
|
goto LoadFailed;
|
|
}
|
|
|
|
ScsiDevice = ScsiDevice->Next;
|
|
}
|
|
|
|
//
|
|
// If the LoadDiskClass flag is set, enumerate all the monolithic disk class drivers
|
|
// and load each one. Note that we also do this if we've "detected" any scsi drivers,
|
|
// so that we preserve the drive order.
|
|
//
|
|
|
|
if((LoadDiskClass) || (SetupBlock->ScalarValues.LoadedScsi == 1)) {
|
|
Status = SlLoadSection(InfFile, "DiskDrivers", FALSE, TRUE, NULL);
|
|
if (Status == ESUCCESS) {
|
|
SetupBlock->ScalarValues.LoadedDiskDrivers = 1;
|
|
} else {
|
|
goto LoadFailed;
|
|
}
|
|
}
|
|
|
|
|
|
#if !defined(_IA64_)
|
|
//
|
|
// There is currently no floppy support on IA64 systems.
|
|
//
|
|
|
|
//
|
|
// Load the floppy driver (flpydisk.sys)
|
|
//
|
|
#if !defined (ARCI386) && defined(_X86_)
|
|
Status=ESUCCESS;
|
|
|
|
//
|
|
// If there are only SFLOPPY devices (such as the LS-120 ATAPI super floppy)
|
|
// DON'T load flpydisk.sys on them. It will collide with SFLOPPY.SYS
|
|
//
|
|
if (!SlpIsOnlySuperFloppy()) {
|
|
#endif
|
|
Status = SlLoadDriver(BlFindMessage(SL_FLOPPY_NAME),
|
|
"flpydisk.sys",
|
|
0,
|
|
TRUE,
|
|
FALSE,
|
|
NULL
|
|
);
|
|
#if !defined (ARCI386) && defined(_X86_)
|
|
}
|
|
#endif
|
|
if (Status == ESUCCESS) {
|
|
SetupBlock->ScalarValues.LoadedFloppyDrivers = 1;
|
|
}
|
|
#endif
|
|
#ifdef i386
|
|
else {
|
|
SlFriendlyError(
|
|
Status,
|
|
"flpydisk.sys",
|
|
__LINE__,
|
|
__FILE__
|
|
);
|
|
goto LoadFailed;
|
|
}
|
|
#endif
|
|
|
|
if(SetupBlock->ScalarValues.LoadedScsi == 1) {
|
|
//
|
|
// Enumerate the entries in the scsi class section and load each one.
|
|
//
|
|
Status = SlLoadSection(InfFile, "ScsiClass",FALSE, TRUE, NULL);
|
|
if (Status != ESUCCESS) {
|
|
goto LoadFailed;
|
|
}
|
|
}
|
|
|
|
if((LoadDiskClass) || (SetupBlock->ScalarValues.LoadedScsi == 1)) {
|
|
Status = SlLoadSection(InfFile, "FileSystems", FALSE, TRUE, NULL);
|
|
if (Status == ESUCCESS) {
|
|
SetupBlock->ScalarValues.LoadedFileSystems = 1;
|
|
} else {
|
|
goto LoadFailed;
|
|
}
|
|
} else {
|
|
|
|
//
|
|
// Load FAT
|
|
//
|
|
Status = SlLoadDriver(BlFindMessage(SL_FAT_NAME),
|
|
"fastfat.sys",
|
|
0,
|
|
TRUE,
|
|
FALSE,
|
|
NULL
|
|
);
|
|
#ifdef i386
|
|
if(Status != ESUCCESS) {
|
|
SlFriendlyError(
|
|
Status,
|
|
"fastfat.sys",
|
|
__LINE__,
|
|
__FILE__
|
|
);
|
|
goto LoadFailed;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// Load CDFS if setupldr was started from a cdrom, or if ForceLoadCdfs is set.
|
|
//
|
|
|
|
if (LoadCdfs || (!BlGetPathMnemonicKey(SetupDevice,
|
|
"cdrom",
|
|
&BootDriveNumber))) {
|
|
Status = SlLoadSection(InfFile, "CdRomDrivers",FALSE, TRUE, NULL);
|
|
if (Status == ESUCCESS) {
|
|
SetupBlock->ScalarValues.LoadedCdRomDrivers = 1;
|
|
} else {
|
|
goto LoadFailed;
|
|
}
|
|
}
|
|
|
|
if (BlBootingFromNet || WinPEBoot) {
|
|
|
|
//
|
|
// Load the network stack.
|
|
//
|
|
|
|
Status = SlLoadDriver(BlFindMessage(SL_KSECDD_NAME),
|
|
"ksecdd.sys",
|
|
0,
|
|
TRUE,
|
|
FALSE,
|
|
NULL
|
|
);
|
|
if(Status != ESUCCESS) {
|
|
SlFriendlyError(
|
|
Status,
|
|
"ksecdd.sys",
|
|
__LINE__,
|
|
__FILE__
|
|
);
|
|
goto LoadFailed;
|
|
|
|
}
|
|
|
|
Status = SlLoadDriver(BlFindMessage(SL_NDIS_NAME),
|
|
"ndis.sys",
|
|
0,
|
|
TRUE,
|
|
FALSE,
|
|
NULL
|
|
);
|
|
if(Status != ESUCCESS) {
|
|
SlFriendlyError(
|
|
Status,
|
|
"ndis.sys",
|
|
__LINE__,
|
|
__FILE__
|
|
);
|
|
goto LoadFailed;
|
|
|
|
}
|
|
|
|
if (BlBootingFromNet) {
|
|
|
|
Status = SlLoadDriver(BlFindMessage(SL_IPSEC_NAME),
|
|
"ipsec.sys",
|
|
0,
|
|
TRUE,
|
|
FALSE,
|
|
NULL
|
|
);
|
|
if(Status != ESUCCESS) {
|
|
SlFriendlyError(
|
|
Status,
|
|
"ipsec.sys",
|
|
__LINE__,
|
|
__FILE__
|
|
);
|
|
goto LoadFailed;
|
|
}
|
|
|
|
Status = SlLoadDriver(BlFindMessage(SL_TCPIP_NAME),
|
|
"tcpip.sys",
|
|
0,
|
|
TRUE,
|
|
FALSE,
|
|
NULL
|
|
);
|
|
if(Status != ESUCCESS) {
|
|
SlFriendlyError(
|
|
Status,
|
|
"tcpip.sys",
|
|
__LINE__,
|
|
__FILE__
|
|
);
|
|
goto LoadFailed;
|
|
}
|
|
|
|
Status = SlLoadDriver(BlFindMessage(SL_NETBT_NAME),
|
|
"netbt.sys",
|
|
0,
|
|
TRUE,
|
|
FALSE,
|
|
NULL
|
|
);
|
|
if(Status != ESUCCESS) {
|
|
SlFriendlyError(
|
|
Status,
|
|
"netbt.sys",
|
|
__LINE__,
|
|
__FILE__
|
|
);
|
|
goto LoadFailed;
|
|
}
|
|
|
|
Status = SlLoadDriver(BlFindMessage(SL_NETADAPTER_NAME),
|
|
NetbootCardDriverName,
|
|
0,
|
|
TRUE,
|
|
FALSE,
|
|
NULL
|
|
);
|
|
if(Status != ESUCCESS) {
|
|
SlFriendlyError(
|
|
Status,
|
|
NetbootCardDriverName,
|
|
__LINE__,
|
|
__FILE__
|
|
);
|
|
goto LoadFailed;
|
|
}
|
|
|
|
//
|
|
// Fill in the registry key for the netboot card because its service name
|
|
// may be different from the driver name.
|
|
//
|
|
DriverEntry = (PBOOT_DRIVER_LIST_ENTRY)(BlLoaderBlock->BootDriverListHead.Blink); // SlLoadDriver inserts at the tail
|
|
DriverEntry->RegistryPath.Buffer = BlAllocateHeap(256);
|
|
if (DriverEntry->RegistryPath.Buffer == NULL) {
|
|
SlNoMemoryError();
|
|
goto LoadFailed;
|
|
}
|
|
DriverEntry->RegistryPath.Length = 0;
|
|
DriverEntry->RegistryPath.MaximumLength = 256;
|
|
RtlAppendUnicodeToString(&DriverEntry->RegistryPath,
|
|
L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
|
|
RtlAppendUnicodeToString(&DriverEntry->RegistryPath,
|
|
SetupBlock->NetbootCardServiceName);
|
|
|
|
Status = SlLoadDriver(BlFindMessage(SL_RDBSS_NAME),
|
|
"rdbss.sys",
|
|
0,
|
|
TRUE,
|
|
FALSE,
|
|
NULL
|
|
);
|
|
if(Status != ESUCCESS) {
|
|
SlFriendlyError(
|
|
Status,
|
|
"rdbss.sys",
|
|
__LINE__,
|
|
__FILE__
|
|
);
|
|
goto LoadFailed;
|
|
}
|
|
}
|
|
|
|
Status = SlLoadDriver(BlFindMessage(SL_MUP_NAME),
|
|
"mup.sys",
|
|
0,
|
|
TRUE,
|
|
FALSE,
|
|
NULL
|
|
);
|
|
|
|
if(Status != ESUCCESS) {
|
|
SlFriendlyError(
|
|
Status,
|
|
"mup.sys",
|
|
__LINE__,
|
|
__FILE__
|
|
);
|
|
goto LoadFailed;
|
|
}
|
|
|
|
if (BlBootingFromNet) {
|
|
Status = SlLoadDriver(BlFindMessage(SL_MRXSMB_NAME),
|
|
"mrxsmb.sys",
|
|
0,
|
|
TRUE,
|
|
FALSE,
|
|
NULL
|
|
);
|
|
if(Status != ESUCCESS) {
|
|
SlFriendlyError(
|
|
Status,
|
|
"mrxsmb.sys",
|
|
__LINE__,
|
|
__FILE__
|
|
);
|
|
goto LoadFailed;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( WinPEBoot && BlLoaderBlock->Extension->HeadlessLoaderBlock != NULL ) {
|
|
//
|
|
// Try and load the sacdriver.
|
|
//
|
|
Status = SlLoadDriver(BlFindMessage(SL_SACDRV_NAME),
|
|
"sacdrv.sys",
|
|
0,
|
|
TRUE,
|
|
FALSE,
|
|
NULL
|
|
);
|
|
|
|
}
|
|
|
|
if (!UseRegularBackground) {
|
|
SlWriteStatusText (BlFindMessage (SL_KERNEL_TRANSITION));
|
|
}
|
|
|
|
//
|
|
// Finally, make sure the appropriate disk containing NTDLL.DLL is in
|
|
// the drive.
|
|
//
|
|
|
|
SlGetDisk("ntdll.dll");
|
|
|
|
//
|
|
// Fill in the SETUPLDR block with relevant information
|
|
//
|
|
SetupBlock->ArcSetupDeviceName = BlLoaderBlock->ArcBootDeviceName;
|
|
|
|
SetupBlock->ScalarValues.SetupFromCdRom = FALSE;
|
|
SetupBlock->ScalarValues.SetupOperation = SetupOperationSetup;
|
|
|
|
//
|
|
// Get the NTFT drive signatures to allow the kernel to create the
|
|
// correct ARC name <=> NT name mappings.
|
|
//
|
|
//
|
|
// X86Only : Go enumerate all the disks and record their ability to
|
|
// support xint13.
|
|
//
|
|
|
|
BlGetArcDiskInformation(TRUE);
|
|
|
|
//
|
|
// ntdetect has already run. Although it's awful to have
|
|
// 2 disks that look just alike, stamping a signature on one
|
|
// after ntdetect has run will also break us. Rather err on
|
|
// the side of caution and not write to the disks.
|
|
//
|
|
// This is much safer on x86 because we've ensured that the
|
|
// boot disk has a signature before we get here. On Alpha,
|
|
// we can't do that. So it's ugly, but call this guy for
|
|
// BIOS-based x86 machines.
|
|
|
|
//
|
|
// don't reboot after stamping signatures
|
|
// the first time
|
|
//
|
|
|
|
SlpMarkDisks(FALSE);
|
|
|
|
//
|
|
// If setup was started from a CD-ROM, generate an entry in the ARC disk
|
|
// information list describing the cd-rom.
|
|
//
|
|
|
|
if (!BlGetPathMnemonicKey(SetupDevice,
|
|
"cdrom",
|
|
&BootDriveNumber)) {
|
|
BlReadSignature(SetupDevice,TRUE);
|
|
}
|
|
|
|
//
|
|
// Close the ARC device.
|
|
//
|
|
|
|
ArcClose(BootDeviceId);
|
|
|
|
|
|
#if 0
|
|
{
|
|
ULONG EndTime = ArcGetRelativeTime();
|
|
char szTemp[256];
|
|
extern ULONG BlFilesOpened;
|
|
|
|
BlPositionCursor(1, 10);
|
|
sprintf(szTemp, "BootTime : %d secs, FilesOpened : %d\r\n",
|
|
EndTime - StartTime, BlFilesOpened );
|
|
|
|
BlPrint(szTemp);
|
|
}
|
|
#endif
|
|
|
|
if (UseRegularBackground) {
|
|
BlOutputStartupMsg(SL_PLEASE_WAIT);
|
|
BlUpdateProgressBar(100);
|
|
}
|
|
|
|
//
|
|
// Remove system32 from the boot path if we added it
|
|
//
|
|
|
|
if (WinPEBoot) {
|
|
PCHAR Sys32 = BlLoaderBlock->NtBootPathName +
|
|
strlen(BlLoaderBlock->NtBootPathName) -
|
|
strlen("system32\\");
|
|
|
|
if (Sys32 && !_stricmp(Sys32, "system32\\")) {
|
|
*Sys32 = 0;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// 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.
|
|
//
|
|
|
|
if ( BlBootingFromNet ) {
|
|
NetTerminate();
|
|
}
|
|
|
|
//
|
|
//
|
|
// Execute the architecture specific setup code.
|
|
//
|
|
// NOTE: If BlBootingFromNet, don't do anything after this point
|
|
// that would cause access to the boot ROM.
|
|
//
|
|
|
|
Status = BlSetupForNt(BlLoaderBlock);
|
|
if (Status != ESUCCESS) {
|
|
SlFriendlyError(
|
|
Status,
|
|
"\"Windows NT Executive\"",
|
|
__LINE__,
|
|
__FILE__
|
|
);
|
|
goto LoadFailed;
|
|
}
|
|
|
|
//
|
|
// Transfer to the kernel
|
|
//
|
|
|
|
// DbgBreakPoint();
|
|
|
|
BlTransferToKernel(SystemEntry, BlLoaderBlock);
|
|
|
|
//
|
|
// Any return from the system is an error.
|
|
//
|
|
|
|
Status = EBADF;
|
|
SlFriendlyError(
|
|
Status,
|
|
"\"Windows NT Executive\"",
|
|
__LINE__,
|
|
__FILE__
|
|
);
|
|
|
|
LoadFailed:
|
|
SlWriteStatusText(BlFindMessage(SL_TOTAL_SETUP_DEATH));
|
|
SlFlushConsoleBuffer();
|
|
SlGetChar();
|
|
ArcRestart();
|
|
return(Status);
|
|
}
|
|
|
|
|
|
VOID
|
|
SlpTruncateMemory(
|
|
IN ULONG MaxMemory
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Eliminates all the memory descriptors above a given boundary
|
|
|
|
Arguments:
|
|
|
|
MaxMemory - Supplies the maximum memory boundary in megabytes
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PLIST_ENTRY NextEntry;
|
|
PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor;
|
|
ULONG MaxPage = MaxMemory * 256; // Convert Mb to pages
|
|
|
|
if (MaxMemory == 0) {
|
|
return;
|
|
}
|
|
|
|
NextEntry = BlLoaderBlock->MemoryDescriptorListHead.Flink;
|
|
while ( NextEntry != &BlLoaderBlock->MemoryDescriptorListHead ) {
|
|
MemoryDescriptor = CONTAINING_RECORD(NextEntry,
|
|
MEMORY_ALLOCATION_DESCRIPTOR,
|
|
ListEntry);
|
|
NextEntry = NextEntry->Flink;
|
|
if ( (MemoryDescriptor->MemoryType != LoaderFree) &&
|
|
(MemoryDescriptor->MemoryType != LoaderFirmwareTemporary) ) {
|
|
continue;
|
|
}
|
|
if (MemoryDescriptor->BasePage >= MaxPage) {
|
|
//
|
|
// This memory descriptor lies entirely above the boundary,
|
|
// eliminate it.
|
|
//
|
|
BlRemoveDescriptor(MemoryDescriptor);
|
|
} else if (MemoryDescriptor->BasePage + MemoryDescriptor->PageCount > MaxPage) {
|
|
//
|
|
// This memory descriptor crosses the boundary, truncate it.
|
|
//
|
|
MemoryDescriptor->PageCount = MaxPage - MemoryDescriptor->BasePage;
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID
|
|
SlGetSetupValuesBeforePrompt(
|
|
IN PSETUP_LOADER_BLOCK SetupBlock
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reads the setup control values out of the given .INI file.
|
|
Also supplies reasonable defaults for values that don't exist.
|
|
|
|
Arguments:
|
|
|
|
SetupBlock - Supplies a pointer to the Setup loader block
|
|
|
|
Return Value:
|
|
|
|
None. Global variables are initialized to reflect the
|
|
contents of the INI file
|
|
|
|
--*/
|
|
|
|
{
|
|
PCHAR NlsName;
|
|
ANSI_STRING NlsString;
|
|
PCHAR Options="1";
|
|
ULONG MaxMemory;
|
|
|
|
if (BlBootingFromNet) {
|
|
BlLoaderBlock->LoadOptions = SlGetIniValue(WinntSifHandle,
|
|
"setupdata",
|
|
"osloadoptions",
|
|
NULL);
|
|
} else {
|
|
BlLoaderBlock->LoadOptions = NULL;
|
|
}
|
|
|
|
if (BlLoaderBlock->LoadOptions == NULL) {
|
|
BlLoaderBlock->LoadOptions = SlGetIniValue(InfFile,
|
|
"setupdata",
|
|
"osloadoptions",
|
|
NULL);
|
|
}
|
|
|
|
AnsiCpName = SlGetIniValue(InfFile,
|
|
"nls",
|
|
"AnsiCodepage",
|
|
"c_1252.nls");
|
|
|
|
//
|
|
// when assigning the length, do some checking to make sure we don't
|
|
// overflow. if we do overflow, assign the length value to 0
|
|
// make sure we don't overflow (USHORT)-1 / sizeof(WCHAR) - sizeof(CHAR))
|
|
// we check this value, since the maximum length of the unicode
|
|
// will include the null character, and be twice it's length
|
|
// or (USHORT) -1.
|
|
//
|
|
NlsString.Buffer = AnsiCpName;
|
|
NlsString.Length = (USHORT) RESET_SIZE_AT_VALUE(strlen(AnsiCpName),
|
|
(USHORT)-1 / sizeof(WCHAR) - sizeof(CHAR));
|
|
NlsString.MaximumLength = (NlsString.Length) ? NlsString.Length + sizeof(CHAR) : 0;
|
|
AnsiCodepage.MaximumLength = NlsString.MaximumLength * sizeof(WCHAR);
|
|
AnsiCodepage.Buffer = BlAllocateHeap(AnsiCodepage.MaximumLength);
|
|
if (AnsiCodepage.Buffer == NULL) {
|
|
SlNoMemoryError();
|
|
}
|
|
RtlAnsiStringToUnicodeString(&AnsiCodepage, &NlsString, FALSE);
|
|
|
|
NlsName = SlGetIniValue(InfFile,
|
|
"nls",
|
|
"OemCodepage",
|
|
"c_437.nls");
|
|
|
|
//
|
|
// when assigning the length, do some checking to make sure we don't
|
|
// overflow. if we do overflow, assign the length value to 0
|
|
// make sure we don't overflow (USHORT)-1 / sizeof(WCHAR) - sizeof(CHAR))
|
|
// we check this value, since the maximum length of the unicode
|
|
// will include the null character, and be twice it's length
|
|
// or (USHORT) -1.
|
|
//
|
|
NlsString.Buffer = NlsName;
|
|
NlsString.Length = (USHORT) RESET_SIZE_AT_VALUE(strlen(NlsName),
|
|
(USHORT)-1 / sizeof(WCHAR) - sizeof(CHAR));
|
|
NlsString.MaximumLength = (NlsString.Length) ? NlsString.Length + sizeof(CHAR) : 0;
|
|
OemCodepage.MaximumLength = NlsString.MaximumLength * sizeof(WCHAR);
|
|
OemCodepage.Buffer = BlAllocateHeap(OemCodepage.MaximumLength);
|
|
if (OemCodepage.Buffer == NULL) {
|
|
SlNoMemoryError();
|
|
}
|
|
RtlAnsiStringToUnicodeString(&OemCodepage, &NlsString, FALSE);
|
|
|
|
NlsName = SlGetIniValue(InfFile,
|
|
"nls",
|
|
"UnicodeCasetable",
|
|
"l_intl.nls");
|
|
|
|
//
|
|
// when assigning the length, do some checking to make sure we don't
|
|
// overflow. if we do overflow, assign the length value to 0
|
|
// make sure we don't overflow (USHORT)-1 / sizeof(WCHAR) - sizeof(CHAR))
|
|
// we check this value, since the maximum length of the unicode
|
|
// will include the null character, and be twice it's length
|
|
// or (USHORT) -1.
|
|
//
|
|
NlsString.Buffer = NlsName;
|
|
NlsString.Length = (USHORT) RESET_SIZE_AT_VALUE(strlen(NlsName),
|
|
(USHORT)-1 / sizeof(WCHAR) - sizeof(CHAR));
|
|
NlsString.MaximumLength = (NlsString.Length) ? NlsString.Length + sizeof(CHAR) : 0;
|
|
UnicodeCaseTable.MaximumLength = NlsString.MaximumLength*sizeof(WCHAR);
|
|
UnicodeCaseTable.Buffer = BlAllocateHeap(UnicodeCaseTable.MaximumLength);
|
|
if (UnicodeCaseTable.Buffer == NULL) {
|
|
SlNoMemoryError();
|
|
}
|
|
RtlAnsiStringToUnicodeString(&UnicodeCaseTable, &NlsString, FALSE);
|
|
|
|
OemHalFontName = SlGetIniValue(InfFile,
|
|
"nls",
|
|
"OemHalFont",
|
|
"vgaoem.fon");
|
|
|
|
//
|
|
// when assigning the length, do some checking to make sure we don't
|
|
// overflow. if we do overflow, assign the length value to 0
|
|
// make sure we don't overflow (USHORT)-1 / sizeof(WCHAR) - sizeof(CHAR))
|
|
// we check this value, since the maximum length of the unicode
|
|
// will include the null character, and be twice it's length
|
|
// or (USHORT) -1.
|
|
//
|
|
NlsString.Buffer = OemHalFontName;
|
|
NlsString.Length = (USHORT) RESET_SIZE_AT_VALUE(strlen(OemHalFontName),
|
|
(USHORT)-1 / sizeof(WCHAR) - sizeof(CHAR));
|
|
NlsString.MaximumLength = (NlsString.Length) ? NlsString.Length + sizeof(CHAR) : 0;
|
|
OemHalFont.MaximumLength = NlsString.MaximumLength*sizeof(WCHAR);
|
|
OemHalFont.Buffer = BlAllocateHeap(OemHalFont.MaximumLength);
|
|
if (OemHalFont.Buffer == NULL) {
|
|
SlNoMemoryError();
|
|
}
|
|
RtlAnsiStringToUnicodeString(&OemHalFont, &NlsString, FALSE);
|
|
|
|
#ifdef _WANT_MACHINE_IDENTIFICATION
|
|
|
|
BiosInfo.Buffer = NULL;
|
|
NlsString.Buffer = SlGetIniValue(InfFile,
|
|
"BiosInfo",
|
|
"InfName",
|
|
NULL);
|
|
|
|
if (NlsString.Buffer) {
|
|
|
|
//
|
|
// when assigning the length, do some checking to make sure we don't
|
|
// overflow. if we do overflow, assign the length value to 0
|
|
// make sure we don't overflow (USHORT)-1 / sizeof(WCHAR) - sizeof(CHAR))
|
|
// we check this value, since the maximum length of the unicode
|
|
// will include the null character, and be twice it's length
|
|
// or (USHORT) -1.
|
|
//
|
|
NlsString.Length = (USHORT) RESET_SIZE_AT_VALUE(strlen(NlsString.Buffer),
|
|
(USHORT)-1 / sizeof(WCHAR) - sizeof(CHAR));
|
|
NlsString.MaximumLength = (NlsString.Length) ? NlsString.Length + sizeof(CHAR) : 0;
|
|
BiosInfo.MaximumLength = NlsString.MaximumLength*sizeof(WCHAR);
|
|
BiosInfo.Buffer = BlAllocateHeap(BiosInfo.MaximumLength);
|
|
if (BiosInfo.Buffer == NULL) {
|
|
SlNoMemoryError();
|
|
}
|
|
RtlAnsiStringToUnicodeString(&BiosInfo, &NlsString, FALSE);
|
|
}
|
|
|
|
#endif
|
|
|
|
//
|
|
// Loading all the miniport will exhaust all free mem <16Mb - ArcSetup dies.
|
|
//
|
|
#ifndef ARCI386
|
|
LoadScsiMiniports = (BOOLEAN) (atoi(SlGetIniValue(InfFile,
|
|
"SetupData",
|
|
"ForceScsi",
|
|
"0")) == 1);
|
|
#endif
|
|
|
|
LoadDiskClass = (BOOLEAN) (atoi(SlGetIniValue(InfFile,
|
|
"setupdata",
|
|
"ForceDiskClass",
|
|
"0")) == 1);
|
|
|
|
LoadCdfs = (BOOLEAN) (atoi(SlGetIniValue(InfFile,
|
|
"setupdata",
|
|
"ForceCdRom",
|
|
"0")) == 1);
|
|
|
|
|
|
BootPath = SlGetIniValue(InfFile,
|
|
"setupdata",
|
|
"BootPath",
|
|
NULL);
|
|
BootDevice = SlGetIniValue(InfFile,
|
|
"setupdata",
|
|
"BootDevice",
|
|
NULL);
|
|
|
|
//
|
|
// Build a linked list with all the P&P hardware ids.
|
|
// listed on [HardwareIdsDatabase]. This list will be used
|
|
// during the initialization phase of setupdd.sys
|
|
//
|
|
SetupBlock->HardwareIdDatabase = NULL;
|
|
|
|
if( SpSearchINFSection( InfFile, "HardwareIdsDatabase" ) ) {
|
|
ULONG i;
|
|
PPNP_HARDWARE_ID TempHardwareId;
|
|
PCHAR p;
|
|
|
|
for( i = 0;
|
|
((p = SlGetKeyName( InfFile, "HardwareIdsDatabase", i )) != NULL);
|
|
i++ ) {
|
|
TempHardwareId = BlAllocateHeap(sizeof(PNP_HARDWARE_ID));
|
|
|
|
if (TempHardwareId==NULL) {
|
|
SlNoMemoryError();
|
|
}
|
|
|
|
TempHardwareId->Id = p;
|
|
p = SlGetSectionKeyIndex( InfFile,
|
|
"HardwareIdsDatabase",
|
|
TempHardwareId->Id,
|
|
0 );
|
|
TempHardwareId->DriverName = p;
|
|
p = SlGetSectionKeyIndex( InfFile,
|
|
"HardwareIdsDatabase",
|
|
TempHardwareId->Id,
|
|
1 );
|
|
TempHardwareId->ClassGuid = p;
|
|
|
|
TempHardwareId->Next = SetupBlock->HardwareIdDatabase;
|
|
SetupBlock->HardwareIdDatabase = TempHardwareId;
|
|
}
|
|
}
|
|
|
|
if (BlLoaderBlock->LoadOptions) {
|
|
_strupr(BlLoaderBlock->LoadOptions);
|
|
|
|
if ( ( Options = strstr(BlLoaderBlock->LoadOptions,"/MAXMEM") ) != 0 ) {
|
|
MaxMemory = atoi(Options+8);
|
|
SlpTruncateMemory( MaxMemory );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
SlGetSetupValuesAfterPrompt(
|
|
IN PSETUP_LOADER_BLOCK SetupBlock
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reads the setup control values out of the given .INI file. Also supplies
|
|
reasonable defaults for values that don't exist.
|
|
|
|
Note : This is called after the user is prompted for F5,
|
|
F6 & F7 behavior.
|
|
|
|
Arguments:
|
|
|
|
SetupBlock - Supplies a pointer to the Setup loader block
|
|
|
|
Return Value:
|
|
|
|
None. Global variables are initialized to reflect the contents
|
|
of the INI file
|
|
|
|
--*/
|
|
{
|
|
PCHAR MachineName = NULL;
|
|
|
|
//
|
|
// Determine which HAL to load. If the appropriate HAL cannot be
|
|
// determined, or if we are to prompt for an OEM HAL, then set the
|
|
// 'PromptOemHal' flag (may have already been set by the user's
|
|
// keypress).
|
|
//
|
|
if(!PromptOemHal) {
|
|
PromptOemHal = (BOOLEAN) (atoi(SlGetIniValue(InfFile,
|
|
"setupdata",
|
|
"ForceOemHal",
|
|
"0")) == 1);
|
|
}
|
|
|
|
if(!PromptOemHal) {
|
|
MachineName = SlDetectHal();
|
|
}
|
|
|
|
SetupBlock->ComputerDevice.Files = 0;
|
|
SetupBlock->ComputerDevice.Next = NULL;
|
|
SetupBlock->ComputerDevice.Description = NULL;
|
|
SetupBlock->ComputerDevice.ThirdPartyOptionSelected = FALSE;
|
|
SetupBlock->ComputerDevice.FileTypeBits = 0;
|
|
SetupBlock->ComputerDevice.Files = 0;
|
|
SetupBlock->ComputerDevice.BaseDllName = SlCopyStringA("");
|
|
|
|
if(MachineName!=NULL) {
|
|
SetupBlock->ComputerDevice.IdString = SlCopyStringA(MachineName);
|
|
//
|
|
// Map the machine name to a HAL name. If we're doing a remote boot,
|
|
// look in the [Hal] section. Otherwise, look in the [Hal.Load]
|
|
// section. (Local setup has a separate section to minimize the
|
|
// number of HAL binaries that need to be on the boot floppies.)
|
|
//
|
|
HalName = SlGetIniValue(InfFile,
|
|
BlBootingFromNet ? "Hal" : "Hal.Load",
|
|
MachineName,
|
|
NULL);
|
|
HalDescription = SlGetIniValue(InfFile,
|
|
"Computer",
|
|
MachineName,
|
|
NULL);
|
|
}
|
|
|
|
if(!(MachineName && HalName && HalDescription)) {
|
|
PromptOemHal = TRUE;
|
|
}
|
|
|
|
//
|
|
// If we haven't already been instructed to prompt for an OEM SCSI disk (by
|
|
// the user's keypress), then get this value from the inf file.
|
|
//
|
|
if(!PromptOemScsi) {
|
|
PromptOemScsi = (BOOLEAN) (atoi(SlGetIniValue(InfFile,
|
|
"setupdata",
|
|
"ForceOemScsi",
|
|
"0")) == 1);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
BlOutputLoadMessage (
|
|
IN PCHAR DeviceName,
|
|
IN PCHAR FileName,
|
|
IN PTCHAR FileDescription OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine outputs a loading message on the status line
|
|
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
static int dots = 0;
|
|
TCHAR OutputBuffer[256];
|
|
PTCHAR FormatString;
|
|
|
|
UNREFERENCED_PARAMETER( FileName );
|
|
UNREFERENCED_PARAMETER( DeviceName );
|
|
|
|
//
|
|
// Construct and output loading file message.
|
|
//
|
|
|
|
if (!UseRegularBackground) {
|
|
FormatString = BlFindMessage(SL_FILE_LOAD_MESSAGE);
|
|
|
|
if (FileDescription) {
|
|
_stprintf(OutputBuffer,FormatString,FileDescription);
|
|
SlWriteStatusText(OutputBuffer);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
ARC_STATUS
|
|
SlLoadDriver(
|
|
IN PTCHAR DriverDescription,
|
|
IN PCHAR DriverName,
|
|
IN ULONG DriverFlags,
|
|
IN BOOLEAN InsertIntoDriverList,
|
|
IN BOOLEAN MigratedDriver,
|
|
IN PCHAR ServiceName OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Attempts to load a driver from the device identified by the global
|
|
variable BootDeviceId.
|
|
|
|
Arguments:
|
|
|
|
DriverDescription - Supplies a friendly description of the driver being
|
|
loaded.
|
|
|
|
DriverName - Supplies the name of the driver.
|
|
|
|
DriverFlags - Flags to set in the LDR_DATA_TABLE_ENTRY.
|
|
|
|
InsertIntoDriverList - Flag specifying whether this 'driver' should be
|
|
placed into the BootDriveListHead list (eg, scsiport.sys
|
|
is not a true driver, and should not be placed in this list)
|
|
|
|
MigratedDriver - Flag specifying whther this driver was migrated from an NT system.
|
|
|
|
ServiceName - The service name for this driver as it may be different from the driver name.
|
|
|
|
Return Value:
|
|
|
|
ESUCCESS - Driver successfully loaded
|
|
|
|
--*/
|
|
|
|
{
|
|
PBOOT_DRIVER_LIST_ENTRY DriverEntry;
|
|
NTSTATUS Status;
|
|
PKLDR_DATA_TABLE_ENTRY DataTableEntry;
|
|
FULL_PATH_SET PathSet;
|
|
|
|
if(BlCheckForLoadedDll(DriverName,&DataTableEntry)) {
|
|
return(ESUCCESS);
|
|
}
|
|
|
|
DriverEntry = SlpCreateDriverEntry(DriverName, ServiceName);
|
|
if(DriverEntry == NULL) {
|
|
SlNoMemoryError();
|
|
return(ENOMEM);
|
|
}
|
|
|
|
if( !WinPEBoot && !MigratedDriver ) {
|
|
SlGetDisk(DriverName);
|
|
}
|
|
|
|
PathSet.PathCount = 1;
|
|
PathSet.AliasName = "\\SystemRoot";
|
|
PathSet.PathOffset[0] = '\0';
|
|
PathSet.Source[0].DeviceId = BootDeviceId;
|
|
PathSet.Source[0].DeviceName = BootDevice;
|
|
|
|
if (WinPEBoot) {
|
|
static PCHAR Path = NULL;
|
|
|
|
if (!Path) {
|
|
CHAR Buffer[256];
|
|
|
|
strcpy(Buffer, BootPath);
|
|
strcat(Buffer, "drivers\\");
|
|
Path = SlCopyStringA(Buffer);
|
|
}
|
|
|
|
PathSet.Source[0].DirectoryPath = Path;
|
|
} else {
|
|
PathSet.Source[0].DirectoryPath = BootPath;
|
|
}
|
|
|
|
Status = BlLoadDeviceDriver(
|
|
&PathSet,
|
|
DriverName,
|
|
DriverDescription,
|
|
DriverFlags,
|
|
&DriverEntry->LdrEntry
|
|
);
|
|
|
|
if((Status == ESUCCESS) && InsertIntoDriverList) {
|
|
InsertTailList(&BlLoaderBlock->BootDriverListHead,&DriverEntry->Link);
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
|
|
ARC_STATUS
|
|
SlLoadOemDriver(
|
|
IN PCHAR ExportDriver OPTIONAL,
|
|
IN PCHAR DriverName,
|
|
IN PVOID BaseAddress,
|
|
IN PTCHAR LoadMessage
|
|
)
|
|
{
|
|
PBOOT_DRIVER_LIST_ENTRY DriverEntry;
|
|
ARC_STATUS Status;
|
|
PKLDR_DATA_TABLE_ENTRY DataTableEntry;
|
|
FULL_PATH_SET PathSet;
|
|
|
|
UNREFERENCED_PARAMETER(LoadMessage);
|
|
|
|
if(BlCheckForLoadedDll(DriverName,&DataTableEntry)) {
|
|
return(ESUCCESS);
|
|
}
|
|
|
|
if(ExportDriver) {
|
|
SlGetDisk(ExportDriver);
|
|
}
|
|
|
|
DriverEntry = SlpCreateDriverEntry(DriverName, NULL);
|
|
if (DriverEntry==NULL) {
|
|
return(ENOMEM);
|
|
}
|
|
|
|
Status = BlAllocateDataTableEntry(
|
|
DriverName,
|
|
DriverName,
|
|
BaseAddress,
|
|
&DriverEntry->LdrEntry
|
|
);
|
|
|
|
if (Status == ESUCCESS) {
|
|
|
|
PathSet.PathCount = 1;
|
|
PathSet.AliasName = "\\SystemRoot";
|
|
PathSet.PathOffset[0] = '\0';
|
|
PathSet.Source[0].DeviceId = BootDeviceId;
|
|
PathSet.Source[0].DeviceName = BootDevice;
|
|
PathSet.Source[0].DirectoryPath = BootPath;
|
|
|
|
Status = BlScanImportDescriptorTable(
|
|
&PathSet,
|
|
DriverEntry->LdrEntry,
|
|
LoaderBootDriver
|
|
);
|
|
|
|
if(Status == ESUCCESS) {
|
|
|
|
InsertTailList(&BlLoaderBlock->BootDriverListHead,&DriverEntry->Link);
|
|
}
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
|
|
|
|
PBOOT_DRIVER_LIST_ENTRY
|
|
SlpCreateDriverEntry(
|
|
IN PCHAR DriverName,
|
|
IN PCHAR ServiceName OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocates and initializes a boot driver list entry structure.
|
|
|
|
Arguments:
|
|
|
|
DriverName - Supplies the name of the driver.
|
|
ServiceName - The service name for this driver as it may be different from the driver name.
|
|
|
|
Return Value:
|
|
|
|
Pointer to the initialized structure.
|
|
|
|
--*/
|
|
|
|
{
|
|
PBOOT_DRIVER_LIST_ENTRY DriverEntry;
|
|
ANSI_STRING String;
|
|
|
|
DriverEntry = BlAllocateHeap(sizeof(BOOT_DRIVER_LIST_ENTRY));
|
|
if (DriverEntry==NULL) {
|
|
SlNoMemoryError();
|
|
return(NULL);
|
|
}
|
|
//
|
|
// when assigning the length, do some checking to make sure we don't
|
|
// overflow. if we do overflow, assign the length value to 0
|
|
// make sure we don't overflow (USHORT)-1 / sizeof(WCHAR) - sizeof(CHAR))
|
|
// we check this value, since the maximum length of the unicode
|
|
// will include the null character, and be twice it's length
|
|
// or (USHORT) -1.
|
|
//
|
|
String.Buffer = DriverName;
|
|
String.Length = (USHORT) RESET_SIZE_AT_VALUE(strlen(DriverName),
|
|
(USHORT)-1 / sizeof(WCHAR) - sizeof(CHAR));
|
|
String.MaximumLength = (String.Length) ? String.Length + sizeof(CHAR) : 0;
|
|
DriverEntry->FilePath.MaximumLength = String.MaximumLength * sizeof(WCHAR);
|
|
DriverEntry->FilePath.Buffer = BlAllocateHeap(DriverEntry->FilePath.MaximumLength);
|
|
if (DriverEntry->FilePath.Buffer==NULL) {
|
|
SlNoMemoryError();
|
|
return(NULL);
|
|
}
|
|
RtlAnsiStringToUnicodeString(&DriverEntry->FilePath, &String, FALSE);
|
|
|
|
if(ServiceName != NULL && ServiceName[0] != 0) {
|
|
ANSI_STRING ansi;
|
|
UNICODE_STRING unicode;
|
|
|
|
RtlInitString(&ansi, ServiceName);
|
|
DriverEntry->RegistryPath.Length = (SL_REGKEY_SERVICES_LEN + ansi.Length) * sizeof(WCHAR);
|
|
DriverEntry->RegistryPath.MaximumLength = DriverEntry->RegistryPath.Length + sizeof(WCHAR);
|
|
DriverEntry->RegistryPath.Buffer = BlAllocateHeap(DriverEntry->RegistryPath.MaximumLength);
|
|
|
|
if(NULL == DriverEntry->RegistryPath.Buffer) {
|
|
SlNoMemoryError();
|
|
return(NULL);
|
|
}
|
|
|
|
RtlCopyMemory(DriverEntry->RegistryPath.Buffer, SL_REGKEY_SERVICES_W, SL_REGKEY_SERVICES_LEN * sizeof(WCHAR));
|
|
unicode.MaximumLength = ansi.MaximumLength * sizeof(WCHAR);
|
|
unicode.Buffer = DriverEntry->RegistryPath.Buffer + SL_REGKEY_SERVICES_LEN;
|
|
RtlAnsiStringToUnicodeString(&unicode, &ansi, FALSE);
|
|
DriverEntry->RegistryPath.Buffer[DriverEntry->RegistryPath.Length / sizeof(WCHAR)] = 0;
|
|
}
|
|
|
|
return(DriverEntry);
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
SlGetDisk(
|
|
IN PCHAR Filename
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Given a filename, this routine ensures that the correct disk is
|
|
in the drive identified by the global variables BootDevice and
|
|
BootDeviceId. The user may be prompted to change disks.
|
|
|
|
Arguments:
|
|
|
|
Filename - Supplies the name of the file to be loaded.
|
|
|
|
Return Value:
|
|
|
|
TRUE - Disk was successfully loaded.
|
|
|
|
FALSE - User has cancelled out of Setup.
|
|
|
|
--*/
|
|
|
|
{
|
|
PCHAR DiskNumber;
|
|
PTCHAR DiskName;
|
|
PCHAR DiskTag;
|
|
ULONG FileId;
|
|
CHAR PlatformSpecificSection[128];
|
|
PCHAR DiskTagSection = NULL;
|
|
|
|
//
|
|
// If the media is fixed, the user can't change disks.
|
|
// Just return TRUE indicating that the disk is in the drive.
|
|
//
|
|
if(FixedBootMedia || BlBootingFromNet) {
|
|
return(TRUE);
|
|
}
|
|
|
|
//
|
|
// Look up filename to get the disk number. Look in the platform-specific
|
|
// directory first.
|
|
//
|
|
strcpy(PlatformSpecificSection,FilesSectionName);
|
|
strcat(PlatformSpecificSection,PlatformExtension);
|
|
|
|
#if defined(ELTORITO)
|
|
if (ElToritoCDBoot) {
|
|
// for Cd boot we use the setup media path instead of a boot-media-specific path
|
|
DiskNumber = SlGetSectionKeyIndex(InfFile,PlatformSpecificSection,Filename,0);
|
|
} else {
|
|
#endif
|
|
|
|
DiskNumber = SlGetSectionKeyIndex(InfFile,PlatformSpecificSection,Filename,6);
|
|
|
|
#if defined(ELTORITO)
|
|
}
|
|
#endif
|
|
|
|
if(DiskNumber == NULL) {
|
|
|
|
#if defined(ELTORITO)
|
|
if (ElToritoCDBoot) {
|
|
// for Cd boot we use the setup media path instead of a boot-media-specific path
|
|
DiskNumber = SlGetSectionKeyIndex(InfFile,FilesSectionName,Filename,0);
|
|
} else {
|
|
#endif
|
|
|
|
DiskNumber = SlGetSectionKeyIndex(InfFile,FilesSectionName,Filename,6);
|
|
|
|
#if defined(ELTORITO)
|
|
}
|
|
#endif
|
|
|
|
}
|
|
|
|
if((DiskNumber==NULL) || !(*DiskNumber)) {
|
|
SlFatalError(SL_INF_ENTRY_MISSING,SlCopyStringAT(Filename),FilesSectionName);
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Look up disk number to get the diskname and tag.
|
|
// Look in platform-specific directory first.
|
|
//
|
|
strcpy(PlatformSpecificSection,MediaSectionName);
|
|
strcat(PlatformSpecificSection,PlatformExtension);
|
|
|
|
#ifdef UNICODE
|
|
if((DiskName = (PTCHAR)SlGetSectionKeyIndexW(
|
|
#else
|
|
if((DiskName = (PTCHAR)SlGetSectionKeyIndex(
|
|
#endif
|
|
InfFile,
|
|
PlatformSpecificSection,
|
|
DiskNumber,
|
|
0)) != 0 ) {
|
|
DiskTag = SlGetSectionKeyIndex(InfFile,PlatformSpecificSection,DiskNumber,1);
|
|
DiskTagSection = PlatformSpecificSection;
|
|
} else {
|
|
#ifdef UNICODE
|
|
if((DiskName = (PTCHAR)SlGetSectionKeyIndexW(
|
|
#else
|
|
if((DiskName = (PTCHAR)SlGetSectionKeyIndex(
|
|
#endif
|
|
InfFile,
|
|
MediaSectionName,
|
|
DiskNumber,
|
|
0)) != 0 ) {
|
|
DiskTag = SlGetSectionKeyIndex(InfFile,MediaSectionName,DiskNumber,1);
|
|
DiskTagSection = MediaSectionName;
|
|
} else {
|
|
SlFatalError(SL_INF_ENTRY_MISSING,SlCopyStringAT(DiskNumber),SlCopyStringAT(MediaSectionName));
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
if (!DiskTag) {
|
|
SlFatalError(SL_INF_ENTRY_MISSING,SlCopyStringAT(DiskNumber), SlCopyStringAT(DiskTagSection));
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// If this disk is known to be in the drive, don't look again
|
|
//
|
|
if ((LastDiskTag != NULL) && (!strcmp(DiskTag, LastDiskTag))) {
|
|
return(TRUE);
|
|
}
|
|
|
|
LastDiskTag = NULL;
|
|
|
|
|
|
while(1) {
|
|
|
|
//
|
|
// Open a new device id onto the disk.
|
|
//
|
|
if(BootDeviceIdValid) {
|
|
ArcClose(BootDeviceId);
|
|
BootDeviceIdValid = FALSE;
|
|
}
|
|
|
|
if(ArcOpen(BootDevice,ArcOpenReadOnly,&BootDeviceId) == ESUCCESS) {
|
|
|
|
BootDeviceIdValid = TRUE;
|
|
//
|
|
// Check for existence of the disk tag.
|
|
//
|
|
if(BlOpen(BootDeviceId,DiskTag,ArcOpenReadOnly,&FileId) == ESUCCESS) {
|
|
|
|
//
|
|
// Disk is in the drive. Return success.
|
|
// Leave BootDeviceId open onto the device.
|
|
//
|
|
BlClose(FileId);
|
|
LastDiskTag = DiskTag;
|
|
return(TRUE);
|
|
|
|
} else {
|
|
|
|
//
|
|
// Prompt for the user to change disks.
|
|
//
|
|
ArcClose(BootDeviceId);
|
|
BootDeviceIdValid = FALSE;
|
|
|
|
SlPromptForDisk(DiskName, FALSE);
|
|
|
|
}
|
|
} else {
|
|
//
|
|
// Can't open device. Prompt for the disk.
|
|
//
|
|
SlPromptForDisk(DiskName, FALSE);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
PTCHAR
|
|
SlCopyString(
|
|
IN PTCHAR String
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Copies a tchar string into the loader heap so it can be passed to the
|
|
kernel.
|
|
|
|
Arguments:
|
|
|
|
String - Supplies the string to be copied.
|
|
|
|
Return Value:
|
|
|
|
PTCHAR - pointer into the loader heap where the string was copied to.
|
|
|
|
--*/
|
|
|
|
{
|
|
PTCHAR Buffer;
|
|
|
|
if (String==NULL) {
|
|
SlNoMemoryError();
|
|
return NULL;
|
|
}
|
|
Buffer = BlAllocateHeap(((ULONG)_tcslen(String)+1)*sizeof(TCHAR));
|
|
if (Buffer==NULL) {
|
|
SlNoMemoryError();
|
|
} else {
|
|
_tcscpy(Buffer, String);
|
|
}
|
|
|
|
return(Buffer);
|
|
}
|
|
|
|
|
|
PCHAR
|
|
SlCopyStringA(
|
|
IN PCSTR String
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Copies an ANSI string into the loader heap so it can be passed to the
|
|
kernel.
|
|
|
|
Arguments:
|
|
|
|
String - Supplies the string to be copied.
|
|
|
|
Return Value:
|
|
|
|
PCHAR - pointer into the loader heap where the string was copied to.
|
|
|
|
--*/
|
|
|
|
{
|
|
PCHAR Buffer;
|
|
|
|
if (String==NULL) {
|
|
SlNoMemoryError();
|
|
return NULL;
|
|
}
|
|
Buffer = BlAllocateHeap((ULONG)strlen(String)+1);
|
|
if (Buffer==NULL) {
|
|
SlNoMemoryError();
|
|
} else {
|
|
strcpy(Buffer, String);
|
|
}
|
|
|
|
return(Buffer);
|
|
}
|
|
|
|
|
|
|
|
ARC_STATUS
|
|
SlLoadSection(
|
|
IN PVOID Inf,
|
|
IN PCSTR SectionName,
|
|
IN BOOLEAN IsScsiSection,
|
|
IN BOOLEAN AppendLoadSuffix,
|
|
IN OUT PULONG StartingInsertIndex OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Enumerates all the drivers in a section and loads them.
|
|
|
|
Arguments:
|
|
|
|
Inf - Supplies a handle to the INF file.
|
|
|
|
SectionName - Supplies the name of the section.
|
|
|
|
IsScsiSection - Flag specifying whether this is the Scsi.Load section.
|
|
If so, we create the DETECTED_DEVICE linked list, but
|
|
don't actually load the drivers.
|
|
|
|
AppendLoadSuffix - Indicates whether to append the ".load" suffix to the
|
|
section name or not.
|
|
|
|
StartingInsertIndex - The position index in the linked list at which
|
|
the device needs to be inserted. The output value
|
|
contains the next available index.
|
|
|
|
Return Value:
|
|
|
|
ESUCCESS if all drivers were loaded successfully/no errors encountered
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG i;
|
|
CHAR LoadSectionName[100];
|
|
PCHAR DriverFilename;
|
|
PCHAR DriverId;
|
|
PTCHAR DriverDescription;
|
|
PCHAR NoLoadSpec;
|
|
PCHAR p;
|
|
ARC_STATUS Status;
|
|
PDETECTED_DEVICE ScsiDevice;
|
|
SCSI_INSERT_STATUS sis;
|
|
ULONG InsertIndex;
|
|
|
|
ULONG LoadSectionNameLength = (AppendLoadSuffix) ? (ULONG)strlen(SectionName) + 1 :
|
|
(ULONG)strlen(SectionName) + sizeof(".Load"); // sizeof include \0
|
|
|
|
if (sizeof(LoadSectionName) < LoadSectionNameLength ) {
|
|
return ENOMEM;
|
|
}
|
|
strcpy(LoadSectionName, SectionName);
|
|
|
|
if (AppendLoadSuffix) {
|
|
strcat(LoadSectionName, ".Load");
|
|
}
|
|
|
|
//
|
|
// Use the specified insert index, if its valid
|
|
//
|
|
if (StartingInsertIndex && ((*StartingInsertIndex) != SL_OEM_DEVICE_ORDINAL)) {
|
|
InsertIndex = *StartingInsertIndex;
|
|
} else {
|
|
InsertIndex = 0;
|
|
}
|
|
|
|
i=0;
|
|
do {
|
|
DriverFilename = SlGetSectionLineIndex(Inf,LoadSectionName,i,SIF_FILENAME_INDEX);
|
|
NoLoadSpec = SlGetSectionLineIndex(Inf,LoadSectionName,i,2);
|
|
|
|
if(DriverFilename && ((NoLoadSpec == NULL) || _stricmp(NoLoadSpec,"noload"))) {
|
|
|
|
if(!IsScsiSection) {
|
|
//
|
|
// We only want to load the drivers if they aren't scsi miniports
|
|
//
|
|
DriverId = SlGetKeyName(Inf,LoadSectionName,i);
|
|
#ifdef UNICODE
|
|
DriverDescription = SlGetIniValueW(
|
|
Inf,
|
|
(PSTR)SectionName,
|
|
DriverId,
|
|
SlCopyStringAW(DriverId));
|
|
#else
|
|
DriverDescription = SlGetIniValue(
|
|
Inf,
|
|
(PSTR)SectionName,
|
|
DriverId,
|
|
DriverId);
|
|
#endif
|
|
|
|
Status = SlLoadDriver(DriverDescription,
|
|
DriverFilename,
|
|
0,
|
|
TRUE,
|
|
FALSE,
|
|
NULL
|
|
);
|
|
|
|
if((Status == ENOENT) && IgnoreMissingFiles) {
|
|
Status = ESUCCESS;
|
|
}
|
|
} else {
|
|
Status = ESUCCESS;
|
|
}
|
|
|
|
if (Status == ESUCCESS) {
|
|
|
|
if(IsScsiSection) {
|
|
|
|
//
|
|
// Create a new detected device entry.
|
|
//
|
|
if((sis = SlInsertScsiDevice(InsertIndex, &ScsiDevice)) == ScsiInsertError) {
|
|
return(ENOMEM);
|
|
}
|
|
|
|
if(sis == ScsiInsertExisting) {
|
|
#if DBG
|
|
//
|
|
// Sanity check to make sure we're talking about the same driver
|
|
//
|
|
if(_stricmp(ScsiDevice->BaseDllName, DriverFilename)) {
|
|
SlError(400);
|
|
return EINVAL;
|
|
}
|
|
#endif
|
|
} else {
|
|
InsertIndex++;
|
|
p = SlGetKeyName(Inf,LoadSectionName,i);
|
|
|
|
//
|
|
// Find the driver description
|
|
//
|
|
if(p) {
|
|
#ifdef UNICODE
|
|
DriverDescription = SlGetIniValueW(
|
|
Inf,
|
|
(PSTR)SectionName,
|
|
p,
|
|
SlCopyStringAW(p));
|
|
#else
|
|
DriverDescription = SlGetIniValue(
|
|
Inf,
|
|
(PSTR)SectionName,
|
|
p,
|
|
p);
|
|
#endif
|
|
} else {
|
|
DriverDescription = SlCopyString(BlFindMessage(SL_TEXT_SCSI_UNNAMED));
|
|
}
|
|
|
|
ScsiDevice->IdString = p ? p : SlCopyStringA("");
|
|
ScsiDevice->Description = DriverDescription;
|
|
ScsiDevice->ThirdPartyOptionSelected = FALSE;
|
|
ScsiDevice->MigratedDriver = FALSE;
|
|
ScsiDevice->FileTypeBits = 0;
|
|
ScsiDevice->Files = NULL;
|
|
ScsiDevice->BaseDllName = DriverFilename;
|
|
}
|
|
}
|
|
} else {
|
|
SlFriendlyError(
|
|
Status,
|
|
DriverFilename,
|
|
__LINE__,
|
|
__FILE__
|
|
);
|
|
return(Status);
|
|
}
|
|
}
|
|
|
|
i++;
|
|
|
|
} while ( DriverFilename != NULL );
|
|
|
|
if (StartingInsertIndex) {
|
|
*StartingInsertIndex = InsertIndex;
|
|
}
|
|
|
|
return(ESUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
SlpMarkDisks(
|
|
IN BOOLEAN Reboot
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine ensures that there is not more than one disk with the
|
|
same checksum, a signature of zero, and a valid partition table.
|
|
|
|
If it finds a disk with a signature of zero, it searches the rest
|
|
of the list for any other disks with a zero signature and the same
|
|
checksum. If it finds one, it stamps a unique signature on the
|
|
first disk.
|
|
|
|
We also use a heuristic to determine if the disk is 'vacant', and if
|
|
so, we stamp a unique signature on it (unless it's the first one we
|
|
found).
|
|
|
|
Arguments:
|
|
|
|
Reboot - Indicates whether to reboot after stamping signatures
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PARC_DISK_INFORMATION DiskInfo;
|
|
PLIST_ENTRY Entry;
|
|
PLIST_ENTRY CheckEntry;
|
|
PARC_DISK_SIGNATURE DiskSignature;
|
|
PARC_DISK_SIGNATURE CheckDiskSignature;
|
|
ARC_STATUS Status = ESUCCESS;
|
|
BOOLEAN SignatureStamped = FALSE;
|
|
ULONG DiskCount = 0;
|
|
ULONG DisksStamped = 0;
|
|
|
|
DiskInfo = BlLoaderBlock->ArcDiskInformation;
|
|
Entry = DiskInfo->DiskSignatures.Flink;
|
|
|
|
while (Entry != &DiskInfo->DiskSignatures) {
|
|
|
|
DiskSignature = CONTAINING_RECORD(Entry,ARC_DISK_SIGNATURE,ListEntry);
|
|
|
|
//
|
|
// Make sure there are no other disks with this same
|
|
// signature.
|
|
//
|
|
CheckEntry = Entry->Flink;
|
|
while( CheckEntry != &DiskInfo->DiskSignatures ) {
|
|
|
|
CheckDiskSignature = CONTAINING_RECORD(CheckEntry,ARC_DISK_SIGNATURE,ListEntry);
|
|
|
|
if( (CheckDiskSignature->Signature == DiskSignature->Signature) ) {
|
|
|
|
//
|
|
// We found another disk with the same disk signature.
|
|
// Stamp a new signature on the disk.
|
|
//
|
|
Status = SlpStampFTSignature(CheckDiskSignature, TRUE);
|
|
SignatureStamped = TRUE;
|
|
DisksStamped++;
|
|
|
|
if (Status != ESUCCESS) {
|
|
SlError(Status);
|
|
}
|
|
}
|
|
|
|
CheckEntry = CheckEntry->Flink;
|
|
}
|
|
|
|
//
|
|
// Now look for disk with no signature.
|
|
//
|
|
if (DiskSignature->ValidPartitionTable) {
|
|
if (DiskSignature->Signature == 0) {
|
|
Status = SlpStampFTSignature(DiskSignature, TRUE);
|
|
SignatureStamped = TRUE;
|
|
DisksStamped++;
|
|
|
|
if (Status != ESUCCESS) {
|
|
SlError(Status);
|
|
}
|
|
}
|
|
} else {
|
|
//
|
|
// See if the disk is vacant.
|
|
//
|
|
if (SlpIsDiskVacant(DiskSignature)) {
|
|
//
|
|
// If disk has the signature then use it otherwise
|
|
// stamp a new signature
|
|
//
|
|
Status = SlpStampFTSignature(DiskSignature,
|
|
(BOOLEAN) (DiskSignature->Signature == 0));
|
|
|
|
SignatureStamped = TRUE;
|
|
DisksStamped++;
|
|
|
|
if (Status != ESUCCESS) {
|
|
SlError(Status);
|
|
}
|
|
}
|
|
}
|
|
|
|
DiskCount++;
|
|
Entry = Entry->Flink;
|
|
}
|
|
|
|
//
|
|
// We've just changed the signatures on a disk. It might be
|
|
// okay to continue with the boot, but may not. Lets not reboot
|
|
// as textmode setup will bugcheck if the signatures
|
|
// are not stamped correctly.
|
|
//
|
|
if( SignatureStamped) {
|
|
|
|
if (Reboot) {
|
|
SlFatalError(SIGNATURE_CHANGED);
|
|
} else {
|
|
//
|
|
// Don't bother rescanning the disks if there is only
|
|
// one disk or we just stamped only one disk
|
|
//
|
|
if ((DiskCount > 1) && (DisksStamped > 1)) {
|
|
|
|
Status = BlGetArcDiskInformation(TRUE);
|
|
|
|
if (Status != ESUCCESS) {
|
|
SlFatalError(SIGNATURE_CHANGED);
|
|
}else {
|
|
//
|
|
// Reboot if first time signature
|
|
// stamping failed to update the disks
|
|
// correctly
|
|
//
|
|
SlpMarkDisks(TRUE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
SlpIsDiskVacant(
|
|
IN PARC_DISK_SIGNATURE DiskSignature
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine attempts to determine if a disk is 'vacant' by
|
|
checking to see if the first half of its MBR has all bytes set
|
|
to the same value.
|
|
|
|
Arguments:
|
|
|
|
DiskSignature - Supplies a pointer to the existing disk
|
|
signature structure.
|
|
|
|
Return Value:
|
|
|
|
TRUE - The disk is vacant.
|
|
FALSE - The disk is not vacant (ie, we can't determine if it
|
|
is vacant using our heuristic)
|
|
|
|
--*/
|
|
{
|
|
UCHAR Partition[100];
|
|
ULONG DiskId;
|
|
ARC_STATUS Status;
|
|
UCHAR SectorBuffer[512+256];
|
|
PUCHAR Sector;
|
|
LARGE_INTEGER SeekValue;
|
|
ULONG Count, i;
|
|
BOOLEAN IsVacant;
|
|
|
|
//
|
|
// Open partition0.
|
|
//
|
|
strcpy((PCHAR)Partition, DiskSignature->ArcName);
|
|
strcat((PCHAR)Partition, "partition(0)");
|
|
Status = ArcOpen((PCHAR)Partition, ArcOpenReadOnly, &DiskId);
|
|
if (Status != ESUCCESS) {
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Read in the first sector
|
|
//
|
|
Sector = ALIGN_BUFFER(SectorBuffer);
|
|
SeekValue.QuadPart = 0;
|
|
Status = ArcSeek(DiskId, &SeekValue, SeekAbsolute);
|
|
if (Status == ESUCCESS) {
|
|
Status = ArcRead(DiskId, Sector, 512, &Count);
|
|
}
|
|
if (Status != ESUCCESS) {
|
|
ArcClose(DiskId);
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// See if 1st 256 bytes are identical
|
|
//
|
|
for(i = 1, IsVacant = TRUE; i<256; i++) {
|
|
if(Sector[i] - *Sector) {
|
|
IsVacant = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
ArcClose(DiskId);
|
|
|
|
return(IsVacant);
|
|
}
|
|
|
|
|
|
|
|
ARC_STATUS
|
|
SlpStampFTSignature(
|
|
IN PARC_DISK_SIGNATURE DiskSignature,
|
|
IN BOOLEAN GenerateNewSignature
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine stamps a given drive with a unique signature.
|
|
It traverses the list of disk signatures to ensure that it
|
|
stamps a signature that is not already present in the
|
|
disk list. Then it writes the new disk signature to the
|
|
disk and recomputes the checksum.
|
|
|
|
Arguments:
|
|
|
|
DiskSignature - Supplies a pointer to the existing disk
|
|
signature structure.
|
|
|
|
GenerateNewSignature - Indicates whether to generate a new
|
|
signature or use the one in DiskSignature. When TRUE
|
|
this will also disable the check of duplicate signatures.
|
|
This argument is ignored when the DiskSignature->Signature
|
|
field is 0, since 0 is not a valid signature
|
|
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
ULONG NewSignature;
|
|
PLIST_ENTRY ListEntry;
|
|
UCHAR SectorBuffer[SECTOR_SIZE * 2];
|
|
PUCHAR Sector;
|
|
LARGE_INTEGER SeekValue;
|
|
UCHAR Partition[100];
|
|
PARC_DISK_SIGNATURE Signature;
|
|
ULONG DiskId;
|
|
ARC_STATUS Status;
|
|
ULONG i;
|
|
ULONG Sum;
|
|
ULONG Count;
|
|
|
|
|
|
if (GenerateNewSignature || (DiskSignature->Signature == 0)) {
|
|
//
|
|
// Get a reasonably unique seed to start with.
|
|
//
|
|
NewSignature = ArcGetRelativeTime();
|
|
NewSignature = (NewSignature & 0xFFFF) << 16;
|
|
NewSignature += ArcGetRelativeTime();
|
|
|
|
//
|
|
// Scan through the list to make sure it's unique.
|
|
//
|
|
ReScan:
|
|
ListEntry = BlLoaderBlock->ArcDiskInformation->DiskSignatures.Flink;
|
|
while (ListEntry != &BlLoaderBlock->ArcDiskInformation->DiskSignatures) {
|
|
Signature = CONTAINING_RECORD(ListEntry,ARC_DISK_SIGNATURE,ListEntry);
|
|
if (Signature->Signature == NewSignature) {
|
|
//
|
|
// Found a duplicate, pick a new number and
|
|
// try again.
|
|
//
|
|
if (++NewSignature == 0) {
|
|
//
|
|
// zero signatures are what we're trying to avoid
|
|
// (like this will ever happen)
|
|
//
|
|
NewSignature = 1;
|
|
}
|
|
goto ReScan;
|
|
}
|
|
ListEntry = ListEntry->Flink;
|
|
}
|
|
} else {
|
|
NewSignature = DiskSignature->Signature;
|
|
}
|
|
|
|
|
|
//
|
|
// Now we have a valid new signature to put on the disk.
|
|
// Read the sector off disk, put the new signature in,
|
|
// write the sector back, and recompute the checksum.
|
|
//
|
|
strcpy((PCHAR)Partition,DiskSignature->ArcName);
|
|
strcat((PCHAR)Partition,"partition(0)");
|
|
|
|
Status = ArcOpen((PCHAR)Partition, ArcOpenReadWrite, &DiskId);
|
|
|
|
if (Status != ESUCCESS) {
|
|
return(Status);
|
|
}
|
|
|
|
//
|
|
// Read in the first sector
|
|
//
|
|
Sector = ALIGN_BUFFER_WITH_SIZE(SectorBuffer, SECTOR_SIZE);
|
|
SeekValue.QuadPart = 0;
|
|
|
|
Status = ArcSeek(DiskId, &SeekValue, SeekAbsolute);
|
|
|
|
if (Status == ESUCCESS) {
|
|
Status = ArcRead(DiskId,Sector,512,&Count);
|
|
}
|
|
|
|
if (Status != ESUCCESS) {
|
|
ArcClose(DiskId);
|
|
return(Status);
|
|
}
|
|
|
|
//
|
|
// If partition table is not valid then initialize it with BOOT_RECORD_SIGNATURE and
|
|
// fill partition entries with zeros
|
|
//
|
|
if (((USHORT UNALIGNED *)Sector)[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE) {
|
|
memset(Sector + (PARTITION_TABLE_OFFSET * 2),
|
|
0,
|
|
SECTOR_SIZE - (PARTITION_TABLE_OFFSET * 2));
|
|
|
|
((USHORT UNALIGNED *)Sector)[BOOT_SIGNATURE_OFFSET] = BOOT_RECORD_SIGNATURE;
|
|
}
|
|
|
|
((ULONG UNALIGNED *)Sector)[PARTITION_TABLE_OFFSET/2-1] = NewSignature;
|
|
|
|
Status = ArcSeek(DiskId, &SeekValue, SeekAbsolute);
|
|
|
|
if (Status == ESUCCESS) {
|
|
Status = ArcWrite(DiskId,Sector,512,&Count);
|
|
}
|
|
|
|
ArcClose(DiskId);
|
|
|
|
if (Status != ESUCCESS) {
|
|
return(Status);
|
|
}
|
|
|
|
//
|
|
// We have successfully written back out the new signature,
|
|
// recompute the checksum.
|
|
//
|
|
DiskSignature->Signature = NewSignature;
|
|
DiskSignature->ValidPartitionTable = TRUE;
|
|
|
|
Sum = 0;
|
|
for (i=0;i<128;i++) {
|
|
Sum += ((PULONG)Sector)[i];
|
|
}
|
|
DiskSignature->CheckSum = 0-Sum;
|
|
|
|
return(ESUCCESS);
|
|
}
|
|
|
|
|
|
VOID
|
|
SlCheckOemKeypress(
|
|
IN ULONG WaitTime
|
|
)
|
|
{
|
|
|
|
ULONG StartTime;
|
|
ULONG EndTime;
|
|
ULONG c;
|
|
PTCHAR StatusText;
|
|
|
|
//
|
|
// For no particular reason some machines occasionally leave F7s
|
|
// in their keyboard buffer. Drain them out here.
|
|
//
|
|
#ifdef EFI
|
|
//
|
|
// disable EFI watchdog when draining keyboard buffer
|
|
//
|
|
DisableEFIWatchDog();
|
|
#endif
|
|
while (ArcGetReadStatus(ARC_CONSOLE_INPUT) == ESUCCESS) {
|
|
c = SlGetChar();
|
|
switch (c) {
|
|
case SL_KEY_F5: // Force OEM HAL prompt
|
|
PromptOemHal = TRUE;
|
|
break;
|
|
|
|
case SL_KEY_F6: // Force OEM SCSI prompt
|
|
PromptOemScsi = TRUE;
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
#ifdef EFI
|
|
//
|
|
// reset EFI watchdog
|
|
//
|
|
SetEFIWatchDog(EFI_WATCHDOG_TIMEOUT);
|
|
#endif
|
|
|
|
//
|
|
// HACK alert: The oem hal and SCSI stuff doesn't make sense in an RIS
|
|
// environment. Instead, the administrator should put the oem drivers
|
|
// on the RIS server. So we don't display the OEM drivers prompt, instead
|
|
// we hide it with some bogus "please wait" text. We do this instead of
|
|
// just skipping the check altogether so that the user will still have a
|
|
// chance to press F7 to disable ACPI.
|
|
//
|
|
StatusText = BlFindMessage(
|
|
BlBootingFromNet
|
|
? SL_PLEASE_WAIT
|
|
: SL_MSG_PRESS_F5_OR_F6);
|
|
if( StatusText != NULL ) {
|
|
SlWriteStatusText(StatusText);
|
|
}
|
|
|
|
StartTime = ArcGetRelativeTime();
|
|
|
|
if (WinPEBoot) {
|
|
EndTime = StartTime + WaitTime;
|
|
} else {
|
|
EndTime = StartTime + WaitTime;
|
|
}
|
|
|
|
do {
|
|
if(ArcGetReadStatus(ARC_CONSOLE_INPUT) == ESUCCESS) {
|
|
//
|
|
// There is a key pending, so see what it is.
|
|
//
|
|
c = SlGetChar();
|
|
|
|
switch(c) {
|
|
case SL_KEY_F4: // Disable OEM virtual devices.
|
|
DisableVirtualOemDevices = TRUE;
|
|
break;
|
|
|
|
case SL_KEY_F5: // Force OEM HAL prompt
|
|
PromptOemHal = TRUE;
|
|
break;
|
|
|
|
case SL_KEY_F6: // Force OEM SCSI prompt
|
|
PromptOemScsi = TRUE;
|
|
break;
|
|
|
|
case SL_KEY_F7:
|
|
DisableACPI = TRUE; // Force ACPI disabled
|
|
break;
|
|
|
|
case SL_KEY_F8: // Enable debugger
|
|
EnableDebugger = TRUE;
|
|
break;
|
|
|
|
case SL_KEY_F10:
|
|
UseCommandConsole = TRUE; // User wants to use cmdcons
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
} while (EndTime > ArcGetRelativeTime());
|
|
|
|
//
|
|
// see comment above -- we reset these values back to FALSE in the RIS
|
|
// scenario because they don't make sense
|
|
//
|
|
if (BlBootingFromNet) {
|
|
PromptOemHal = FALSE;
|
|
PromptOemScsi = FALSE;
|
|
} else {
|
|
SlWriteStatusText(TEXT(""));
|
|
}
|
|
}
|
|
|
|
VOID
|
|
SlCheckASRKeypress(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
See if the user is doing an ASR. If so, see if he's got a floppy
|
|
with asrpnp.sif on it. We'll ask him to press F5 for this.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
ARC_STATUS Status;
|
|
#define ASR_FILE "asrpnp.sif"
|
|
ULONG StartTime;
|
|
ULONG EndTime;
|
|
ULONG c;
|
|
PTCHAR StatusText;
|
|
CHAR FloppyName[80];
|
|
ULONG FloppyId;
|
|
CHAR FileName[128];
|
|
PVOID ASRPNPSifHandle = NULL;
|
|
BOOLEAN PromptASR = FALSE;
|
|
BOOLEAN Done = FALSE;
|
|
BOOLEAN FirstTry = TRUE;
|
|
|
|
#if defined(EFI)
|
|
//
|
|
// Turn off the EFI Watchdog
|
|
//
|
|
DisableEFIWatchDog();
|
|
#endif
|
|
|
|
do {
|
|
SlClearClientArea();
|
|
|
|
//
|
|
// Drain the keyboard buffer.
|
|
//
|
|
while (ArcGetReadStatus(ARC_CONSOLE_INPUT) == ESUCCESS) {
|
|
c = SlGetChar();
|
|
}
|
|
|
|
if (FirstTry) {
|
|
StatusText = BlFindMessage(SL_MSG_PRESS_ASR);
|
|
FirstTry = FALSE;
|
|
}
|
|
else {
|
|
StatusText = BlFindMessage(SL_MSG_PREPARING_ASR);
|
|
}
|
|
|
|
|
|
if( StatusText != NULL ) {
|
|
SlWriteStatusText(StatusText);
|
|
}
|
|
|
|
StartTime = ArcGetRelativeTime();
|
|
EndTime = StartTime + 5;
|
|
|
|
do {
|
|
if(ArcGetReadStatus(ARC_CONSOLE_INPUT) == ESUCCESS) {
|
|
//
|
|
// There is a key pending, so see what it is.
|
|
//
|
|
c = SlGetChar();
|
|
|
|
switch(c) {
|
|
|
|
case SL_KEY_F2: // Force ASR prompt
|
|
PromptASR = TRUE;
|
|
Done = TRUE;
|
|
break;
|
|
|
|
case ASCI_ESC:
|
|
PromptASR = FALSE;
|
|
Done = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
} while( !Done && (EndTime > ArcGetRelativeTime()) );
|
|
|
|
SlWriteStatusText(TEXT(""));
|
|
|
|
if( PromptASR ) {
|
|
Done = FALSE;
|
|
|
|
StatusText = BlFindMessage(SL_MSG_ENTERING_ASR);
|
|
if( StatusText != NULL ) {
|
|
SlWriteStatusText(StatusText);
|
|
}
|
|
|
|
//
|
|
// Build the filename we're looking for.
|
|
//
|
|
strcpy( FileName, "\\" );
|
|
strcat( FileName, ASR_FILE );
|
|
|
|
//
|
|
// Initialize pointers in loader block.
|
|
//
|
|
BlLoaderBlock->SetupLoaderBlock->ASRPnPSifFile = NULL;
|
|
BlLoaderBlock->SetupLoaderBlock->ASRPnPSifFileLength = 0;
|
|
Status = ESUCCESS;
|
|
|
|
//
|
|
// Try checking the installation media for asrpnp.sif
|
|
//
|
|
Status = SlInitIniFile( NULL,
|
|
BootDeviceId,
|
|
FileName,
|
|
&ASRPNPSifHandle,
|
|
&BlLoaderBlock->SetupLoaderBlock->ASRPnPSifFile,
|
|
&BlLoaderBlock->SetupLoaderBlock->ASRPnPSifFileLength,
|
|
&c );
|
|
|
|
if (ESUCCESS != Status) {
|
|
//
|
|
// Installation media doesn't contain the ASR files, we're
|
|
// going to have to prompt for the ASR floppy.
|
|
//
|
|
// Build the path to the floppy.
|
|
//
|
|
if (SlpFindFloppy(0,FloppyName)) {
|
|
Status = ArcOpen(FloppyName,ArcOpenReadOnly,&FloppyId);
|
|
|
|
//
|
|
// We found the floppy and opened him. See if he's
|
|
// got our file.
|
|
//
|
|
if( Status == ESUCCESS ) {
|
|
ASRPNPSifHandle = NULL;
|
|
|
|
Status = SlInitIniFile( NULL,
|
|
FloppyId,
|
|
FileName,
|
|
&ASRPNPSifHandle,
|
|
&BlLoaderBlock->SetupLoaderBlock->ASRPnPSifFile,
|
|
&BlLoaderBlock->SetupLoaderBlock->ASRPnPSifFileLength,
|
|
&c );
|
|
|
|
ArcClose(FloppyId);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// See if we successfully loaded the file off the
|
|
// floppy.
|
|
//
|
|
|
|
SlWriteStatusText(TEXT(""));
|
|
|
|
if( (Status != ESUCCESS) ||
|
|
(BlLoaderBlock->SetupLoaderBlock->ASRPnPSifFile == NULL) ) {
|
|
|
|
//
|
|
// Missed. Inform the user and we'll try again.
|
|
//
|
|
SlMessageBox(SL_MSG_WARNING_ASR);
|
|
|
|
} else if (BlLoaderBlock->SetupLoaderBlock->ASRPnPSifFileLength == 0) {
|
|
//
|
|
// Invalid ASR file: inform user and we'll try again
|
|
//
|
|
|
|
StatusText = BlFindMessage(SL_MSG_INVALID_ASRPNP_FILE);
|
|
|
|
//
|
|
// First display the ASR insert floppy message
|
|
//
|
|
SlDisplayMessageBox(SL_MSG_WARNING_ASR);
|
|
//
|
|
// Populate status area with the error
|
|
//
|
|
if( StatusText != NULL ) {
|
|
SlWriteStatusText(StatusText);
|
|
}
|
|
//
|
|
// Now wait for user to hit a key
|
|
//
|
|
SlFlushConsoleBuffer();
|
|
SlGetChar();
|
|
//
|
|
// Clear status just in case ...
|
|
//
|
|
if( StatusText != NULL ) {
|
|
SlWriteStatusText(TEXT(""));
|
|
}
|
|
|
|
} else {
|
|
Done = TRUE;
|
|
}
|
|
}
|
|
} while( PromptASR && !Done );
|
|
|
|
#if defined(EFI)
|
|
//
|
|
// Turn EFI Watchdog back on
|
|
//
|
|
SetEFIWatchDog(EFI_WATCHDOG_TIMEOUT);
|
|
#endif
|
|
}
|
|
|
|
|
|
SCSI_INSERT_STATUS
|
|
SlInsertScsiDevice(
|
|
IN ULONG Ordinal,
|
|
OUT PDETECTED_DEVICE *pScsiDevice
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine
|
|
|
|
Arguments:
|
|
|
|
Ordinal - Supplies the 0-based ordinal of the Scsi device
|
|
to insert (based on order listed in [Scsi.Load]
|
|
section of txtsetup.sif). If the Scsi device is a third party
|
|
driver, then Ordinal is -1 (SL_OEM_DEVICE_ORDINAL).
|
|
|
|
pScsiDevice - Receives a pointer to the inserted DETECTED_DEVICE structure,
|
|
the existing structure, or NULL.
|
|
Return Value:
|
|
|
|
ScsiInsertError - Not enough memory to allocate a new DETECTED_DEVICE.
|
|
ScsiInsertNewEntry - A new entry was inserted into the DETECTED_DEVICE list.
|
|
ScsiInsertExisting - An existing entry was found that matched the specified
|
|
ordinal, so we returned this entry.
|
|
|
|
--*/
|
|
{
|
|
PDETECTED_DEVICE prev, cur;
|
|
|
|
if(Ordinal == SL_OEM_DEVICE_ORDINAL) {
|
|
//
|
|
// This is a third-party driver, so find the end of the linked list
|
|
// (we want to preserve the order in which the user specifies the drivers).
|
|
//
|
|
for(prev=BlLoaderBlock->SetupLoaderBlock->ScsiDevices, cur = NULL;
|
|
prev && prev->Next;
|
|
prev=prev->Next);
|
|
} else {
|
|
//
|
|
// Find the insertion point in the linked list for this driver,
|
|
// based on its ordinal. (Note that we will insert all supported drivers
|
|
// before any third-party ones, since (ULONG)-1 = maximum unsigned long value)
|
|
//
|
|
for(prev = NULL, cur = BlLoaderBlock->SetupLoaderBlock->ScsiDevices;
|
|
cur && (Ordinal > cur->Ordinal);
|
|
prev = cur, cur = cur->Next);
|
|
}
|
|
|
|
if(cur && (cur->Ordinal == Ordinal)) {
|
|
//
|
|
// We found an existing entry for this driver
|
|
//
|
|
*pScsiDevice = cur;
|
|
return ScsiInsertExisting;
|
|
}
|
|
|
|
if((*pScsiDevice = BlAllocateHeap(sizeof(DETECTED_DEVICE))) == 0) {
|
|
return ScsiInsertError;
|
|
}
|
|
|
|
(*pScsiDevice)->Next = cur;
|
|
if(prev) {
|
|
prev->Next = *pScsiDevice;
|
|
} else {
|
|
BlLoaderBlock->SetupLoaderBlock->ScsiDevices = *pScsiDevice;
|
|
}
|
|
|
|
(*pScsiDevice)->Ordinal = Ordinal;
|
|
|
|
return ScsiInsertNewEntry;
|
|
}
|
|
|
|
|
|
ARC_STATUS
|
|
SlLoadPnpDriversSection(
|
|
IN PVOID Inf,
|
|
IN PCHAR SectionName,
|
|
IN OUT PDETECTED_DEVICE* DetectedDeviceList OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Enumerates all pnp drivers listed in [<section name>.Load], loads them, and puts
|
|
a list with all the the drivers loaded, in the setup loader block.
|
|
|
|
Arguments:
|
|
|
|
Inf - Supplies a handle to the INF file.
|
|
|
|
SectionName - Name of the section in the inf file that contains the list of
|
|
drivers to be loaded.
|
|
|
|
DetectedDeviceList - Address of the variable in Setup loader block that will contain
|
|
the list of drivers loaded. If this argument is NULL, then the list of
|
|
loaded devices will not be created.
|
|
|
|
Return Value:
|
|
|
|
ESUCCESS if all drivers were loaded successfully/no errors encountered
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG i;
|
|
CHAR LoadSectionName[100];
|
|
PCHAR DriverFilename;
|
|
PCHAR DriverId;
|
|
PTCHAR DriverDescription;
|
|
PCHAR NoLoadSpec;
|
|
ARC_STATUS Status;
|
|
PDETECTED_DEVICE TempDevice;
|
|
|
|
sprintf(LoadSectionName, "%s.Load",SectionName);
|
|
|
|
i=0;
|
|
do {
|
|
DriverFilename = SlGetSectionLineIndex(Inf,LoadSectionName,i,SIF_FILENAME_INDEX);
|
|
NoLoadSpec = SlGetSectionLineIndex(Inf,LoadSectionName,i,2);
|
|
|
|
if(DriverFilename && ((NoLoadSpec == NULL) || _stricmp(NoLoadSpec,"noload"))) {
|
|
DriverId = SlGetKeyName(Inf,LoadSectionName,i);
|
|
|
|
#ifdef UNICODE
|
|
DriverDescription = SlGetIniValueW(
|
|
Inf,
|
|
SectionName,
|
|
DriverId,
|
|
SlCopyStringAW(DriverId));
|
|
#else
|
|
DriverDescription = SlGetIniValue(
|
|
Inf,
|
|
SectionName,
|
|
DriverId,
|
|
DriverId);
|
|
#endif
|
|
|
|
Status = SlLoadDriver(DriverDescription,
|
|
DriverFilename,
|
|
0,
|
|
TRUE,
|
|
FALSE,
|
|
NULL
|
|
);
|
|
|
|
// if((Status == ENOENT) && IgnoreMissingFiles) {
|
|
// Status = ESUCCESS;
|
|
// }
|
|
|
|
if (Status == ESUCCESS) {
|
|
if( DetectedDeviceList != NULL ) {
|
|
//
|
|
// if the enumerator loaded, then record DETECTED_DEVICE info
|
|
//
|
|
TempDevice = BlAllocateHeap(sizeof(DETECTED_DEVICE));
|
|
|
|
if(!TempDevice) {
|
|
SlNoMemoryError();
|
|
|
|
return ENOMEM;
|
|
}
|
|
|
|
TempDevice->IdString = SlCopyStringA(DriverId);
|
|
TempDevice->Description = DriverDescription;
|
|
TempDevice->ThirdPartyOptionSelected = FALSE;
|
|
TempDevice->MigratedDriver = FALSE;
|
|
TempDevice->FileTypeBits = 0;
|
|
TempDevice->BaseDllName = SlCopyStringA(DriverFilename);
|
|
TempDevice->Next = *DetectedDeviceList;
|
|
*DetectedDeviceList = TempDevice;
|
|
}
|
|
} else {
|
|
SlFriendlyError(
|
|
Status,
|
|
DriverFilename,
|
|
__LINE__,
|
|
__FILE__
|
|
);
|
|
return(Status);
|
|
}
|
|
}
|
|
i++;
|
|
|
|
} while ( DriverFilename != NULL );
|
|
|
|
return(ESUCCESS);
|
|
}
|
|
|
|
|
|
ARC_STATUS
|
|
SlDetectMigratedScsiDrivers(
|
|
IN PVOID Inf
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Create an entry in the ScsiDevice list for each migrated SCSI driver.
|
|
|
|
Arguments:
|
|
|
|
Inf - Supplies a handle to the INF file.
|
|
|
|
Return Value:
|
|
|
|
ESUCCESS if all drivers were added to the ScsiDevice list.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG i;
|
|
CHAR LoadSectionName[100];
|
|
PCHAR DriverFilename;
|
|
PCHAR DriverId;
|
|
PTCHAR DriverDescription;
|
|
PDETECTED_DEVICE ScsiDevice;
|
|
SCSI_INSERT_STATUS sis;
|
|
|
|
i=0;
|
|
do {
|
|
DriverId = SlGetSectionLineIndex(Inf,"Devices",i,0);
|
|
if( DriverId ) {
|
|
sprintf(LoadSectionName, "Files.%s", DriverId);
|
|
|
|
DriverFilename = SlGetSectionLineIndex(Inf,LoadSectionName,0,0);
|
|
if(DriverFilename) {
|
|
|
|
//
|
|
// Remove inbox drivers with the same name as a winnt32-migrated OEM driver (if any)
|
|
//
|
|
SlRemoveInboxDriver (DriverFilename);
|
|
|
|
//
|
|
// Create a new detected device entry.
|
|
//
|
|
if((sis = SlInsertScsiDevice(SL_OEM_DEVICE_ORDINAL, &ScsiDevice)) == ScsiInsertError) {
|
|
return(ENOMEM);
|
|
}
|
|
|
|
if(sis == ScsiInsertExisting) {
|
|
#if DBG
|
|
//
|
|
// Sanity check to make sure we're talking about the same driver
|
|
//
|
|
if(_stricmp(ScsiDevice->BaseDllName, DriverFilename)) {
|
|
SlError(400);
|
|
return EINVAL;
|
|
}
|
|
#endif
|
|
} else {
|
|
DriverDescription = SlCopyString(BlFindMessage(SL_TEXT_SCSI_UNNAMED));
|
|
|
|
ScsiDevice->IdString = DriverId;
|
|
ScsiDevice->Description = DriverDescription;
|
|
ScsiDevice->ThirdPartyOptionSelected = FALSE;
|
|
ScsiDevice->MigratedDriver = TRUE;
|
|
ScsiDevice->FileTypeBits = 0;
|
|
ScsiDevice->Files = NULL;
|
|
ScsiDevice->BaseDllName = DriverFilename;
|
|
}
|
|
}
|
|
}
|
|
i++;
|
|
|
|
} while ( DriverId != NULL );
|
|
|
|
return(ESUCCESS);
|
|
}
|
|
|
|
|
|
|
|
ARC_STATUS
|
|
SlGetMigratedHardwareIds(
|
|
IN PSETUP_LOADER_BLOCK SetupBlock,
|
|
IN PVOID Inf
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add the hardware ids for the migrated scsi drivers, to the hardware id list.
|
|
|
|
Arguments:
|
|
|
|
SetupBlock - Supplies a pointer to the Setup loader block
|
|
|
|
Return Value:
|
|
|
|
ESUCCESS if all hardware ids were added to the hardware id list
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PCHAR DriverId;
|
|
ULONG i, j;
|
|
PPNP_HARDWARE_ID TempHardwareId;
|
|
PCHAR p;
|
|
|
|
for( j = 0;
|
|
(DriverId = SlGetSectionLineIndex(Inf,"Devices",j,0)) != NULL;
|
|
j++ ) {
|
|
CHAR SectionName[100];
|
|
|
|
sprintf(SectionName, "HardwareIds.%s", DriverId);
|
|
for( i = 0;
|
|
((p = SlGetKeyName( Inf, SectionName, i )) != NULL);
|
|
i++ ) {
|
|
TempHardwareId = BlAllocateHeap(sizeof(PNP_HARDWARE_ID));
|
|
|
|
if (TempHardwareId==NULL) {
|
|
SlNoMemoryError();
|
|
|
|
return ENOMEM;
|
|
}
|
|
|
|
TempHardwareId->Id = p;
|
|
p = SlGetSectionKeyIndex( Inf,
|
|
SectionName,
|
|
TempHardwareId->Id,
|
|
0 );
|
|
TempHardwareId->DriverName = p;
|
|
p = SlGetSectionKeyIndex( Inf,
|
|
SectionName,
|
|
TempHardwareId->Id,
|
|
1 );
|
|
TempHardwareId->ClassGuid = p;
|
|
|
|
TempHardwareId->Next = SetupBlock->HardwareIdDatabase;
|
|
SetupBlock->HardwareIdDatabase = TempHardwareId;
|
|
}
|
|
}
|
|
return( ESUCCESS );
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
SlIsCdBootUpgrade(
|
|
IN PCHAR InstallDirectory,
|
|
IN PCHAR SetupFileName,
|
|
IN ULONG MaxDisksToScan,
|
|
IN ULONG MaxPartitionsPerDisk,
|
|
OUT PCHAR NewSetupDevice
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Finds out by looking into the hard disk if the specified
|
|
directory exists and if the the user was indeed
|
|
trying to uprgade
|
|
|
|
Arguments:
|
|
|
|
InstallDirectory - Directory used on the hard disk
|
|
for installation
|
|
|
|
SetupFileName - Inf file name which has the key which
|
|
indicates if upgrade was in progress or
|
|
not
|
|
|
|
MaxDisksToScan - Maximum number of disks to scan
|
|
|
|
MaxPartitionsPerDisk - Maximum partitions per disk to look into
|
|
for the install directory.
|
|
|
|
NewSetupDevice - Place holder for arc name for the device
|
|
if user wants to switch to harddisk boot.
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE if upgrade was in progress and user selected to continue on
|
|
otherwise FALSE.
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN Result = FALSE;
|
|
CHAR DeviceName[128];
|
|
ARC_STATUS Status;
|
|
ULONG CurrentPartition;
|
|
ULONG CurrentDisk;
|
|
|
|
//
|
|
// Go through each disk
|
|
//
|
|
for (CurrentDisk = 0;
|
|
(!Result && (CurrentDisk < MaxDisksToScan));
|
|
CurrentDisk++) {
|
|
|
|
Status = ESUCCESS;
|
|
|
|
//
|
|
// Go through each valid partition
|
|
// for the current disk
|
|
//
|
|
for (CurrentPartition = 1;
|
|
(!Result && (Status == ESUCCESS));
|
|
CurrentPartition++) {
|
|
|
|
ULONG DiskId;
|
|
|
|
sprintf(DeviceName,
|
|
"multi(0)disk(0)rdisk(%d)partition(%d)",
|
|
CurrentDisk,
|
|
CurrentPartition);
|
|
|
|
Status = ArcOpen(DeviceName, ArcOpenReadOnly, &DiskId);
|
|
|
|
if (Status == ESUCCESS) {
|
|
CHAR FullName[128];
|
|
PVOID SifHandle = NULL;
|
|
ULONG ErrorLine = 0;
|
|
ARC_STATUS FileStatus;
|
|
|
|
//
|
|
// Function does not support the return of failures.
|
|
// so lets just truncate the string
|
|
//
|
|
_snprintf(FullName,
|
|
sizeof(FullName),
|
|
"%s\\%s",
|
|
InstallDirectory,
|
|
SetupFileName);
|
|
FullName[sizeof(FullName) - 1] = '\0';
|
|
|
|
FileStatus = SlInitIniFile(NULL,
|
|
DiskId,
|
|
FullName,
|
|
&SifHandle,
|
|
NULL,
|
|
NULL,
|
|
&ErrorLine);
|
|
|
|
if ((FileStatus == ESUCCESS) && SifHandle) {
|
|
Result = SlIsUpgrade(SifHandle);
|
|
}
|
|
|
|
ArcClose(DiskId);
|
|
} else {
|
|
//
|
|
// Ignore the error till the maximum number of
|
|
// partitions are searched for
|
|
//
|
|
if (CurrentPartition < MaxPartitionsPerDisk) {
|
|
Status = ESUCCESS;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Result) {
|
|
ULONG UserInput;
|
|
BOOLEAN OldStatus = SlGetStatusBarStatus();
|
|
|
|
//
|
|
// Reset the result based on user input
|
|
//
|
|
Result = FALSE;
|
|
|
|
SlEnableStatusBar(FALSE);
|
|
SlClearClientArea();
|
|
SlDisplayMessageBox(SL_UPGRADE_IN_PROGRESS);
|
|
|
|
#ifdef EFI
|
|
//
|
|
// disable watchdog timer for user input
|
|
//
|
|
DisableEFIWatchDog();
|
|
#endif
|
|
|
|
do {
|
|
SlFlushConsoleBuffer();
|
|
UserInput = SlGetChar();
|
|
}
|
|
while ((UserInput != ASCI_CR) &&
|
|
(UserInput != SL_KEY_F3) &&
|
|
(UserInput != SL_KEY_F10));
|
|
#ifdef EFI
|
|
//
|
|
// reset watchdog timer
|
|
//
|
|
SetEFIWatchDog(EFI_WATCHDOG_TIMEOUT);
|
|
#endif
|
|
|
|
SlClearClientArea();
|
|
|
|
if (UserInput == SL_KEY_F3) {
|
|
ArcRestart();
|
|
} else if (UserInput == ASCI_CR) {
|
|
Result = TRUE;
|
|
strcpy(NewSetupDevice, DeviceName);
|
|
}
|
|
|
|
SlEnableStatusBar(OldStatus);
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
SlIsUpgrade(
|
|
IN PVOID SifHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Finds out by looking into the SIF file if upgrade is
|
|
in progress or not
|
|
|
|
Arguments:
|
|
|
|
InfHandle - Handle to winnt.sif file
|
|
|
|
Return Value:
|
|
|
|
TRUE if upgrade is in progress otherwise FALSE
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN Result = FALSE;
|
|
|
|
if (SifHandle) {
|
|
PCHAR NtUpgrade = SlGetSectionKeyIndex(SifHandle,
|
|
WINNT_DATA_A,
|
|
WINNT_D_NTUPGRADE_A,
|
|
0);
|
|
|
|
if (NtUpgrade) {
|
|
Result = (BOOLEAN) (_stricmp(NtUpgrade, WINNT_A_YES_A) == 0);
|
|
}
|
|
|
|
if (!Result) {
|
|
PCHAR Win9xUpgrade = SlGetSectionKeyIndex(SifHandle,
|
|
WINNT_DATA_A,
|
|
WINNT_D_WIN95UPGRADE_A,
|
|
0);
|
|
|
|
|
|
if (Win9xUpgrade) {
|
|
Result = (BOOLEAN) (_stricmp(Win9xUpgrade, WINNT_A_YES_A) == 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
BOOLEAN
|
|
SlIsVirtualOemDeviceDisabled(
|
|
IN PVOID SifHandle,
|
|
IN PPREINSTALL_DRIVER_INFO PreinstallDriverList
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
Finds out if we need to enable or disable the loading of virtual OEM devices.
|
|
|
|
Arguments:
|
|
|
|
InfHandle - Handle to winnt.sif file
|
|
|
|
PreinstallDriverList - PreInstall Driver List
|
|
|
|
Return Value:
|
|
BOOLEAN, TRUE/FALSE
|
|
--*/
|
|
{
|
|
|
|
|
|
if((!DisableVirtualOemDevices) && (SifHandle)){
|
|
//
|
|
// Is Preinstall?
|
|
//
|
|
if (PreinstallDriverList != NULL){
|
|
DisableVirtualOemDevices = TRUE;
|
|
}else{
|
|
PCHAR p;
|
|
p = SlGetSectionKeyIndex(SifHandle,
|
|
WINNT_UNATTENDED_A,
|
|
WINNT_DISABLE_VIRTUAL_OEM_DEVICES_A,
|
|
0);
|
|
|
|
//
|
|
// In case of unattended setup.
|
|
// if we have set the option in the unattend file DisableVirtualOemDevices = yes
|
|
// then disable the virtual oem source devices
|
|
//
|
|
if(p && (!_stricmp(p ,WINNT_A_YES_A))) {
|
|
DisableVirtualOemDevices = TRUE;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
return DisableVirtualOemDevices;
|
|
}
|
|
|
|
VOID
|
|
SlDisableVirtualOemDevices(
|
|
IN POEM_SOURCE_DEVICE OemDeviceList
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
Marks the Virtual Oem Devices as Skipped.
|
|
|
|
Arguments:
|
|
|
|
OemDeviceList - The list of OEM devices
|
|
|
|
Return Value:
|
|
None.
|
|
--*/
|
|
{
|
|
//
|
|
// If the DisableVirtualOemDevices is set to TRUE mark the Virtual OEM devices
|
|
// as skipped.
|
|
//
|
|
if ((DisableVirtualOemDevices) && (OemDeviceList)){
|
|
POEM_SOURCE_DEVICE CurrentDevice = OemDeviceList;
|
|
|
|
while (CurrentDevice) {
|
|
//
|
|
// If this is an OEM source device marked virtual then mark it as skipped.
|
|
//
|
|
if(SL_OEM_SOURCE_DEVICE_TYPE(CurrentDevice,
|
|
SL_OEM_SOURCE_DEVICE_TYPE_VIRTUAL)){
|
|
|
|
SL_OEM_SET_SOURCE_DEVICE_STATE( CurrentDevice,
|
|
SL_OEM_SOURCE_DEVICE_SKIPPED);
|
|
}
|
|
CurrentDevice = CurrentDevice->Next;
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOLEAN
|
|
SlpIsDynamicUpdate(
|
|
IN PVOID InfHandle,
|
|
OUT PCSTR *DynamicUpdateRootDir
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Finds out whether there are any dynamic update boot drivers
|
|
to process or not.
|
|
|
|
Arguments:
|
|
|
|
InfHandle - Handle to winnt.sif file
|
|
|
|
DynamicUpdateRootDir - Receives the root directory under which all
|
|
the dynamic update boot driver packages are present.
|
|
|
|
Return Value:
|
|
|
|
TRUE, if there are dynamic update boot drivers otherwise
|
|
FALSE
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN Result = FALSE;
|
|
|
|
if (InfHandle) {
|
|
PCHAR DynUpdateKey = SlGetSectionKeyIndex(InfHandle,
|
|
WINNT_SETUPPARAMS_A,
|
|
WINNT_SP_DYNUPDTBOOTDRIVERPRESENT_A,
|
|
0);
|
|
|
|
PCHAR DynUpdateRoot = SlGetSectionKeyIndex(InfHandle,
|
|
WINNT_SETUPPARAMS_A,
|
|
WINNT_SP_DYNUPDTBOOTDRIVERROOT_A,
|
|
0);
|
|
|
|
//
|
|
// DynamicUpdateBootDriverPresent and DynamicUpateBootDriverRoot
|
|
// should have valid values
|
|
//
|
|
Result = (BOOLEAN) (DynUpdateKey && DynUpdateRoot &&
|
|
!_stricmp(DynUpdateKey, "yes"));
|
|
|
|
if (Result && DynamicUpdateRootDir) {
|
|
*DynamicUpdateRootDir = SlCopyStringA(DynUpdateRoot);
|
|
}
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
UCHAR
|
|
SlGetDefaultAttr(
|
|
VOID
|
|
)
|
|
{
|
|
return (UCHAR)((UseRegularBackground) ? (ATT_FG_WHITE | ATT_BG_BLACK) : (ATT_FG_WHITE | ATT_BG_BLUE));
|
|
}
|
|
|
|
UCHAR
|
|
SlGetDefaultInvAttr(
|
|
VOID
|
|
)
|
|
{
|
|
return (UCHAR)((UseRegularBackground) ? (ATT_FG_BLACK | ATT_BG_WHITE) : (ATT_FG_BLUE | ATT_BG_WHITE));
|
|
}
|
|
|
|
#ifdef _IA64_
|
|
|
|
BOOLEAN
|
|
SlIsWinPEAutoBoot(
|
|
IN PSTR LoaderDeviceName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determines if this is an automated WinPE boot.
|
|
|
|
NOTE : Automated WinPE boot is determined by the presence
|
|
of the $WINPE$.$$$ file at the same location where
|
|
setupldr.efi was started from.
|
|
|
|
Arguments:
|
|
|
|
LoaderDeviceName : Arcname of the device where setupldr
|
|
was started from.
|
|
|
|
Return Value:
|
|
|
|
TRUE if this is WinPE auto boot, otherwise FALSE.
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN Result = FALSE;
|
|
|
|
if (LoaderDeviceName) {
|
|
ULONG DiskId;
|
|
ARC_STATUS Status;
|
|
|
|
//
|
|
// open the partition
|
|
//
|
|
Status = ArcOpen(LoaderDeviceName, ArcOpenReadOnly, &DiskId);
|
|
|
|
if (Status == ESUCCESS) {
|
|
CHAR FileName[128];
|
|
ARC_STATUS FileStatus;
|
|
ULONG FileId;
|
|
|
|
//
|
|
// check for the existence of \$WINPE$.$$$
|
|
//
|
|
strcpy(FileName, "\\");
|
|
strcat(FileName, WINPE_AUTOBOOT_FILENAME);
|
|
|
|
FileStatus = BlOpen(DiskId, FileName, ArcOpenReadOnly, &FileId);
|
|
|
|
if (FileStatus == ESUCCESS) {
|
|
BlClose(FileId);
|
|
Result = TRUE;
|
|
}
|
|
|
|
ArcClose(DiskId);
|
|
}
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
ARC_STATUS
|
|
SlGetWinPEStartupParams(
|
|
IN OUT PSTR StartupDeviceName,
|
|
IN OUT PSTR StartupDirectory
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Searches for the WinPE installation on the available
|
|
partitions on the first 4 disks.
|
|
|
|
Arguments:
|
|
|
|
StartupDeviceName - place holder for receiving device name
|
|
where WinPE installation was found.
|
|
|
|
StartupDirectory - place holder for receiving WinPE installation
|
|
directory.
|
|
|
|
Return Value:
|
|
|
|
Appropriate ARC_STATUS error code.
|
|
|
|
--*/
|
|
{
|
|
ARC_STATUS Status = EINVAL;
|
|
|
|
//
|
|
// validate arguments
|
|
//
|
|
if (StartupDeviceName && StartupDirectory) {
|
|
BOOLEAN Found = FALSE;
|
|
CHAR DeviceName[128];
|
|
ULONG CurrentPartition;
|
|
ULONG CurrentDisk;
|
|
|
|
//
|
|
// Go through each disk (at the max 4)
|
|
//
|
|
for (CurrentDisk = 0;
|
|
(!Found && (CurrentDisk < 4));
|
|
CurrentDisk++) {
|
|
|
|
//
|
|
// Go through each valid partition
|
|
// for the current disk
|
|
//
|
|
for (CurrentPartition = 1, Status = ESUCCESS;
|
|
(!Found && (Status == ESUCCESS));
|
|
CurrentPartition++) {
|
|
|
|
ULONG DiskId;
|
|
|
|
sprintf(DeviceName,
|
|
"multi(0)disk(0)rdisk(%d)partition(%d)",
|
|
CurrentDisk,
|
|
CurrentPartition);
|
|
|
|
//
|
|
// open the disk
|
|
//
|
|
Status = ArcOpen(DeviceName, ArcOpenReadOnly, &DiskId);
|
|
|
|
if (Status == ESUCCESS) {
|
|
CHAR FullName[128];
|
|
ARC_STATUS FileStatus;
|
|
ULONG DirId;
|
|
|
|
//
|
|
// check for the existence of \\winpe\\ia64\\system32 directory
|
|
//
|
|
strcpy(FullName, "\\WINPE\\ia64\\system32");
|
|
|
|
FileStatus = BlOpen(DiskId, FullName, ArcOpenDirectory, &DirId);
|
|
|
|
if (FileStatus == ESUCCESS) {
|
|
BlClose(DirId);
|
|
Found = TRUE;
|
|
}
|
|
|
|
ArcClose(DiskId);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// update return arguments
|
|
//
|
|
if (Found && (ESUCCESS == Status)) {
|
|
strcpy(StartupDeviceName, DeviceName);
|
|
strcpy(StartupDirectory, "\\WINPE\\ia64\\");
|
|
}
|
|
|
|
if (!Found) {
|
|
Status = EBADF;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
#endif // _IA64_
|
|
|
|
|
|
#ifdef _X86_
|
|
|
|
ARC_STATUS
|
|
SlLoadBootFontFile(
|
|
IN PSETUP_LOADER_BLOCK SetupLoaderBlock,
|
|
IN ULONG DiskId,
|
|
IN ULONG BootFontImageLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Loads the bootfont.bin into memory and initializes
|
|
relevant fields in setup loader block.
|
|
|
|
Arguments:
|
|
|
|
SetupLoaderBlock - pointer to setup loader block.
|
|
|
|
DiskId - Disk ID where bootfont.bin resides on the root
|
|
|
|
BootFontImageLength - The length of the bootfont.bin file.
|
|
|
|
Return Value:
|
|
|
|
Appropriate ARC_STATUS error code.
|
|
|
|
--*/
|
|
{
|
|
ARC_STATUS Status = EINVAL;
|
|
|
|
//
|
|
// verify arguments
|
|
//
|
|
if (SetupLoaderBlock && BootFontImageLength) {
|
|
ULONG FileId;
|
|
PVOID Image = NULL;
|
|
|
|
//
|
|
// open the bootfont.bin file
|
|
//
|
|
if (BlBootingFromNet
|
|
#if defined(REMOTE_BOOT)
|
|
&& NetworkBootRom
|
|
#endif // defined(REMOTE_BOOT)
|
|
) {
|
|
CHAR Buffer[129];
|
|
|
|
strcpy(Buffer, NetBootPath);
|
|
strcat(Buffer, "BOOTFONT.BIN");
|
|
|
|
Status = BlOpen(DiskId,
|
|
Buffer,
|
|
ArcOpenReadOnly,
|
|
&FileId);
|
|
} else {
|
|
Status = BlOpen(DiskId,
|
|
"\\BOOTFONT.BIN",
|
|
ArcOpenReadOnly,
|
|
&FileId);
|
|
}
|
|
|
|
//
|
|
// allocate memory and read the contents of the file
|
|
// into memory
|
|
//
|
|
if (ESUCCESS == Status) {
|
|
Image = BlAllocateHeap(BootFontImageLength);
|
|
|
|
if (Image) {
|
|
ULONG BytesRead = 0;
|
|
|
|
Status = BlRead(FileId, Image, BootFontImageLength, &BytesRead);
|
|
|
|
if ((ESUCCESS == Status) && (BytesRead != BootFontImageLength)) {
|
|
Status = EIO;
|
|
}
|
|
} else {
|
|
Status = ENOMEM;
|
|
}
|
|
|
|
BlClose(FileId);
|
|
}
|
|
|
|
if (Image && (ESUCCESS == Status)) {
|
|
SetupLoaderBlock->BootFontFile = Image;
|
|
SetupLoaderBlock->BootFontFileLength = BootFontImageLength;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
#endif
|
|
|
|
BOOLEAN
|
|
SlGetNextOption(
|
|
IN OUT PCSTR* Options,
|
|
IN OUT ULONG_PTR* Length
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Scans and returns the next load option in the input string. Scanning stops at the
|
|
end of the string or at the first empty option (should not happen).
|
|
|
|
Arguments:
|
|
|
|
Options - On input, holds the pointer to the current load option, not including the starting slash.
|
|
On output, contains the start of the next load option, not including the starting slash.
|
|
Options cannot be NULL, but *Options can.
|
|
|
|
Length - On input, contains the length of the current load option (pointed to by *Options), not inlcuding
|
|
the starting slash.
|
|
On output, holds the length of the next load option (pointed to by the new *Options), not
|
|
including the starting slash.
|
|
Cannot be NULL.
|
|
|
|
Note: to get the first load option in the string, *Options must point to the start of the
|
|
string (before or at the first slash) and *Length must be zero.
|
|
|
|
Return Value:
|
|
|
|
TRUE if there is a non-empty load option retured in *Options; FALSE if no subsequent options in the string
|
|
or if the next option is empty (e.g. '//' - shouldn't happen).
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN bFound = FALSE;
|
|
|
|
if(*Options != NULL) {
|
|
*Options = strchr(*Options + *Length, '/');
|
|
|
|
if(*Options != NULL) {
|
|
PCSTR szEnd = strchr(++(*Options), '/');
|
|
|
|
if(NULL == szEnd) {
|
|
szEnd = *Options + strlen(*Options);
|
|
}
|
|
|
|
while(szEnd != *Options && ' ' == szEnd[-1]) {
|
|
--szEnd;
|
|
}
|
|
|
|
*Length = szEnd - *Options;
|
|
bFound = (BOOLEAN) (*Length != 0);
|
|
}
|
|
}
|
|
|
|
return bFound;
|
|
}
|
|
|
|
BOOLEAN
|
|
SlModifyOsLoadOptions(
|
|
IN OUT PSTR* LoadOptions,
|
|
IN PCSTR OptionsToAdd OPTIONAL,
|
|
IN PCSTR OptionsToRemove OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Modifies the string containing the load options by adding and/or removing options to/from the string.
|
|
First, the options to remove are removed from the options string, and then the options to add are added.
|
|
This function does not check if OptionsToAdd and OptionsToRemove have common options; if this happens,
|
|
those options will be removed and then added back.
|
|
|
|
Arguments:
|
|
|
|
LoadOptions - On input, holds the pointer to the current load options string, which must be allocated on the heap.
|
|
On output, holds the new options string (if modified), also allocated on the heap (can be empty).
|
|
|
|
OptionsToAdd - Contains the string of options to add to the *LoadOptions string. All options must be
|
|
preceded by a slash. Can be NULL or empty.
|
|
|
|
OptionsToRemove - Contains the string of options to remove from the *LoadOptions string. All options must be
|
|
preceded by a slash. Can be NULL or empty.
|
|
|
|
Return Value:
|
|
|
|
TRUE if the *LoadOptions string was modified and thus reallocated; FALSE if *LoadOptions was left alone.
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN bChanged = FALSE;
|
|
PSTR szOption = *LoadOptions;
|
|
ULONG_PTR Length = 0;
|
|
PCSTR szSearch;
|
|
ULONG_PTR Length2;
|
|
ULONG_PTR TotalLength = 0;
|
|
ULONG_PTR Count = 0;
|
|
ULONG_PTR i;
|
|
|
|
static struct {
|
|
PCSTR szOption;
|
|
ULONG_PTR Length;
|
|
} Options[50];
|
|
|
|
const ULONG_PTR MaxOptions = sizeof(Options) / sizeof(Options[0]);
|
|
|
|
while(Count < MaxOptions && SlGetNextOption(&szOption, &Length)) {
|
|
BOOLEAN bRemove = FALSE;
|
|
szSearch = OptionsToRemove;
|
|
Length2 = 0;
|
|
|
|
while(SlGetNextOption(&szSearch, &Length2)) {
|
|
if(Length == Length2 && 0 == _strnicmp(szOption, szSearch, Length)) {
|
|
//
|
|
// Need to remove this option
|
|
//
|
|
bChanged = bRemove = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(!bRemove) {
|
|
//
|
|
// Add the option to the list. We'll prepend '/' and append a space so we'll need 2 extra chars.
|
|
// The space will become the terminator for the last option.
|
|
//
|
|
Options[Count].szOption = szOption;
|
|
Options[Count].Length = Length;
|
|
TotalLength += Options[Count].Length + 2;
|
|
++Count;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Add the new options if they are not already present
|
|
//
|
|
szSearch = OptionsToAdd;
|
|
Length2 = 0;
|
|
|
|
while(Count < MaxOptions && SlGetNextOption(&szSearch, &Length2)) {
|
|
BOOLEAN bAdd = TRUE;
|
|
|
|
for(i = 0; i < Count; ++i) {
|
|
if(Options[i].Length == Length2 && 0 == _strnicmp(Options[i].szOption, szSearch, Length2)) {
|
|
bAdd = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(bAdd) {
|
|
Options[Count].szOption = szSearch;
|
|
Options[Count].Length = Length2;
|
|
TotalLength += Options[Count].Length + 2;
|
|
++Count;
|
|
bChanged = TRUE;
|
|
}
|
|
}
|
|
|
|
if(bChanged) {
|
|
//
|
|
// Need to create a new options string
|
|
//
|
|
PSTR szNewOptions;
|
|
|
|
if(0 == Count) {
|
|
//
|
|
// We'll allocate an empty string
|
|
//
|
|
TotalLength = 1;
|
|
}
|
|
|
|
ASSERT(TotalLength != 0);
|
|
szNewOptions = (LPSTR) BlAllocateHeap((ULONG) TotalLength);
|
|
|
|
if(NULL == szNewOptions) {
|
|
SlNoMemoryError();
|
|
} else {
|
|
szNewOptions[0] = 0;
|
|
|
|
if(Count != 0) {
|
|
szOption = szNewOptions;
|
|
|
|
for(i = 0; i < Count; ++i) {
|
|
*szOption++ = '/';
|
|
RtlCopyMemory(szOption, Options[i].szOption, Options[i].Length);
|
|
szOption += Options[i].Length;
|
|
*szOption++ = ' ';
|
|
}
|
|
|
|
szOption[-1] = 0;
|
|
}
|
|
}
|
|
|
|
*LoadOptions = szNewOptions;
|
|
}
|
|
|
|
return bChanged;
|
|
}
|
|
|