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.
3085 lines
85 KiB
3085 lines
85 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:
|
|
|
|
Doug Fritz (dFritz) 07-Oct-1997 & KenRay Feb 98
|
|
|
|
- Filter hardware profiles based on detected hardware
|
|
configuration (docking station) information
|
|
|
|
--*/
|
|
#include "bldr.h"
|
|
#include "msg.h"
|
|
#include "cmp.h"
|
|
#include "stdio.h"
|
|
#include "string.h"
|
|
#include <dockinfo.h>
|
|
#include <netboot.h>
|
|
|
|
#ifdef i386
|
|
#include "bldrx86.h"
|
|
#endif
|
|
|
|
#if defined(_IA64_)
|
|
#include "bldria64.h"
|
|
#endif
|
|
|
|
#ifdef _WANT_MACHINE_IDENTIFICATION
|
|
#include <stdlib.h>
|
|
#include <ntverp.h>
|
|
#endif
|
|
|
|
#include "bldrint.h"
|
|
#include "vmode.h"
|
|
|
|
|
|
#define MAX_DRIVER_NAME_LENGTH 64
|
|
|
|
CMHIVE BootHive;
|
|
ULONG CmLogLevel=100;
|
|
ULONG CmLogSelect=0;
|
|
|
|
ULONG ScreenWidth=80;
|
|
#ifdef EFI
|
|
ULONG ScreenHeight=24;
|
|
#else
|
|
ULONG ScreenHeight=25;
|
|
#endif
|
|
|
|
ULONG LkgStartTime;
|
|
|
|
//
|
|
// used by the advanced boot screen to force a LKG boot
|
|
//
|
|
BOOLEAN ForceLastKnownGood;
|
|
|
|
//
|
|
// Variable used to check whether to display
|
|
// "Return to OS Choices Menu" or not in adv. boot
|
|
//
|
|
BOOLEAN BlShowReturnToOSChoices = TRUE;
|
|
|
|
|
|
VOID
|
|
BlRedrawProgressBar(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
BlOutputStartupMsg(
|
|
ULONG uMsgID
|
|
);
|
|
|
|
ULONG
|
|
BlGetAdvancedBootID(
|
|
LONG BootOption
|
|
);
|
|
|
|
//
|
|
// 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,
|
|
ULONG Tag
|
|
);
|
|
|
|
VOID
|
|
BlDockInfoFilterProfileList(
|
|
IN OUT PCM_HARDWARE_PROFILE_LIST ProfileList,
|
|
IN OUT PCM_HARDWARE_PROFILE_ALIAS_LIST AliasList
|
|
);
|
|
|
|
|
|
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;
|
|
PTCHAR LkgPrompt;
|
|
|
|
LkgPrompt = BlFindMessage(BL_LKG_MENU_PROMPT);
|
|
if (LkgPrompt==NULL) {
|
|
return;
|
|
}
|
|
//
|
|
// display LKG prompt
|
|
//
|
|
#if 0
|
|
BlPositionCursor(1,3);
|
|
ArcWrite(BlConsoleOutDeviceId,
|
|
LkgPrompt,
|
|
_tcslen(LkgPrompt)*sizeof(TCHAR),
|
|
&Count);
|
|
BlPositionCursor(1,2);
|
|
#endif
|
|
LkgStartTime = ArcGetRelativeTime();
|
|
|
|
#if defined(REMOTE_BOOT) && defined(i386)
|
|
//
|
|
// Wait to allow the user to type space or F8. If anything is typed then behave
|
|
// conservatively and load the kernel, etc., from the server just in case CSC or
|
|
// the local filesystem is broken.
|
|
//
|
|
if (BlBootingFromNet) {
|
|
|
|
ULONG EndTime;
|
|
ULONG Status;
|
|
ULONG CurrentTime;
|
|
|
|
EndTime = LkgStartTime + 3;
|
|
if (EndTime <= ArcGetRelativeTime()) {
|
|
EndTime = ArcGetRelativeTime()+1;
|
|
}
|
|
|
|
do {
|
|
if (ArcGetReadStatus(ARC_CONSOLE_INPUT) == ESUCCESS) {
|
|
|
|
//
|
|
// There is a key pending, assume it is CSC related. If it isn't
|
|
// CSC then it just means we laod a few extra files from the
|
|
// server.
|
|
//
|
|
|
|
NetBootCSC = FALSE;
|
|
break;
|
|
|
|
}
|
|
|
|
CurrentTime = ArcGetRelativeTime();
|
|
|
|
//
|
|
// Terminate the loop if the EndTime has been reached, or
|
|
// if the CurrentTime has wrapped at midnight.
|
|
//
|
|
} while ((CurrentTime < EndTime) &&
|
|
(CurrentTime >= LkgStartTime));
|
|
}
|
|
#endif // defined(REMOTE_BOOT) && defined(i386)
|
|
|
|
}
|
|
|
|
|
|
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 Key;
|
|
ULONG CurrentTime;
|
|
#if defined(EFI)
|
|
ULONGLONG OriginalInputTimeout;
|
|
#endif
|
|
|
|
//
|
|
// We do not wait for a keypress if there is not already one.
|
|
//
|
|
EndTime = 0;
|
|
|
|
if( BlIsTerminalConnected() ) {
|
|
//
|
|
// If we're booting headless, give the user lots of time
|
|
// to press any of the advanced options keys.
|
|
//
|
|
EndTime = ArcGetRelativeTime() + 5;
|
|
}
|
|
|
|
#if defined(EFI)
|
|
//
|
|
// on certain machines the boot manager will
|
|
// reset ConIn and the usb keyboard is still
|
|
// reinitialize when we get here. add a short
|
|
// timeout period to BlGetKey() that will
|
|
// give the necessary time required for
|
|
// for interface to behave properly.
|
|
//
|
|
OriginalInputTimeout = BlGetInputTimeout();
|
|
if (EndTime) {
|
|
BlSetInputTimeout(50000000); // 5 seconds
|
|
}
|
|
else {
|
|
BlSetInputTimeout(10000000); // 1 second
|
|
}
|
|
#endif
|
|
|
|
#if defined(REMOTE_BOOT) && defined(i386)
|
|
//
|
|
// If a key was detected and CSC turned off then re-enable CSC until
|
|
// we find out if it should be disabled for this whole boot.
|
|
//
|
|
|
|
NetBootCSC = TRUE;
|
|
#endif // defined(REMOTE_BOOT) && defined(i386)
|
|
|
|
do {
|
|
LONG AdvancedBoot = -1;
|
|
BOOLEAN bOldState = BlShowReturnToOSChoices;
|
|
|
|
if ((Key = BlGetKey()) != 0) {
|
|
|
|
//
|
|
// return if the pending key was the spacebar.
|
|
//
|
|
if (Key == ' ') {
|
|
#if defined(EFI)
|
|
BlSetInputTimeout(OriginalInputTimeout);
|
|
#endif
|
|
return(TRUE);
|
|
}
|
|
|
|
//
|
|
// look to see if the user pressed the F5 or F8 keys,
|
|
// these keys trigger the advanced boot menu. the advanced
|
|
// boot menu can also be entered from the main boot menu by
|
|
// pressing the same keys.
|
|
//
|
|
if (Key == F5_KEY || Key == F8_KEY) {
|
|
//
|
|
// present the menu and get the user's request
|
|
//
|
|
BlShowReturnToOSChoices = FALSE;
|
|
|
|
if (DisplayLogoOnBoot) {
|
|
if (!DbcsLangId)
|
|
HW_CURSOR(0x80000000,0x3);
|
|
else
|
|
HW_CURSOR(0x80000000,0x12);
|
|
}
|
|
|
|
AdvancedBoot = BlDoAdvancedBoot( BL_ADVANCEDBOOT_TITLE, 0, FALSE, 0 );
|
|
|
|
if (DisplayLogoOnBoot) {
|
|
|
|
PSTR BootOption;
|
|
|
|
if ((AdvancedBoot != -1) &&
|
|
((BootOption = BlGetAdvancedBootLoadOptions(AdvancedBoot)) != NULL ) &&
|
|
(!strncmp("SAFEBOOT",BootOption,8))) {
|
|
DisplayLogoOnBoot = FALSE; // on safe boot let the "Checking file system" message
|
|
// appear as it appears today (in graphics mode)
|
|
} else {
|
|
#ifndef EFI
|
|
HW_CURSOR(0x80000000,0x12);
|
|
if (DbcsLangId)
|
|
|
|
TextClearDisplay();
|
|
VgaEnableVideo();
|
|
PaletteOn();
|
|
DrawBitmap ();
|
|
BlUpdateBootStatus();
|
|
#endif
|
|
}
|
|
}
|
|
|
|
BlShowReturnToOSChoices = bOldState;
|
|
|
|
if (AdvancedBoot != -1) {
|
|
//
|
|
// they chose a valid boot option so append
|
|
// any os load options and perform any necessary
|
|
// option processing.
|
|
//
|
|
PSTR NewOptions = BlGetAdvancedBootLoadOptions(AdvancedBoot);
|
|
|
|
if( BlGetAdvancedBootID(AdvancedBoot) == BL_MSG_REBOOT ) {
|
|
BlClearScreen();
|
|
ArcReboot();
|
|
}
|
|
|
|
|
|
if (NewOptions != NULL && strstr(BlLoaderBlock->LoadOptions,NewOptions) == NULL) {
|
|
ULONG len = (ULONG)strlen(NewOptions) + // new options
|
|
1 + // seperated by a space
|
|
(ULONG)strlen(BlLoaderBlock->LoadOptions) + // old options
|
|
1; // null terminator
|
|
NewOptions = BlAllocateHeap(len * sizeof(UCHAR));
|
|
strcpy(NewOptions,BlLoaderBlock->LoadOptions);
|
|
strcat(NewOptions," ");
|
|
strcat(NewOptions,BlGetAdvancedBootLoadOptions(AdvancedBoot));
|
|
BlLoaderBlock->LoadOptions = NewOptions;
|
|
|
|
DBGTRACE(TEXT("Load Options = %S"), BlLoaderBlock->LoadOptions);
|
|
}
|
|
|
|
BlDoAdvancedBootLoadProcessing(AdvancedBoot);
|
|
}
|
|
}
|
|
}
|
|
|
|
CurrentTime = ArcGetRelativeTime();
|
|
|
|
//
|
|
// Terminate the loop if the EndTime has been reached, or
|
|
// if the CurrentTime has wrapped at midnight.
|
|
//
|
|
} while ((CurrentTime < EndTime) &&
|
|
(CurrentTime >= LkgStartTime));
|
|
|
|
#if defined(EFI)
|
|
BlSetInputTimeout(OriginalInputTimeout);
|
|
#endif
|
|
|
|
//
|
|
// make LKG prompt go away, so as not to startle the user.
|
|
// remote the trailer & update progress bar
|
|
//
|
|
#if defined(_IA64_)
|
|
BlOutputStartupMsg(BL_MSG_STARTING_WINDOWS);
|
|
#endif
|
|
BlRedrawProgressBar();
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
VOID
|
|
BlpSwitchControlSet(
|
|
OUT PCM_HARDWARE_PROFILE_LIST *ProfileList,
|
|
OUT PCM_HARDWARE_PROFILE_ALIAS_LIST *AliasList,
|
|
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
|
|
|
|
//
|
|
// 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,
|
|
AliasList,
|
|
NULL);
|
|
*ControlSet = NewControlSet;
|
|
}
|
|
|
|
|
|
ULONG
|
|
BlCountLines(
|
|
IN PTCHAR 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.
|
|
|
|
--*/
|
|
|
|
{
|
|
PTCHAR p;
|
|
ULONG NumLines = 0;
|
|
|
|
p=Lines;
|
|
while (*p != TEXT('\0')) {
|
|
if ((*p == TEXT('\r')) && (*(p+1) == TEXT('\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_ALIAS_LIST *AliasList,
|
|
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;
|
|
ULONG flags;
|
|
ULONG Key;
|
|
PTCHAR MenuHeader;
|
|
PTCHAR MenuTrailer1;
|
|
PTCHAR MenuTrailer2;
|
|
PTCHAR p;
|
|
#ifndef UNICODE
|
|
ULONG OptionLength;
|
|
#endif
|
|
TCHAR MenuOption[80];
|
|
PCM_HARDWARE_PROFILE Profile;
|
|
ULONG ProfileCount;
|
|
_TUCHAR LkgMnemonic;
|
|
_TUCHAR DefaultMnemonic;
|
|
PTCHAR Temp;
|
|
ULONG DisplayLines;
|
|
ULONG TopProfileLine=0;
|
|
ULONG CurrentSelection = 0;
|
|
ULONG CurrentProfile;
|
|
ULONG EndTime = 0;
|
|
ULONG CurrentTime = 0;
|
|
PTCHAR TimeoutPrompt;
|
|
|
|
UNREFERENCED_PARAMETER( HardwareProfile );
|
|
|
|
if ((Timeout != (ULONG)-1) && (Timeout != 0)) {
|
|
CurrentTime = ArcGetRelativeTime();
|
|
EndTime = CurrentTime + Timeout;
|
|
TimeoutPrompt = BlFindMessage(BL_LKG_TIMEOUT);
|
|
|
|
if (TimeoutPrompt != NULL) {
|
|
|
|
p=_tcschr(TimeoutPrompt, TEXT('\n'));
|
|
if (p) {
|
|
*p = TEXT('\0');
|
|
}
|
|
p=_tcschr(TimeoutPrompt, TEXT('\r'));
|
|
if (p) {
|
|
*p = TEXT('\0');
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
TimeoutPrompt = NULL;
|
|
|
|
}
|
|
|
|
MenuHeader = BlFindMessage(BL_LKG_MENU_HEADER);
|
|
Temp = BlFindMessage(BL_LKG_SELECT_MNEMONIC);
|
|
if (Temp == NULL) {
|
|
return(TRUE);
|
|
}
|
|
LkgMnemonic = (_TUCHAR)_totupper(Temp[0]);
|
|
Temp = BlFindMessage(BL_DEFAULT_SELECT_MNEMONIC);
|
|
if (Temp == NULL) {
|
|
return(TRUE);
|
|
}
|
|
DefaultMnemonic = (_TUCHAR)_totupper(Temp[0]);
|
|
|
|
if ((*UseLastKnownGood) &&
|
|
(*ProfileList) && ((*ProfileList)->CurrentProfileCount == 1)) {
|
|
|
|
//
|
|
// The user selected last known good via boot.ini/nvram/etc. Since this
|
|
// was a concious decision, and we don't have more than one profile to
|
|
// choose, just skip this UI altogether.
|
|
//
|
|
ASSERT(CurrentSelection == 0);
|
|
return TRUE;
|
|
}
|
|
|
|
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 == TEXT('\r')) || (*p == TEXT('\n'))) {
|
|
*p = TEXT('\0');
|
|
--p;
|
|
}
|
|
#endif
|
|
BlClearScreen();
|
|
#ifdef EFI
|
|
BlEfiSetAttribute( DEFATT );
|
|
#else
|
|
BlSetInverseMode(FALSE);
|
|
#endif
|
|
|
|
//
|
|
// Count the number of lines in the header.
|
|
//
|
|
HeaderLines=BlCountLines(MenuHeader);
|
|
|
|
//
|
|
// Display the menu header.
|
|
//
|
|
|
|
ArcWrite(BlConsoleOutDeviceId,
|
|
MenuHeader,
|
|
(ULONG)_tcslen(MenuHeader)*sizeof(TCHAR),
|
|
&Count);
|
|
|
|
//
|
|
// Count the number of lines in the trailer.
|
|
//
|
|
TrailerLines=BlCountLines(MenuTrailer1) + BlCountLines(MenuTrailer2);
|
|
|
|
//
|
|
// Display the trailing prompt.
|
|
//
|
|
if (TimeoutPrompt) {
|
|
TrailerLines += 1;
|
|
}
|
|
|
|
BlPositionCursor(1, ScreenHeight-TrailerLines);
|
|
ArcWrite(BlConsoleOutDeviceId,
|
|
MenuTrailer1,
|
|
(ULONG)_tcslen(MenuTrailer1)*sizeof(TCHAR),
|
|
&Count);
|
|
ArcWrite(BlConsoleOutDeviceId,
|
|
MenuTrailer2,
|
|
(ULONG)_tcslen(MenuTrailer2)*sizeof(TCHAR),
|
|
&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];
|
|
BlPositionCursor(5, HeaderLines+i+2);
|
|
#ifdef EFI
|
|
BlEfiSetAttribute( (CurrentProfile == CurrentSelection) ? INVATT : DEFATT );
|
|
#else
|
|
BlSetInverseMode((BOOLEAN)(CurrentProfile == CurrentSelection));
|
|
#endif
|
|
#ifdef UNICODE
|
|
ArcWrite(BlConsoleOutDeviceId,
|
|
Profile->FriendlyName,
|
|
Profile->NameLength,
|
|
&Count );
|
|
#else
|
|
RtlUnicodeToMultiByteN(MenuOption,
|
|
sizeof(MenuOption),
|
|
&OptionLength,
|
|
Profile->FriendlyName,
|
|
Profile->NameLength);
|
|
ArcWrite(BlConsoleOutDeviceId,
|
|
MenuOption,
|
|
OptionLength,
|
|
&Count);
|
|
#endif
|
|
#ifdef EFI
|
|
BlEfiSetAttribute( DEFATT );
|
|
#else
|
|
BlSetInverseMode(FALSE);
|
|
#endif
|
|
BlClearToEndOfLine();
|
|
}
|
|
|
|
} 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) {
|
|
BlPositionCursor(5, HeaderLines+3);
|
|
#ifdef EFI
|
|
BlEfiSetAttribute( INVATT );
|
|
#else
|
|
BlSetInverseMode(TRUE);
|
|
#endif
|
|
ArcWrite(BlConsoleOutDeviceId,
|
|
Temp,
|
|
(ULONG)_tcslen(Temp)*sizeof(TCHAR),
|
|
&Count);
|
|
#ifdef EFI
|
|
BlEfiSetAttribute( INVATT );
|
|
#else
|
|
BlSetInverseMode(TRUE);
|
|
#endif
|
|
}
|
|
}
|
|
if (TimeoutPrompt) {
|
|
CurrentTime = ArcGetRelativeTime();
|
|
_stprintf(MenuOption, TimeoutPrompt, EndTime-CurrentTime);
|
|
BlPositionCursor(1, ScreenHeight);
|
|
ArcWrite(BlConsoleOutDeviceId,
|
|
MenuOption,
|
|
(ULONG)_tcslen(MenuOption)*sizeof(TCHAR),
|
|
&Count);
|
|
BlClearToEndOfLine();
|
|
}
|
|
|
|
//
|
|
// Loop waiting for keypress or time change.
|
|
//
|
|
do {
|
|
if ((Key = BlGetKey()) != 0) {
|
|
TimeoutPrompt = NULL; // turn off timeout prompt
|
|
BlPositionCursor(1,ScreenHeight);
|
|
BlClearToEndOfLine();
|
|
break;
|
|
}
|
|
|
|
if (TimeoutPrompt) {
|
|
if (ArcGetRelativeTime() != CurrentTime) {
|
|
//
|
|
// Time has changed, update the countdown and check for timeout
|
|
//
|
|
|
|
CurrentTime = ArcGetRelativeTime();
|
|
_stprintf(MenuOption, TimeoutPrompt, EndTime-CurrentTime);
|
|
BlPositionCursor(1, ScreenHeight);
|
|
ArcWrite(BlConsoleOutDeviceId,
|
|
MenuOption,
|
|
(ULONG)_tcslen(MenuOption)*sizeof(TCHAR),
|
|
&Count);
|
|
BlClearToEndOfLine();
|
|
if (EndTime == CurrentTime) {
|
|
goto ProcessSelection;
|
|
}
|
|
}
|
|
}
|
|
|
|
} while ( TRUE );
|
|
|
|
switch (Key) {
|
|
case UP_ARROW:
|
|
//
|
|
// 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 DOWN_ARROW:
|
|
//
|
|
// 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 F3_KEY:
|
|
//
|
|
// F3
|
|
//
|
|
*ControlSet = HCELL_NIL;
|
|
return(FALSE);
|
|
|
|
|
|
default:
|
|
//
|
|
// Check to see if the Key indicates the user selection LKG
|
|
// first, we have to make sure we are looking at an alpha char.
|
|
//
|
|
if ( ((Key >> 8) == 0) && _istalpha((TCHAR)Key) ) {
|
|
|
|
if ((_totupper((TCHAR)Key) == LkgMnemonic) && (*UseLastKnownGood == FALSE)) {
|
|
*UseLastKnownGood = TRUE;
|
|
BlpSwitchControlSet(ProfileList,
|
|
AliasList,
|
|
TRUE,
|
|
ControlSet);
|
|
|
|
if (NULL != *ProfileList) {
|
|
if ((*ProfileList)->CurrentProfileCount > 0) {
|
|
BlDockInfoFilterProfileList (*ProfileList, *AliasList);
|
|
}
|
|
}
|
|
|
|
goto Restart;
|
|
//
|
|
// regenerate profile list here
|
|
//
|
|
} else if ((_totupper((TCHAR)Key) == DefaultMnemonic) && (*UseLastKnownGood)) {
|
|
*UseLastKnownGood = FALSE;
|
|
BlpSwitchControlSet(ProfileList,
|
|
AliasList,
|
|
FALSE,
|
|
ControlSet);
|
|
|
|
if (NULL != *ProfileList) {
|
|
if ((*ProfileList)->CurrentProfileCount > 0) {
|
|
BlDockInfoFilterProfileList (*ProfileList, *AliasList);
|
|
}
|
|
}
|
|
|
|
goto Restart;
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
} // switch
|
|
|
|
} while ( (Key != ASCII_CR) && (Key != ASCII_LF) );
|
|
|
|
ProcessSelection:
|
|
|
|
if (ProfileCount > 0) {
|
|
|
|
if (HW_PROFILE_STATUS_SUCCESS == BlLoaderBlock->Extension->Profile.Status) {
|
|
|
|
flags = ((*ProfileList)->Profile[CurrentSelection].Flags);
|
|
|
|
if (flags & CM_HP_FLAGS_PRISTINE) {
|
|
BlLoaderBlock->Extension->Profile.Status =
|
|
HW_PROFILE_STATUS_PRISTINE_MATCH;
|
|
|
|
} else if (flags & CM_HP_FLAGS_TRUE_MATCH) {
|
|
BlLoaderBlock->Extension->Profile.Status =
|
|
HW_PROFILE_STATUS_TRUE_MATCH;
|
|
|
|
} else if (flags & CM_HP_FLAGS_ALIASABLE) {
|
|
BlLoaderBlock->Extension->Profile.Status =
|
|
HW_PROFILE_STATUS_ALIAS_MATCH;
|
|
}
|
|
}
|
|
|
|
CmpSetCurrentProfile(&BootHive.Hive,
|
|
*ControlSet,
|
|
&(*ProfileList)->Profile[CurrentSelection]);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
ARC_STATUS
|
|
BlLoadBootDrivers(
|
|
IN PPATH_SET DefaultPathSet,
|
|
IN PLIST_ENTRY BootDriverListHead,
|
|
OUT PCHAR BadFileName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Walks the boot driver list and loads all the drivers
|
|
|
|
Arguments:
|
|
|
|
DefaultPathSet - Describes the possible locations drivers could be loaded
|
|
from.
|
|
|
|
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 = 0;
|
|
PBOOT_DRIVER_NODE DriverNode;
|
|
PBOOT_DRIVER_LIST_ENTRY DriverEntry;
|
|
PLIST_ENTRY NextEntry;
|
|
CHAR DriverName[MAX_DRIVER_NAME_LENGTH];
|
|
PCHAR NameStart;
|
|
CHAR DriverDevice[128];
|
|
CHAR DriverPath[128];
|
|
ARC_STATUS Status;
|
|
UNICODE_STRING DeviceName;
|
|
UNICODE_STRING FileName;
|
|
WCHAR SystemRootBuffer[] = L"\\SystemRoot\\";
|
|
ULONG SystemRootLength;
|
|
PWSTR p;
|
|
ULONG Index;
|
|
BOOLEAN AbsolutePath;
|
|
FULL_PATH_SET LocalPathSet;
|
|
PPATH_SOURCE PathSource;
|
|
|
|
SystemRootLength = (ULONG)wcslen(SystemRootBuffer);
|
|
|
|
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, "%wZ", &DriverEntry->FilePath);
|
|
AbsolutePath = FALSE;
|
|
|
|
} else if (memcmp(DriverEntry->FilePath.Buffer,
|
|
SystemRootBuffer,
|
|
(SystemRootLength * sizeof(WCHAR))) == 0) {
|
|
|
|
//
|
|
// This is a pathname starting with "\SystemRoot\", so just ignore
|
|
// that part and treat like the previous case.
|
|
//
|
|
FileName.Buffer = DriverEntry->FilePath.Buffer + SystemRootLength;
|
|
FileName.Length = (USHORT)(DriverEntry->FilePath.Length - (SystemRootLength * sizeof(WCHAR)));
|
|
|
|
sprintf(DriverPath, "%wZ", &FileName);
|
|
AbsolutePath = FALSE;
|
|
|
|
} 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);
|
|
AbsolutePath = TRUE;
|
|
}
|
|
|
|
//
|
|
// Parse out the driver name from the driver path
|
|
//
|
|
NameStart = strrchr(DriverPath, '\\');
|
|
if (NameStart != NULL) {
|
|
strncpy(DriverName, NameStart+1, MAX_DRIVER_NAME_LENGTH - 1);
|
|
DriverName[MAX_DRIVER_NAME_LENGTH - 1] = '\0';
|
|
*NameStart = '\0';
|
|
|
|
} else if (DriverPath[0]) {
|
|
|
|
strncpy(DriverName, DriverPath, MAX_DRIVER_NAME_LENGTH - 1);
|
|
DriverName[MAX_DRIVER_NAME_LENGTH - 1] = '\0';
|
|
*DriverPath = '\0';
|
|
|
|
} else {
|
|
|
|
NextEntry = DriverEntry->Link.Flink;
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Ensure DriverPath is terminated with a '\\' if it's filled out.
|
|
//
|
|
if (DriverPath[0]) {
|
|
|
|
strcat(DriverPath, "\\");
|
|
}
|
|
|
|
if (AbsolutePath) {
|
|
|
|
//
|
|
// There is only one entry if an absolute path is specified (in
|
|
// this case we cannot do last known good).
|
|
//
|
|
PathSource = &LocalPathSet.Source[0];
|
|
PathSource->DeviceId = DeviceId;
|
|
PathSource->DeviceName = DriverDevice;
|
|
PathSource->DirectoryPath = "\\";
|
|
|
|
LocalPathSet.PathCount = 1;
|
|
LocalPathSet.AliasName = NULL;
|
|
strcpy(LocalPathSet.PathOffset, DriverPath);
|
|
|
|
} else {
|
|
|
|
//
|
|
// It's relative. Copy over the DefaultPathSet array so we can
|
|
// edit our own local copy.
|
|
//
|
|
*((PSPARSE_PATH_SET) &LocalPathSet) = *((PSPARSE_PATH_SET) DefaultPathSet);
|
|
|
|
for(Index=0; Index < DefaultPathSet->PathCount; Index++) {
|
|
|
|
LocalPathSet.Source[Index] = DefaultPathSet->Source[Index];
|
|
}
|
|
|
|
//
|
|
// Now append our relative path to the PathOffset already present
|
|
// in our local copy.
|
|
//
|
|
strcat(LocalPathSet.PathOffset, DriverPath);
|
|
}
|
|
|
|
if (Status == ESUCCESS) {
|
|
Status = BlLoadDeviceDriver(&LocalPathSet,
|
|
DriverName,
|
|
NULL,
|
|
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);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
return(ESUCCESS);
|
|
|
|
}
|
|
|
|
BOOLEAN
|
|
BlRecoverHive(
|
|
PVOID RegistryBase,
|
|
ULONG_PTR LogBase
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Applies log from LogBase over the RegistryBase
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
ESUCCESS is returned if the system hive was successfully loaded.
|
|
Otherwise, an unsuccessful status is returned.
|
|
|
|
--*/
|
|
{
|
|
PHBASE_BLOCK BaseBlockHive;
|
|
PHBASE_BLOCK BaseBlockLog;
|
|
ULONG FileOffset = HSECTOR_SIZE;
|
|
ULONG DirtyVectorSignature = 0;
|
|
PUCHAR FlatLog;
|
|
PUCHAR FlatReg;
|
|
ULONG VectorSize;
|
|
ULONG Length;
|
|
ULONG ClusterSize;
|
|
ULONG HeaderLength;
|
|
RTL_BITMAP BitMap;
|
|
PULONG Vector;
|
|
ULONG Current;
|
|
ULONG Start;
|
|
ULONG End;
|
|
PUCHAR MemoryBlock;
|
|
PUCHAR Dest;
|
|
ULONG i;
|
|
|
|
|
|
BaseBlockHive = (PHBASE_BLOCK)RegistryBase;
|
|
BaseBlockLog = (PHBASE_BLOCK)LogBase;
|
|
|
|
FlatLog = (PUCHAR)LogBase;
|
|
FlatReg = (PUCHAR)RegistryBase;
|
|
ClusterSize = BaseBlockLog->Cluster * HSECTOR_SIZE;
|
|
HeaderLength = ROUND_UP(HLOG_HEADER_SIZE, ClusterSize);
|
|
FileOffset = ClusterSize;
|
|
FileOffset = ROUND_UP(FileOffset, HeaderLength);
|
|
|
|
if(HvpHeaderCheckSum(BaseBlockHive) != BaseBlockHive->CheckSum ) {
|
|
//
|
|
// recover header case
|
|
//
|
|
RtlCopyMemory((PVOID)BaseBlockHive,(PVOID)BaseBlockLog,ClusterSize);
|
|
BaseBlockHive->Type = HFILE_TYPE_PRIMARY;
|
|
} else {
|
|
//
|
|
// if not recoverheader (which implies recoverdata)
|
|
//
|
|
ASSERT( BaseBlockHive->Sequence1 != BaseBlockHive->Sequence2 );
|
|
}
|
|
|
|
DirtyVectorSignature = *((PULONG)(FlatLog + FileOffset));
|
|
FileOffset += sizeof(DirtyVectorSignature);
|
|
|
|
if (DirtyVectorSignature != HLOG_DV_SIGNATURE) {
|
|
return FALSE;
|
|
}
|
|
|
|
Length = BaseBlockHive->Length;
|
|
VectorSize = Length / HSECTOR_SIZE;
|
|
Vector = (PULONG)(FlatLog + FileOffset);
|
|
|
|
RtlInitializeBitMap(&BitMap, Vector, VectorSize);
|
|
|
|
FileOffset += VectorSize / 8;
|
|
FileOffset = ROUND_UP(FileOffset, ClusterSize);
|
|
|
|
//
|
|
// step through the diry map, and copy from the log to the flat hive
|
|
//
|
|
Current = 0;
|
|
|
|
while (Current < VectorSize) {
|
|
|
|
//
|
|
// find next contiguous block of entries to read in
|
|
//
|
|
for (i = Current; i < VectorSize; i++) {
|
|
if (RtlCheckBit(&BitMap, i) == 1) {
|
|
break;
|
|
}
|
|
}
|
|
Start = i;
|
|
|
|
for ( ; i < VectorSize; i++) {
|
|
if (RtlCheckBit(&BitMap, i) == 0) {
|
|
break;
|
|
}
|
|
}
|
|
End = i;
|
|
Current = End;
|
|
|
|
//
|
|
// Start == number of 1st sector, End == number of Last sector + 1
|
|
//
|
|
Length = (End - Start) * HSECTOR_SIZE;
|
|
|
|
if( 0 == Length ) {
|
|
// no more dirty blocks.
|
|
break;
|
|
}
|
|
MemoryBlock = (PUCHAR)(FlatLog + FileOffset);
|
|
FileOffset += Length;
|
|
|
|
ASSERT((FileOffset % ClusterSize) == 0);
|
|
|
|
Dest = (PUCHAR)(FlatReg + HBLOCK_SIZE + Start * HSECTOR_SIZE);
|
|
|
|
//
|
|
// copy recovered data in the right locations inside the flat hive image
|
|
//
|
|
RtlCopyMemory(Dest,MemoryBlock, Length);
|
|
}
|
|
|
|
BaseBlockHive->Sequence2 = BaseBlockHive->Sequence1;
|
|
BaseBlockHive->CheckSum = HvpHeaderCheckSum(BaseBlockHive);
|
|
return TRUE;
|
|
}
|
|
|
|
ARC_STATUS
|
|
BlLoadAndInitSystemHive(
|
|
IN ULONG DeviceId,
|
|
IN PCHAR DeviceName,
|
|
IN PCHAR DirectoryPath,
|
|
IN PCHAR HiveName,
|
|
IN BOOLEAN IsAlternate,
|
|
OUT PBOOLEAN RestartSetup,
|
|
OUT PBOOLEAN LogPresent
|
|
)
|
|
|
|
/*++
|
|
|
|
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;
|
|
ULONG_PTR LogData;
|
|
|
|
*RestartSetup = FALSE;
|
|
*LogPresent = FALSE;
|
|
|
|
BlClearToEndOfLine();
|
|
|
|
Status = BlLoadSystemHive(DeviceId,
|
|
DeviceName,
|
|
DirectoryPath,
|
|
HiveName);
|
|
if (Status!=ESUCCESS) {
|
|
return(Status);
|
|
}
|
|
|
|
if (!BlInitializeHive(BlLoaderBlock->RegistryBase,
|
|
&BootHive,
|
|
IsAlternate)) {
|
|
if( !IsAlternate ) {
|
|
//
|
|
// try to recover the hive
|
|
//
|
|
Status = BlLoadSystemHiveLog(DeviceId,
|
|
DeviceName,
|
|
DirectoryPath,
|
|
"system.log",
|
|
&LogData );
|
|
if (Status!=ESUCCESS) {
|
|
return(Status);
|
|
}
|
|
|
|
*LogPresent = TRUE;
|
|
|
|
if( !BlRecoverHive( BlLoaderBlock->RegistryBase,
|
|
LogData ) ) {
|
|
BlFreeDescriptor( (ULONG)((ULONG_PTR)LogData & (~KSEG0_BASE)) >> PAGE_SHIFT );
|
|
return(EINVAL);
|
|
}
|
|
BlFreeDescriptor( (ULONG)((ULONG_PTR)LogData & (~KSEG0_BASE)) >> PAGE_SHIFT );
|
|
|
|
//
|
|
// we successfully recovered. Try setting up the hive again
|
|
//
|
|
if (!BlInitializeHive(BlLoaderBlock->RegistryBase,
|
|
&BootHive,
|
|
IsAlternate)) {
|
|
return(EINVAL);
|
|
}
|
|
//
|
|
// mark the hive as "recovered"
|
|
//
|
|
BootHive.Hive.BaseBlock->BootRecover = 1;
|
|
} else {
|
|
return(EINVAL);
|
|
}
|
|
} else {
|
|
//
|
|
// mark the hive as "no-recovered"
|
|
//
|
|
BootHive.Hive.BaseBlock->BootRecover = 0;
|
|
}
|
|
//
|
|
// See whether we need to switch to the backup setup hive.
|
|
//
|
|
*RestartSetup = BlpCheckRestartSetup();
|
|
|
|
return(ESUCCESS);
|
|
}
|
|
|
|
HCELL_INDEX
|
|
BlpDetermineControlSet(
|
|
IN OUT BOOLEAN *LastKnownGoodBoot
|
|
)
|
|
|
|
/*++
|
|
|
|
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:
|
|
|
|
LastKnownGoodBoot - On input, LastKnownGood indicates whether LKG has been
|
|
selected. This value is updated to TRUE if the user
|
|
chooses LKG via the profile configuration menu.
|
|
|
|
Return Value:
|
|
|
|
On success, HCELL_INDEX is control the set to boot from.
|
|
On error, HCELL_NIL is returned and LastKnownGoodBoot is unchanged.
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOLEAN UseLastKnownGood;
|
|
BOOLEAN ConfigMenu = FALSE;
|
|
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_ALIAS_LIST AliasList;
|
|
PCM_HARDWARE_PROFILE SelectedProfile;
|
|
DOCKING_STATION_INFO dockInfo = { 0, 0, 0, FW_DOCKINFO_DOCK_STATE_UNKNOWN };
|
|
PCONFIGURATION_COMPONENT_DATA dockInfoData;
|
|
ULONG flags;
|
|
|
|
#if DOCKINFO_VERBOSE
|
|
_TUCHAR Buffer[1024];
|
|
ULONG count;
|
|
USHORT dkState;
|
|
PTCHAR stateTxt;
|
|
#endif
|
|
|
|
//
|
|
// Preinit for failure
|
|
//
|
|
RtlInitUnicodeString(&DefaultControlName, L"Default");
|
|
RtlInitUnicodeString(&LkgControlName, L"LastKnownGood");
|
|
|
|
UseLastKnownGood = (*LastKnownGoodBoot);
|
|
|
|
if (ForceLastKnownGood) {
|
|
//
|
|
// last known good was selected from the
|
|
// advanced boot menu.
|
|
// this code path is entered when the user
|
|
// enters the advanced boot menu via the
|
|
// main boot menu.
|
|
//
|
|
UseLastKnownGood = TRUE;
|
|
}
|
|
|
|
if( !CmpValidateSelect(&BootHive.Hive,
|
|
BootHive.Hive.BaseBlock->RootCell) ) {
|
|
//
|
|
// some of the essential values (Current,Default,Failed,LastKnownGood)
|
|
// does not exist under \SYSTEM\Select key
|
|
//
|
|
return HCELL_NIL;
|
|
}
|
|
|
|
do_it_again:
|
|
//
|
|
// 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;
|
|
AliasList = NULL;
|
|
ProfileControl = CmpFindProfileOption(&BootHive.Hive,
|
|
ControlSet,
|
|
&ProfileList,
|
|
&AliasList,
|
|
&ProfileTimeout);
|
|
|
|
//
|
|
// Pull the Docking information from the hardware tree.
|
|
//
|
|
|
|
dockInfoData = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
|
|
PeripheralClass,
|
|
DockingInformation,
|
|
NULL);
|
|
|
|
if (NULL == dockInfoData) {
|
|
BlLoaderBlock->Extension->Profile.Status = HW_PROFILE_STATUS_SUCCESS;
|
|
BlLoaderBlock->Extension->Profile.DockingState = HW_PROFILE_DOCKSTATE_UNKNOWN;
|
|
BlLoaderBlock->Extension->Profile.Capabilities = 0;
|
|
BlLoaderBlock->Extension->Profile.DockID = 0;
|
|
BlLoaderBlock->Extension->Profile.SerialNumber = 0;
|
|
|
|
} else if (sizeof (dockInfo) <=
|
|
dockInfoData->ComponentEntry.ConfigurationDataLength) {
|
|
|
|
RtlCopyMemory (
|
|
&dockInfo,
|
|
(PUCHAR) (dockInfoData->ConfigurationData) + sizeof(CM_PARTIAL_RESOURCE_LIST),
|
|
sizeof (dockInfo));
|
|
|
|
BlLoaderBlock->Extension->Profile.Status = HW_PROFILE_STATUS_FAILURE;
|
|
|
|
switch (dockInfo.ReturnCode) {
|
|
case FW_DOCKINFO_SUCCESS:
|
|
BlLoaderBlock->Extension->Profile.Status = HW_PROFILE_STATUS_SUCCESS;
|
|
BlLoaderBlock->Extension->Profile.DockingState = HW_PROFILE_DOCKSTATE_DOCKED;
|
|
BlLoaderBlock->Extension->Profile.Capabilities = dockInfo.Capabilities;
|
|
BlLoaderBlock->Extension->Profile.DockID = dockInfo.DockID;
|
|
BlLoaderBlock->Extension->Profile.SerialNumber = dockInfo.SerialNumber;
|
|
break;
|
|
|
|
case FW_DOCKINFO_SYSTEM_NOT_DOCKED:
|
|
BlLoaderBlock->Extension->Profile.Status = HW_PROFILE_STATUS_SUCCESS;
|
|
BlLoaderBlock->Extension->Profile.DockingState = HW_PROFILE_DOCKSTATE_UNDOCKED;
|
|
BlLoaderBlock->Extension->Profile.Capabilities = dockInfo.Capabilities;
|
|
BlLoaderBlock->Extension->Profile.DockID = dockInfo.DockID;
|
|
BlLoaderBlock->Extension->Profile.SerialNumber = dockInfo.SerialNumber;
|
|
break;
|
|
|
|
case FW_DOCKINFO_DOCK_STATE_UNKNOWN:
|
|
BlLoaderBlock->Extension->Profile.Status = HW_PROFILE_STATUS_SUCCESS;
|
|
BlLoaderBlock->Extension->Profile.DockingState = HW_PROFILE_DOCKSTATE_UNKNOWN;
|
|
BlLoaderBlock->Extension->Profile.Capabilities = dockInfo.Capabilities;
|
|
BlLoaderBlock->Extension->Profile.DockID = dockInfo.DockID;
|
|
BlLoaderBlock->Extension->Profile.SerialNumber = dockInfo.SerialNumber;
|
|
break;
|
|
|
|
case FW_DOCKINFO_FUNCTION_NOT_SUPPORTED:
|
|
case FW_DOCKINFO_BIOS_NOT_CALLED:
|
|
BlLoaderBlock->Extension->Profile.Status = HW_PROFILE_STATUS_SUCCESS;
|
|
default:
|
|
BlLoaderBlock->Extension->Profile.DockingState = HW_PROFILE_DOCKSTATE_UNSUPPORTED;
|
|
BlLoaderBlock->Extension->Profile.Capabilities = dockInfo.Capabilities;
|
|
BlLoaderBlock->Extension->Profile.DockID = dockInfo.DockID;
|
|
BlLoaderBlock->Extension->Profile.SerialNumber = dockInfo.SerialNumber;
|
|
break;
|
|
}
|
|
|
|
} else {
|
|
BlLoaderBlock->Extension->Profile.Status = HW_PROFILE_STATUS_SUCCESS;
|
|
BlLoaderBlock->Extension->Profile.Capabilities = 0;
|
|
BlLoaderBlock->Extension->Profile.DockID = 0;
|
|
BlLoaderBlock->Extension->Profile.SerialNumber = 0;
|
|
}
|
|
|
|
#ifdef DOCKINFO_VERBOSE
|
|
|
|
dkState = BlLoaderBlock->Extension->Profile.DockingState;
|
|
|
|
if ((dkState & HW_PROFILE_DOCKSTATE_UNKNOWN) == HW_PROFILE_DOCKSTATE_UNKNOWN) {
|
|
stateTxt = TEXT("Unknown");
|
|
} else if (dkState & HW_PROFILE_DOCKSTATE_DOCKED) {
|
|
stateTxt = TEXT("Docked");
|
|
} else if (dkState & HW_PROFILE_DOCKSTATE_UNDOCKED) {
|
|
stateTxt = TEXT("Undocked");
|
|
} else {
|
|
stateTxt = TEXT("Truely unknown");
|
|
}
|
|
|
|
_stprintf(Buffer,
|
|
TEXT("Profile Docking: <%x, %s> := %x [%x, %x] \r\n\0"),
|
|
BlLoaderBlock->Extension->Profile.Status,
|
|
stateTxt,
|
|
BlLoaderBlock->Extension->Profile.Capabilities,
|
|
BlLoaderBlock->Extension->Profile.DockID,
|
|
BlLoaderBlock->Extension->Profile.SerialNumber);
|
|
|
|
ArcWrite(BlConsoleOutDeviceId, Buffer, _tcslen(Buffer)*sizeof(TCHAR), &count);
|
|
|
|
_stprintf(Buffer, TEXT("press 'y' (lowercase) to continue...\r\n\0"));
|
|
ArcWrite(BlConsoleOutDeviceId, Buffer, _tcslen(Buffer)*sizeof(TCHAR), &count);
|
|
#ifdef EFI
|
|
//
|
|
// disable efi watchdog when waiting for user input
|
|
//
|
|
DisableEFIWatchDog();
|
|
#endif
|
|
while (BlGetKey() != 'y') {
|
|
//
|
|
// Nothing
|
|
//
|
|
}
|
|
#ifdef EFI
|
|
//
|
|
// reset EFI watchdog
|
|
//
|
|
SetEFIWatchDog(EFI_WATCHDOG_TIMEOUT);
|
|
#endif
|
|
|
|
#endif
|
|
|
|
//
|
|
// Filter the list of Hardware Profiles to
|
|
// eliminate profiles that should not be considered
|
|
//
|
|
if (NULL != ProfileList) {
|
|
if (ProfileList->CurrentProfileCount > 0) {
|
|
BlDockInfoFilterProfileList (ProfileList, AliasList);
|
|
}
|
|
}
|
|
|
|
//
|
|
// 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()) {
|
|
if (!UseLastKnownGood && ForceLastKnownGood) {
|
|
//
|
|
// last known good was selected from the
|
|
// advanced boot menu.
|
|
// this code path is entered when the user
|
|
// enters the advanced boot menu by pressing
|
|
// F8 while the cinfiguration hives are preparing to load.
|
|
//
|
|
// the currentcontrolset has already been set to the
|
|
// "default" control set, so go back and try this again to
|
|
// load the "lastknowngood" controlset.
|
|
//
|
|
UseLastKnownGood = TRUE;
|
|
|
|
goto do_it_again;
|
|
}
|
|
|
|
ConfigMenu = FALSE;
|
|
|
|
} else {
|
|
ConfigMenu = TRUE;
|
|
}
|
|
|
|
if (ConfigMenu || ForceLastKnownGood ||
|
|
(UseLastKnownGood && !AutoSelect) ||
|
|
((ProfileTimeout != 0) &&
|
|
(ProfileList != NULL) &&
|
|
(ProfileList->CurrentProfileCount > 1))) {
|
|
//
|
|
// Display the configuration menu.
|
|
//
|
|
BlRebootSystem = !BlConfigMenuPrompt(ProfileTimeout,
|
|
&UseLastKnownGood,
|
|
&ControlSet,
|
|
&ProfileList,
|
|
&AliasList,
|
|
&SelectedProfile);
|
|
|
|
if (BlRebootSystem) {
|
|
ArcReboot();
|
|
}
|
|
BlClearScreen();
|
|
} 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.
|
|
//
|
|
if (HW_PROFILE_STATUS_SUCCESS ==
|
|
BlLoaderBlock->Extension->Profile.Status) {
|
|
|
|
flags = (ProfileList->Profile[0].Flags);
|
|
|
|
if (flags & CM_HP_FLAGS_PRISTINE) {
|
|
BlLoaderBlock->Extension->Profile.Status =
|
|
HW_PROFILE_STATUS_PRISTINE_MATCH;
|
|
|
|
} else if (flags & CM_HP_FLAGS_TRUE_MATCH) {
|
|
BlLoaderBlock->Extension->Profile.Status =
|
|
HW_PROFILE_STATUS_TRUE_MATCH;
|
|
|
|
} else if (flags & CM_HP_FLAGS_ALIASABLE) {
|
|
BlLoaderBlock->Extension->Profile.Status =
|
|
HW_PROFILE_STATUS_ALIAS_MATCH;
|
|
}
|
|
}
|
|
|
|
CmpSetCurrentProfile(&BootHive.Hive,
|
|
ControlSet,
|
|
&ProfileList->Profile[0]);
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// Update the passed in parameter. We should only be doing this if we have
|
|
// something real to return.
|
|
//
|
|
//ASSERT(ControlSet != HCELL_NIL);
|
|
*LastKnownGoodBoot = UseLastKnownGood;
|
|
|
|
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));
|
|
}
|
|
|
|
|
|
#if defined(REMOTE_BOOT)
|
|
BOOLEAN
|
|
BlpQueryRemoteBootParameter(
|
|
IN HCELL_INDEX ControlSet,
|
|
IN PWSTR ValueName,
|
|
IN ULONG ValueType,
|
|
OUT PVOID ValueBuffer,
|
|
IN ULONG ValueBufferLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Query a parameter from under Control\RemoteBoot.
|
|
|
|
Arguments:
|
|
|
|
ControlSet - The index of the current control set.
|
|
|
|
ValueName - The name of the value to query.
|
|
|
|
ValueType - The expected type of the value.
|
|
|
|
ValueBuffer - The location to return the data.
|
|
|
|
ValueBufferLength - The length of the buffer.
|
|
|
|
Return Value:
|
|
|
|
Boolean value indicating whether the data was read successfully.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
UNICODE_STRING Name;
|
|
HCELL_INDEX Control;
|
|
HCELL_INDEX RemoteBoot;
|
|
HCELL_INDEX ValueCell;
|
|
PCM_KEY_VALUE Value;
|
|
ULONG RealSize;
|
|
BOOLEAN ValueSmall;
|
|
|
|
//
|
|
// Find Services node
|
|
//
|
|
RtlInitUnicodeString(&Name, L"Control");
|
|
Control = CmpFindSubKeyByName(
|
|
&BootHive.Hive,
|
|
(PCM_KEY_NODE)HvGetCell(&BootHive.Hive,ControlSet),
|
|
&Name);
|
|
if (Control == HCELL_NIL) {
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Find RemoteBoot node
|
|
//
|
|
RtlInitUnicodeString(&Name, L"RemoteBoot");
|
|
RemoteBoot = CmpFindSubKeyByName(
|
|
&BootHive.Hive,
|
|
(PCM_KEY_NODE)HvGetCell(&BootHive.Hive,Control),
|
|
&Name);
|
|
if (RemoteBoot == HCELL_NIL) {
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Find value
|
|
//
|
|
RtlInitUnicodeString(&Name, ValueName);
|
|
ValueCell = CmpFindValueByName(
|
|
&BootHive.Hive,
|
|
(PCM_KEY_NODE)HvGetCell(&BootHive.Hive,RemoteBoot),
|
|
&Name);
|
|
if (ValueCell == HCELL_NIL) {
|
|
return(FALSE);
|
|
}
|
|
|
|
Value = (PCM_KEY_VALUE)HvGetCell(&BootHive.Hive, ValueCell);
|
|
|
|
if (Value->Type != ValueType) {
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// This determines if the value is small (stored right in Value)
|
|
// or not, and also returns the real size of it.
|
|
//
|
|
|
|
ValueSmall = CmpIsHKeyValueSmall(RealSize,Value->DataLength);
|
|
|
|
if (RealSize > ValueBufferLength) {
|
|
return(FALSE);
|
|
}
|
|
|
|
RtlMoveMemory(
|
|
ValueBuffer,
|
|
(ValueSmall ?
|
|
(struct _CELL_DATA *)&Value->Data :
|
|
HvGetCell(&BootHive.Hive,Value->Data)),
|
|
RealSize);
|
|
|
|
return(TRUE);
|
|
}
|
|
#endif // defined(REMOTE_BOOT)
|
|
|
|
|
|
PTCHAR
|
|
BlScanRegistry(
|
|
IN PWSTR BootFileSystemPath,
|
|
IN OUT BOOLEAN *LastKnownGoodBoot,
|
|
OUT PLIST_ENTRY BootDriverListHead,
|
|
OUT PUNICODE_STRING AnsiCodepage,
|
|
OUT PUNICODE_STRING OemCodepage,
|
|
OUT PUNICODE_STRING LanguageTable,
|
|
OUT PUNICODE_STRING OemHalFont,
|
|
#ifdef _WANT_MACHINE_IDENTIFICATION
|
|
OUT PUNICODE_STRING Biosinfo,
|
|
#endif
|
|
OUT PSETUP_LOADER_BLOCK SetupLoaderBlock,
|
|
OUT BOOLEAN *ServerHive
|
|
)
|
|
|
|
/*++
|
|
|
|
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.
|
|
|
|
LastKnownGoodBoot - On input, LastKnownGood indicates whether LKG has been
|
|
selected. This value is updated to TRUE if the user
|
|
chooses LKG via the profile configuration menu.
|
|
|
|
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.
|
|
|
|
SetupLoaderBlock - if non-NULL, used to return information about the
|
|
net boot card.
|
|
|
|
ServerHive - Returns TRUE if this is a server hive, else FALSE.
|
|
|
|
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. On error LastKnownGood
|
|
is unchanged.
|
|
|
|
--*/
|
|
|
|
{
|
|
HCELL_INDEX ControlSet;
|
|
UNICODE_STRING TmpName;
|
|
HCELL_INDEX Control;
|
|
HCELL_INDEX ProductOptions;
|
|
HCELL_INDEX ValueCell;
|
|
PCM_KEY_VALUE Value;
|
|
ULONG RealSize;
|
|
PWCHAR CellString;
|
|
BOOLEAN UsingLastKnownGood;
|
|
#ifdef _WANT_MACHINE_IDENTIFICATION
|
|
UNICODE_STRING regDate;
|
|
CHAR date[9];
|
|
ANSI_STRING ansiString;
|
|
UNICODE_STRING biosDate;
|
|
WCHAR buffer[9];
|
|
BOOLEAN biosDateChanged;
|
|
#endif
|
|
|
|
#if !defined(REMOTE_BOOT)
|
|
UNREFERENCED_PARAMETER(SetupLoaderBlock);
|
|
#endif
|
|
|
|
//
|
|
// Preinit.
|
|
//
|
|
UsingLastKnownGood = *LastKnownGoodBoot;
|
|
|
|
//
|
|
// Get the appropriate control set.
|
|
//
|
|
ControlSet = BlpDetermineControlSet(&UsingLastKnownGood);
|
|
|
|
if (ControlSet == HCELL_NIL) {
|
|
return(TEXT("CmpFindControlSet"));
|
|
}
|
|
|
|
if (!CmpFindNLSData(&BootHive.Hive,
|
|
ControlSet,
|
|
AnsiCodepage,
|
|
OemCodepage,
|
|
LanguageTable,
|
|
OemHalFont)) {
|
|
return(TEXT("CmpFindNLSData"));
|
|
}
|
|
|
|
InitializeListHead(BootDriverListHead);
|
|
if (!CmpFindDrivers(&BootHive.Hive,
|
|
ControlSet,
|
|
BootLoad,
|
|
BootFileSystemPath,
|
|
BootDriverListHead)) {
|
|
return(TEXT("CmpFindDriver"));
|
|
}
|
|
|
|
if (!CmpSortDriverList(&BootHive.Hive,
|
|
ControlSet,
|
|
BootDriverListHead)) {
|
|
return(TEXT("Missing or invalid Control\\ServiceGroupOrder\\List registry value"));
|
|
}
|
|
|
|
if (!CmpResolveDriverDependencies(BootDriverListHead)) {
|
|
return(TEXT("CmpResolveDriverDependencies"));
|
|
}
|
|
|
|
if (ServerHive != NULL) {
|
|
|
|
*ServerHive = FALSE;
|
|
|
|
//
|
|
// Find Control node
|
|
//
|
|
RtlInitUnicodeString(&TmpName, L"Control");
|
|
|
|
Control = CmpFindSubKeyByName(&BootHive.Hive,
|
|
(PCM_KEY_NODE)HvGetCell(&BootHive.Hive, ControlSet),
|
|
&TmpName
|
|
);
|
|
if (Control == HCELL_NIL) {
|
|
return(TEXT("Missing Control key"));
|
|
}
|
|
|
|
//
|
|
// Find ProductOptions node
|
|
//
|
|
RtlInitUnicodeString(&TmpName, L"ProductOptions");
|
|
ProductOptions = CmpFindSubKeyByName(&BootHive.Hive,
|
|
(PCM_KEY_NODE)HvGetCell(&BootHive.Hive,Control),
|
|
&TmpName
|
|
);
|
|
if (ProductOptions == HCELL_NIL) {
|
|
return(TEXT("Missing ProductOptions key"));
|
|
}
|
|
|
|
//
|
|
// Find value
|
|
//
|
|
RtlInitUnicodeString(&TmpName, L"ProductType");
|
|
ValueCell = CmpFindValueByName(&BootHive.Hive,
|
|
(PCM_KEY_NODE)HvGetCell(&BootHive.Hive, ProductOptions),
|
|
&TmpName
|
|
);
|
|
|
|
if (ValueCell == HCELL_NIL) {
|
|
return(TEXT("Missing ProductType value"));
|
|
}
|
|
|
|
Value = (PCM_KEY_VALUE)HvGetCell(&BootHive.Hive, ValueCell);
|
|
|
|
if (Value->Type != REG_SZ) {
|
|
return(TEXT("Bad ProductType value"));
|
|
}
|
|
|
|
//
|
|
// This determines if the value is small (stored right in Value)
|
|
// or not, and also returns the real size of it.
|
|
//
|
|
CellString = (PWCHAR)(CmpIsHKeyValueSmall(RealSize, Value->DataLength) ?
|
|
(struct _CELL_DATA *)&Value->Data :
|
|
HvGetCell(&BootHive.Hive, Value->Data)
|
|
);
|
|
|
|
//
|
|
// Now compare if this is a server hive or not.
|
|
// The proper way to check this is to check the string against
|
|
// the "professional" type 'WinNT'. If it's not professional,
|
|
// it must be a server. (There are multiple strings for different
|
|
// server flavours.)
|
|
//
|
|
*ServerHive = (BOOLEAN)(_wcsicmp(L"WinNT", CellString) != 0);
|
|
}
|
|
|
|
#if defined(REMOTE_BOOT)
|
|
if (SetupLoaderBlock != NULL) {
|
|
|
|
ULONG EnableIpSecurity;
|
|
|
|
if (BlpQueryRemoteBootParameter(
|
|
ControlSet,
|
|
L"EnableIpSecurity",
|
|
REG_DWORD,
|
|
&EnableIpSecurity,
|
|
sizeof(EnableIpSecurity))) {
|
|
if (EnableIpSecurity != 0) {
|
|
SetupLoaderBlock->Flags |= SETUPBLK_FLAGS_IPSEC_ENABLED;
|
|
}
|
|
}
|
|
|
|
if (BlpQueryRemoteBootParameter(
|
|
ControlSet,
|
|
L"NetCardInfo",
|
|
REG_BINARY,
|
|
SetupLoaderBlock->NetbootCardInfo,
|
|
SetupLoaderBlock->NetbootCardInfoLength)) {
|
|
|
|
if (!BlpQueryRemoteBootParameter(
|
|
ControlSet,
|
|
L"HardwareId",
|
|
REG_SZ,
|
|
SetupLoaderBlock->NetbootCardHardwareId,
|
|
sizeof(SetupLoaderBlock->NetbootCardHardwareId))) {
|
|
SetupLoaderBlock->NetbootCardHardwareId[0] = L'\0';
|
|
}
|
|
|
|
if (!BlpQueryRemoteBootParameter(
|
|
ControlSet,
|
|
L"DriverName",
|
|
REG_SZ,
|
|
SetupLoaderBlock->NetbootCardDriverName,
|
|
sizeof(SetupLoaderBlock->NetbootCardDriverName))) {
|
|
SetupLoaderBlock->NetbootCardDriverName[0] = L'\0';
|
|
}
|
|
|
|
if (!BlpQueryRemoteBootParameter(
|
|
ControlSet,
|
|
L"ServiceName",
|
|
REG_SZ,
|
|
SetupLoaderBlock->NetbootCardServiceName,
|
|
sizeof(SetupLoaderBlock->NetbootCardServiceName))) {
|
|
SetupLoaderBlock->NetbootCardServiceName[0] = L'\0';
|
|
}
|
|
}
|
|
}
|
|
#endif // defined(REMOTE_BOOT)
|
|
|
|
#ifdef _WANT_MACHINE_IDENTIFICATION
|
|
|
|
biosDateChanged = TRUE;
|
|
if (CmpGetBiosDateFromRegistry(&BootHive.Hive, ControlSet, ®Date)) {
|
|
|
|
//
|
|
// Read the date from the BIOS ROM.
|
|
//
|
|
memcpy(date, (PVOID)0xffff5, 8);
|
|
date[8] = '\0';
|
|
|
|
//
|
|
// Convert the date into unicode string.
|
|
//
|
|
|
|
ansiString.Buffer = date;
|
|
ansiString.Length = (USHORT) strlen(date);
|
|
ansiString.MaximumLength = ansiString.Length + 1;
|
|
biosDate.Buffer = buffer;
|
|
biosDate.MaximumLength = (ansiString.Length << 1) + sizeof(UNICODE_NULL);
|
|
RtlAnsiStringToUnicodeString(&biosDate, &ansiString, FALSE);
|
|
|
|
//
|
|
// Check if the dates are different.
|
|
//
|
|
|
|
if (RtlCompareUnicodeString(&biosDate, ®Date, FALSE) == 0) {
|
|
|
|
biosDateChanged = FALSE;
|
|
}
|
|
}
|
|
|
|
Biosinfo->Length = 0;
|
|
if (biosDateChanged) {
|
|
|
|
CmpGetBiosinfoFileNameFromRegistry(&BootHive.Hive, ControlSet, Biosinfo);
|
|
}
|
|
|
|
#endif // defined(_WANT_MACHINE_IDENTIFICATION)
|
|
|
|
*LastKnownGoodBoot = UsingLastKnownGood;
|
|
return( NULL );
|
|
}
|
|
|
|
|
|
ARC_STATUS
|
|
BlAddToBootDriverList(
|
|
IN PLIST_ENTRY BootDriverListHead,
|
|
IN PWSTR DriverName,
|
|
IN PWSTR Name,
|
|
IN PWSTR Group,
|
|
IN ULONG Tag,
|
|
IN ULONG ErrorControl,
|
|
IN BOOLEAN InsertAtHead
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Adds a single driver to the boot driver list. The list
|
|
is NOT re-sorted.
|
|
|
|
Arguments:
|
|
|
|
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.
|
|
|
|
DriverName - The name of the driver. This will be stored with
|
|
\system32\drivers on the front.
|
|
|
|
Name - The service name of the driver. Typically will be DriverName
|
|
without the ".sys".
|
|
|
|
Group - The group this driver is in.
|
|
|
|
Tag - The tag value within the group for this driver.
|
|
|
|
ErrorControl - The error control value for this driver.
|
|
|
|
InsertAtHead - Should this driver be inserted at the head of the list, otw tail.
|
|
|
|
Return Value:
|
|
|
|
ESUCCESS if the driver is successfully inserted.
|
|
ENOMEM if there is an allocation failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
PBOOT_DRIVER_NODE DriverNode;
|
|
PBOOT_DRIVER_LIST_ENTRY DriverListEntry;
|
|
USHORT Length;
|
|
|
|
DriverNode = BlpHiveAllocate(sizeof(BOOT_DRIVER_NODE),FALSE,0);
|
|
if (DriverNode == FALSE) {
|
|
return ENOMEM;
|
|
}
|
|
|
|
DriverListEntry = &DriverNode->ListEntry;
|
|
|
|
//
|
|
// FilePath
|
|
//
|
|
|
|
//
|
|
// when assigning the length, do some checking to make sure we don't
|
|
// overflow. if we do overflow, assign the length value to 0
|
|
// make sure we don't overflow (USHORT)-1
|
|
//
|
|
Length = RESET_SIZE_AT_USHORT_MAX(sizeof(L"System32\\Drivers\\") + (wcslen(DriverName) * sizeof(WCHAR)));
|
|
DriverListEntry->FilePath.Buffer = BlpHiveAllocate(Length,FALSE,0);
|
|
if (DriverListEntry->FilePath.Buffer == NULL) {
|
|
return ENOMEM;
|
|
}
|
|
DriverListEntry->FilePath.Length = 0;
|
|
DriverListEntry->FilePath.MaximumLength = Length;
|
|
RtlAppendUnicodeToString(&DriverListEntry->FilePath, L"System32\\Drivers\\");
|
|
RtlAppendUnicodeToString(&DriverListEntry->FilePath, DriverName);
|
|
|
|
//
|
|
// Registry Path
|
|
//
|
|
|
|
//
|
|
// when assigning the length, do some checking to make sure we don't
|
|
// overflow. if we do overflow, assign the length value to 0
|
|
// make sure we don't overflow (USHORT)-1
|
|
//
|
|
Length = RESET_SIZE_AT_USHORT_MAX(sizeof(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\") +
|
|
(wcslen(Name) * sizeof(WCHAR)));
|
|
DriverListEntry->RegistryPath.Buffer = BlpHiveAllocate(Length,FALSE,0);
|
|
if (DriverListEntry->RegistryPath.Buffer == NULL) {
|
|
return ENOMEM;
|
|
}
|
|
DriverListEntry->RegistryPath.Length = 0;
|
|
DriverListEntry->RegistryPath.MaximumLength = Length;
|
|
RtlAppendUnicodeToString(&DriverListEntry->RegistryPath, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
|
|
RtlAppendUnicodeToString(&DriverListEntry->RegistryPath, Name);
|
|
|
|
//
|
|
// Group
|
|
//
|
|
|
|
//
|
|
// when assigning the length, do some checking to make sure we don't
|
|
// overflow. if we do overflow, assign the length value to 0
|
|
// make sure we don't overflow (USHORT)-1
|
|
//
|
|
Length = RESET_SIZE_AT_USHORT_MAX((wcslen(Group) + 1) * sizeof(WCHAR));
|
|
DriverNode->Group.Buffer = BlpHiveAllocate(Length,FALSE,0);
|
|
if (DriverNode->Group.Buffer == NULL) {
|
|
return ENOMEM;
|
|
}
|
|
DriverNode->Group.Length = 0;
|
|
DriverNode->Group.MaximumLength = Length;
|
|
RtlAppendUnicodeToString(&DriverNode->Group, Group);
|
|
|
|
//
|
|
// Name
|
|
//
|
|
|
|
//
|
|
// when assigning the length, do some checking to make sure we don't
|
|
// overflow. if we do overflow, assign the length value to 0
|
|
// make sure we don't overflow (USHORT)-1
|
|
//
|
|
Length = RESET_SIZE_AT_USHORT_MAX((wcslen(Name) + 1) * sizeof(WCHAR));
|
|
DriverNode->Name.Buffer = BlpHiveAllocate(Length,FALSE,0);
|
|
if (DriverNode->Name.Buffer == NULL) {
|
|
return ENOMEM;
|
|
}
|
|
DriverNode->Name.Length = 0;
|
|
DriverNode->Name.MaximumLength = Length;
|
|
RtlAppendUnicodeToString(&DriverNode->Name, Name);
|
|
|
|
//
|
|
// Tag/ErrorControl
|
|
//
|
|
|
|
DriverNode->Tag = Tag;
|
|
DriverNode->ErrorControl = ErrorControl;
|
|
|
|
if (InsertAtHead) {
|
|
InsertHeadList(BootDriverListHead, &DriverListEntry->Link);
|
|
} else {
|
|
InsertTailList(BootDriverListHead, &DriverListEntry->Link);
|
|
}
|
|
|
|
return ESUCCESS;
|
|
|
|
}
|
|
|
|
#define HFILE_TYPE_ALTERNATE 1 // alternate, in order for boot to be able to boot downlevel OSes
|
|
|
|
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,CM_CHECK_REGISTRY_LOADER_CLEAN|CM_CHECK_REGISTRY_HIVE_CHECK);
|
|
if (HiveCheckCode != 0) {
|
|
return(FALSE);
|
|
} else {
|
|
return TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
PVOID
|
|
BlpHiveAllocate(
|
|
IN ULONG Length,
|
|
IN BOOLEAN UseForIo,
|
|
IN ULONG Tag
|
|
)
|
|
|
|
/*++
|
|
|
|
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
|
|
|
|
--*/
|
|
|
|
{
|
|
UNREFERENCED_PARAMETER( Length );
|
|
UNREFERENCED_PARAMETER( UseForIo );
|
|
UNREFERENCED_PARAMETER( Tag );
|
|
|
|
return(BlAllocateHeap(Length));
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
HvLoadHive(
|
|
PHHIVE Hive
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(Hive);
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
NTSTATUS
|
|
HvMapHive(
|
|
PHHIVE Hive
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(Hive);
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
NTSTATUS
|
|
HvpAdjustHiveFreeDisplay(
|
|
IN PHHIVE Hive,
|
|
IN ULONG HiveLength,
|
|
IN HSTORAGE_TYPE Type
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(Hive);
|
|
UNREFERENCED_PARAMETER(HiveLength);
|
|
UNREFERENCED_PARAMETER(Type);
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
VOID
|
|
HvpAddFreeCellHint(
|
|
PHHIVE Hive,
|
|
HCELL_INDEX Cell,
|
|
ULONG Index,
|
|
HSTORAGE_TYPE Type
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(Hive);
|
|
UNREFERENCED_PARAMETER(Cell);
|
|
UNREFERENCED_PARAMETER(Index);
|
|
UNREFERENCED_PARAMETER(Type);
|
|
}
|
|
|
|
VOID
|
|
HvpRemoveFreeCellHint(
|
|
PHHIVE Hive,
|
|
HCELL_INDEX Cell,
|
|
ULONG Index,
|
|
HSTORAGE_TYPE Type
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(Hive);
|
|
UNREFERENCED_PARAMETER(Cell);
|
|
UNREFERENCED_PARAMETER(Index);
|
|
UNREFERENCED_PARAMETER(Type);
|
|
}
|
|
|
|
HCELL_INDEX
|
|
HvpFindFreeCell(
|
|
PHHIVE Hive,
|
|
ULONG Index,
|
|
ULONG NewSize,
|
|
HSTORAGE_TYPE Type,
|
|
HCELL_INDEX Vicinity
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(Hive);
|
|
UNREFERENCED_PARAMETER(Index);
|
|
UNREFERENCED_PARAMETER(Type);
|
|
UNREFERENCED_PARAMETER(NewSize);
|
|
UNREFERENCED_PARAMETER(Vicinity);
|
|
return HCELL_NIL;
|
|
}
|
|
|
|
VOID
|
|
CmpTouchView(
|
|
IN PCMHIVE CmHive,
|
|
IN PCM_VIEW_OF_FILE CmView,
|
|
IN ULONG Cell
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(CmHive);
|
|
UNREFERENCED_PARAMETER(CmView);
|
|
UNREFERENCED_PARAMETER(Cell);
|
|
}
|
|
|
|
NTSTATUS
|
|
CmpMapThisBin(
|
|
PCMHIVE CmHive,
|
|
HCELL_INDEX Cell,
|
|
BOOLEAN Touch
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(CmHive);
|
|
UNREFERENCED_PARAMETER(Cell);
|
|
UNREFERENCED_PARAMETER(Touch);
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
/*
|
|
NTSTATUS
|
|
CmpMapCmView(
|
|
IN PCMHIVE CmHive,
|
|
IN ULONG FileOffset,
|
|
OUT PCM_VIEW_OF_FILE *CmView
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(CmHive);
|
|
UNREFERENCED_PARAMETER(FileOffset);
|
|
UNREFERENCED_PARAMETER(CmView);
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
VOID
|
|
CmpPinCmView (
|
|
IN PCMHIVE CmHive,
|
|
PCM_VIEW_OF_FILE CmView
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(CmHive);
|
|
UNREFERENCED_PARAMETER(CmView);
|
|
}
|
|
|
|
VOID
|
|
CmpUnPinCmView (
|
|
IN PCMHIVE CmHive,
|
|
IN PCM_VIEW_OF_FILE CmView,
|
|
IN BOOLEAN SetClean
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(CmHive);
|
|
UNREFERENCED_PARAMETER(CmView);
|
|
UNREFERENCED_PARAMETER(SetClean);
|
|
}
|
|
|
|
VOID
|
|
CmpLazyFlush(
|
|
VOID
|
|
)
|
|
{
|
|
}
|
|
*/
|
|
|
|
/*
|
|
NTSTATUS
|
|
CmpDoFileSetSize(
|
|
PHHIVE Hive,
|
|
ULONG FileType,
|
|
ULONG FileSize
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(Hive);
|
|
UNREFERENCED_PARAMETER(FileType);
|
|
UNREFERENCED_PARAMETER(FileSize);
|
|
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,
|
|
BOOLEAN DirtyAndPin
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(Hive);
|
|
UNREFERENCED_PARAMETER(Start);
|
|
UNREFERENCED_PARAMETER(Length);
|
|
UNREFERENCED_PARAMETER(DirtyAndPin);
|
|
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,
|
|
OUT PBOOLEAN ResetSD
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(Hive);
|
|
UNREFERENCED_PARAMETER( ResetSD );
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
CmpTestRegistryLock()
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
CmpTestRegistryLockExclusive()
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
HvIsBinDirty(
|
|
IN PHHIVE Hive,
|
|
IN HCELL_INDEX Cell
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER( Hive );
|
|
UNREFERENCED_PARAMETER( Cell );
|
|
|
|
return(FALSE);
|
|
}
|
|
PHBIN
|
|
HvpAddBin(
|
|
IN PHHIVE Hive,
|
|
IN ULONG NewSize,
|
|
IN HSTORAGE_TYPE Type
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER( Hive );
|
|
UNREFERENCED_PARAMETER( NewSize );
|
|
UNREFERENCED_PARAMETER( Type );
|
|
|
|
return(NULL);
|
|
}
|
|
VOID
|
|
CmpReleaseGlobalQuota(
|
|
IN ULONG Size
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER( Size );
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
#if DOCKINFO_VERBOSE
|
|
VOID
|
|
BlDiagDisplayProfileList(
|
|
IN PCM_HARDWARE_PROFILE_LIST ProfileList,
|
|
IN PCM_HARDWARE_PROFILE_ALIAS_LIST AliasList,
|
|
IN BOOLEAN WaitForUserInput
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is a diagnostic function only!
|
|
|
|
Display hardware profile list on console, optionally wait for user
|
|
input before proceeding.
|
|
|
|
Arguments:
|
|
|
|
ProfileList - Supplies a list of hardware profiles to display
|
|
|
|
WaitForUserInput - Prompt user to hit a key ('y') to continue, and wait
|
|
for user's input if TRUE. Don't wait if FALSE.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
TCHAR Buffer[200];
|
|
TCHAR StrFriendlyName[30];
|
|
PTCHAR AliasType [] = {
|
|
TEXT("NotAliasable"), // 0
|
|
TEXT("Aliasable "), // 1
|
|
TEXT("True Match "), // 2
|
|
TEXT("True & Alias"), // 3
|
|
TEXT("Pristine "), // 4
|
|
TEXT("Pris & Alias"), // 5
|
|
TEXT("Pris & True "), // 6
|
|
TEXT("P & A & T ") // 7
|
|
};
|
|
|
|
ULONG Count;
|
|
ULONG i;
|
|
|
|
// display header
|
|
_stprintf(Buffer, TEXT("Profiles: <PrefOrd, Id - Aliased FriendlyName>\r\n\0"));
|
|
ArcWrite(BlConsoleOutDeviceId, Buffer, _tcslen(Buffer)*sizeof(TCHAR), &Count);
|
|
|
|
|
|
// for each hardware profile
|
|
for (i = 0; i < ProfileList->CurrentProfileCount; ++i) {
|
|
#ifdef UNICODE
|
|
wcsncpy(
|
|
StrFriendlyName,
|
|
ProfileList->Profile[i].FriendlyName,
|
|
ProfileList->Profile[i].NameLength,
|
|
);
|
|
StrFriendlyName[29] = L'\0';
|
|
StrFriendlyName[ProfileList->Profile[i].NameLength] = L'\0';
|
|
#else
|
|
|
|
// copy and convert unicode fields to ascii for output
|
|
RtlUnicodeToMultiByteN(StrFriendlyName,
|
|
sizeof(StrFriendlyName),
|
|
&Count,
|
|
ProfileList->Profile[i].FriendlyName,
|
|
ProfileList->Profile[i].NameLength);
|
|
StrFriendlyName[Count] = '\0';
|
|
#endif
|
|
|
|
// display info for current profile
|
|
_stprintf(Buffer,
|
|
TEXT(" <%2ld> %2ld - %s \"%s\"\r\n\0"),
|
|
ProfileList->Profile[i].PreferenceOrder,
|
|
ProfileList->Profile[i].Id,
|
|
AliasType[ ProfileList->Profile[i].Flags ],
|
|
StrFriendlyName);
|
|
ArcWrite(
|
|
BlConsoleOutDeviceId,
|
|
Buffer,
|
|
_tcslen(Buffer)*sizeof(TCHAR),
|
|
&Count );
|
|
}
|
|
|
|
// display header
|
|
_stprintf(Buffer, TEXT("Aliases: <Profile #> DockState [DockID, SerialNumber]\r\n\0"));
|
|
ArcWrite(BlConsoleOutDeviceId, Buffer, _tcslen(Buffer)*sizeof(TCHAR), &Count);
|
|
|
|
if (AliasList) {
|
|
for (i = 0; i < AliasList->CurrentAliasCount; i++) {
|
|
_stprintf(Buffer, TEXT(" <%2ld> %x [%x, %x]\r\n\0"),
|
|
AliasList->Alias[i].ProfileNumber,
|
|
AliasList->Alias[i].DockState,
|
|
AliasList->Alias[i].DockID,
|
|
AliasList->Alias[i].SerialNumber);
|
|
ArcWrite(BlConsoleOutDeviceId, Buffer, _tcslen(Buffer)*sizeof(TCHAR), &Count);
|
|
}
|
|
}
|
|
|
|
if(WaitForUserInput) {
|
|
#ifdef EFI
|
|
//
|
|
// disable efi watchdog when waiting for user input
|
|
//
|
|
DisableEFIWatchDog();
|
|
#endif
|
|
// display prompt and wait for user input to continue
|
|
_stprintf(Buffer, TEXT("press 'y' (lowercase) to continue...\r\n\0"));
|
|
ArcWrite(BlConsoleOutDeviceId, Buffer, _tcslen(Buffer)*sizeof(TCHAR), &Count);
|
|
while (BlGetKey() != 'y') {
|
|
//
|
|
// nothing
|
|
//
|
|
}
|
|
#ifdef EFI
|
|
//
|
|
// reset efi watchdog
|
|
//
|
|
SetEFIWatchDog(EFI_WATCHDOG_TIMEOUT);
|
|
#endif
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
VOID
|
|
BlDockInfoFilterDockingState(
|
|
IN OUT PCM_HARDWARE_PROFILE_LIST ProfileList,
|
|
IN OUT PCM_HARDWARE_PROFILE_ALIAS_LIST AliasList,
|
|
IN ULONG DockingState,
|
|
IN ULONG DockID,
|
|
IN ULONG SerialNumber
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Discard all hardware profiles that do not have the
|
|
DOCKINFO_UNDOCKED bit set in the DockState field
|
|
|
|
Arguments:
|
|
|
|
ProfileList - Supplies a list of hardware profiles.
|
|
Returns a list containing a subset of the supplied
|
|
hardware profiles.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
ULONG i = 0;
|
|
ULONG j;
|
|
ULONG len;
|
|
ULONG mask = HW_PROFILE_DOCKSTATE_UNDOCKED | HW_PROFILE_DOCKSTATE_DOCKED;
|
|
BOOLEAN trueMatch = FALSE;
|
|
#if DOCKINFO_VERBOSE
|
|
TCHAR buffer[200];
|
|
ULONG count;
|
|
#endif
|
|
|
|
if (AliasList) {
|
|
while (i < AliasList->CurrentAliasCount) {
|
|
if (((AliasList->Alias[i].DockState & mask) != 0) &&
|
|
((AliasList->Alias[i].DockState & mask) != DockingState)) {
|
|
|
|
//
|
|
// This alias claims to be docked or undocked, but does not
|
|
// match the current state. Therefore skip it.
|
|
//
|
|
;
|
|
|
|
} else if ((AliasList->Alias[i].DockID == DockID) &&
|
|
(AliasList->Alias[i].SerialNumber == SerialNumber)) {
|
|
|
|
//
|
|
// This alias matches so mark the profile.
|
|
//
|
|
for (j = 0; j < ProfileList->CurrentProfileCount; j++) {
|
|
if (ProfileList->Profile[j].Id ==
|
|
AliasList->Alias[i].ProfileNumber) {
|
|
|
|
ProfileList->Profile[j].Flags =
|
|
CM_HP_FLAGS_TRUE_MATCH;
|
|
|
|
trueMatch = TRUE;
|
|
}
|
|
}
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
|
|
#if DOCKINFO_VERBOSE
|
|
_stprintf(buffer, TEXT("Filtering Profiles ...\r\n\0"));
|
|
ArcWrite(BlConsoleOutDeviceId, buffer, _tcslen(buffer)*sizeof(TCHAR), &count);
|
|
#endif
|
|
|
|
i = 0;
|
|
while (i < ProfileList->CurrentProfileCount) {
|
|
|
|
if ((ProfileList->Profile[i].Flags & CM_HP_FLAGS_PRISTINE) &&
|
|
!trueMatch &&
|
|
AliasList) {
|
|
//
|
|
// Leave this one in the list
|
|
//
|
|
i++;
|
|
continue;
|
|
|
|
} else if (ProfileList->Profile[i].Flags & CM_HP_FLAGS_ALIASABLE) {
|
|
//
|
|
// Leave this one in the list
|
|
//
|
|
i++;
|
|
continue;
|
|
|
|
} else if (ProfileList->Profile[i].Flags & CM_HP_FLAGS_TRUE_MATCH) {
|
|
//
|
|
// Leave this one in the list
|
|
//
|
|
i++;
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// discard this profile by (1) shifting remaining profiles in
|
|
// array to fill in the space of this discarded profile
|
|
// and (2) decrementing profile count
|
|
//
|
|
len = ProfileList->CurrentProfileCount - i - 1;
|
|
if (0 < len) {
|
|
RtlMoveMemory(&ProfileList->Profile[i],
|
|
&ProfileList->Profile[i+1],
|
|
sizeof(CM_HARDWARE_PROFILE) * len);
|
|
}
|
|
|
|
--ProfileList->CurrentProfileCount;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
BlDockInfoFilterProfileList(
|
|
IN OUT PCM_HARDWARE_PROFILE_LIST ProfileList,
|
|
IN OUT PCM_HARDWARE_PROFILE_ALIAS_LIST AliasList
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Filters hardware profile list by discarding hardware profiles that
|
|
do not match the docking station information returned by NTDETECT.
|
|
|
|
|
|
Arguments:
|
|
|
|
ProfileList - Supplies a list of hardware profiles.
|
|
- Returns a list containing a subset of the supplied
|
|
hardware profiles.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
#if DOCKINFO_VERBOSE
|
|
// display ProfileList prior to filtering
|
|
BlDiagDisplayProfileList(ProfileList, AliasList, TRUE);
|
|
#endif
|
|
|
|
if (1 == ProfileList->CurrentProfileCount) {
|
|
if (ProfileList->Profile[0].Flags & CM_HP_FLAGS_PRISTINE) {
|
|
//
|
|
// Nothing to filter.
|
|
//
|
|
return;
|
|
}
|
|
}
|
|
BlDockInfoFilterDockingState (
|
|
ProfileList,
|
|
AliasList,
|
|
BlLoaderBlock->Extension->Profile.DockingState,
|
|
BlLoaderBlock->Extension->Profile.DockID,
|
|
BlLoaderBlock->Extension->Profile.SerialNumber);
|
|
|
|
#if DOCKINFO_VERBOSE
|
|
// display ProfileList prior to filtering
|
|
BlDiagDisplayProfileList(ProfileList, AliasList, TRUE);
|
|
#endif
|
|
|
|
}
|
|
|
|
int
|
|
BlIsReturnToOSChoicesValid(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Indicates whether the "Return to OS Choices Menu" should
|
|
be shown as advanced boot option or not.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
|
|
Return Value:
|
|
|
|
1 if yes otherwise 0.
|
|
|
|
--*/
|
|
{
|
|
return BlShowReturnToOSChoices;
|
|
}
|