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.
1858 lines
48 KiB
1858 lines
48 KiB
/*++
|
|
|
|
Copyright (c) 1991 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
parsboot.c
|
|
|
|
Abstract:
|
|
|
|
Parses the boot.ini file, displays a menu, and provides a kernel
|
|
path and name to be passed to osloader.
|
|
|
|
Author:
|
|
|
|
John Vert (jvert) 22-Jul-1991
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
#include "bldrx86.h"
|
|
#include "msg.h"
|
|
#include "ntdddisk.h"
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
|
|
#define MAX_SELECTIONS 10
|
|
#define MAX_TITLE_LENGTH 71
|
|
|
|
#define WIN95_DOS 1
|
|
#define DOS_WIN95 2
|
|
|
|
typedef struct _MENU_OPTION {
|
|
PCHAR Title;
|
|
PCHAR Path;
|
|
BOOLEAN EnableDebug;
|
|
ULONG MaxMemory;
|
|
PCHAR LoadOptions;
|
|
int ForcedScsiOrdinal;
|
|
int Win95;
|
|
BOOLEAN HeadlessRedirect;
|
|
} MENU_OPTION, *PMENU_OPTION;
|
|
|
|
PCHAR pDefSwitches = NULL;
|
|
|
|
int ForcedScsiOrdinal = -1;
|
|
CHAR szDebug[] = "unsupporteddebug";
|
|
CHAR BlankLine[] = " \r";
|
|
|
|
//
|
|
// global to hold the user's last
|
|
// selection from the advanced boot menu.
|
|
//
|
|
LONG AdvancedBoot = -1;
|
|
|
|
#define DEBUG_LOAD_OPTION_LENGTH 60
|
|
CHAR DebugLoadOptions[DEBUG_LOAD_OPTION_LENGTH];
|
|
|
|
|
|
//
|
|
// Defines for options for redirecting to a headless terminal
|
|
//
|
|
#define COM1_19_2 "com1at19200"
|
|
#define COM2_19_2 "com2at19200"
|
|
|
|
|
|
//
|
|
// Private function prototypes
|
|
//
|
|
VOID
|
|
BlpRebootDOS(
|
|
IN PCHAR BootSectorImage OPTIONAL,
|
|
IN PCHAR LoadOptions OPTIONAL
|
|
);
|
|
|
|
PCHAR
|
|
BlpNextLine(
|
|
IN PCHAR String
|
|
);
|
|
|
|
VOID
|
|
BlpTranslateDosToArc(
|
|
IN PCHAR DosName,
|
|
OUT PCHAR ArcName
|
|
);
|
|
|
|
ULONG
|
|
BlpPresentMenu(
|
|
IN PMENU_OPTION MenuOptions,
|
|
IN ULONG NumberSelections,
|
|
IN ULONG Default,
|
|
IN LONG Timeout
|
|
);
|
|
|
|
PCHAR *
|
|
BlpFileToLines(
|
|
IN PCHAR File,
|
|
OUT PULONG LineCount
|
|
);
|
|
|
|
PCHAR *
|
|
BlpFindSection(
|
|
IN PCHAR SectionName,
|
|
IN PCHAR *BootFile,
|
|
IN ULONG BootFileLines,
|
|
OUT PULONG NumberLines
|
|
);
|
|
|
|
VOID
|
|
BlpRenameWin95Files(
|
|
IN ULONG DriveId,
|
|
IN ULONG Type
|
|
);
|
|
|
|
VOID
|
|
BlParseOsOptions (
|
|
IN PMENU_OPTION MenuOption,
|
|
IN PCHAR pCurrent
|
|
);
|
|
|
|
ULONG
|
|
BlGetAdvancedBootID(
|
|
LONG BootOption
|
|
);
|
|
|
|
|
|
PCHAR
|
|
BlSelectKernel(
|
|
IN ULONG DriveId,
|
|
IN PCHAR BootFile,
|
|
OUT PCHAR *LoadOptions,
|
|
IN BOOLEAN UseTimeOut
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Parses the boot.txt file and determines the fully-qualified name of
|
|
the kernel to be booted.
|
|
|
|
Arguments:
|
|
|
|
BootFile - Pointer to the beginning of the loaded boot.txt file
|
|
|
|
Debugger - Returns the enable/disable state of the kernel debugger
|
|
|
|
UseTimeOut - Supplies whether the boot menu should time out or not.
|
|
|
|
Return Value:
|
|
|
|
Pointer to the name of a kernel to boot.
|
|
|
|
--*/
|
|
|
|
{
|
|
PCHAR *MbLines = NULL;
|
|
PCHAR *OsLines = NULL;
|
|
PCHAR *FileLines;
|
|
#if DBG
|
|
PCHAR *DebugLines = NULL;
|
|
ULONG DebugLineCount = 0;
|
|
#endif
|
|
ULONG FileLineCount;
|
|
ULONG OsLineCount = 0;
|
|
ULONG MbLineCount = 0;
|
|
PCHAR pCurrent;
|
|
MENU_OPTION MenuOption[MAX_SELECTIONS+1];
|
|
ULONG NumberSystems=0;
|
|
ULONG i;
|
|
LONG Timeout;
|
|
ULONG Selection;
|
|
ULONG DefaultSelection=0;
|
|
static CHAR Kernel[128];
|
|
CHAR DosName[3];
|
|
PCHAR DefaultOldPath="C:\\winnt";
|
|
PCHAR WinntDir = DefaultOldPath + 2;
|
|
PCHAR DefaultNewPath="C:\\windows\\";
|
|
CHAR DefaultPathBuffer[128] = {0};
|
|
PCHAR DefaultPath = DefaultPathBuffer;
|
|
PCHAR DefaultTitle=BlFindMessage(BL_DEFAULT_TITLE);
|
|
ULONG DirId;
|
|
|
|
//
|
|
// Check to see if "winnt" directory exists on the boot
|
|
// device. If it does not exist then make the default path point
|
|
// to "windows" directory
|
|
//
|
|
if (BlOpen(DriveId, WinntDir, ArcOpenDirectory, &DirId) != ESUCCESS) {
|
|
strcpy(DefaultPath, DefaultNewPath);
|
|
} else {
|
|
BlClose(DirId);
|
|
strcpy(DefaultPath, DefaultOldPath);
|
|
strcat(DefaultPath, "\\");
|
|
}
|
|
|
|
*LoadOptions = NULL;
|
|
|
|
if (*BootFile == '\0') {
|
|
//
|
|
// No boot.ini file, so we boot the default.
|
|
//
|
|
BlPrint(BlFindMessage(BL_INVALID_BOOT_INI),DefaultPath);
|
|
MenuOption[0].Path = DefaultPath;
|
|
MenuOption[0].Title = DefaultTitle;
|
|
MenuOption[0].MaxMemory = 0;
|
|
MenuOption[0].LoadOptions = NULL;
|
|
MenuOption[0].Win95 = 0;
|
|
NumberSystems = 1;
|
|
DefaultSelection = 0;
|
|
MbLineCount = 0;
|
|
OsLineCount = 0;
|
|
MenuOption[0].EnableDebug = FALSE;
|
|
#if DBG
|
|
DebugLineCount = 0;
|
|
#endif
|
|
} else {
|
|
FileLines = BlpFileToLines(BootFile, &FileLineCount);
|
|
MbLines = BlpFindSection("[boot loader]",
|
|
FileLines,
|
|
FileLineCount,
|
|
&MbLineCount);
|
|
if (MbLines==NULL) {
|
|
MbLines = BlpFindSection("[flexboot]",
|
|
FileLines,
|
|
FileLineCount,
|
|
&MbLineCount);
|
|
if (MbLines==NULL) {
|
|
MbLines = BlpFindSection("[multiboot]",
|
|
FileLines,
|
|
FileLineCount,
|
|
&MbLineCount);
|
|
}
|
|
}
|
|
|
|
OsLines = BlpFindSection("[operating systems]",
|
|
FileLines,
|
|
FileLineCount,
|
|
&OsLineCount);
|
|
|
|
if (OsLineCount == 0) {
|
|
|
|
if (BlBootingFromNet) {
|
|
return NULL;
|
|
}
|
|
|
|
BlPrint(BlFindMessage(BL_INVALID_BOOT_INI),DefaultPath);
|
|
MenuOption[0].Path = DefaultPath;
|
|
MenuOption[0].Title = DefaultTitle;
|
|
MenuOption[0].MaxMemory = 0;
|
|
MenuOption[0].LoadOptions = NULL;
|
|
MenuOption[0].Win95 = 0;
|
|
MenuOption[0].HeadlessRedirect = FALSE;
|
|
NumberSystems = 1;
|
|
DefaultSelection = 0;
|
|
}
|
|
|
|
#if DBG
|
|
DebugLines = BlpFindSection("[debug]",
|
|
FileLines,
|
|
FileLineCount,
|
|
&DebugLineCount);
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// Set default timeout value
|
|
//
|
|
if (UseTimeOut) {
|
|
Timeout = 0;
|
|
} else {
|
|
Timeout = -1;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Before we look through the [boot loader] section, initialize
|
|
// our headless redirection information so that the default is
|
|
// to not redirect.
|
|
//
|
|
RtlZeroMemory( &LoaderRedirectionInformation, sizeof(HEADLESS_LOADER_BLOCK) );
|
|
BlTerminalConnected = FALSE;
|
|
|
|
|
|
|
|
//
|
|
// Parse the [boot loader] section
|
|
//
|
|
for (i=0; i<MbLineCount; i++) {
|
|
|
|
pCurrent = MbLines[i];
|
|
|
|
//
|
|
// Throw away any leading whitespace
|
|
//
|
|
pCurrent += strspn(pCurrent, " \t");
|
|
if (*pCurrent == '\0') {
|
|
//
|
|
// This is a blank line, so we just throw it away.
|
|
//
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Check for "DefSwitches" line
|
|
//
|
|
if (_strnicmp(pCurrent,"DefSwitches",sizeof("DefSwitches")-1) == 0) {
|
|
pCurrent = strchr(pCurrent,'=');
|
|
if (pCurrent != NULL) {
|
|
pDefSwitches = pCurrent + 1;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Check for "timeout" line
|
|
//
|
|
if (_strnicmp(pCurrent,"timeout",7) == 0) {
|
|
|
|
pCurrent = strchr(pCurrent,'=');
|
|
if (pCurrent != NULL) {
|
|
if (UseTimeOut) {
|
|
Timeout = atoi(++pCurrent);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Check for "redirectbaudrate" line
|
|
//
|
|
if (_strnicmp(pCurrent,"redirectbaudrate",16) == 0) {
|
|
|
|
pCurrent = strchr(pCurrent,'=');
|
|
|
|
if (pCurrent != NULL) {
|
|
|
|
//
|
|
// Skip whitespace
|
|
//
|
|
++pCurrent;
|
|
pCurrent += strspn(pCurrent, " \t");
|
|
|
|
if (*pCurrent != '\0') {
|
|
|
|
//
|
|
// Fill in our global structure with the information.
|
|
//
|
|
if( _strnicmp(pCurrent,"115200",6) == 0 ) {
|
|
LoaderRedirectionInformation.BaudRate = BD_115200;
|
|
} else if( _strnicmp(pCurrent,"57600",5) == 0 ) {
|
|
LoaderRedirectionInformation.BaudRate = BD_57600;
|
|
} else if( _strnicmp(pCurrent,"19200",5) == 0 ) {
|
|
LoaderRedirectionInformation.BaudRate = BD_19200;
|
|
} else {
|
|
LoaderRedirectionInformation.BaudRate = BD_9600;
|
|
}
|
|
}
|
|
}
|
|
|
|
} else if (_strnicmp(pCurrent,"redirect",8) == 0) {
|
|
|
|
//
|
|
// Check for "redirect" line
|
|
//
|
|
|
|
pCurrent = strchr(pCurrent,'=');
|
|
|
|
if (pCurrent != NULL) {
|
|
|
|
//
|
|
// Skip whitespace
|
|
//
|
|
++pCurrent;
|
|
pCurrent += strspn(pCurrent, " \t");
|
|
|
|
if (*pCurrent != '\0') {
|
|
|
|
//
|
|
// Fill in our global structure with the information.
|
|
//
|
|
#if 0
|
|
|
|
//
|
|
// Since we now support variable baudrates, there's no
|
|
// reason to support these hardcoded 19200 strings.
|
|
//
|
|
|
|
|
|
if (_strnicmp(pCurrent, COM1_19_2, sizeof(COM1_19_2)) == 0) {
|
|
|
|
pCurrent += sizeof(COM1_19_2);
|
|
|
|
LoaderRedirectionInformation.PortNumber = 1;
|
|
LoaderRedirectionInformation.BaudRate = 19200;
|
|
|
|
} else if (_strnicmp(pCurrent, COM2_19_2, sizeof(COM2_19_2)) == 0) {
|
|
|
|
pCurrent += sizeof(COM2_19_2);
|
|
|
|
LoaderRedirectionInformation.PortNumber = 2;
|
|
LoaderRedirectionInformation.BaudRate = 19200;
|
|
|
|
} else if (_strnicmp(pCurrent,"com",3) == 0) {
|
|
#else
|
|
|
|
if (_strnicmp(pCurrent,"com",3) == 0) {
|
|
#endif
|
|
pCurrent +=3;
|
|
|
|
|
|
LoaderRedirectionInformation.PortNumber = atoi(pCurrent);
|
|
|
|
} else if (_strnicmp(pCurrent, "usebiossettings", 15) == 0) {
|
|
|
|
BlRetrieveBIOSRedirectionInformation();
|
|
|
|
} else {
|
|
|
|
//
|
|
// See if they gave us a hardcoded address.
|
|
//
|
|
LoaderRedirectionInformation.PortAddress = (PUCHAR)ULongToPtr(strtoul(pCurrent,NULL,16));
|
|
|
|
if( LoaderRedirectionInformation.PortAddress != (PUCHAR)NULL ) {
|
|
LoaderRedirectionInformation.PortNumber = 3;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Check for "default" line
|
|
//
|
|
if (_strnicmp(pCurrent,"default",7) == 0) {
|
|
|
|
pCurrent = strchr(pCurrent,'=');
|
|
if (pCurrent != NULL) {
|
|
DefaultPath = ++pCurrent;
|
|
DefaultPath += strspn(DefaultPath," \t");
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// If we found any headless redirection settings, go initialize
|
|
// the port now.
|
|
//
|
|
if( LoaderRedirectionInformation.PortNumber ) {
|
|
|
|
// make sure we got a baudrate.
|
|
if( LoaderRedirectionInformation.BaudRate == 0 ) {
|
|
LoaderRedirectionInformation.BaudRate = 9600;
|
|
}
|
|
|
|
BlInitializeHeadlessPort();
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Parse the [operating systems] section
|
|
//
|
|
|
|
for (i=0; i<OsLineCount; i++) {
|
|
|
|
if (NumberSystems == MAX_SELECTIONS) {
|
|
break;
|
|
}
|
|
|
|
pCurrent = OsLines[i];
|
|
|
|
//
|
|
// Throw away any leading whitespace
|
|
//
|
|
|
|
pCurrent += strspn(pCurrent, " \t");
|
|
if (*pCurrent == '\0') {
|
|
//
|
|
// This is a blank line, so we just throw it away.
|
|
//
|
|
continue;
|
|
}
|
|
|
|
MenuOption[NumberSystems].Path = pCurrent;
|
|
|
|
//
|
|
// The first space or '=' character indicates the end of the
|
|
// path specifier, so we need to replace it with a '\0'
|
|
//
|
|
while ((*pCurrent != ' ')&&
|
|
(*pCurrent != '=')&&
|
|
(*pCurrent != '\0')) {
|
|
++pCurrent;
|
|
}
|
|
*pCurrent = '\0';
|
|
|
|
//
|
|
// The next character that is not space, equals, or double-quote
|
|
// is the start of the title.
|
|
//
|
|
|
|
++pCurrent;
|
|
while ((*pCurrent == ' ') ||
|
|
(*pCurrent == '=') ||
|
|
(*pCurrent == '"')) {
|
|
++pCurrent;
|
|
}
|
|
|
|
if (pCurrent=='\0') {
|
|
//
|
|
// No title was found, so just use the path as the title.
|
|
//
|
|
MenuOption[NumberSystems].Title = MenuOption[NumberSystems].Path;
|
|
} else {
|
|
MenuOption[NumberSystems].Title = pCurrent;
|
|
}
|
|
|
|
//
|
|
// The next character that is either a double-quote or a \0
|
|
// indicates the end of the title.
|
|
//
|
|
while ((*pCurrent != '\0')&&
|
|
(*pCurrent != '"')) {
|
|
++pCurrent;
|
|
}
|
|
|
|
//
|
|
// Parse the os load options for this selection
|
|
//
|
|
|
|
BlParseOsOptions (&MenuOption[NumberSystems], pCurrent);
|
|
*pCurrent = 0;
|
|
|
|
++NumberSystems;
|
|
}
|
|
|
|
|
|
#if DBG
|
|
//
|
|
// Parse the [debug] section
|
|
//
|
|
for (i=0; i<DebugLineCount; i++) {
|
|
extern ULONG ScsiDebug;
|
|
|
|
pCurrent = DebugLines[i];
|
|
|
|
//
|
|
// Throw away leading whitespace
|
|
//
|
|
pCurrent += strspn(pCurrent, " \t");
|
|
if (*pCurrent == '\0') {
|
|
//
|
|
// throw away blank lines
|
|
//
|
|
continue;
|
|
}
|
|
|
|
if (_strnicmp(pCurrent,"scsidebug",9) == 0) {
|
|
pCurrent = strchr(pCurrent,'=');
|
|
if (pCurrent != NULL) {
|
|
ScsiDebug = atoi(++pCurrent);
|
|
}
|
|
} else if (_strnicmp(pCurrent,"/debug ",7) == 0) {
|
|
|
|
//
|
|
// This line contains something to do with debug,
|
|
// pass to BdInitDebugger to handle.
|
|
//
|
|
// Note: very strict rules, debug keyword begins with
|
|
// a slash and is followed by a space. "/debugport"
|
|
// won't match, nor will "/debug" at the end of the
|
|
// line.
|
|
//
|
|
// Note: If the debugger is hard compiled on, it
|
|
// will already be enabled and these options will
|
|
// have no effect. Also, the first occurence is
|
|
// the one that takes effect.
|
|
//
|
|
|
|
BdInitDebugger((PCHAR)OsLoaderName, (PVOID)OsLoaderBase, pCurrent);
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
//
|
|
// Now look for a Title entry from the [operating systems] section
|
|
// that matches the default entry from the [multiboot] section. This
|
|
// will give us a title. If no entry matches, we will add an entry
|
|
// at the end of the list and provide a default Title.
|
|
//
|
|
i=0;
|
|
while (_stricmp(MenuOption[i].Path,DefaultPath) != 0) {
|
|
++i;
|
|
if (i==NumberSystems) {
|
|
//
|
|
// Create a default entry in the Title and Path arrays
|
|
//
|
|
MenuOption[NumberSystems].Path = DefaultPath;
|
|
MenuOption[NumberSystems].Title = DefaultTitle;
|
|
MenuOption[NumberSystems].EnableDebug = FALSE;
|
|
MenuOption[NumberSystems].MaxMemory = 0;
|
|
MenuOption[NumberSystems].LoadOptions = NULL;
|
|
MenuOption[NumberSystems].Win95 = 0;
|
|
++NumberSystems;
|
|
}
|
|
}
|
|
|
|
DefaultSelection = i;
|
|
|
|
//
|
|
// Display the menu of choices
|
|
//
|
|
|
|
Selection = BlpPresentMenu( MenuOption,
|
|
NumberSystems,
|
|
DefaultSelection,
|
|
Timeout);
|
|
|
|
pCurrent = MenuOption[Selection].LoadOptions;
|
|
if (pCurrent != NULL) {
|
|
|
|
//
|
|
// Remove '/' from LoadOptions string.
|
|
//
|
|
|
|
*LoadOptions = pCurrent + 1;
|
|
while (*pCurrent != '\0') {
|
|
if (*pCurrent == '/') {
|
|
*pCurrent = ' ';
|
|
}
|
|
++pCurrent;
|
|
}
|
|
} else {
|
|
*LoadOptions = NULL;
|
|
}
|
|
|
|
if (MenuOption[Selection].Win95) {
|
|
BlpRenameWin95Files( DriveId, MenuOption[Selection].Win95 );
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// We need to take care of the following cases:
|
|
// 1. The user has asked us to redirect via the osload
|
|
// option entry, but did not ask the loader to redirect.
|
|
// In this case, we will default to COM1.
|
|
//
|
|
// 2. The loader was asked to redirect via the "redirect"
|
|
// specifier in the [boot loader] section. But the
|
|
// user did NOT have a /redirect option on the osload
|
|
// options. In this case, we need to kill the
|
|
// LoaderRedirectionInformation variable.
|
|
//
|
|
if( MenuOption[Selection].HeadlessRedirect ) {
|
|
|
|
#if 0
|
|
// matth (7/25/2000) Don't do this for now. If the user has
|
|
// this configuration in their boot.ini, it's
|
|
// an error on their part.
|
|
//
|
|
// he's asked us to redirect the operating system. Make
|
|
// sure the Loader was also asked to redirect too.
|
|
//
|
|
if( LoaderRedirectionInformation.PortNumber == 0 ) {
|
|
|
|
//
|
|
// the loader wasn't asked to redirect. The user
|
|
// made a mistake here, but let's guess as to what
|
|
// he wants.
|
|
//
|
|
RtlZeroMemory( &LoaderRedirectionInformation, sizeof(HEADLESS_LOADER_BLOCK) );
|
|
LoaderRedirectionInformation.PortNumber = 1;
|
|
LoaderRedirectionInformation.BaudRate = 9600;
|
|
|
|
}
|
|
#endif
|
|
|
|
} else {
|
|
|
|
//
|
|
// He's asked us to not redirect. Make sure we don't pass
|
|
// information to the OS so he won't be able to redirect.
|
|
//
|
|
RtlZeroMemory( &LoaderRedirectionInformation, sizeof(HEADLESS_LOADER_BLOCK) );
|
|
|
|
BlTerminalConnected = FALSE;
|
|
}
|
|
|
|
|
|
|
|
if (_strnicmp(MenuOption[Selection].Path,"C:\\",3) == 0) {
|
|
|
|
//
|
|
// This syntax means that we are booting a root-based os
|
|
// from an alternate boot sector image.
|
|
// If no file name is specified, BlpRebootDos will default to
|
|
// \bootsect.dos.
|
|
//
|
|
BlpRebootDOS(MenuOption[Selection].Path[3] ? &MenuOption[Selection].Path[2] : NULL,*LoadOptions);
|
|
|
|
//
|
|
// If this returns, it means that the file does not exist as a bootsector.
|
|
// This allows c:\winnt35 to work as a boot path specifier as opposed to
|
|
// a boot sector image filename specifier.
|
|
//
|
|
}
|
|
|
|
if (MenuOption[Selection].Path[1]==':') {
|
|
//
|
|
// We need to translate the DOS name into an ARC name
|
|
//
|
|
DosName[0] = MenuOption[Selection].Path[0];
|
|
DosName[1] = MenuOption[Selection].Path[1];
|
|
DosName[2] = '\0';
|
|
|
|
BlpTranslateDosToArc(DosName,Kernel);
|
|
strcat(Kernel,MenuOption[Selection].Path+2);
|
|
} else {
|
|
strcpy(Kernel,MenuOption[Selection].Path);
|
|
}
|
|
|
|
//
|
|
// the use made a valid selection from the
|
|
// advanced boot menu so append the advanced
|
|
// boot load options and perform any load
|
|
// option processing.
|
|
//
|
|
if (AdvancedBoot != -1) {
|
|
PSTR s = BlGetAdvancedBootLoadOptions(AdvancedBoot);
|
|
if (s) {
|
|
ULONG len = strlen(s) + (*LoadOptions ? strlen(*LoadOptions) : 0);
|
|
s = BlAllocateHeap(len * sizeof(PCHAR));
|
|
if (s) {
|
|
*s = 0;
|
|
if (*LoadOptions) {
|
|
strcat(s,*LoadOptions);
|
|
strcat(s," ");
|
|
}
|
|
strcat(s,BlGetAdvancedBootLoadOptions(AdvancedBoot));
|
|
*LoadOptions = s;
|
|
}
|
|
}
|
|
BlDoAdvancedBootLoadProcessing(AdvancedBoot);
|
|
}
|
|
|
|
//
|
|
// Make sure there is no trailing slash
|
|
//
|
|
|
|
if (Kernel[strlen(Kernel)-1] == '\\') {
|
|
Kernel[strlen(Kernel)-1] = '\0';
|
|
}
|
|
|
|
//
|
|
// If MaxMemory is not zero, adjust the memory descriptors to eliminate
|
|
// memory above the boundary line
|
|
//
|
|
// [chuckl 12/03/2001] Note that we use BlpTruncateDescriptors, not
|
|
// BlpTruncateMemory. BlpTruncateMemory truncates the low-level MDArray
|
|
// descriptors, while BlTruncateDescriptors truncates the loader-level
|
|
// memory descriptor list. Using BlpTruncateMemory worked when the loader
|
|
// initialized its memory list twice. (BlMemoryInitialize was called twice.)
|
|
// But this no longer happens, so we have to truncate the descriptors
|
|
// directly here.
|
|
//
|
|
|
|
if (MenuOption[Selection].MaxMemory != 0) {
|
|
ULONG MaxPage = (MenuOption[Selection].MaxMemory * ((1024 * 1024) / PAGE_SIZE)) - 1;
|
|
BlTruncateDescriptors(MaxPage);
|
|
}
|
|
|
|
ForcedScsiOrdinal = MenuOption[Selection].ForcedScsiOrdinal;
|
|
|
|
return(Kernel);
|
|
}
|
|
|
|
VOID
|
|
BlParseOsOptions (
|
|
IN PMENU_OPTION MenuOption,
|
|
IN PCHAR pCurrent
|
|
)
|
|
{
|
|
PCHAR p;
|
|
|
|
//
|
|
// Clear all settings
|
|
//
|
|
|
|
MenuOption->ForcedScsiOrdinal = -1;
|
|
MenuOption->MaxMemory = 0;
|
|
MenuOption->LoadOptions = NULL;
|
|
MenuOption->Win95 = 0;
|
|
MenuOption->EnableDebug = FALSE;
|
|
MenuOption->HeadlessRedirect = FALSE;
|
|
|
|
// If there are no switches specified for this line, use the DefSwitches
|
|
|
|
if ((strchr(pCurrent,'/') == NULL) && (pDefSwitches)) {
|
|
pCurrent = pDefSwitches;
|
|
}
|
|
|
|
//
|
|
// Convert to all one case
|
|
//
|
|
|
|
_strupr(pCurrent);
|
|
|
|
//
|
|
// Look for a scsi(x) ordinal to use for opens on scsi ARC paths.
|
|
// This spec must immediately follow the title and is not part
|
|
// of the load options.
|
|
//
|
|
|
|
p = strstr(pCurrent,"/SCSIORDINAL:");
|
|
if(p) {
|
|
MenuOption->ForcedScsiOrdinal = atoi(p + sizeof("/SCSIORDINAL:") - 1);
|
|
}
|
|
|
|
//
|
|
// If there is a REDIRECT parameter after the description, then
|
|
// we need to pass this to the osloader.
|
|
//
|
|
|
|
p = strstr(pCurrent,"/REDIRECT");
|
|
if(p) {
|
|
MenuOption->HeadlessRedirect = TRUE;
|
|
}
|
|
|
|
//
|
|
// If there is a DEBUG parameter after the description, then
|
|
// we need to pass the DEBUG option to the osloader.
|
|
//
|
|
|
|
if (strchr(pCurrent,'/') != NULL) {
|
|
pCurrent = strchr(pCurrent+1,'/');
|
|
MenuOption->LoadOptions = pCurrent;
|
|
|
|
if (pCurrent != NULL) {
|
|
|
|
p = strstr(pCurrent,"/MAXMEM");
|
|
if (p) {
|
|
MenuOption->MaxMemory = atoi(p+8);
|
|
}
|
|
|
|
if (strstr(pCurrent, "/WIN95DOS")) {
|
|
MenuOption->Win95 = WIN95_DOS;
|
|
} else if (strstr(pCurrent, "/WIN95")) {
|
|
MenuOption->Win95 = DOS_WIN95;
|
|
}
|
|
|
|
//
|
|
// As long as /nodebug or /crashdebug is specified, this is NO debug system
|
|
// If /NODEBUG is not specified, and either one of the
|
|
// DEBUG or BAUDRATE is specified, this is debug system.
|
|
//
|
|
|
|
if ((strstr(pCurrent, "NODEBUG") == NULL) &&
|
|
(strstr(pCurrent, "CRASHDEBUG") == NULL)) {
|
|
if (strstr(pCurrent, "DEBUG") || strstr(pCurrent, "BAUDRATE")) {
|
|
|
|
if (_stricmp(MenuOption->Path, "C:\\")) {
|
|
MenuOption->EnableDebug = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
PCHAR *
|
|
BlpFileToLines(
|
|
IN PCHAR File,
|
|
OUT PULONG LineCount
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine converts the loaded BOOT.INI file into an array of
|
|
pointers to NULL-terminated ASCII strings.
|
|
|
|
Arguments:
|
|
|
|
File - supplies a pointer to the in-memory image of the BOOT.INI file.
|
|
This will be converted in place by turning CR/LF pairs into
|
|
null terminators.
|
|
|
|
LineCount - Returns the number of lines in the BOOT.INI file.
|
|
|
|
Return Value:
|
|
|
|
A pointer to an array of pointers to ASCIIZ strings. The array will
|
|
have LineCount elements.
|
|
|
|
NULL if the function did not succeed for some reason.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG Line;
|
|
PCHAR *LineArray;
|
|
PCHAR p;
|
|
PCHAR Space;
|
|
|
|
p = File;
|
|
|
|
//
|
|
// First count the number of lines in the file so we know how large
|
|
// an array to allocate.
|
|
//
|
|
*LineCount=1;
|
|
while (*p != '\0') {
|
|
p=strchr(p, '\n');
|
|
if (p==NULL) {
|
|
break;
|
|
}
|
|
++p;
|
|
|
|
//
|
|
// See if there's any text following the CR/LF.
|
|
//
|
|
if (*p=='\0') {
|
|
break;
|
|
}
|
|
|
|
*LineCount += 1;
|
|
}
|
|
|
|
LineArray = BlAllocateHeap(*LineCount * sizeof(PCHAR));
|
|
|
|
//
|
|
// Now step through the file again, replacing CR/LF with \0\0 and
|
|
// filling in the array of pointers.
|
|
//
|
|
p=File;
|
|
for (Line=0; Line < *LineCount; Line++) {
|
|
LineArray[Line] = p;
|
|
p=strchr(p, '\r');
|
|
if (p != NULL) {
|
|
*p = '\0';
|
|
++p;
|
|
if (*p=='\n') {
|
|
*p = '\0';
|
|
++p;
|
|
}
|
|
} else {
|
|
p=strchr(LineArray[Line], '\n');
|
|
if (p != NULL) {
|
|
*p = '\0';
|
|
++p;
|
|
}
|
|
}
|
|
|
|
//
|
|
// remove trailing white space
|
|
//
|
|
Space = LineArray[Line] + strlen(LineArray[Line])-1;
|
|
while ((*Space == ' ') || (*Space == '\t')) {
|
|
*Space = '\0';
|
|
--Space;
|
|
}
|
|
}
|
|
|
|
return(LineArray);
|
|
}
|
|
|
|
|
|
PCHAR *
|
|
BlpFindSection(
|
|
IN PCHAR SectionName,
|
|
IN PCHAR *BootFile,
|
|
IN ULONG BootFileLines,
|
|
OUT PULONG NumberLines
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Finds a section ([multiboot], [operating systems], etc) in the boot.ini
|
|
file and returns a pointer to its first line. The search will be
|
|
case-insensitive.
|
|
|
|
Arguments:
|
|
|
|
SectionName - Supplies the name of the section. No brackets.
|
|
|
|
BootFile - Supplies the array of pointers to lines of the ini file.
|
|
|
|
BootFileLines - Supplies the number of lines in the ini file.
|
|
|
|
NumberLines - Returns the number of lines in the section.
|
|
|
|
Return Value:
|
|
|
|
Pointer to an array of ASCIIZ strings, one entry per line.
|
|
|
|
NULL, if the section was not found.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG cnt;
|
|
ULONG StartLine;
|
|
|
|
for (cnt=0; cnt<BootFileLines; cnt++) {
|
|
|
|
//
|
|
// Check to see if this is the line we are looking for
|
|
//
|
|
if (_stricmp(BootFile[cnt],SectionName) == 0) {
|
|
|
|
//
|
|
// found it
|
|
//
|
|
break;
|
|
}
|
|
}
|
|
if (cnt==BootFileLines) {
|
|
//
|
|
// We ran out of lines, never found the right section.
|
|
//
|
|
*NumberLines = 0;
|
|
return(NULL);
|
|
}
|
|
|
|
StartLine = cnt+1;
|
|
|
|
//
|
|
// Find end of section
|
|
//
|
|
for (cnt=StartLine; cnt<BootFileLines; cnt++) {
|
|
if (BootFile[cnt][0] == '[') {
|
|
break;
|
|
}
|
|
}
|
|
|
|
*NumberLines = cnt-StartLine;
|
|
|
|
return(&BootFile[StartLine]);
|
|
}
|
|
|
|
PCHAR
|
|
BlpNextLine(
|
|
IN PCHAR String
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Finds the beginning of the next text line
|
|
|
|
Arguments:
|
|
|
|
String - Supplies a pointer to a null-terminated string
|
|
|
|
Return Value:
|
|
|
|
Pointer to the character following the first CR/LF found in String
|
|
|
|
- or -
|
|
|
|
NULL - No CR/LF found before the end of the string.
|
|
|
|
--*/
|
|
|
|
{
|
|
PCHAR p;
|
|
|
|
p=strchr(String, '\n');
|
|
if (p==NULL) {
|
|
return(p);
|
|
}
|
|
|
|
++p;
|
|
|
|
//
|
|
// If there is no text following the CR/LF, there is no next line
|
|
//
|
|
if (*p=='\0') {
|
|
return(NULL);
|
|
} else {
|
|
return(p);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
BlpRebootDOS(
|
|
IN PCHAR BootSectorImage OPTIONAL,
|
|
IN PCHAR LoadOptions OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Loads up the bootstrap sectors and executes them (thereby rebooting
|
|
into DOS or OS/2)
|
|
|
|
Arguments:
|
|
|
|
BootSectorImage - If specified, supplies name of file on the C: drive
|
|
that contains the boot sector image. In this case, this routine
|
|
will return if that file cannot be opened (for example, if it's
|
|
a directory). If not specified, then default to \bootsect.dos,
|
|
and this routine will never return.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG SectorId;
|
|
ARC_STATUS Status;
|
|
ULONG Read;
|
|
ULONG DriveId;
|
|
ULONG BootType;
|
|
LARGE_INTEGER SeekPosition;
|
|
extern UCHAR BootPartitionName[];
|
|
|
|
//
|
|
// HACKHACK John Vert (jvert)
|
|
// Some SCSI drives get really confused and return zeroes when
|
|
// you use the BIOS to query their size after the AHA driver has
|
|
// initialized. This can completely tube OS/2 or DOS. So here
|
|
// we try and open both BIOS-accessible hard drives. Our open
|
|
// code is smart enough to retry if it gets back zeros, so hopefully
|
|
// this will give the SCSI drives a chance to get their act together.
|
|
//
|
|
Status = ArcOpen("multi(0)disk(0)rdisk(0)partition(0)",
|
|
ArcOpenReadOnly,
|
|
&DriveId);
|
|
if (Status == ESUCCESS) {
|
|
ArcClose(DriveId);
|
|
}
|
|
|
|
Status = ArcOpen("multi(0)disk(0)rdisk(1)partition(0)",
|
|
ArcOpenReadOnly,
|
|
&DriveId);
|
|
if (Status == ESUCCESS) {
|
|
ArcClose(DriveId);
|
|
}
|
|
|
|
//
|
|
// Load the boot sector at address 0x7C00 (expected by Reboot callback)
|
|
//
|
|
Status = ArcOpen((PCHAR)BootPartitionName,
|
|
ArcOpenReadOnly,
|
|
&DriveId);
|
|
if (Status != ESUCCESS) {
|
|
BlPrint(BlFindMessage(BL_REBOOT_IO_ERROR),BootPartitionName);
|
|
while (1) {
|
|
BlGetKey();
|
|
}
|
|
}
|
|
Status = BlOpen( DriveId,
|
|
BootSectorImage ? BootSectorImage : "\\bootsect.dos",
|
|
ArcOpenReadOnly,
|
|
&SectorId );
|
|
|
|
if (Status != ESUCCESS) {
|
|
if(BootSectorImage) {
|
|
//
|
|
// The boot sector image might actually be a directory.
|
|
// Return to the caller to attempt standard boot.
|
|
//
|
|
ArcClose(DriveId);
|
|
return;
|
|
}
|
|
BlPrint(BlFindMessage(BL_REBOOT_IO_ERROR),BootPartitionName);
|
|
while (1) {
|
|
}
|
|
}
|
|
|
|
Status = BlRead( SectorId,
|
|
(PVOID)0x7c00,
|
|
SECTOR_SIZE,
|
|
&Read );
|
|
|
|
if (Status != ESUCCESS) {
|
|
BlPrint(BlFindMessage(BL_REBOOT_IO_ERROR),BootPartitionName);
|
|
while (1) {
|
|
}
|
|
}
|
|
|
|
//
|
|
// The FAT boot code is only one sector long so we just want
|
|
// to load it up and jump to it.
|
|
//
|
|
// For HPFS and NTFS, we can't do this because the first sector
|
|
// loads the rest of the boot sectors -- but we want to use
|
|
// the boot code in the boot sector image file we loaded.
|
|
//
|
|
// For HPFS, we load the first 20 sectors (boot code + super and
|
|
// space blocks) into d00:200. Fortunately this works for both
|
|
// NT and OS/2.
|
|
//
|
|
// For NTFS, we load the first 16 sectors and jump to d00:256.
|
|
// If the OEM field of the boot sector starts with NTFS, we
|
|
// assume it's NTFS boot code.
|
|
//
|
|
|
|
//
|
|
// Try to read 8K from the boot code image.
|
|
// If this succeeds, we have either HPFS or NTFS.
|
|
//
|
|
SeekPosition.QuadPart = 0;
|
|
BlSeek(SectorId,&SeekPosition,SeekAbsolute);
|
|
BlRead(SectorId,(PVOID)0xd000,SECTOR_SIZE*16,&Read);
|
|
|
|
if(Read == SECTOR_SIZE*16) {
|
|
|
|
if(memcmp((PVOID)0x7c03,"NTFS",4)) {
|
|
|
|
//
|
|
// HPFS -- we need to load the super block.
|
|
//
|
|
BootType = 1; // HPFS
|
|
|
|
SeekPosition.QuadPart = 16*SECTOR_SIZE;
|
|
ArcSeek(DriveId,&SeekPosition,SeekAbsolute);
|
|
ArcRead(DriveId,(PVOID)0xf000,SECTOR_SIZE*4,&Read);
|
|
|
|
} else {
|
|
|
|
//
|
|
// NTFS -- we've loaded everything we need to load.
|
|
//
|
|
BootType = 2; // NTFS
|
|
}
|
|
} else {
|
|
|
|
BootType = 0; // FAT
|
|
|
|
}
|
|
|
|
if (LoadOptions) {
|
|
if (strstr(LoadOptions,"CMDCONS") != NULL) {
|
|
strcpy( (PCHAR)(0x7c03), "cmdcons" );
|
|
} else if (strcmp(LoadOptions,"ROLLBACK") == 0) {
|
|
|
|
//
|
|
// By definition, when /rollback is specified, it is the only load
|
|
// option. It eventually gets parsed, gets upper-cased, and gets
|
|
// its slash removed. So we check for the exact text "ROLLBACK".
|
|
//
|
|
// When rollback is specified, we have to write a token somewhere
|
|
// in the boot sector. This is our only way to send runtime
|
|
// options to the setup loader.
|
|
//
|
|
// There is a data buffer of 8 bytes at 0000:7C03 in all boot
|
|
// sectors today. Fortunately we can overwrite it. So we hard-code
|
|
// this address here and in the setup loader.
|
|
//
|
|
|
|
strcpy( (PCHAR)(0x7c03), "undo" );
|
|
}
|
|
}
|
|
|
|
//
|
|
// DX must be the drive to boot from
|
|
//
|
|
|
|
_asm {
|
|
mov dx, 0x80
|
|
}
|
|
REBOOT(BootType);
|
|
|
|
}
|
|
|
|
|
|
ULONG
|
|
BlpPresentMenu(
|
|
IN PMENU_OPTION MenuOption,
|
|
IN ULONG NumberSelections,
|
|
IN ULONG Default,
|
|
IN LONG Timeout
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Displays the menu of boot options and allows the user to select one
|
|
by using the arrow keys.
|
|
|
|
Arguments:
|
|
|
|
MenuOption - Supplies array of menu options
|
|
|
|
NumberSelections - Supplies the number of entries in the MenuOption array.
|
|
|
|
Default - Supplies the index of the default operating system choice.
|
|
|
|
Timeout - Supplies the timeout (in seconds) before the highlighted
|
|
operating system choice is booted. If this value is -1,
|
|
the menu will never timeout.
|
|
|
|
Return Value:
|
|
|
|
ULONG - The index of the operating system choice selected.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG i;
|
|
ULONG Selection;
|
|
ULONG StartTime;
|
|
ULONG LastTime;
|
|
ULONG BiasTime=0;
|
|
ULONG CurrentTime;
|
|
LONG SecondsLeft;
|
|
LONG LastSecondsLeft = -1;
|
|
ULONG EndTime;
|
|
ULONG Key;
|
|
ULONG CurrentLength;
|
|
PCHAR DebugSelect;
|
|
PCHAR SelectOs;
|
|
PCHAR MoveHighlight;
|
|
PCHAR TimeoutCountdown;
|
|
PCHAR EnabledKd;
|
|
PCHAR AdvancedBootMessage;
|
|
PCHAR HeadlessRedirect;
|
|
PCHAR p;
|
|
BOOLEAN Moved;
|
|
BOOLEAN ResetDisplay;
|
|
BOOLEAN AllowNewOptions;
|
|
BOOLEAN BlankLineDrawn;
|
|
PCHAR pDebug;
|
|
|
|
//
|
|
// Get the strings we'll need to display.
|
|
//
|
|
SelectOs = BlFindMessage(BL_SELECT_OS);
|
|
MoveHighlight = BlFindMessage(BL_MOVE_HIGHLIGHT);
|
|
TimeoutCountdown = BlFindMessage(BL_TIMEOUT_COUNTDOWN);
|
|
EnabledKd = BlFindMessage(BL_ENABLED_KD_TITLE);
|
|
AdvancedBootMessage = BlFindMessage(BL_ADVANCED_BOOT_MESSAGE);
|
|
HeadlessRedirect = BlFindMessage(BL_HEADLESS_REDIRECT_TITLE);
|
|
if ((SelectOs == NULL) ||
|
|
(MoveHighlight == NULL) ||
|
|
(EnabledKd == NULL) ||
|
|
(TimeoutCountdown==NULL)||
|
|
(AdvancedBootMessage == NULL)) {
|
|
|
|
return(Default);
|
|
}
|
|
|
|
p=strchr(TimeoutCountdown,'\r');
|
|
if (p!=NULL) {
|
|
*p='\0';
|
|
}
|
|
|
|
p=strchr(EnabledKd,'\r');
|
|
if (p!=NULL) {
|
|
*p='\0';
|
|
}
|
|
|
|
p=strchr(HeadlessRedirect,'\r');
|
|
if (p!=NULL) {
|
|
*p='\0';
|
|
}
|
|
|
|
if (NumberSelections<=1) {
|
|
Timeout = 0;
|
|
}
|
|
|
|
if (Timeout == 0) {
|
|
|
|
//
|
|
// Check for F5 or F8 key
|
|
//
|
|
switch (BlGetKey()) {
|
|
case F5_KEY:
|
|
case F8_KEY:
|
|
Timeout = -1;
|
|
break;
|
|
|
|
default:
|
|
//
|
|
// Timeout is zero, and we didn't get a f5 or f8.
|
|
// immediately boot the default
|
|
//
|
|
return(Default);
|
|
}
|
|
}
|
|
|
|
//
|
|
// By default, on a free build of the loader only allow the
|
|
// user to specify new options if there is some selection
|
|
// which supports debugging or selection to boot dos. If
|
|
// all the selections are for non-debug versions of NT then
|
|
// do not allow the user to change any of them
|
|
//
|
|
|
|
AllowNewOptions = FALSE;
|
|
#if DBG
|
|
AllowNewOptions = TRUE;
|
|
#endif
|
|
|
|
//
|
|
// Find the longest string in the selections, so we know how long to
|
|
// make the highlight bar.
|
|
//
|
|
|
|
for (i=0; i<NumberSelections; i++) {
|
|
if( strlen(MenuOption[i].Title)> MAX_TITLE_LENGTH ) {
|
|
MenuOption[i].Title[MAX_TITLE_LENGTH - 1] = '\0';
|
|
}
|
|
|
|
if (MenuOption[i].EnableDebug == TRUE ||
|
|
MenuOption[i].Win95 != 0 ||
|
|
_stricmp(MenuOption[i].Path, "C:\\") == 0) {
|
|
AllowNewOptions = TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
Selection = Default;
|
|
CurrentTime = StartTime = GET_COUNTER();
|
|
EndTime = StartTime + (Timeout * 182) / 10;
|
|
pDebug = szDebug;
|
|
DebugSelect = NULL;
|
|
ResetDisplay = TRUE;
|
|
Moved = TRUE;
|
|
BlankLineDrawn = FALSE;
|
|
do {
|
|
|
|
if (ResetDisplay) {
|
|
ARC_DISPLAY_ATTRIBUTES_OFF();
|
|
ARC_DISPLAY_CLEAR();
|
|
// ARC_DISPLAY_POSITION_CURSOR(0, 0);
|
|
// BlPrint(OsLoaderVersion);
|
|
ARC_DISPLAY_POSITION_CURSOR(0, 23);
|
|
if (AdvancedBoot != -1) {
|
|
ARC_DISPLAY_SET_COLOR("1;34"); // high-intensity red
|
|
BlPrint(BlGetAdvancedBootDisplayString(AdvancedBoot));
|
|
ARC_DISPLAY_ATTRIBUTES_OFF();
|
|
} else {
|
|
ARC_DISPLAY_CLEAR_TO_EOL();
|
|
}
|
|
ARC_DISPLAY_POSITION_CURSOR(0, 21);
|
|
BlPrint(AdvancedBootMessage);
|
|
ARC_DISPLAY_POSITION_CURSOR(0, 2);
|
|
BlPrint(SelectOs);
|
|
ResetDisplay = FALSE;
|
|
ARC_DISPLAY_POSITION_CURSOR(0, 5+NumberSelections-1);
|
|
BlPrint(MoveHighlight);
|
|
}
|
|
|
|
if(Moved) {
|
|
for (i=0; i<NumberSelections; i++) {
|
|
|
|
//
|
|
// keep track of how many characters we've printed
|
|
// on this line.
|
|
//
|
|
CurrentLength = 0;
|
|
|
|
//
|
|
// Display the title.
|
|
//
|
|
ARC_DISPLAY_POSITION_CURSOR(0, 5+i);
|
|
if (i==Selection) {
|
|
ARC_DISPLAY_INVERSE_VIDEO();
|
|
}
|
|
BlPrint( " %s", MenuOption[i].Title);
|
|
|
|
CurrentLength += 4; // spaces
|
|
CurrentLength += strlen(MenuOption[i].Title);
|
|
|
|
|
|
if (MenuOption[i].HeadlessRedirect == TRUE) {
|
|
if( (CurrentLength + strlen(HeadlessRedirect)) < MAX_TITLE_LENGTH ) {
|
|
BlPrint(HeadlessRedirect);
|
|
CurrentLength += strlen(HeadlessRedirect);
|
|
}
|
|
}
|
|
|
|
if (MenuOption[i].EnableDebug == TRUE) {
|
|
if( (CurrentLength + strlen(EnabledKd)) < MAX_TITLE_LENGTH ) {
|
|
BlPrint(EnabledKd);
|
|
CurrentLength += strlen(EnabledKd);
|
|
}
|
|
}
|
|
ARC_DISPLAY_ATTRIBUTES_OFF();
|
|
}
|
|
|
|
if (DebugSelect) {
|
|
ARC_DISPLAY_POSITION_CURSOR(0, 7+NumberSelections-1);
|
|
ARC_DISPLAY_CLEAR_TO_EOD();
|
|
DebugLoadOptions[0] = 0;
|
|
DebugLoadOptions[DEBUG_LOAD_OPTION_LENGTH-1] = 0;
|
|
if (MenuOption[Selection].LoadOptions) {
|
|
i = strlen(MenuOption[Selection].LoadOptions) + 1;
|
|
if (i > DEBUG_LOAD_OPTION_LENGTH-1) {
|
|
i = DEBUG_LOAD_OPTION_LENGTH-1;
|
|
}
|
|
|
|
memcpy (DebugLoadOptions, MenuOption[Selection].LoadOptions, i);
|
|
}
|
|
|
|
BlPrint (
|
|
DebugSelect,
|
|
MenuOption[Selection].Title,
|
|
MenuOption[Selection].Path,
|
|
DebugLoadOptions
|
|
);
|
|
|
|
}
|
|
|
|
Moved = FALSE;
|
|
}
|
|
|
|
|
|
if (!DebugSelect) {
|
|
if (Timeout != -1) {
|
|
LastTime = CurrentTime;
|
|
CurrentTime = GET_COUNTER();
|
|
|
|
//
|
|
// deal with wraparound at midnight
|
|
// We can't do it the easy way because there are not exactly
|
|
// 18.2 * 60 * 60 * 24 tics/day. (just approximately)
|
|
//
|
|
if (CurrentTime < StartTime) {
|
|
if (BiasTime == 0) {
|
|
BiasTime = LastTime + 1;
|
|
}
|
|
CurrentTime += BiasTime;
|
|
}
|
|
SecondsLeft = ((LONG)(EndTime - CurrentTime) * 10) / 182;
|
|
|
|
if (SecondsLeft < 0) {
|
|
|
|
//
|
|
// Note that if the user hits the PAUSE key, the counter stops
|
|
// and, as a result, SecondsLeft can become < 0.
|
|
//
|
|
|
|
SecondsLeft = 0;
|
|
}
|
|
|
|
if (SecondsLeft != LastSecondsLeft) {
|
|
|
|
ARC_DISPLAY_POSITION_CURSOR(0, 5+NumberSelections-1);
|
|
BlPrint(MoveHighlight);
|
|
BlPrint(TimeoutCountdown);
|
|
BlPrint(" %d \n",SecondsLeft);
|
|
LastSecondsLeft = SecondsLeft;
|
|
|
|
}
|
|
|
|
} else if (!BlankLineDrawn) {
|
|
BlankLineDrawn = TRUE;
|
|
ARC_DISPLAY_POSITION_CURSOR(0, 5+NumberSelections-1);
|
|
BlPrint(MoveHighlight);
|
|
BlPrint(BlankLine);
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Poll for a key.
|
|
//
|
|
Key = BlGetKey();
|
|
|
|
if (Key) {
|
|
|
|
//
|
|
// Any key stops timeout
|
|
//
|
|
|
|
Timeout = -1;
|
|
|
|
//
|
|
// Check for debug string
|
|
//
|
|
|
|
if ((UCHAR) Key == *pDebug) {
|
|
pDebug++;
|
|
if (!*pDebug) {
|
|
Moved = TRUE;
|
|
DebugSelect = BlFindMessage(BL_DEBUG_SELECT_OS);
|
|
SelectOs = DebugSelect;
|
|
}
|
|
} else {
|
|
pDebug = szDebug;
|
|
}
|
|
}
|
|
|
|
#if defined(ENABLE_LOADER_DEBUG) || DBG
|
|
|
|
//
|
|
// for debugging only.
|
|
// lets you break into the debugger
|
|
// with the F10 key.
|
|
//
|
|
if (Key == F10_KEY) {
|
|
extern LOGICAL BdDebuggerEnabled;
|
|
|
|
if (BdDebuggerEnabled == TRUE) {
|
|
DbgBreakPoint();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// check for advanced boot options
|
|
//
|
|
|
|
if (Key == F8_KEY || Key == F5_KEY) {
|
|
|
|
AdvancedBoot = BlDoAdvancedBoot( BL_ADVANCEDBOOT_TITLE, AdvancedBoot, FALSE, 0 );
|
|
|
|
#if 0
|
|
if ((AdvancedBoot != -1) &&
|
|
(BlGetAdvancedBootID(AdvancedBoot) == BL_MSG_BOOT_NORMALLY)) {
|
|
AdvancedBoot = -1;
|
|
// break; // the current selection need to be booted (normally)
|
|
}
|
|
#endif
|
|
|
|
if ((AdvancedBoot != -1) &&
|
|
(BlGetAdvancedBootID(AdvancedBoot) == BL_MSG_REBOOT)) {
|
|
BlClearScreen();
|
|
ArcReboot();
|
|
}
|
|
|
|
ResetDisplay = TRUE;
|
|
Moved = TRUE;
|
|
|
|
} else
|
|
|
|
//
|
|
// Check for selection
|
|
//
|
|
|
|
if ( (Key==UP_ARROW) ||
|
|
(Key==DOWN_ARROW) ||
|
|
(Key==HOME_KEY) ||
|
|
(Key==END_KEY)
|
|
) {
|
|
Moved = TRUE;
|
|
ARC_DISPLAY_POSITION_CURSOR(0, 5+Selection);
|
|
ARC_DISPLAY_ATTRIBUTES_OFF();
|
|
BlPrint( " %s", MenuOption[Selection].Title);
|
|
if (Key==DOWN_ARROW) {
|
|
Selection = (Selection+1) % NumberSelections;
|
|
} else if (Key==UP_ARROW) {
|
|
Selection = (Selection == 0) ? (NumberSelections-1)
|
|
: (Selection - 1);
|
|
} else if (Key==HOME_KEY) {
|
|
Selection = 0;
|
|
} else if (Key==END_KEY) {
|
|
Selection = NumberSelections-1;
|
|
}
|
|
}
|
|
|
|
} while ( ((Key&(ULONG)0xff) != ENTER_KEY) &&
|
|
((CurrentTime < EndTime) || (Timeout == -1)) );
|
|
|
|
//
|
|
// If debugging, prompt the user for new load options
|
|
//
|
|
|
|
if (DebugSelect && AllowNewOptions) {
|
|
ARC_DISPLAY_CLEAR();
|
|
ARC_DISPLAY_POSITION_CURSOR(0, 2);
|
|
ARC_DISPLAY_CLEAR_TO_EOD();
|
|
|
|
BlPrint (
|
|
DebugSelect,
|
|
MenuOption[Selection].Title,
|
|
MenuOption[Selection].Path,
|
|
DebugLoadOptions
|
|
);
|
|
|
|
BlInputString (
|
|
BL_DEBUG_NEW_OPTIONS,
|
|
0, 7,
|
|
(PUCHAR)DebugLoadOptions,
|
|
DEBUG_LOAD_OPTION_LENGTH - 1
|
|
);
|
|
|
|
BlParseOsOptions (
|
|
&MenuOption[Selection],
|
|
DebugLoadOptions
|
|
);
|
|
}
|
|
|
|
return(Selection);
|
|
}
|
|
|
|
|
|
|
|
ARC_STATUS
|
|
BlpRenameWin95SystemFile(
|
|
IN ULONG DriveId,
|
|
IN ULONG Type,
|
|
IN PCHAR FileName,
|
|
IN PCHAR Ext,
|
|
IN PCHAR NewName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Renames a file from one name to another.
|
|
|
|
Arguments:
|
|
|
|
DriveId - Open drive identifier
|
|
Type - WIN95_DOS or DOS_WIN95
|
|
FileName - Base file name
|
|
Ext - Base extension
|
|
NewName - Non-NULL value causes an override of a generated name
|
|
|
|
Return Value:
|
|
|
|
Arc status of the failed opperation or E_SUCCESS.
|
|
|
|
--*/
|
|
|
|
{
|
|
ARC_STATUS Status;
|
|
ULONG FileId;
|
|
ULONG FileIdCur;
|
|
CHAR Fname[16];
|
|
CHAR FnameCur[16];
|
|
CHAR FnameNew[16];
|
|
|
|
|
|
if (Type == WIN95_DOS) {
|
|
sprintf( Fname, "%s.dos", FileName );
|
|
} else {
|
|
if (NewName) {
|
|
strcpy( Fname, NewName );
|
|
} else {
|
|
sprintf( Fname, "%s.w40", FileName );
|
|
}
|
|
}
|
|
|
|
Status = BlOpen(
|
|
DriveId,
|
|
Fname,
|
|
ArcOpenReadOnly,
|
|
&FileId
|
|
);
|
|
if (Status != ESUCCESS) {
|
|
return Status;
|
|
}
|
|
|
|
sprintf( FnameCur, "%s.%s", FileName, Ext );
|
|
|
|
Status = BlOpen(
|
|
DriveId,
|
|
FnameCur,
|
|
ArcOpenReadOnly,
|
|
&FileIdCur
|
|
);
|
|
if (Status != ESUCCESS) {
|
|
BlClose( FileId );
|
|
return Status;
|
|
}
|
|
|
|
if (Type == WIN95_DOS) {
|
|
if (NewName) {
|
|
strcpy( FnameNew, NewName );
|
|
} else {
|
|
sprintf( FnameNew, "%s.w40", FileName );
|
|
}
|
|
} else {
|
|
sprintf( FnameNew, "%s.dos", FileName );
|
|
}
|
|
|
|
Status = BlRename(
|
|
FileIdCur,
|
|
FnameNew
|
|
);
|
|
|
|
BlClose( FileIdCur );
|
|
|
|
if (Status != ESUCCESS) {
|
|
BlClose( FileId );
|
|
return Status;
|
|
}
|
|
|
|
Status = BlRename(
|
|
FileId,
|
|
FnameCur
|
|
);
|
|
|
|
BlClose( FileId );
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
VOID
|
|
BlpRenameWin95Files(
|
|
IN ULONG DriveId,
|
|
IN ULONG Type
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Renames all Windows 95 system files from either their
|
|
Win95 DOS names to their Win95 name or the reverse.
|
|
|
|
Arguments:
|
|
|
|
DriveId - Open drive identifier
|
|
Type - 1=dos to win95, 2=win95 to dos
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
BlpRenameWin95SystemFile( DriveId, Type, "command", "com", NULL );
|
|
BlpRenameWin95SystemFile( DriveId, Type, "msdos", "sys", NULL );
|
|
BlpRenameWin95SystemFile( DriveId, Type, "io", "sys", "winboot.sys" );
|
|
BlpRenameWin95SystemFile( DriveId, Type, "autoexec", "bat", NULL );
|
|
BlpRenameWin95SystemFile( DriveId, Type, "config", "sys", NULL );
|
|
}
|
|
|
|
ULONG
|
|
BlGetAdvancedBootOption(
|
|
VOID
|
|
)
|
|
{
|
|
return AdvancedBoot;
|
|
}
|
|
|