Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

2526 lines
67 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"
#define BlDiagLoadMessage(x,y,z)
#define VGA_DRIVER_FILENAME "vga.sys"
#define KERNEL_IMAGE_FILENAME "ntkrnlmp.exe"
//
// Global string constants.
//
PCHAR FilesSectionName = "SourceDisksFiles";
PCHAR MediaSectionName = "SourceDisksNames";
#if defined(_ALPHA_)
PCHAR PlatformExtension = ".alpha";
#elif defined(_MIPS_)
PCHAR PlatformExtension = ".mips";
#elif defined(_PPC_)
PCHAR PlatformExtension = ".ppc";
#elif defined(_X86_)
PCHAR PlatformExtension = ".x86";
#endif
//
// Global data
//
ULONG BlDcacheFillSize = 32;
//
// 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;
BOOLEAN LoadScsiMiniports;
BOOLEAN LoadDiskClass;
BOOLEAN LoadCdfs;
BOOLEAN FixedBootMedia = FALSE;
PVOID InfFile;
PVOID WinntSifHandle;
BOOLEAN IgnoreMissingFiles;
//
// Pre-install stuff
//
PCHAR OemTag = "OEM";
BOOLEAN PreInstall = FALSE;
PCHAR ComputerType = NULL;
BOOLEAN OemHal = FALSE;
PPREINSTALL_DRIVER_INFO PreinstallDriverList = NULL;
#if defined(ELTORITO)
extern BOOLEAN ElToritoCDBoot;
#endif
//
// Define transfer entry of loaded image.
//
typedef
VOID
(*PTRANSFER_ROUTINE) (
PLOADER_PARAMETER_BLOCK LoaderBlock
);
//
// Local function prototypes
//
VOID
SlGetSetupValues(
IN PSETUP_LOADER_BLOCK SetupBlock
);
ARC_STATUS
SlLoadDriver(
IN PCHAR DeviceName,
IN PCHAR DriverName,
IN ULONG DriverFlags,
IN BOOLEAN InsertIntoDriverList
);
ARC_STATUS
SlLoadOemDriver(
IN PCHAR ExportDriver, OPTIONAL
IN PCHAR DriverName,
IN PVOID BaseAddress,
IN PCHAR LoadMessage
);
PBOOT_DRIVER_LIST_ENTRY
SlpCreateDriverEntry(
IN PCHAR DriverName
);
ARC_STATUS
SlLoadSection(
IN PVOID Inf,
IN PCHAR SectionName,
IN BOOLEAN IsScsiSection
);
BOOLEAN
SlpIsDiskVacant(
IN PARC_DISK_SIGNATURE DiskSignature
);
ARC_STATUS
SlpStampFTSignature(
IN PARC_DISK_SIGNATURE DiskSignature
);
VOID
SlpMarkDisks(
VOID
);
VOID
SlCheckOemKeypress(
VOID
);
ARC_STATUS
SlLoadBusExtender(
IN PVOID Inf
);
ARC_STATUS
SlInit(
IN ULONG Argc,
IN PCHAR Argv[],
IN PCHAR 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.
--*/
{
PCONFIGURATION_COMPONENT_DATA DataCache;
ARC_STATUS Status;
ULONG LinesPerBlock;
ULONG CacheLineSize;
CHAR SetupDevice[128];
CHAR SetupDirectory[128];
CHAR BadFileName[128];
CHAR CanonicalName[128];
CHAR HalDirectoryPath[256];
CHAR KernelDirectoryPath[256];
PCHAR p;
ULONG ErrorLine=0;
ULONG DontCare;
PVOID SystemBase;
PVOID HalBase;
PVOID ScsiBase;
PVOID VideoBase;
PLDR_DATA_TABLE_ENTRY SystemDataTableEntry;
PLDR_DATA_TABLE_ENTRY HalDataTableEntry;
PTRANSFER_ROUTINE SystemEntry;
PIMAGE_NT_HEADERS NtHeaders;
PBOOT_DRIVER_LIST_ENTRY DriverEntry;
PSETUP_LOADER_BLOCK SetupBlock;
PDETECTED_DEVICE ScsiDevice;
PCHAR VideoFileName;
PCHAR VideoDescription;
PCHAR OemScsiName;
POEMSCSIINFO OemScsiInfo;
PCHAR OemVideoName;
BOOLEAN LoadedAVideoDriver = FALSE;
//
// 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;
}
SetupBlock = BlAllocateHeap(sizeof(SETUP_LOADER_BLOCK));
if (SetupBlock==NULL) {
SlNoMemoryError();
goto LoadFailed;
}
BlLoaderBlock->SetupLoaderBlock = SetupBlock;
SetupBlock->ScsiDevices = NULL;
SetupBlock->ScalarValues.SetupFromCdRom = FALSE;
SetupBlock->ScalarValues.SetupOperation = SetupOperationSetup;
SetupBlock->ScalarValues.LoadedScsi = 0;
SetupBlock->ScalarValues.LoadedCdRomDrivers = 0;
SetupBlock->ScalarValues.LoadedDiskDrivers = 0;
SetupBlock->ScalarValues.LoadedFloppyDrivers = 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;
}
SlPositionCursor(5,3);
//
// 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);
}
//
// Initialize the display and announce ourselves
//
SlInitDisplay();
SlWriteHeaderText(SL_WELCOME_HEADER);
SlClearClientArea();
#if defined(_X86_) && !defined(ALLOW_386)
//
// Disallow installation on a 386
//
{
extern BOOLEAN SlIs386(VOID);
if(SlIs386()) {
SlFatalError(SL_TEXT_REQUIRES_486);
}
}
#endif
//
// 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],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);
//
// extract directory from our startup path.
//
if(*(p+1) != '\\') {
//
// directory must begin at root
//
strcpy(SetupDirectory, "\\");
} else {
*SetupDirectory = '\0';
}
strcat(SetupDirectory, p+1);
p=strrchr(SetupDirectory, '\\');
*(p+1) = '\0';
}
#if defined(ELTORITO)
if (ElToritoCDBoot) {
//
// Use the i386 directory for setup files when we boot from an El Torito CD
//
strcat(SetupDirectory, "i386\\");
}
#endif
//
// 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();
strcpy(KernelDirectoryPath, SetupDirectory);
strcat(KernelDirectoryPath, "txtsetup.sif");
BlLoaderBlock->SetupLoaderBlock->IniFile = NULL;
Status = SlInitIniFile(SetupDevice,
0,
KernelDirectoryPath,
&InfFile,
&ErrorLine);
if (Status != ESUCCESS) {
SlFatalError(SL_BAD_INF_FILE,"txtsetup.sif");
goto LoadFailed;
}
SlGetSetupValues(SetupBlock);
//
// 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 = SlCopyString(SetupDevice);
}
Status = ArcOpen(BootDevice, ArcOpenReadOnly, &BootDeviceId);
if (Status != ESUCCESS) {
SlFatalError(SL_IO_ERROR,BootDevice);
goto LoadFailed;
} else {
BootDeviceIdValid = TRUE;
}
_strlwr(BootDevice);
FixedBootMedia = (strstr(BootDevice,")rdisk(") != 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.
//
#ifdef _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.
//
if(FixedBootMedia) {
BootPath = SlCopyString("\\$WIN_NT$.~BT\\");
} else
#endif
BootPath = SlCopyString(SetupDirectory);
}
BlLoaderBlock->NtBootPathName = BootPath;
//
// Attempt to load winnt.sif from the path where we are
// loading setup files. Borrow the BadFileName buffer
// for temporary use.
//
strcpy(BadFileName,BootPath);
strcat(BadFileName,WINNT_SIF_FILE);
Status = SlInitIniFile(NULL,BootDeviceId,BadFileName,&WinntSifHandle,&DontCare);
if(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,WINNT_U_OEMPREINSTALL,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 ) {
ComputerType = SlGetSectionKeyIndex(WinntSifHandle,WINNT_UNATTENDED,WINNT_U_COMPUTERTYPE,0);
if(ComputerType) {
//
// If the hal to load is an OEM one, then set OemHal to TRUE
//
p = SlGetSectionKeyIndex(WinntSifHandle,WINNT_UNATTENDED,WINNT_U_COMPUTERTYPE,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 ) ) {
ULONG i;
PPREINSTALL_DRIVER_INFO TempDriverInfo;
PreinstallDriverList = NULL;
for( i = 0;
((p = SlGetKeyName( WinntSifHandle, WINNT_OEMSCSIDRIVERS, i )) != NULL);
i++ ) {
TempDriverInfo = BlAllocateHeap(sizeof(PREINSTALL_DRIVER_INFO));
if (TempDriverInfo==NULL) {
SlNoMemoryError();
goto LoadFailed;
}
TempDriverInfo->DriverDescription = p;
p = SlGetIniValue( WinntSifHandle,
WINNT_OEMSCSIDRIVERS,
TempDriverInfo->DriverDescription,
NULL );
TempDriverInfo->OemDriver = (p && !_stricmp(p, OemTag))? 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,WINNT_S_SKIPMISSING,0);
if(p && (*p != '0')) {
IgnoreMissingFiles = TRUE;
}
} else {
WinntSifHandle = NULL;
}
//
// Initialize the debugging system.
//
BlLogInitialize(BootDeviceId);
//
// Do PPC-specific initialization.
//
#if defined(_PPC_)
Status = BlPpcInitialize();
if (Status != ESUCCESS) {
goto LoadFailed;
}
#endif // defined(_PPC_)
SlGetDisk(KERNEL_IMAGE_FILENAME);
strcpy(KernelDirectoryPath, BootPath);
strcat(KernelDirectoryPath,KERNEL_IMAGE_FILENAME);
BlOutputLoadMessage(BlFindMessage(SL_KERNEL_NAME), KernelDirectoryPath);
Status = BlLoadImage(BootDeviceId,
LoaderSystemCode,
KernelDirectoryPath,
TARGET_IMAGE,
&SystemBase);
if (Status != ESUCCESS) {
SlFatalError(SL_FILE_LOAD_FAILED,KernelDirectoryPath,Status);
goto LoadFailed;
}
strcpy(HalDirectoryPath, BootPath);
if (PromptOemHal || (PreInstall && (ComputerType != NULL))) {
if(PreInstall && OemHal) {
//
// This is a pre-install and an OEM hal was specified
//
strcat( HalDirectoryPath,
#ifdef _X86_
WINNT_OEM_DIR
#else
WINNT_OEM_TEXTMODE_DIR
#endif
);
strcat( HalDirectoryPath, "\\" );
}
SlPromptOemHal(&HalBase, &HalName);
strcat(HalDirectoryPath,HalName);
} else {
strcat(HalDirectoryPath,HalName);
SlGetDisk(HalName);
BlOutputLoadMessage(BlFindMessage(SL_HAL_NAME), HalDirectoryPath);
Status = BlLoadImage(BootDeviceId,
LoaderHalCode,
HalDirectoryPath,
TARGET_IMAGE,
&HalBase);
if (Status != ESUCCESS) {
SlFatalError(SL_FILE_LOAD_FAILED,HalDirectoryPath,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,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,HalDirectoryPath,Status);
goto LoadFailed;
}
#if defined(_ALPHA_)
{
CHAR PalFileName[32];
CHAR FloppyName[80];
PCHAR DiskDescription;
ULONG FloppyId;
PDETECTED_DEVICE OemPal;
PDETECTED_DEVICE_FILE OemPalFile;
//
// Get the name of the pal file we are suppose to load.
//
Status = BlGeneratePalName(PalFileName);
//
// If we get an error from BlGenereatePalName, something is
// really wrong with the firmware or the ARC tree. Abort and
// bail out.
//
if (Status != ESUCCESS) {
SlFatalError(SL_FILE_LOAD_FAILED,PalFileName,Status);
goto LoadFailed;
}
//
// Try loading the pal file from the boot device.
//
//
// NOTE John Vert (jvert) 4-Feb-1994
// Below call assumes all the PALs are on
// the same floppy. We really should check the SIF
// file and go immediately to the diskette prompt
// if it's not in the SIF file, otherwise get
// the appropriate disk.
//
SetupBlock->OemPal = NULL;
SlGetDisk("A321064.PAL");
Status = BlLoadPal(BootDeviceId,
LoaderSystemCode,
BootPath,
TARGET_IMAGE,
&BlLoaderBlock->u.Alpha.PalBaseAddress,
BlFindMessage(SL_PAL_NAME));
//
// If we have failed, prompt the user for a floppy that contains
// the pal code and load it from floppy. We keep looping until
// either we get the right disk, or we get an error other than
// 'file not found'.
//
if(Status == ENOENT) {
DiskDescription = BlFindMessage(SL_OEM_DISK_PROMPT);
}
while (Status == ENOENT) {
SlClearClientArea();
//
// Compute the name of the A: drive.
//
if (!SlpFindFloppy(0,FloppyName)) {
//
// No floppy drive available, bail out.
//
SlFatalError(SL_FILE_LOAD_FAILED,PalFileName,Status);
goto LoadFailed;
}
//
// Prompt for the disk.
//
SlPromptForDisk(DiskDescription, FALSE);
//
// Open the floppy.
//
Status = ArcOpen(FloppyName, ArcOpenReadOnly, &FloppyId);
if (Status != ESUCCESS) {
//
// We want to give the user another chance if they didn't
// have a floppy inserted.
//
if(Status != ENOENT) {
Status = (Status == EIO) ? ENOENT : Status;
}
continue;
}
//
// Load the pal file from the root of the floppy.
//
Status = BlLoadPal(FloppyId,
LoaderSystemCode,
"\\",
TARGET_IMAGE,
&BlLoaderBlock->u.Alpha.PalBaseAddress,
BlFindMessage(SL_PAL_NAME));
ArcClose(FloppyId);
//
// if we found the PAL, then record DETECTED_DEVICE info
//
if(Status == ESUCCESS) {
OemPal = BlAllocateHeap(sizeof(DETECTED_DEVICE));
if(!OemPal) {
SlNoMemoryError();
}
SetupBlock->OemPal = OemPal;
OemPal->Next = NULL;
OemPal->IdString = NULL;
OemPal->Description = NULL;
OemPal->ThirdPartyOptionSelected = TRUE;
OemPal->FileTypeBits = 0;
OemPalFile = BlAllocateHeap(sizeof(DETECTED_DEVICE_FILE));
if(!OemPalFile) {
SlNoMemoryError();
}
OemPal->Files = OemPalFile;
OemPalFile->Next = NULL;
OemPalFile->Filename = SlCopyString(PalFileName);
OemPalFile->FileType = HwFileMax;
OemPalFile->ConfigName = NULL;
OemPalFile->RegistryValueList = NULL;
OemPalFile->DiskDescription = SlCopyString(DiskDescription);
OemPalFile->DiskTagfile = NULL;
OemPalFile->Directory = SlCopyString("");
}
}
if(Status != ESUCCESS) {
SlFriendlyError(
Status,
PalFileName,
__LINE__,
__FILE__
);
goto LoadFailed;
}
}
#endif // ifdef _ALPHA_
Status = BlScanImportDescriptorTable(BootDeviceId,
BootDevice,
BootPath,
SystemDataTableEntry);
if (Status != ESUCCESS) {
SlFatalError(SL_FILE_LOAD_FAILED,KERNEL_IMAGE_FILENAME,Status);
}
//
// Scan the import table for the HAL DLL and load all referenced DLLs.
//
Status = BlScanImportDescriptorTable(BootDeviceId,
BootDevice,
BootPath,
HalDataTableEntry);
if (Status != ESUCCESS) {
SlFatalError(SL_FILE_LOAD_FAILED,"hal.dll",Status);
goto LoadFailed;
}
//
// Relocate the system entry point and set system specific information.
//
NtHeaders = RtlImageNtHeader(SystemBase);
SystemEntry = (PTRANSFER_ROUTINE)((ULONG)SystemBase +
NtHeaders->OptionalHeader.AddressOfEntryPoint);
#if defined(_MIPS_)
BlLoaderBlock->u.Mips.GpBase = (ULONG)SystemBase +
NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_GLOBALPTR].VirtualAddress;
#endif
#if defined(_ALPHA_)
BlLoaderBlock->u.Alpha.GpBase = (ULONG)SystemBase +
NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_GLOBALPTR].VirtualAddress;
#endif
//
// Load registry's SYSTEM hive
//
SlGetDisk("SETUPREG.HIV");
Status = BlLoadSystemHive(BootDeviceId,
BlFindMessage(SL_HIVE_NAME),
BootPath,
"SETUPREG.HIV");
if (Status != ESUCCESS) {
SlFatalError(SL_FILE_LOAD_FAILED,"SETUPREG.HIV",Status);
goto LoadFailed;
}
//
// 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,
BlFindMessage(SL_OEM_FONT_NAME),
BootPath,
&OemHalFont,
BadFileName);
if(Status != ESUCCESS) {
SlFatalError(SL_FILE_LOAD_FAILED, OemHalFontName, 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,
BlFindMessage(SL_NLS_NAME),
BootPath,
&AnsiCodepage,
&OemCodepage,
&UnicodeCaseTable,
BadFileName);
if(Status != ESUCCESS) {
SlFatalError(SL_FILE_LOAD_FAILED, AnsiCpName, Status);
goto LoadFailed;
}
//
// Load the system drivers we will need here
//
InitializeListHead(&BlLoaderBlock->BootDriverListHead);
//
// Always load setupdd.sys first, it will need to prep the rest of the
// system.
//
Status = SlLoadDriver(BlFindMessage(SL_SETUP_NAME),
"setupdd.sys",
0,
TRUE
);
if (Status != ESUCCESS) {
SlFatalError(SL_FILE_LOAD_FAILED,"setupdd.sys",Status);
goto LoadFailed;
}
//
// Fill in its registry key.
//
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");
//
// Load the Winnt.SIF file *here*
//
//
// Load bus extenders.
// It has to be done before scsiport.sys
//
Status = SlLoadBusExtender( InfFile );
//
// 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
);
//
// Detect scsi, video
//
// (If the user wants to select their own SCSI devices, we won't
// do any detection)
//
if(!PromptOemScsi && (PreinstallDriverList == NULL) ) {
SlDetectScsi(SetupBlock);
}
SlDetectVideo(SetupBlock);
#if defined(ELTORITO)
//
// If this is an El Torito CD-ROM install, then we want to load all SCSI miniports
// and disk class drivers.
//
if(ElToritoCDBoot) {
LoadScsiMiniports = TRUE;
}
#endif
//
// If the LoadScsi flag is set, enumerate all the known SCSI miniports and load each
// one.
//
if(LoadScsiMiniports) {
Status = SlLoadSection(InfFile,"Scsi",TRUE);
if (Status!=ESUCCESS) {
goto LoadFailed;
}
SetupBlock->ScalarValues.LoadedScsi = 1;
}
//
// Allow the user to pick an OEM SCSI driver here
//
if (PromptOemScsi || (PreinstallDriverList != NULL) ) {
SlPromptOemScsi(&OemScsiInfo);
}
//
// 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 {
Status = SlLoadDriver(ScsiDevice->Description,
ScsiDevice->BaseDllName,
0,
TRUE
);
}
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);
if (Status == ESUCCESS) {
SetupBlock->ScalarValues.LoadedDiskDrivers = 1;
} else {
goto LoadFailed;
}
}
//
// 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) {
#if 0
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
Status = SlLoadDriver(VideoDescription,
VideoFileName,
0,
TRUE
);
if (Status == ESUCCESS) {
SetupBlock->VideoDevice.BaseDllName = SlCopyString(VideoFileName);
} else {
SlFriendlyError(
Status,
VideoFileName,
__LINE__,
__FILE__
);
goto LoadFailed;
}
LoadedAVideoDriver = TRUE;
}
} else if (PromptOemVideo) {
SlPromptOemVideo(&VideoBase, &OemVideoName);
Status = SlLoadOemDriver(
"VIDEOPRT.SYS",
OemVideoName,
VideoBase,
BlFindMessage(SL_VIDEO_NAME)
);
if(Status==ESUCCESS) {
LoadedAVideoDriver = TRUE;
SetupBlock->VideoDevice.BaseDllName = SlCopyString(OemVideoName);
}
}
if(!LoadedAVideoDriver) {
Status = SlLoadDriver(BlFindMessage(SL_VIDEO_NAME),
VGA_DRIVER_FILENAME,
0,
TRUE
);
if(Status == ESUCCESS) {
SetupBlock->VideoDevice.BaseDllName = SlCopyString(VGA_DRIVER_FILENAME);
} else {
SlFriendlyError(
Status,
VGA_DRIVER_FILENAME,
__LINE__,
__FILE__
);
goto LoadFailed;
}
}
if(SetupBlock->VideoDevice.IdString == NULL) {
SetupBlock->VideoDevice.IdString = SlCopyString("VGA");
}
//
// Load the floppy driver
//
Status = SlLoadDriver(BlFindMessage(SL_FLOPPY_NAME),
"floppy.sys",
0,
TRUE
);
if (Status == ESUCCESS) {
SetupBlock->ScalarValues.LoadedFloppyDrivers = 1;
}
#ifdef i386
else {
SlFriendlyError(
Status,
"floppy.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);
if (Status != ESUCCESS) {
goto LoadFailed;
}
}
//
// Load the keyboard driver
//
SetupBlock->KeyboardDevice.Next = NULL;
SetupBlock->KeyboardDevice.IdString = SlCopyString("Keyboard");
SetupBlock->KeyboardDevice.ThirdPartyOptionSelected = FALSE;
SetupBlock->KeyboardDevice.FileTypeBits = 0;
SetupBlock->KeyboardDevice.BaseDllName = SlCopyString("i8042prt.sys");
Status = SlLoadDriver(BlFindMessage(SL_KBD_NAME),
"i8042prt.sys",
0,
TRUE
);
if(Status != ESUCCESS) {
SlFriendlyError(
Status,
"i8042prt.sys",
__LINE__,
__FILE__
);
goto LoadFailed;
}
Status = SlLoadDriver(BlFindMessage(SL_KBD_NAME),
"kbdclass.sys",
0,
TRUE
);
if(Status != ESUCCESS) {
SlFriendlyError(
Status,
"kbdclass.sys",
__LINE__,
__FILE__
);
goto LoadFailed;
}
//
// Load FAT
//
Status = SlLoadDriver(BlFindMessage(SL_FAT_NAME),
"fastfat.sys",
0,
TRUE
);
#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);
if (Status == ESUCCESS) {
SetupBlock->ScalarValues.LoadedCdRomDrivers = 1;
} else {
goto LoadFailed;
}
}
//
// 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.
//
BlGetArcDiskInformation();
SlpMarkDisks();
//
// 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);
}
//
//
// Execute the architecture specific setup code.
//
Status = BlSetupForNt(BlLoaderBlock);
if (Status != ESUCCESS) {
SlFriendlyError(
Status,
"\"Windows NT Executive\"",
__LINE__,
__FILE__
);
goto LoadFailed;
}
//
// Turn off the debugging system.
//
BlLogTerminate();
//
// Transfer control to loaded image.
//
(SystemEntry)(BlLoaderBlock);
Status = EBADF;
SlFriendlyError(
Status,
"\"Windows NT Executive\"",
__LINE__,
__FILE__
);
LoadFailed:
SlWriteStatusText(BlFindMessage(SL_TOTAL_SETUP_DEATH));
SlFlushConsoleBuffer();
SlGetChar();
ArcRestart();
return(Status);
}
VOID
SlGetSetupValues(
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 MachineName = NULL;
PCHAR NlsName;
ANSI_STRING NlsString;
BlLoaderBlock->LoadOptions = SlGetIniValue(InfFile,
"setupdata",
"osloadoptions",
"");
//
// 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 = (atoi(SlGetIniValue(InfFile,
"setupdata",
"ForceOemHal",
"0")) == 1);
}
if(!PromptOemHal) {
MachineName = SlDetectHal(SetupBlock);
}
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 = SlCopyString("");
if(MachineName!=NULL) {
SetupBlock->ComputerDevice.IdString = SlCopyString(MachineName);
HalName = SlGetIniValue(InfFile,
"Hal.Load",
MachineName,
NULL);
HalDescription = SlGetIniValue(InfFile,
"Computer",
MachineName,
NULL);
}
if(!(MachineName && HalName && HalDescription)) {
PromptOemHal = TRUE;
}
AnsiCpName = SlGetIniValue(InfFile,
"nls",
"AnsiCodepage",
"c_1252.nls");
NlsString.Buffer = AnsiCpName;
NlsString.Length = strlen(AnsiCpName);
AnsiCodepage.MaximumLength = strlen(AnsiCpName)*sizeof(WCHAR)+sizeof(UNICODE_NULL);
AnsiCodepage.Buffer = BlAllocateHeap(AnsiCodepage.MaximumLength);
RtlAnsiStringToUnicodeString(&AnsiCodepage, &NlsString, FALSE);
NlsName = SlGetIniValue(InfFile,
"nls",
"OemCodepage",
"c_437.nls");
NlsString.Buffer = NlsName;
NlsString.Length = strlen(NlsName);
OemCodepage.MaximumLength = strlen(NlsName)*sizeof(WCHAR)+sizeof(UNICODE_NULL);
OemCodepage.Buffer = BlAllocateHeap(OemCodepage.MaximumLength);
RtlAnsiStringToUnicodeString(&OemCodepage, &NlsString, FALSE);
NlsName = SlGetIniValue(InfFile,
"nls",
"UnicodeCasetable",
"l_intl.nls");
NlsString.Buffer = NlsName;
NlsString.Length = strlen(NlsName);
UnicodeCaseTable.MaximumLength = strlen(NlsName)*sizeof(WCHAR)+sizeof(UNICODE_NULL);
UnicodeCaseTable.Buffer = BlAllocateHeap(UnicodeCaseTable.MaximumLength);
RtlAnsiStringToUnicodeString(&UnicodeCaseTable, &NlsString, FALSE);
OemHalFontName = SlGetIniValue(InfFile,
"nls",
"OemHalFont",
"vgaoem.fon");
NlsString.Buffer = OemHalFontName;
NlsString.Length = strlen(OemHalFontName);
OemHalFont.MaximumLength = strlen(OemHalFontName)*sizeof(WCHAR)+sizeof(UNICODE_NULL);
OemHalFont.Buffer = BlAllocateHeap(OemHalFont.MaximumLength);
RtlAnsiStringToUnicodeString(&OemHalFont, &NlsString, FALSE);
LoadScsiMiniports = (atoi(SlGetIniValue(InfFile,
"SetupData",
"ForceScsi",
"0")) == 1);
LoadDiskClass = (atoi(SlGetIniValue(InfFile,
"setupdata",
"ForceDiskClass",
"0")) == 1);
LoadCdfs = (atoi(SlGetIniValue(InfFile,
"setupdata",
"ForceCdRom",
"0")) == 1);
//
// 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 = (atoi(SlGetIniValue(InfFile,
"setupdata",
"ForceOemScsi",
"0")) == 1);
}
BootPath = SlGetIniValue(InfFile,
"setupdata",
"BootPath",
NULL);
BootDevice = SlGetIniValue(InfFile,
"setupdata",
"BootDevice",
NULL);
return;
}
VOID
BlOutputLoadMessage (
IN PCHAR DeviceName,
IN PCHAR FileName
)
/*++
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.
Return Value:
None.
--*/
{
CHAR OutputBuffer[256];
PCHAR FormatString;
//
// Construct and output loading file message.
//
FormatString = BlFindMessage(SL_FILE_LOAD_MESSAGE);
sprintf(OutputBuffer,FormatString,DeviceName);
SlWriteStatusText(OutputBuffer);
return;
}
ARC_STATUS
SlLoadDriver(
IN PCHAR DeviceName,
IN PCHAR DriverName,
IN ULONG DriverFlags,
IN BOOLEAN InsertIntoDriverList
)
/*++
Routine Description:
Attempts to load a driver from the device identified by the global
variable BootDeviceId.
Arguments:
DeviceName - Supplies the name of the device.
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)
Return Value:
ESUCCESS - Driver successfully loaded
--*/
{
PBOOT_DRIVER_LIST_ENTRY DriverEntry;
NTSTATUS Status;
CHAR DriverPath[128];
PLDR_DATA_TABLE_ENTRY DataTableEntry;
if(BlCheckForLoadedDll(DriverName,&DataTableEntry)) {
return(ESUCCESS);
}
DriverEntry = SlpCreateDriverEntry(DriverName);
if(DriverEntry == NULL) {
SlNoMemoryError();
return(ENOMEM);
}
SlGetDisk(DriverName);
strcpy(DriverPath,BootPath);
Status = BlLoadDeviceDriver(
BootDeviceId,
DeviceName,
DriverPath,
DriverName,
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 PCHAR LoadMessage
)
{
PBOOT_DRIVER_LIST_ENTRY DriverEntry;
ARC_STATUS Status;
PLDR_DATA_TABLE_ENTRY DataTableEntry;
if(BlCheckForLoadedDll(DriverName,&DataTableEntry)) {
return(ESUCCESS);
}
if(ExportDriver) {
SlGetDisk(ExportDriver);
}
DriverEntry = SlpCreateDriverEntry(DriverName);
if (DriverEntry==NULL) {
return(ENOMEM);
}
Status = BlAllocateDataTableEntry(
DriverName,
DriverName,
BaseAddress,
&DriverEntry->LdrEntry
);
if (Status == ESUCCESS) {
Status = BlScanImportDescriptorTable(
BootDeviceId,
LoadMessage,
BootPath,
DriverEntry->LdrEntry
);
if(Status == ESUCCESS) {
InsertTailList(&BlLoaderBlock->BootDriverListHead,&DriverEntry->Link);
}
}
return(Status);
}
PBOOT_DRIVER_LIST_ENTRY
SlpCreateDriverEntry(
IN PCHAR DriverName
)
/*++
Routine Description:
Allocates and initializes a boot driver list entry structure.
Arguments:
DriverName - Supplies the name of the driver.
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);
}
DriverEntry->FilePath.MaximumLength = strlen(DriverName)*sizeof(WCHAR)+1;
DriverEntry->FilePath.Buffer = BlAllocateHeap(DriverEntry->FilePath.MaximumLength);
if (DriverEntry->FilePath.Buffer==NULL) {
SlNoMemoryError();
return(NULL);
}
String.Length = strlen(DriverName);
String.Buffer = DriverName;
RtlAnsiStringToUnicodeString(&DriverEntry->FilePath, &String, FALSE);
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;
PCHAR DiskName;
PCHAR DiskTag;
ULONG FileId;
CHAR PlatformSpecificSection[128];
//
// If the media is fixed, the user can't change disks.
// Just return TRUE indicating that the disk is in the drive.
//
if(FixedBootMedia) {
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,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);
if(DiskName = SlGetSectionKeyIndex(InfFile,PlatformSpecificSection,DiskNumber,0)) {
DiskTag = SlGetSectionKeyIndex(InfFile,PlatformSpecificSection,DiskNumber,1);
} else {
if(DiskName = SlGetSectionKeyIndex(InfFile,MediaSectionName,DiskNumber,0)) {
DiskTag = SlGetSectionKeyIndex(InfFile,MediaSectionName,DiskNumber,1);
} else {
SlFatalError(SL_INF_ENTRY_MISSING,DiskNumber,MediaSectionName);
return(FALSE);
}
}
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);
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);
}
}
}
PCHAR
SlCopyString(
IN PCHAR String
)
/*++
Routine Description:
Copies a 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();
}
Buffer = BlAllocateHeap(strlen(String)+1);
if (Buffer==NULL) {
SlNoMemoryError();
} else {
strcpy(Buffer, String);
}
return(Buffer);
}
ARC_STATUS
SlLoadSection(
IN PVOID Inf,
IN PCHAR SectionName,
IN BOOLEAN IsScsiSection
)
/*++
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.
Return Value:
ESUCCESS if all drivers were loaded successfully/no errors encountered
--*/
{
ULONG i;
CHAR LoadSectionName[100];
PCHAR DriverFilename;
PCHAR DriverId;
PCHAR DriverDescription;
PCHAR NoLoadSpec;
PCHAR p;
ARC_STATUS Status;
PDETECTED_DEVICE ScsiDevice;
SCSI_INSERT_STATUS sis;
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"))) {
if(!IsScsiSection) {
//
// We only want to load the drivers if they aren't scsi miniports
//
DriverId = SlGetKeyName(Inf,LoadSectionName,i);
DriverDescription = SlGetIniValue(Inf,SectionName,DriverId,"noname");
Status = SlLoadDriver(DriverDescription,
DriverFilename,
0,
TRUE
);
if((Status == ENOENT) && IgnoreMissingFiles) {
Status = ESUCCESS;
}
} else {
Status = ESUCCESS;
}
if (Status == ESUCCESS) {
if(IsScsiSection) {
//
// Create a new detected device entry.
//
if((sis = SlInsertScsiDevice(i, &ScsiDevice)) == ScsiInsertError) {
return(ENOMEM);
}
if(sis == ScsiInsertExisting) {
#if DBG
//
// Sanity check to make sure we're talking about the same driver
//
if(_strcmpi(ScsiDevice->BaseDllName, DriverFilename)) {
SlError(400);
return EINVAL;
}
#endif
} else {
p = SlGetKeyName(Inf,LoadSectionName,i);
//
// Find the driver description
//
if(p) {
DriverDescription = SlGetIniValue(Inf,
SectionName,
p,
p);
} else {
DriverDescription = SlCopyString(BlFindMessage(SL_TEXT_SCSI_UNNAMED));
}
ScsiDevice->IdString = p ? p : SlCopyString("");
ScsiDevice->Description = DriverDescription;
ScsiDevice->ThirdPartyOptionSelected = FALSE;
ScsiDevice->FileTypeBits = 0;
ScsiDevice->Files = NULL;
ScsiDevice->BaseDllName = DriverFilename;
}
}
} else {
SlFriendlyError(
Status,
DriverFilename,
__LINE__,
__FILE__
);
return(Status);
}
}
i++;
} while ( DriverFilename != NULL );
return(ESUCCESS);
}
VOID
SlpMarkDisks(
VOID
)
/*++
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:
None.
Return Value:
None.
--*/
{
PARC_DISK_INFORMATION DiskInfo;
PLIST_ENTRY Entry;
PLIST_ENTRY CheckEntry;
PARC_DISK_SIGNATURE DiskSignature;
PARC_DISK_SIGNATURE CheckSignature;
ARC_STATUS Status;
BOOLEAN VacantDiskFound = FALSE;
DiskInfo = BlLoaderBlock->ArcDiskInformation;
Entry = DiskInfo->DiskSignatures.Flink;
while (Entry != &DiskInfo->DiskSignatures) {
DiskSignature = CONTAINING_RECORD(Entry,ARC_DISK_SIGNATURE,ListEntry);
if (DiskSignature->ValidPartitionTable) {
if (DiskSignature->Signature==0) {
//
// Check the rest of the list to see if there is another
// disk with the same checksum and an signature of zero.
//
CheckEntry = Entry->Flink;
while (CheckEntry != &DiskInfo->DiskSignatures) {
CheckSignature = CONTAINING_RECORD(CheckEntry,ARC_DISK_SIGNATURE,ListEntry);
if ((CheckSignature->Signature==0) &&
(CheckSignature->ValidPartitionTable) &&
(CheckSignature->CheckSum == DiskSignature->CheckSum)) {
//
// We have two disks that are indistinguishable, both do
// not have signatures. Mark the first one with a signature
// so that they can be differentiated by textmode setup.
//
Status = SlpStampFTSignature(DiskSignature);
if (Status != ESUCCESS) {
SlError(Status);
}
break;
} else {
CheckEntry = CheckEntry->Flink;
}
}
}
} else {
//
// See if the disk is vacant, to find out whether we can mess with it.
//
if (SlpIsDiskVacant(DiskSignature)) {
//
// stamp all but the first one.
//
if (VacantDiskFound) {
Status = SlpStampFTSignature(DiskSignature);
if (Status != ESUCCESS) {
SlError(Status);
}
} else {
VacantDiskFound = TRUE;
}
}
}
Entry = Entry->Flink;
}
}
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(Partition, DiskSignature->ArcName);
strcat(Partition, "partition(0)");
Status = ArcOpen(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
)
/*++
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.
Return Value:
None.
--*/
{
ULONG NewSignature;
PLIST_ENTRY ListEntry;
UCHAR SectorBuffer[512+256];
PUCHAR Sector;
LARGE_INTEGER SeekValue;
UCHAR Partition[100];
PARC_DISK_SIGNATURE Signature;
ULONG DiskId;
ARC_STATUS Status;
ULONG i;
ULONG Sum;
ULONG Count;
//
// Get a reasonably unique seed to start with.
//
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;
}
//
// 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(Partition,DiskSignature->ArcName);
strcat(Partition,"partition(0)");
Status = ArcOpen(Partition, ArcOpenReadWrite, &DiskId);
if (Status != ESUCCESS) {
return(Status);
}
//
// 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(Status);
}
((PULONG)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;
Sum = 0;
for (i=0;i<128;i++) {
Sum += ((PULONG)Sector)[i];
}
DiskSignature->CheckSum = 0-Sum;
return(ESUCCESS);
}
VOID
SlCheckOemKeypress(
VOID
)
{
ULONG StartTime;
ULONG EndTime;
ULONG c;
StartTime = ArcGetRelativeTime();
EndTime = StartTime + 3;
do {
if(ArcGetReadStatus(ARC_CONSOLE_INPUT) == ESUCCESS) {
//
// There is a key pending, so see what it is.
//
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;
}
}
} while (EndTime > ArcGetRelativeTime());
}
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.
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 == (ULONG)-1) {
//
// 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)))) {
return ScsiInsertError;
}
(*pScsiDevice)->Next = cur;
if(prev) {
prev->Next = *pScsiDevice;
} else {
BlLoaderBlock->SetupLoaderBlock->ScsiDevices = *pScsiDevice;
}
(*pScsiDevice)->Ordinal = Ordinal;
return ScsiInsertNewEntry;
}
ARC_STATUS
SlLoadBusExtender(
IN PVOID Inf
)
/*++
Routine Description:
Loads all known extender drivers.
Arguments:
Inf - Supplies a handle to the INF file.
Return Value:
ESUCCESS if all drivers were loaded successfully/no errors encountered
--*/
{
return( SlLoadSection(Inf,"Extenders",FALSE) );
}