mirror of https://github.com/lianthony/NT4.0
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.
1588 lines
37 KiB
1588 lines
37 KiB
/*++
|
|
|
|
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);
|
|
}
|