2020-09-30 17:12:29 +02:00

1589 lines
37 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
regboot.c
Abstract:
Provides a minimal registry implementation designed to be used by the
osloader at boot time. This includes loading the system hive
( <SystemRoot>\config\SYSTEM ) into memory, and computing the driver
load list from it.
Author:
John Vert (jvert) 10-Mar-1992
Revision History:
--*/
#include "bldr.h"
#include "msg.h"
#include "cmp.h"
#include "stdio.h"
#include "string.h"
CMHIVE BootHive;
ULONG CmLogLevel=100;
ULONG CmLogSelect=0;
ULONG ScreenWidth=80;
ULONG ScreenHeight=25;
ULONG LkgStartTime;
//
// defines for doing console I/O
//
#define ASCII_CR 0x0d
#define ASCII_LF 0x0a
#define ESC 0x1B
#define SGR_INVERSE 7
#define SGR_INTENSE 1
#define SGR_NORMAL 0
//
// Private function prototypes
//
BOOLEAN
BlInitializeHive(
IN PVOID HiveImage,
IN PCMHIVE Hive,
IN BOOLEAN IsAlternate
);
BOOLEAN
BlpCheckRestartSetup(
VOID
);
PVOID
BlpHiveAllocate(
IN ULONG Length,
IN BOOLEAN UseForIo
);
//
// prototypes for console I/O routines
//
VOID
BlpClearScreen(
VOID
);
VOID
BlClearToEndOfScreen(
VOID
);
VOID
BlpClearToEndOfLine(
VOID
);
VOID
BlpPositionCursor(
IN ULONG Column,
IN ULONG Row
);
VOID
BlpSetInverseMode(
IN BOOLEAN InverseOn
);
VOID
BlStartConfigPrompt(
VOID
)
/*++
Routine Description:
This routine displays the LKG prompt, records the current time,
and returns. The prompt is displayed before the kernel and HAL
are loaded, and then removed afterwards.
Arguments:
None.
Return Value:
None.
--*/
{
ULONG Count;
PCHAR LkgPrompt;
LkgPrompt = BlFindMessage(BL_LKG_MENU_PROMPT);
if (LkgPrompt==NULL) {
return;
}
//
// display LKG prompt
//
BlpPositionCursor(1,3);
ArcWrite(BlConsoleOutDeviceId,
LkgPrompt,
strlen(LkgPrompt),
&Count);
BlpPositionCursor(1,2);
LkgStartTime = ArcGetRelativeTime();
}
BOOLEAN
BlEndConfigPrompt(
VOID
)
/*++
Routine Description:
This routine waits until the LKG timeout has expired or the
user presses a key and then removes the LKG prompt.
Arguments:
None.
Return Value:
TRUE - Space bar pressed.
FALSE - Space bar was not pressed.
--*/
{
ULONG EndTime;
ULONG Count;
UCHAR Key;
ULONG Status;
EndTime = LkgStartTime + 3;
if (EndTime <= ArcGetRelativeTime()) {
EndTime = ArcGetRelativeTime()+1;
}
do {
if ((Status = ArcGetReadStatus(ARC_CONSOLE_INPUT)) == ESUCCESS) {
//
// There is a key pending, so see if it's the spacebar.
//
ArcRead(ARC_CONSOLE_INPUT,
&Key,
sizeof(Key),
&Count);
if (Key == ' ') {
return(TRUE);
}
}
} while (ArcGetRelativeTime() < EndTime);
//
// make LKG prompt go away, so as not to startle the user.
//
BlClearToEndOfScreen();
return(FALSE);
}
VOID
BlpSwitchControlSet(
OUT PCM_HARDWARE_PROFILE_LIST *ProfileList,
IN BOOLEAN UseLastKnownGood,
OUT PHCELL_INDEX ControlSet
)
/*++
Routine Description:
Switches the current control set to the specified control
set and rebuilds the hardware profile list.
Arguments:
ProfileList - Returns the new hardware profile list
UseLastKnownGood - Supplies whether the LKG control set is to be used.
ControlSet - Returns the HCELL_INDEX of the new control set.
Return Value:
None.
--*/
{
UNICODE_STRING ControlName;
HCELL_INDEX NewControlSet;
BOOLEAN AutoSelect; // ignored
ULONG ProfileTimeout; // ignored
//
// Find the new control set.
//
if (UseLastKnownGood) {
RtlInitUnicodeString(&ControlName, L"LastKnownGood");
} else {
RtlInitUnicodeString(&ControlName, L"Default");
}
NewControlSet = CmpFindControlSet(&BootHive.Hive,
BootHive.Hive.BaseBlock->RootCell,
&ControlName,
&AutoSelect);
if (NewControlSet == HCELL_NIL) {
return;
}
CmpFindProfileOption(&BootHive.Hive,
NewControlSet,
ProfileList,
NULL);
*ControlSet = NewControlSet;
}
ULONG
BlpCountLines(
IN PCHAR Lines
)
/*++
Routine Description:
Counts the number of lines in the given string.
Arguments:
Lines - Supplies a pointer to the start of the string
Return Value:
The number of lines in the string.
--*/
{
PCHAR p;
ULONG NumLines = 0;
p=Lines;
while (*p != 0) {
if ((*p == '\r') && (*(p+1) == '\n')) {
++NumLines;
++p; // move forward to \n
}
++p;
}
return(NumLines);
}
BOOLEAN
BlConfigMenuPrompt(
IN ULONG Timeout,
IN OUT PBOOLEAN UseLastKnownGood,
IN OUT PHCELL_INDEX ControlSet,
OUT PCM_HARDWARE_PROFILE_LIST *ProfileList,
OUT PCM_HARDWARE_PROFILE *HardwareProfile
)
/*++
Routine Description:
This routine provides the user-interface for the configuration menu.
The prompt is given if the user hits the break-in key, or if the
LastKnownGood environment variable is TRUE and AutoSelect is FALSE, or
if the timeout value on the hardware profile configuration is non-zero
Arguments:
Timeout - Supplies the timeout value for the menu. -1 or 0 implies the menu
will never timeout.
UseLastKnownGood - Returns the LastKnownGood setting that should be
used for the boot.
ControlSet - Returns the control set (either Default or LKG)
ProfileList - Supplies the default list of profiles.
Returns the current list of profiles.
(may change due to switching to/from the LKG controlset)
HardwareProfile - Returns the hardware profile that should be used.
Return Value:
TRUE - Boot should proceed.
FALSE - The user has chosen to return to the firmware menu/flexboot menu.
--*/
{
ULONG HeaderLines;
ULONG TrailerLines;
ULONG i;
ULONG Count;
UCHAR Key;
PCHAR MenuHeader;
PCHAR MenuTrailer1;
PCHAR MenuTrailer2;
PCHAR p;
ULONG OptionLength;
CHAR MenuOption[80];
PCM_HARDWARE_PROFILE Profile;
ULONG ProfileCount;
UCHAR LkgMnemonic;
UCHAR DefaultMnemonic;
PCHAR Temp;
ULONG DisplayLines;
ULONG TopProfileLine=0;
ULONG CurrentSelection = 0;
ULONG CurrentProfile;
ULONG EndTime;
ULONG CurrentTime;
PCHAR TimeoutPrompt;
if ((Timeout != (ULONG)-1) && (Timeout != 0)) {
CurrentTime = ArcGetRelativeTime();
EndTime = CurrentTime + Timeout;
TimeoutPrompt = BlFindMessage(BL_LKG_TIMEOUT);
p=strchr(TimeoutPrompt, '\n');
if (p) {
*p = '\0';
}
p=strchr(TimeoutPrompt, '\r');
if (p) {
*p = '\0';
}
} else {
TimeoutPrompt = NULL;
}
MenuHeader = BlFindMessage(BL_LKG_MENU_HEADER);
Temp = BlFindMessage(BL_LKG_SELECT_MNEMONIC);
if (Temp == NULL) {
return(TRUE);
}
LkgMnemonic = toupper(Temp[0]);
Temp = BlFindMessage(BL_DEFAULT_SELECT_MNEMONIC);
if (Temp == NULL) {
return(TRUE);
}
DefaultMnemonic = toupper(Temp[0]);
Restart:
if (*ProfileList == NULL) {
ProfileCount = 0;
} else {
ProfileCount = (*ProfileList)->CurrentProfileCount;
}
if (ProfileCount == 0) {
MenuTrailer1 = BlFindMessage(BL_LKG_MENU_TRAILER_NO_PROFILES);
} else {
MenuTrailer1 = BlFindMessage(BL_LKG_MENU_TRAILER);
}
if (*UseLastKnownGood) {
MenuTrailer2 = BlFindMessage(BL_SWITCH_DEFAULT_TRAILER);
} else {
MenuTrailer2 = BlFindMessage(BL_SWITCH_LKG_TRAILER);
}
if ((MenuHeader==NULL) || (MenuTrailer1==NULL) || (MenuTrailer2==NULL)) {
return(TRUE);
}
//
// strip trailing /r/n from MenuTrailer2 to prevent it from scrolling
// the screen when we output it.
//
#if 0
p=MenuTrailer2 + strlen(MenuTrailer2) - 1;
while ((*p == '\r') || (*p == '\n')) {
*p = '\0';
--p;
}
#endif
BlpClearScreen();
BlpSetInverseMode(FALSE);
//
// Count the number of lines in the header.
//
HeaderLines=BlpCountLines(MenuHeader);
//
// Display the menu header.
//
ArcWrite(BlConsoleOutDeviceId,
MenuHeader,
strlen(MenuHeader),
&Count);
//
// Count the number of lines in the trailer.
//
TrailerLines=BlpCountLines(MenuTrailer1) + BlpCountLines(MenuTrailer2);
//
// Display the trailing prompt.
//
if (TimeoutPrompt) {
TrailerLines += 1;
}
BlpPositionCursor(1, ScreenHeight-TrailerLines);
ArcWrite(BlConsoleOutDeviceId,
MenuTrailer1,
strlen(MenuTrailer1),
&Count);
ArcWrite(BlConsoleOutDeviceId,
MenuTrailer2,
strlen(MenuTrailer2),
&Count);
//
// Compute number of selections that can be displayed
//
DisplayLines = ScreenHeight-HeaderLines-TrailerLines-3;
if (ProfileCount < DisplayLines) {
DisplayLines = ProfileCount;
}
//
// Start menu selection loop.
//
do {
if (ProfileCount > 0) {
//
// Display options with current selection highlighted
//
for (i=0; i < DisplayLines; i++) {
CurrentProfile = i+TopProfileLine;
Profile = &(*ProfileList)->Profile[CurrentProfile];
RtlUnicodeToMultiByteN(MenuOption,
sizeof(MenuOption),
&OptionLength,
Profile->FriendlyName,
Profile->NameLength);
BlpPositionCursor(5, HeaderLines+i+2);
BlpSetInverseMode((BOOLEAN)(CurrentProfile == CurrentSelection));
ArcWrite(BlConsoleOutDeviceId,
MenuOption,
OptionLength,
&Count);
BlpSetInverseMode(FALSE);
BlpClearToEndOfLine();
}
} else {
//
// No profile options available, just display the default
// highlighted to indicate that ENTER will start the system.
//
Temp = BlFindMessage(BL_BOOT_DEFAULT_PROMPT);
if (Temp != NULL) {
BlpPositionCursor(5, HeaderLines+3);
BlpSetInverseMode(TRUE);
ArcWrite(BlConsoleOutDeviceId,
Temp,
strlen(Temp),
&Count);
BlpSetInverseMode(FALSE);
}
}
if (TimeoutPrompt) {
CurrentTime = ArcGetRelativeTime();
sprintf(MenuOption, TimeoutPrompt, EndTime-CurrentTime);
BlpPositionCursor(1, ScreenHeight);
ArcWrite(BlConsoleOutDeviceId,
MenuOption,
strlen(MenuOption),
&Count);
BlpClearToEndOfLine();
}
//
// Loop waiting for keypress or time change.
//
do {
if (ArcGetReadStatus(ARC_CONSOLE_INPUT) == ESUCCESS) {
TimeoutPrompt = NULL; // turn off timeout prompt
BlpPositionCursor(1,ScreenHeight);
BlpClearToEndOfLine();
ArcRead(ARC_CONSOLE_INPUT,
&Key,
sizeof(Key),
&Count);
break;
}
if (TimeoutPrompt) {
if (ArcGetRelativeTime() != CurrentTime) {
//
// Time has changed, update the countdown and check for timeout
//
CurrentTime = ArcGetRelativeTime();
sprintf(MenuOption, TimeoutPrompt, EndTime-CurrentTime);
BlpPositionCursor(1, ScreenHeight);
ArcWrite(BlConsoleOutDeviceId,
MenuOption,
strlen(MenuOption),
&Count);
BlpClearToEndOfLine();
if (EndTime == CurrentTime) {
goto ProcessSelection;
}
}
}
} while ( TRUE );
switch (Key) {
case ESC:
//
// See if the next character is '[' in which case we
// have a special control sequence.
//
ArcRead(ARC_CONSOLE_INPUT,
&Key,
sizeof(Key),
&Count);
if (Key!='[') {
break;
}
//
// deliberate fall-through
//
case ASCI_CSI_IN:
ArcRead(ARC_CONSOLE_INPUT,
&Key,
sizeof(Key),
&Count);
switch (Key) {
case 'A':
//
// Cursor up
//
if (ProfileCount > 0) {
if (CurrentSelection==0) {
CurrentSelection = ProfileCount - 1;
if (TopProfileLine + DisplayLines <= CurrentSelection) {
TopProfileLine = CurrentSelection - DisplayLines + 1;
}
} else {
if (--CurrentSelection < TopProfileLine) {
//
// Scroll up
//
TopProfileLine = CurrentSelection;
}
}
}
break;
case 'B':
//
// Cursor down
//
if (ProfileCount > 0) {
CurrentSelection = (CurrentSelection+1) % ProfileCount;
if (CurrentSelection == 0) {
TopProfileLine = 0;
} else if (TopProfileLine + DisplayLines <= CurrentSelection) {
TopProfileLine = CurrentSelection - DisplayLines + 1;
}
}
break;
case 'O':
//
// Function key
//
ArcRead(ARC_CONSOLE_INPUT,
&Key,
sizeof(Key),
&Count);
switch (Key) {
case 'w':
//
// F3
//
*ControlSet = HCELL_NIL;
return(FALSE);
default:
break;
}
default:
break;
}
continue;
default:
if ((toupper(Key) == LkgMnemonic) && (*UseLastKnownGood == FALSE)) {
*UseLastKnownGood = TRUE;
BlpSwitchControlSet(ProfileList,
TRUE,
ControlSet);
goto Restart;
//
// regenerate profile list here
//
} else if ((toupper(Key) == DefaultMnemonic) && (*UseLastKnownGood)) {
*UseLastKnownGood = FALSE;
BlpSwitchControlSet(ProfileList,
FALSE,
ControlSet);
goto Restart;
}
break;
}
} while ( (Key != ASCII_CR) && (Key != ASCII_LF) );
ProcessSelection:
if (ProfileCount > 0) {
CmpSetCurrentProfile(&BootHive.Hive,
*ControlSet,
&(*ProfileList)->Profile[CurrentSelection]);
}
return(TRUE);
}
ARC_STATUS
BlLoadBootDrivers(
IN ULONG DefaultDeviceId,
IN PCHAR DefaultLoadDevice,
IN PCHAR SystemPath,
IN PLIST_ENTRY BootDriverListHead,
OUT PCHAR BadFileName
)
/*++
Routine Description:
Walks the boot driver list and loads all the drivers
Arguments:
DefaultDeviceId - Supplies the device ID of the boot partition
DefaultLoadDevice - Supplies the ARC name of the boot partition
SystemPath - Supplies the path to the system root
BootDriverListHead - Supplies the head of the boot driver list
BadFileName - Returns the filename of the critical driver that
did not load. Not valid if ESUCCESS is returned.
Return Value:
ESUCCESS is returned if all the boot drivers were successfully loaded.
Otherwise, an unsuccessful status is returned.
--*/
{
ULONG DeviceId;
PCHAR LoadDevice;
PBOOT_DRIVER_NODE DriverNode;
PBOOT_DRIVER_LIST_ENTRY DriverEntry;
PLIST_ENTRY NextEntry;
CHAR DriverName[64];
PCHAR NameStart;
CHAR DriverDevice[128];
CHAR DriverPath[128];
ARC_STATUS Status;
UNICODE_STRING DeviceName;
UNICODE_STRING FileName;
PWSTR p;
NextEntry = BootDriverListHead->Flink;
while (NextEntry != BootDriverListHead) {
DriverNode = CONTAINING_RECORD(NextEntry,
BOOT_DRIVER_NODE,
ListEntry.Link);
Status = ESUCCESS;
DriverEntry = &DriverNode->ListEntry;
if (DriverEntry->FilePath.Buffer[0] != L'\\') {
//
// This is a relative pathname, so generate the full pathname
// relative to the boot partition.
//
sprintf(DriverPath, "%s%wZ",SystemPath,&DriverEntry->FilePath);
DeviceId = DefaultDeviceId;
LoadDevice = DefaultLoadDevice;
} else {
//
// This is an absolute pathname, of the form
// "\ArcDeviceName\dir\subdir\filename"
//
// We need to open the specified ARC device and pass that
// to BlLoadDeviceDriver.
//
p = DeviceName.Buffer = DriverEntry->FilePath.Buffer+1;
DeviceName.Length = 0;
DeviceName.MaximumLength = DriverEntry->FilePath.MaximumLength-sizeof(WCHAR);
while ((*p != L'\\') &&
(DeviceName.Length < DeviceName.MaximumLength)) {
++p;
DeviceName.Length += sizeof(WCHAR);
}
DeviceName.MaximumLength = DeviceName.Length;
sprintf(DriverDevice, "%wZ", &DeviceName);
Status = ArcOpen(DriverDevice,ArcOpenReadOnly,&DeviceId);
FileName.Buffer = p+1;
FileName.Length = DriverEntry->FilePath.Length - DeviceName.Length - 2*sizeof(WCHAR);
FileName.MaximumLength = FileName.Length;
//
// Device successfully opened, parse out the path and filename.
//
sprintf(DriverPath, "%wZ", &FileName);
LoadDevice = DriverDevice;
}
NameStart = strrchr(DriverPath, '\\');
if (NameStart != NULL) {
strcpy(DriverName, NameStart+1);
*(NameStart+1) = '\0';
if (Status == ESUCCESS) {
Status = BlLoadDeviceDriver(DeviceId,
LoadDevice,
DriverPath,
DriverName,
LDRP_ENTRY_PROCESSED,
&DriverEntry->LdrEntry);
}
NextEntry = DriverEntry->Link.Flink;
if (Status != ESUCCESS) {
//
// Attempt to load driver failed, remove it from the list.
//
RemoveEntryList(&DriverEntry->Link);
//
// Check the Error Control of the failed driver. If it
// was critical, fail the boot. If the driver
// wasn't critical, keep going.
//
if (DriverNode->ErrorControl == CriticalError) {
strcpy(BadFileName,DriverPath);
strcat(BadFileName,DriverName);
return(Status);
}
}
} else {
NextEntry = DriverEntry->Link.Flink;
}
}
return(ESUCCESS);
}
ARC_STATUS
BlLoadAndInitSystemHive(
IN ULONG DeviceId,
IN PCHAR DeviceName,
IN PCHAR DirectoryPath,
IN PCHAR HiveName,
IN BOOLEAN IsAlternate,
OUT PBOOLEAN RestartSetup
)
/*++
Routine Description:
Loads the registry SYSTEM hive, verifies it is a valid hive file,
and inits the relevant registry structures. (particularly the HHIVE)
Arguments:
DeviceId - Supplies the file id of the device the system tree is on.
DeviceName - Supplies the name of the device the system tree is on.
DirectoryPath - Supplies a pointer to the zero-terminated directory path
of the root of the NT tree.
HiveName - Supplies the name of the system hive (ie, "SYSTEM",
"SYSTEM.ALT", or "SYSTEM.SAV").
IsAlternate - Supplies whether or not the hive to be loaded is the
alternate hive.
RestartSetup - if the hive to be loaded is not the alternate, then
this routine will check for a value of RestartSetup in the Setup
key. If present and non-0, then this variable receives TRUE.
Otherwise it receives FALSE.
Return Value:
ESUCCESS is returned if the system hive was successfully loaded.
Otherwise, an unsuccessful status is returned.
--*/
{
ARC_STATUS Status;
*RestartSetup = FALSE;
BlpClearToEndOfLine();
Status = BlLoadSystemHive(DeviceId,
DeviceName,
DirectoryPath,
HiveName);
if (Status!=ESUCCESS) {
return(Status);
}
if (!BlInitializeHive(BlLoaderBlock->RegistryBase,
&BootHive,
IsAlternate)) {
return(EINVAL);
}
//
// See whether we need to switch to the backup setup hive.
//
*RestartSetup = BlpCheckRestartSetup();
return(ESUCCESS);
}
HCELL_INDEX
BlpDetermineControlSet(
VOID
)
/*++
Routine Description:
Determines the appropriate control set and static hardware profile.
This routine ends the configuration prompt. If the user has hit a
key, the configuration menu is displayed. If the user has not hit
a key, but the default controlset specifies a non-zero timeout for
the configuration menu, the configuration menu is displayed.
If the configuration menu is displayed, further modifications to the
control set and hardware profile can be made by the user. If not,
the default hardware profile is selected.
Arguments:
None
Return Value:
HCELL_INDEX of control set to boot from.
HCELL_NIL on error.
--*/
{
BOOLEAN UseLastKnownGood;
BOOLEAN ConfigMenu = FALSE;
PCHAR LastKnownGood;
HCELL_INDEX ControlSet;
HCELL_INDEX ProfileControl;
UNICODE_STRING DefaultControlName;
UNICODE_STRING LkgControlName;
PUNICODE_STRING ControlName;
BOOLEAN AutoSelect;
ULONG ProfileTimeout = (ULONG)0;
PCM_HARDWARE_PROFILE_LIST ProfileList;
PCM_HARDWARE_PROFILE SelectedProfile;
RtlInitUnicodeString(&DefaultControlName, L"Default");
RtlInitUnicodeString(&LkgControlName, L"LastKnownGood");
//
// The initial decision of whether to use LKG is based on the
// LastKnownGood environment variable
//
LastKnownGood = ArcGetEnvironmentVariable("LastKnownGood");
if (LastKnownGood == NULL) {
UseLastKnownGood = FALSE;
} else {
UseLastKnownGood = (_stricmp(LastKnownGood, "TRUE") == 0);
}
//
// Get the appropriate control set
// and check the hardware profile timeout value.
//
if (UseLastKnownGood) {
ControlName = &LkgControlName;
} else {
ControlName = &DefaultControlName;
}
ControlSet = CmpFindControlSet(&BootHive.Hive,
BootHive.Hive.BaseBlock->RootCell,
ControlName,
&AutoSelect);
if (ControlSet == HCELL_NIL) {
return(HCELL_NIL);
}
//
// Check the hardware profile configuration options to
// determine the timeout value for the config menu.
//
ProfileList = NULL;
ProfileControl = CmpFindProfileOption(&BootHive.Hive,
ControlSet,
&ProfileList,
&ProfileTimeout);
//
// Now check to see whether the config menu should be displayed.
// Display the menu if:
// - user has pressed a key OR
// - we are booting from LKG and AutoSelect is FALSE. OR
// - ProfileTimeout != 0
//
if (BlEndConfigPrompt() ||
(UseLastKnownGood && !AutoSelect) ||
((ProfileTimeout != 0) &&
(ProfileList != NULL) &&
(ProfileList->CurrentProfileCount > 1))) {
//
// Display the configuration menu.
//
BlRebootSystem = !BlConfigMenuPrompt(ProfileTimeout,
&UseLastKnownGood,
&ControlSet,
&ProfileList,
&SelectedProfile);
BlpClearScreen();
} else {
if ((ProfileControl != HCELL_NIL) &&
(ProfileList != NULL)) {
//
// The system is configured to boot the default
// profile directly. Since the returned profile
// list is sorted by priority, the first entry in
// the list is our default.
//
CmpSetCurrentProfile(&BootHive.Hive,
ControlSet,
&ProfileList->Profile[0]);
}
}
return(ControlSet);
}
BOOLEAN
BlpCheckRestartSetup(
VOID
)
/*++
Routine Description:
Examine the system hive loaded and described by BootHive, to see
whether it contains a Setup key, and if so, whether that key has
a "RestartSetup" value that is non-0.
Arguments:
None.
Return Value:
Boolean value indicating whether the above condition is satisfied.
--*/
{
HCELL_INDEX KeyCell;
HCELL_INDEX ValueCell;
UNICODE_STRING UnicodeString;
PCM_KEY_VALUE Value;
PULONG Data;
ULONG DataSize;
//
// Address the Setup key
//
RtlInitUnicodeString(&UnicodeString,L"Setup");
KeyCell = CmpFindSubKeyByName(
&BootHive.Hive,
(PCM_KEY_NODE)HvGetCell(&BootHive.Hive,BootHive.Hive.BaseBlock->RootCell),
&UnicodeString
);
if(KeyCell == HCELL_NIL) {
return(FALSE);
}
//
// Find RestartSetup value in Setup key
//
RtlInitUnicodeString(&UnicodeString,L"RestartSetup");
ValueCell = CmpFindValueByName(
&BootHive.Hive,
(PCM_KEY_NODE)HvGetCell(&BootHive.Hive,KeyCell),
&UnicodeString
);
if(ValueCell == HCELL_NIL) {
return(FALSE);
}
//
// Validate value and check.
//
Value = (PCM_KEY_VALUE)HvGetCell(&BootHive.Hive,ValueCell);
if(Value->Type != REG_DWORD) {
return(FALSE);
}
Data = (PULONG)(CmpIsHKeyValueSmall(DataSize,Value->DataLength)
? (struct _CELL_DATA *)&Value->Data
: HvGetCell(&BootHive.Hive,Value->Data));
if(DataSize != sizeof(ULONG)) {
return(FALSE);
}
return((BOOLEAN)(*Data != 0));
}
PCHAR
BlScanRegistry(
IN PWSTR BootFileSystemPath,
OUT PLIST_ENTRY BootDriverListHead,
OUT PUNICODE_STRING AnsiCodepage,
OUT PUNICODE_STRING OemCodepage,
OUT PUNICODE_STRING LanguageTable,
OUT PUNICODE_STRING OemHalFont
)
/*++
Routine Description:
Scans the SYSTEM hive, determines the control set and static hardware
profile (with appropriate input from the user) and finally
computes the list of boot drivers to be loaded.
Arguments:
BootFileSystemPath - Supplies the name of the image the filesystem
for the boot volume was read from. The last entry in
BootDriverListHead will refer to this file, and to the registry
key entry that controls it.
BootDriverListHead - Receives a pointer to the first element of the
list of boot drivers. Each element in this singly linked list will
provide the loader with two paths. The first is the path of the
file that contains the driver to load, the second is the path of
the registry key that controls that driver. Both will be passed
to the system via the loader heap.
AnsiCodepage - Receives the name of the ANSI codepage data file
OemCodepage - Receives the name of the OEM codepage data file
Language - Receives the name of the language case table data file
OemHalfont - receives the name of the OEM font to be used by the HAL.
Return Value:
NULL if all is well.
NON-NULL if the hive is corrupt or inconsistent. Return value is a
pointer to a string that describes what is wrong.
--*/
{
HCELL_INDEX ControlSet;
UNICODE_STRING ControlName;
BOOLEAN AutoSelect;
BOOLEAN KeepGoing;
ControlSet = BlpDetermineControlSet();
if (ControlSet == HCELL_NIL) {
return("CmpFindControlSet");
}
#if 0
need to move this to BlpDetermineControlSet()
if (UseLastKnownGood && !AutoSelect) {
KeepGoing = BlLastKnownGoodPrompt(&UseLastKnownGood);
if (!UseLastKnownGood) {
RtlInitUnicodeString(&ControlName, L"Default");
ControlSet = CmpFindControlSet(&BootHive.Hive,
BootHive.Hive.BaseBlock->RootCell,
&ControlName,
&AutoSelect);
if (ControlSet == HCELL_NIL) {
return("CmpFindControlSet");
}
}
}
#endif
if (!CmpFindNLSData(&BootHive.Hive,
ControlSet,
AnsiCodepage,
OemCodepage,
LanguageTable,
OemHalFont)) {
return("CmpFindNLSData");
}
InitializeListHead(BootDriverListHead);
if (!CmpFindDrivers(&BootHive.Hive,
ControlSet,
BootLoad,
BootFileSystemPath,
BootDriverListHead)) {
return("CmpFindDriver");
}
if (!CmpSortDriverList(&BootHive.Hive,
ControlSet,
BootDriverListHead)) {
return("Missing or invalid Control\\ServiceGroupOrder\\List registry value");
}
if (!CmpResolveDriverDependencies(BootDriverListHead)) {
return("CmpResolveDriverDependencies");
}
return( NULL );
}
BOOLEAN
BlInitializeHive(
IN PVOID HiveImage,
IN PCMHIVE Hive,
IN BOOLEAN IsAlternate
)
/*++
Routine Description:
Initializes the hive data structure based on the in-memory hive image.
Arguments:
HiveImage - Supplies a pointer to the in-memory hive image.
Hive - Supplies the CMHIVE structure to be filled in.
IsAlternate - Supplies whether or not the hive is the alternate hive,
which indicates that the primary hive is corrupt and should be
rewritten by the system.
Return Value:
TRUE - Hive successfully initialized.
FALSE - Hive is corrupt.
--*/
{
NTSTATUS status;
ULONG HiveCheckCode;
status = HvInitializeHive(
&Hive->Hive,
HINIT_MEMORY_INPLACE,
FALSE,
IsAlternate ? HFILE_TYPE_ALTERNATE : HFILE_TYPE_PRIMARY,
HiveImage,
(PALLOCATE_ROUTINE)BlpHiveAllocate, // allocate
NULL, // free
NULL, // setsize
NULL, // write
NULL, // read
NULL, // flush
1, // cluster
NULL
);
if (!NT_SUCCESS(status)) {
return FALSE;
}
HiveCheckCode = CmCheckRegistry(Hive,TRUE);
if (HiveCheckCode != 0) {
return(FALSE);
} else {
return TRUE;
}
}
PVOID
BlpHiveAllocate(
IN ULONG Length,
IN BOOLEAN UseForIo
)
/*++
Routine Description:
Wrapper for hive allocation calls. It just calls BlAllocateHeap.
Arguments:
Length - Supplies the size of block required in bytes.
UseForIo - Supplies whether or not the memory is to be used for I/O
(this is currently ignored)
Return Value:
address of the block of memory
or
NULL if no memory available
--*/
{
return(BlAllocateHeap(Length));
}
VOID
BlpClearScreen(
VOID
)
/*++
Routine Description:
Clears the screen.
Arguments:
None
Return Value:
None.
--*/
{
CHAR Buffer[16];
ULONG Count;
sprintf(Buffer, ASCI_CSI_OUT "2J");
ArcWrite(BlConsoleOutDeviceId,
Buffer,
strlen(Buffer),
&Count);
}
VOID
BlClearToEndOfScreen(
VOID
)
{
CHAR Buffer[16];
ULONG Count;
sprintf(Buffer, ASCI_CSI_OUT "J");
ArcWrite(BlConsoleOutDeviceId,
Buffer,
strlen(Buffer),
&Count);
}
VOID
BlpClearToEndOfLine(
VOID
)
{
CHAR Buffer[16];
ULONG Count;
sprintf(Buffer, ASCI_CSI_OUT "K");
ArcWrite(BlConsoleOutDeviceId,
Buffer,
strlen(Buffer),
&Count);
}
VOID
BlpPositionCursor(
IN ULONG Column,
IN ULONG Row
)
/*++
Routine Description:
Sets the position of the cursor on the screen.
Arguments:
Column - supplies new Column for the cursor position.
Row - supplies new Row for the cursor position.
Return Value:
None.
--*/
{
CHAR Buffer[16];
ULONG Count;
sprintf(Buffer, ASCI_CSI_OUT "%d;%dH", Row, Column);
ArcWrite(BlConsoleOutDeviceId,
Buffer,
strlen(Buffer),
&Count);
}
VOID
BlpSetInverseMode(
IN BOOLEAN InverseOn
)
/*++
Routine Description:
Sets inverse console output mode on or off.
Arguments:
InverseOn - supplies whether inverse mode should be turned on (TRUE)
or off (FALSE)
Return Value:
None.
--*/
{
CHAR Buffer[16];
ULONG Count;
sprintf(Buffer, ASCI_CSI_OUT ";%dm", InverseOn ? SGR_INVERSE : SGR_INTENSE);
ArcWrite(BlConsoleOutDeviceId,
Buffer,
strlen(Buffer),
&Count);
}
NTSTATUS
HvLoadHive(
PHHIVE Hive,
PVOID *Image
)
{
UNREFERENCED_PARAMETER(Hive);
UNREFERENCED_PARAMETER(Image);
return(STATUS_SUCCESS);
}
BOOLEAN
HvMarkCellDirty(
PHHIVE Hive,
HCELL_INDEX Cell
)
{
UNREFERENCED_PARAMETER(Hive);
UNREFERENCED_PARAMETER(Cell);
return(TRUE);
}
BOOLEAN
HvMarkDirty(
PHHIVE Hive,
HCELL_INDEX Start,
ULONG Length
)
{
UNREFERENCED_PARAMETER(Hive);
UNREFERENCED_PARAMETER(Start);
UNREFERENCED_PARAMETER(Length);
return(TRUE);
}
BOOLEAN
HvMarkClean(
PHHIVE Hive,
HCELL_INDEX Start,
ULONG Length
)
{
UNREFERENCED_PARAMETER(Hive);
UNREFERENCED_PARAMETER(Start);
UNREFERENCED_PARAMETER(Length);
return(TRUE);
}
BOOLEAN
HvpDoWriteHive(
PHHIVE Hive,
ULONG FileType
)
{
UNREFERENCED_PARAMETER(Hive);
UNREFERENCED_PARAMETER(FileType);
return(TRUE);
}
BOOLEAN
HvpGrowLog1(
PHHIVE Hive,
ULONG Count
)
{
UNREFERENCED_PARAMETER(Hive);
UNREFERENCED_PARAMETER(Count);
return(TRUE);
}
BOOLEAN
HvpGrowLog2(
PHHIVE Hive,
ULONG Size
)
{
UNREFERENCED_PARAMETER(Hive);
UNREFERENCED_PARAMETER(Size);
return(TRUE);
}
BOOLEAN
CmpValidateHiveSecurityDescriptors(
IN PHHIVE Hive
)
{
UNREFERENCED_PARAMETER(Hive);
return(TRUE);
}
BOOLEAN
CmpTestRegistryLock()
{
return TRUE;
}
BOOLEAN
CmpTestRegistryLockExclusive()
{
return TRUE;
}
BOOLEAN
HvIsBinDirty(
IN PHHIVE Hive,
IN HCELL_INDEX Cell
)
{
return(FALSE);
}
PHBIN
HvpAddBin(
IN PHHIVE Hive,
IN ULONG NewSize,
IN HSTORAGE_TYPE Type
)
{
return(NULL);
}