Source code of Windows XP (NT5)
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.

1889 lines
47 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. parsboot.c
  5. Abstract:
  6. Parses the boot.ini file, displays a menu, and provides a kernel
  7. path and name to be passed to osloader.
  8. Author:
  9. John Vert (jvert) 22-Jul-1991
  10. Revision History:
  11. --*/
  12. #include "bldrx86.h"
  13. #include "msg.h"
  14. #include "ntdddisk.h"
  15. #include <string.h>
  16. #include <stdlib.h>
  17. #include <stdio.h>
  18. VOID
  19. BlpTruncateDescriptors (
  20. IN ULONG HighestPage
  21. );
  22. #define MAX_SELECTIONS 10
  23. #define MAX_TITLE_LENGTH 71
  24. #define WIN95_DOS 1
  25. #define DOS_WIN95 2
  26. typedef struct _MENU_OPTION {
  27. PCHAR Title;
  28. PCHAR Path;
  29. BOOLEAN EnableDebug;
  30. ULONG MaxMemory;
  31. PCHAR LoadOptions;
  32. int ForcedScsiOrdinal;
  33. int Win95;
  34. BOOLEAN HeadlessRedirect;
  35. } MENU_OPTION, *PMENU_OPTION;
  36. PCHAR pDefSwitches = NULL;
  37. int ForcedScsiOrdinal = -1;
  38. CHAR szDebug[] = "unsupporteddebug";
  39. CHAR BlankLine[] = " \r";
  40. //
  41. // global to hold the user's last
  42. // selection from the advanced boot menu.
  43. //
  44. LONG AdvancedBoot = -1;
  45. #define DEBUG_LOAD_OPTION_LENGTH 60
  46. CHAR DebugLoadOptions[DEBUG_LOAD_OPTION_LENGTH];
  47. //
  48. // Defines for options for redirecting to a headless terminal
  49. //
  50. #define COM1_19_2 "com1at19200"
  51. #define COM2_19_2 "com2at19200"
  52. //
  53. // Private function prototypes
  54. //
  55. VOID
  56. BlpRebootDOS(
  57. IN PCHAR BootSectorImage OPTIONAL,
  58. IN PCHAR LoadOptions OPTIONAL
  59. );
  60. PCHAR
  61. BlpNextLine(
  62. IN PCHAR String
  63. );
  64. VOID
  65. BlpTranslateDosToArc(
  66. IN PCHAR DosName,
  67. OUT PCHAR ArcName
  68. );
  69. VOID
  70. BlpTruncateMemory(
  71. IN ULONG MaxMemory
  72. );
  73. ULONG
  74. BlpPresentMenu(
  75. IN PMENU_OPTION MenuOptions,
  76. IN ULONG NumberSelections,
  77. IN ULONG Default,
  78. IN LONG Timeout
  79. );
  80. PCHAR *
  81. BlpFileToLines(
  82. IN PCHAR File,
  83. OUT PULONG LineCount
  84. );
  85. PCHAR *
  86. BlpFindSection(
  87. IN PCHAR SectionName,
  88. IN PCHAR *BootFile,
  89. IN ULONG BootFileLines,
  90. OUT PULONG NumberLines
  91. );
  92. VOID
  93. BlpRenameWin95Files(
  94. IN ULONG DriveId,
  95. IN ULONG Type
  96. );
  97. VOID
  98. BlParseOsOptions (
  99. IN PMENU_OPTION MenuOption,
  100. IN PUCHAR pCurrent
  101. );
  102. ULONG
  103. BlGetAdvancedBootID(
  104. LONG BootOption
  105. );
  106. PCHAR
  107. BlSelectKernel(
  108. IN ULONG DriveId,
  109. IN PCHAR BootFile,
  110. OUT PCHAR *LoadOptions,
  111. IN BOOLEAN UseTimeOut
  112. )
  113. /*++
  114. Routine Description:
  115. Parses the boot.txt file and determines the fully-qualified name of
  116. the kernel to be booted.
  117. Arguments:
  118. BootFile - Pointer to the beginning of the loaded boot.txt file
  119. Debugger - Returns the enable/disable state of the kernel debugger
  120. UseTimeOut - Supplies whether the boot menu should time out or not.
  121. Return Value:
  122. Pointer to the name of a kernel to boot.
  123. --*/
  124. {
  125. PCHAR *MbLines;
  126. PCHAR *OsLines;
  127. PCHAR *FileLines;
  128. #if DBG
  129. PCHAR *DebugLines;
  130. ULONG DebugLineCount;
  131. #endif
  132. ULONG FileLineCount;
  133. ULONG OsLineCount;
  134. ULONG MbLineCount;
  135. PCHAR pCurrent;
  136. PCHAR Option;
  137. MENU_OPTION MenuOption[MAX_SELECTIONS+1];
  138. ULONG NumberSystems=0;
  139. ULONG i;
  140. LONG Timeout;
  141. ULONG Selection;
  142. ULONG DefaultSelection=0;
  143. static CHAR Kernel[128];
  144. CHAR DosName[3];
  145. PCHAR DefaultOldPath="C:\\winnt";
  146. PCHAR WinntDir = DefaultOldPath + 2;
  147. PCHAR DefaultNewPath="C:\\windows\\";
  148. CHAR DefaultPathBuffer[128] = {0};
  149. PCHAR DefaultPath = DefaultPathBuffer;
  150. PCHAR DefaultTitle=BlFindMessage(BL_DEFAULT_TITLE);
  151. PCHAR p;
  152. ULONG DirId;
  153. //
  154. // Check to see if "winnt" directory exists on the boot
  155. // device. If it does not exist then make the default path point
  156. // to "windows" directory
  157. //
  158. if (BlOpen(DriveId, WinntDir, ArcOpenDirectory, &DirId) != ESUCCESS) {
  159. strcpy(DefaultPath, DefaultNewPath);
  160. } else {
  161. BlClose(DirId);
  162. strcpy(DefaultPath, DefaultOldPath);
  163. strcat(DefaultPath, "\\");
  164. }
  165. *LoadOptions = NULL;
  166. if (*BootFile == '\0') {
  167. //
  168. // No boot.ini file, so we boot the default.
  169. //
  170. BlPrint(BlFindMessage(BL_INVALID_BOOT_INI),DefaultPath);
  171. MenuOption[0].Path = DefaultPath;
  172. MenuOption[0].Title = DefaultTitle;
  173. MenuOption[0].MaxMemory = 0;
  174. MenuOption[0].LoadOptions = NULL;
  175. MenuOption[0].Win95 = 0;
  176. NumberSystems = 1;
  177. DefaultSelection = 0;
  178. MbLineCount = 0;
  179. OsLineCount = 0;
  180. MenuOption[0].EnableDebug = FALSE;
  181. #if DBG
  182. DebugLineCount = 0;
  183. #endif
  184. } else {
  185. FileLines = BlpFileToLines(BootFile, &FileLineCount);
  186. MbLines = BlpFindSection("[boot loader]",
  187. FileLines,
  188. FileLineCount,
  189. &MbLineCount);
  190. if (MbLines==NULL) {
  191. MbLines = BlpFindSection("[flexboot]",
  192. FileLines,
  193. FileLineCount,
  194. &MbLineCount);
  195. if (MbLines==NULL) {
  196. MbLines = BlpFindSection("[multiboot]",
  197. FileLines,
  198. FileLineCount,
  199. &MbLineCount);
  200. }
  201. }
  202. OsLines = BlpFindSection("[operating systems]",
  203. FileLines,
  204. FileLineCount,
  205. &OsLineCount);
  206. if (OsLineCount == 0) {
  207. if (BlBootingFromNet) {
  208. return NULL;
  209. }
  210. BlPrint(BlFindMessage(BL_INVALID_BOOT_INI),DefaultPath);
  211. MenuOption[0].Path = DefaultPath;
  212. MenuOption[0].Title = DefaultTitle;
  213. MenuOption[0].MaxMemory = 0;
  214. MenuOption[0].LoadOptions = NULL;
  215. MenuOption[0].Win95 = 0;
  216. MenuOption[0].HeadlessRedirect = FALSE;
  217. NumberSystems = 1;
  218. DefaultSelection = 0;
  219. }
  220. #if DBG
  221. DebugLines = BlpFindSection("[debug]",
  222. FileLines,
  223. FileLineCount,
  224. &DebugLineCount);
  225. #endif
  226. }
  227. //
  228. // Set default timeout value
  229. //
  230. if (UseTimeOut) {
  231. Timeout = 0;
  232. } else {
  233. Timeout = -1;
  234. }
  235. //
  236. // Before we look through the [boot loader] section, initialize
  237. // our headless redirection information so that the default is
  238. // to not redirect.
  239. //
  240. RtlZeroMemory( &LoaderRedirectionInformation, sizeof(HEADLESS_LOADER_BLOCK) );
  241. BlTerminalConnected = FALSE;
  242. //
  243. // Parse the [boot loader] section
  244. //
  245. for (i=0; i<MbLineCount; i++) {
  246. pCurrent = MbLines[i];
  247. //
  248. // Throw away any leading whitespace
  249. //
  250. pCurrent += strspn(pCurrent, " \t");
  251. if (*pCurrent == '\0') {
  252. //
  253. // This is a blank line, so we just throw it away.
  254. //
  255. continue;
  256. }
  257. //
  258. // Check for "DefSwitches" line
  259. //
  260. if (_strnicmp(pCurrent,"DefSwitches",sizeof("DefSwitches")-1) == 0) {
  261. pCurrent = strchr(pCurrent,'=');
  262. if (pCurrent != NULL) {
  263. pDefSwitches = pCurrent + 1;
  264. }
  265. continue;
  266. }
  267. //
  268. // Check for "timeout" line
  269. //
  270. if (_strnicmp(pCurrent,"timeout",7) == 0) {
  271. pCurrent = strchr(pCurrent,'=');
  272. if (pCurrent != NULL) {
  273. if (UseTimeOut) {
  274. Timeout = atoi(++pCurrent);
  275. }
  276. }
  277. }
  278. //
  279. // Check for "redirectbaudrate" line
  280. //
  281. if (_strnicmp(pCurrent,"redirectbaudrate",16) == 0) {
  282. pCurrent = strchr(pCurrent,'=');
  283. if (pCurrent != NULL) {
  284. //
  285. // Skip whitespace
  286. //
  287. ++pCurrent;
  288. pCurrent += strspn(pCurrent, " \t");
  289. if (*pCurrent != '\0') {
  290. //
  291. // Fill in our global structure with the information.
  292. //
  293. if( _strnicmp(pCurrent,"115200",6) == 0 ) {
  294. LoaderRedirectionInformation.BaudRate = BD_115200;
  295. } else if( _strnicmp(pCurrent,"57600",5) == 0 ) {
  296. LoaderRedirectionInformation.BaudRate = BD_57600;
  297. } else if( _strnicmp(pCurrent,"19200",5) == 0 ) {
  298. LoaderRedirectionInformation.BaudRate = BD_19200;
  299. } else {
  300. LoaderRedirectionInformation.BaudRate = BD_9600;
  301. }
  302. }
  303. }
  304. } else if (_strnicmp(pCurrent,"redirect",8) == 0) {
  305. //
  306. // Check for "redirect" line
  307. //
  308. pCurrent = strchr(pCurrent,'=');
  309. if (pCurrent != NULL) {
  310. //
  311. // Skip whitespace
  312. //
  313. ++pCurrent;
  314. pCurrent += strspn(pCurrent, " \t");
  315. if (*pCurrent != '\0') {
  316. //
  317. // Fill in our global structure with the information.
  318. //
  319. #if 0
  320. //
  321. // Since we now support variable baudrates, there's no
  322. // reason to support these hardcoded 19200 strings.
  323. //
  324. if (_strnicmp(pCurrent, COM1_19_2, sizeof(COM1_19_2)) == 0) {
  325. pCurrent += sizeof(COM1_19_2);
  326. LoaderRedirectionInformation.PortNumber = 1;
  327. LoaderRedirectionInformation.BaudRate = 19200;
  328. } else if (_strnicmp(pCurrent, COM2_19_2, sizeof(COM2_19_2)) == 0) {
  329. pCurrent += sizeof(COM2_19_2);
  330. LoaderRedirectionInformation.PortNumber = 2;
  331. LoaderRedirectionInformation.BaudRate = 19200;
  332. } else if (_strnicmp(pCurrent,"com",3) == 0) {
  333. #else
  334. if (_strnicmp(pCurrent,"com",3) == 0) {
  335. #endif
  336. pCurrent +=3;
  337. LoaderRedirectionInformation.PortNumber = atoi(pCurrent);
  338. } else if (_strnicmp(pCurrent, "usebiossettings", 15) == 0) {
  339. BlRetrieveBIOSRedirectionInformation();
  340. } else {
  341. //
  342. // See if they gave us a hardcoded address.
  343. //
  344. LoaderRedirectionInformation.PortAddress = (PUCHAR)ULongToPtr(strtoul(pCurrent,NULL,16));
  345. if( LoaderRedirectionInformation.PortAddress != (PUCHAR)NULL ) {
  346. LoaderRedirectionInformation.PortNumber = 3;
  347. }
  348. }
  349. }
  350. }
  351. }
  352. //
  353. // Check for "default" line
  354. //
  355. if (_strnicmp(pCurrent,"default",7) == 0) {
  356. pCurrent = strchr(pCurrent,'=');
  357. if (pCurrent != NULL) {
  358. DefaultPath = ++pCurrent;
  359. DefaultPath += strspn(DefaultPath," \t");
  360. }
  361. }
  362. }
  363. //
  364. // If we found any headless redirection settings, go initialize
  365. // the port now.
  366. //
  367. if( LoaderRedirectionInformation.PortNumber ) {
  368. // make sure we got a baudrate.
  369. if( LoaderRedirectionInformation.BaudRate == 0 ) {
  370. LoaderRedirectionInformation.BaudRate = 9600;
  371. }
  372. BlInitializeHeadlessPort();
  373. }
  374. //
  375. // Parse the [operating systems] section
  376. //
  377. for (i=0; i<OsLineCount; i++) {
  378. if (NumberSystems == MAX_SELECTIONS) {
  379. break;
  380. }
  381. pCurrent = OsLines[i];
  382. //
  383. // Throw away any leading whitespace
  384. //
  385. pCurrent += strspn(pCurrent, " \t");
  386. if (*pCurrent == '\0') {
  387. //
  388. // This is a blank line, so we just throw it away.
  389. //
  390. continue;
  391. }
  392. MenuOption[NumberSystems].Path = pCurrent;
  393. //
  394. // The first space or '=' character indicates the end of the
  395. // path specifier, so we need to replace it with a '\0'
  396. //
  397. while ((*pCurrent != ' ')&&
  398. (*pCurrent != '=')&&
  399. (*pCurrent != '\0')) {
  400. ++pCurrent;
  401. }
  402. *pCurrent = '\0';
  403. //
  404. // The next character that is not space, equals, or double-quote
  405. // is the start of the title.
  406. //
  407. ++pCurrent;
  408. while ((*pCurrent == ' ') ||
  409. (*pCurrent == '=') ||
  410. (*pCurrent == '"')) {
  411. ++pCurrent;
  412. }
  413. if (pCurrent=='\0') {
  414. //
  415. // No title was found, so just use the path as the title.
  416. //
  417. MenuOption[NumberSystems].Title = MenuOption[NumberSystems].Path;
  418. } else {
  419. MenuOption[NumberSystems].Title = pCurrent;
  420. }
  421. //
  422. // The next character that is either a double-quote or a \0
  423. // indicates the end of the title.
  424. //
  425. while ((*pCurrent != '\0')&&
  426. (*pCurrent != '"')) {
  427. ++pCurrent;
  428. }
  429. //
  430. // Parse the os load options for this selection
  431. //
  432. BlParseOsOptions (&MenuOption[NumberSystems], pCurrent);
  433. *pCurrent = 0;
  434. ++NumberSystems;
  435. }
  436. #if DBG
  437. //
  438. // Parse the [debug] section
  439. //
  440. for (i=0; i<DebugLineCount; i++) {
  441. extern ULONG ScsiDebug;
  442. pCurrent = DebugLines[i];
  443. //
  444. // Throw away leading whitespace
  445. //
  446. pCurrent += strspn(pCurrent, " \t");
  447. if (*pCurrent == '\0') {
  448. //
  449. // throw away blank lines
  450. //
  451. continue;
  452. }
  453. if (_strnicmp(pCurrent,"scsidebug",9) == 0) {
  454. pCurrent = strchr(pCurrent,'=');
  455. if (pCurrent != NULL) {
  456. ScsiDebug = atoi(++pCurrent);
  457. }
  458. } else if (_strnicmp(pCurrent,"/debug ",7) == 0) {
  459. //
  460. // This line contains something to do with debug,
  461. // pass to BdInitDebugger to handle.
  462. //
  463. // Note: very strict rules, debug keyword begins with
  464. // a slash and is followed by a space. "/debugport"
  465. // won't match, nor will "/debug" at the end of the
  466. // line.
  467. //
  468. // Note: If the debugger is hard compiled on, it
  469. // will already be enabled and these options will
  470. // have no effect. Also, the first occurence is
  471. // the one that takes effect.
  472. //
  473. BdInitDebugger(OsLoaderName, (PVOID)OsLoaderBase, pCurrent);
  474. }
  475. }
  476. #endif
  477. //
  478. // Now look for a Title entry from the [operating systems] section
  479. // that matches the default entry from the [multiboot] section. This
  480. // will give us a title. If no entry matches, we will add an entry
  481. // at the end of the list and provide a default Title.
  482. //
  483. i=0;
  484. while (_stricmp(MenuOption[i].Path,DefaultPath) != 0) {
  485. ++i;
  486. if (i==NumberSystems) {
  487. //
  488. // Create a default entry in the Title and Path arrays
  489. //
  490. MenuOption[NumberSystems].Path = DefaultPath;
  491. MenuOption[NumberSystems].Title = DefaultTitle;
  492. MenuOption[NumberSystems].EnableDebug = FALSE;
  493. MenuOption[NumberSystems].MaxMemory = 0;
  494. MenuOption[NumberSystems].LoadOptions = NULL;
  495. MenuOption[NumberSystems].Win95 = 0;
  496. ++NumberSystems;
  497. }
  498. }
  499. DefaultSelection = i;
  500. //
  501. // Display the menu of choices
  502. //
  503. Selection = BlpPresentMenu( MenuOption,
  504. NumberSystems,
  505. DefaultSelection,
  506. Timeout);
  507. pCurrent = MenuOption[Selection].LoadOptions;
  508. if (pCurrent != NULL) {
  509. //
  510. // Remove '/' from LoadOptions string.
  511. //
  512. *LoadOptions = pCurrent + 1;
  513. while (*pCurrent != '\0') {
  514. if (*pCurrent == '/') {
  515. *pCurrent = ' ';
  516. }
  517. ++pCurrent;
  518. }
  519. } else {
  520. *LoadOptions = NULL;
  521. }
  522. if (MenuOption[Selection].Win95) {
  523. BlpRenameWin95Files( DriveId, MenuOption[Selection].Win95 );
  524. }
  525. //
  526. // We need to take care of the following cases:
  527. // 1. The user has asked us to redirect via the osload
  528. // option entry, but did not ask the loader to redirect.
  529. // In this case, we will default to COM1.
  530. //
  531. // 2. The loader was asked to redirect via the "redirect"
  532. // specifier in the [boot loader] section. But the
  533. // user did NOT have a /redirect option on the osload
  534. // options. In this case, we need to kill the
  535. // LoaderRedirectionInformation variable.
  536. //
  537. if( MenuOption[Selection].HeadlessRedirect ) {
  538. #if 0
  539. // matth (7/25/2000) Don't do this for now. If the user has
  540. // this configuration in their boot.ini, it's
  541. // an error on their part.
  542. //
  543. // he's asked us to redirect the operating system. Make
  544. // sure the Loader was also asked to redirect too.
  545. //
  546. if( LoaderRedirectionInformation.PortNumber == 0 ) {
  547. //
  548. // the loader wasn't asked to redirect. The user
  549. // made a mistake here, but let's guess as to what
  550. // he wants.
  551. //
  552. RtlZeroMemory( &LoaderRedirectionInformation, sizeof(HEADLESS_LOADER_BLOCK) );
  553. LoaderRedirectionInformation.PortNumber = 1;
  554. LoaderRedirectionInformation.BaudRate = 9600;
  555. }
  556. #endif
  557. } else {
  558. //
  559. // He's asked us to not redirect. Make sure we don't pass
  560. // information to the OS so he won't be able to redirect.
  561. //
  562. RtlZeroMemory( &LoaderRedirectionInformation, sizeof(HEADLESS_LOADER_BLOCK) );
  563. BlTerminalConnected = FALSE;
  564. }
  565. if (_strnicmp(MenuOption[Selection].Path,"C:\\",3) == 0) {
  566. //
  567. // This syntax means that we are booting a root-based os
  568. // from an alternate boot sector image.
  569. // If no file name is specified, BlpRebootDos will default to
  570. // \bootsect.dos.
  571. //
  572. BlpRebootDOS(MenuOption[Selection].Path[3] ? &MenuOption[Selection].Path[2] : NULL,*LoadOptions);
  573. //
  574. // If this returns, it means that the file does not exist as a bootsector.
  575. // This allows c:\winnt35 to work as a boot path specifier as opposed to
  576. // a boot sector image filename specifier.
  577. //
  578. }
  579. if (MenuOption[Selection].Path[1]==':') {
  580. //
  581. // We need to translate the DOS name into an ARC name
  582. //
  583. DosName[0] = MenuOption[Selection].Path[0];
  584. DosName[1] = MenuOption[Selection].Path[1];
  585. DosName[2] = '\0';
  586. BlpTranslateDosToArc(DosName,Kernel);
  587. strcat(Kernel,MenuOption[Selection].Path+2);
  588. } else {
  589. strcpy(Kernel,MenuOption[Selection].Path);
  590. }
  591. //
  592. // the use made a valid selection from the
  593. // advanced boot menu so append the advanced
  594. // boot load options and perform any load
  595. // option processing.
  596. //
  597. if (AdvancedBoot != -1) {
  598. PSTR s = BlGetAdvancedBootLoadOptions(AdvancedBoot);
  599. if (s) {
  600. ULONG len = strlen(s) + (*LoadOptions ? strlen(*LoadOptions) : 0);
  601. s = BlAllocateHeap(len * sizeof(PCHAR));
  602. if (s) {
  603. *s = 0;
  604. if (*LoadOptions) {
  605. strcat(s,*LoadOptions);
  606. strcat(s," ");
  607. }
  608. strcat(s,BlGetAdvancedBootLoadOptions(AdvancedBoot));
  609. *LoadOptions = s;
  610. }
  611. }
  612. BlDoAdvancedBootLoadProcessing(AdvancedBoot);
  613. }
  614. //
  615. // Make sure there is no trailing slash
  616. //
  617. if (Kernel[strlen(Kernel)-1] == '\\') {
  618. Kernel[strlen(Kernel)-1] = '\0';
  619. }
  620. //
  621. // If MaxMemory is not zero, adjust the memory descriptors to eliminate
  622. // memory above the boundary line
  623. //
  624. // [chuckl 12/03/2001] Note that we use BlpTruncateDescriptors, not
  625. // BlpTruncateMemory. BlpTruncateMemory truncates the low-level MDArray
  626. // descriptors, while BlpTruncateDescriptors truncates the loader-level
  627. // memory descriptor list. Using BlpTruncateMemory worked when the loader
  628. // initialized its memory list twice. (BlMemoryInitialize was called twice.)
  629. // But this no longer happens, so we have to truncate the descriptors
  630. // directly here.
  631. //
  632. if (MenuOption[Selection].MaxMemory != 0) {
  633. ULONG MaxPage = (MenuOption[Selection].MaxMemory * ((1024 * 1024) / PAGE_SIZE)) - 1;
  634. BlpTruncateDescriptors(MaxPage);
  635. }
  636. ForcedScsiOrdinal = MenuOption[Selection].ForcedScsiOrdinal;
  637. return(Kernel);
  638. }
  639. VOID
  640. BlParseOsOptions (
  641. IN PMENU_OPTION MenuOption,
  642. IN PUCHAR pCurrent
  643. )
  644. {
  645. PUCHAR p;
  646. //
  647. // Clear all settings
  648. //
  649. MenuOption->ForcedScsiOrdinal = -1;
  650. MenuOption->MaxMemory = 0;
  651. MenuOption->LoadOptions = NULL;
  652. MenuOption->Win95 = 0;
  653. MenuOption->EnableDebug = FALSE;
  654. MenuOption->HeadlessRedirect = FALSE;
  655. // If there are no switches specified for this line, use the DefSwitches
  656. if ((strchr(pCurrent,'/') == NULL) && (pDefSwitches)) {
  657. pCurrent = pDefSwitches;
  658. }
  659. //
  660. // Convert to all one case
  661. //
  662. _strupr(pCurrent);
  663. //
  664. // Look for a scsi(x) ordinal to use for opens on scsi ARC paths.
  665. // This spec must immediately follow the title and is not part
  666. // of the load options.
  667. //
  668. p = strstr(pCurrent,"/SCSIORDINAL:");
  669. if(p) {
  670. MenuOption->ForcedScsiOrdinal = atoi(p + sizeof("/SCSIORDINAL:") - 1);
  671. }
  672. //
  673. // If there is a REDIRECT parameter after the description, then
  674. // we need to pass this to the osloader.
  675. //
  676. p = strstr(pCurrent,"/REDIRECT");
  677. if(p) {
  678. MenuOption->HeadlessRedirect = TRUE;
  679. }
  680. //
  681. // If there is a DEBUG parameter after the description, then
  682. // we need to pass the DEBUG option to the osloader.
  683. //
  684. if (strchr(pCurrent,'/') != NULL) {
  685. pCurrent = strchr(pCurrent+1,'/');
  686. MenuOption->LoadOptions = pCurrent;
  687. if (pCurrent != NULL) {
  688. p = strstr(pCurrent,"/MAXMEM");
  689. if (p) {
  690. MenuOption->MaxMemory = atoi(p+8);
  691. }
  692. if (strstr(pCurrent, "/WIN95DOS")) {
  693. MenuOption->Win95 = WIN95_DOS;
  694. } else if (strstr(pCurrent, "/WIN95")) {
  695. MenuOption->Win95 = DOS_WIN95;
  696. }
  697. //
  698. // As long as /nodebug or /crashdebug is specified, this is NO debug system
  699. // If /NODEBUG is not specified, and either one of the
  700. // DEBUG or BAUDRATE is specified, this is debug system.
  701. //
  702. if ((strstr(pCurrent, "NODEBUG") == NULL) &&
  703. (strstr(pCurrent, "CRASHDEBUG") == NULL)) {
  704. if (strstr(pCurrent, "DEBUG") || strstr(pCurrent, "BAUDRATE")) {
  705. if (_stricmp(MenuOption->Path, "C:\\")) {
  706. MenuOption->EnableDebug = TRUE;
  707. }
  708. }
  709. }
  710. }
  711. }
  712. }
  713. PCHAR *
  714. BlpFileToLines(
  715. IN PCHAR File,
  716. OUT PULONG LineCount
  717. )
  718. /*++
  719. Routine Description:
  720. This routine converts the loaded BOOT.INI file into an array of
  721. pointers to NULL-terminated ASCII strings.
  722. Arguments:
  723. File - supplies a pointer to the in-memory image of the BOOT.INI file.
  724. This will be converted in place by turning CR/LF pairs into
  725. null terminators.
  726. LineCount - Returns the number of lines in the BOOT.INI file.
  727. Return Value:
  728. A pointer to an array of pointers to ASCIIZ strings. The array will
  729. have LineCount elements.
  730. NULL if the function did not succeed for some reason.
  731. --*/
  732. {
  733. ULONG Line;
  734. PCHAR *LineArray;
  735. PCHAR p;
  736. PCHAR Space;
  737. p = File;
  738. //
  739. // First count the number of lines in the file so we know how large
  740. // an array to allocate.
  741. //
  742. *LineCount=1;
  743. while (*p != '\0') {
  744. p=strchr(p, '\n');
  745. if (p==NULL) {
  746. break;
  747. }
  748. ++p;
  749. //
  750. // See if there's any text following the CR/LF.
  751. //
  752. if (*p=='\0') {
  753. break;
  754. }
  755. *LineCount += 1;
  756. }
  757. LineArray = BlAllocateHeap(*LineCount * sizeof(PCHAR));
  758. //
  759. // Now step through the file again, replacing CR/LF with \0\0 and
  760. // filling in the array of pointers.
  761. //
  762. p=File;
  763. for (Line=0; Line < *LineCount; Line++) {
  764. LineArray[Line] = p;
  765. p=strchr(p, '\r');
  766. if (p != NULL) {
  767. *p = '\0';
  768. ++p;
  769. if (*p=='\n') {
  770. *p = '\0';
  771. ++p;
  772. }
  773. } else {
  774. p=strchr(LineArray[Line], '\n');
  775. if (p != NULL) {
  776. *p = '\0';
  777. ++p;
  778. }
  779. }
  780. //
  781. // remove trailing white space
  782. //
  783. Space = LineArray[Line] + strlen(LineArray[Line])-1;
  784. while ((*Space == ' ') || (*Space == '\t')) {
  785. *Space = '\0';
  786. --Space;
  787. }
  788. }
  789. return(LineArray);
  790. }
  791. PCHAR *
  792. BlpFindSection(
  793. IN PCHAR SectionName,
  794. IN PCHAR *BootFile,
  795. IN ULONG BootFileLines,
  796. OUT PULONG NumberLines
  797. )
  798. /*++
  799. Routine Description:
  800. Finds a section ([multiboot], [operating systems], etc) in the boot.ini
  801. file and returns a pointer to its first line. The search will be
  802. case-insensitive.
  803. Arguments:
  804. SectionName - Supplies the name of the section. No brackets.
  805. BootFile - Supplies the array of pointers to lines of the ini file.
  806. BootFileLines - Supplies the number of lines in the ini file.
  807. NumberLines - Returns the number of lines in the section.
  808. Return Value:
  809. Pointer to an array of ASCIIZ strings, one entry per line.
  810. NULL, if the section was not found.
  811. --*/
  812. {
  813. ULONG cnt;
  814. ULONG StartLine;
  815. for (cnt=0; cnt<BootFileLines; cnt++) {
  816. //
  817. // Check to see if this is the line we are looking for
  818. //
  819. if (_stricmp(BootFile[cnt],SectionName) == 0) {
  820. //
  821. // found it
  822. //
  823. break;
  824. }
  825. }
  826. if (cnt==BootFileLines) {
  827. //
  828. // We ran out of lines, never found the right section.
  829. //
  830. *NumberLines = 0;
  831. return(NULL);
  832. }
  833. StartLine = cnt+1;
  834. //
  835. // Find end of section
  836. //
  837. for (cnt=StartLine; cnt<BootFileLines; cnt++) {
  838. if (BootFile[cnt][0] == '[') {
  839. break;
  840. }
  841. }
  842. *NumberLines = cnt-StartLine;
  843. return(&BootFile[StartLine]);
  844. }
  845. PCHAR
  846. BlpNextLine(
  847. IN PCHAR String
  848. )
  849. /*++
  850. Routine Description:
  851. Finds the beginning of the next text line
  852. Arguments:
  853. String - Supplies a pointer to a null-terminated string
  854. Return Value:
  855. Pointer to the character following the first CR/LF found in String
  856. - or -
  857. NULL - No CR/LF found before the end of the string.
  858. --*/
  859. {
  860. PCHAR p;
  861. p=strchr(String, '\n');
  862. if (p==NULL) {
  863. return(p);
  864. }
  865. ++p;
  866. //
  867. // If there is no text following the CR/LF, there is no next line
  868. //
  869. if (*p=='\0') {
  870. return(NULL);
  871. } else {
  872. return(p);
  873. }
  874. }
  875. VOID
  876. BlpRebootDOS(
  877. IN PCHAR BootSectorImage OPTIONAL,
  878. IN PCHAR LoadOptions OPTIONAL
  879. )
  880. /*++
  881. Routine Description:
  882. Loads up the bootstrap sectors and executes them (thereby rebooting
  883. into DOS or OS/2)
  884. Arguments:
  885. BootSectorImage - If specified, supplies name of file on the C: drive
  886. that contains the boot sector image. In this case, this routine
  887. will return if that file cannot be opened (for example, if it's
  888. a directory). If not specified, then default to \bootsect.dos,
  889. and this routine will never return.
  890. Return Value:
  891. None.
  892. --*/
  893. {
  894. ULONG SectorId;
  895. ARC_STATUS Status;
  896. ULONG Read;
  897. ULONG DriveId;
  898. ULONG BootType;
  899. LARGE_INTEGER SeekPosition;
  900. extern UCHAR BootPartitionName[];
  901. //
  902. // HACKHACK John Vert (jvert)
  903. // Some SCSI drives get really confused and return zeroes when
  904. // you use the BIOS to query their size after the AHA driver has
  905. // initialized. This can completely tube OS/2 or DOS. So here
  906. // we try and open both BIOS-accessible hard drives. Our open
  907. // code is smart enough to retry if it gets back zeros, so hopefully
  908. // this will give the SCSI drives a chance to get their act together.
  909. //
  910. Status = ArcOpen("multi(0)disk(0)rdisk(0)partition(0)",
  911. ArcOpenReadOnly,
  912. &DriveId);
  913. if (Status == ESUCCESS) {
  914. ArcClose(DriveId);
  915. }
  916. Status = ArcOpen("multi(0)disk(0)rdisk(1)partition(0)",
  917. ArcOpenReadOnly,
  918. &DriveId);
  919. if (Status == ESUCCESS) {
  920. ArcClose(DriveId);
  921. }
  922. //
  923. // Load the boot sector at address 0x7C00 (expected by Reboot callback)
  924. //
  925. Status = ArcOpen(BootPartitionName,
  926. ArcOpenReadOnly,
  927. &DriveId);
  928. if (Status != ESUCCESS) {
  929. BlPrint(BlFindMessage(BL_REBOOT_IO_ERROR),BootPartitionName);
  930. while (1) {
  931. BlGetKey();
  932. }
  933. }
  934. Status = BlOpen( DriveId,
  935. BootSectorImage ? BootSectorImage : "\\bootsect.dos",
  936. ArcOpenReadOnly,
  937. &SectorId );
  938. if (Status != ESUCCESS) {
  939. if(BootSectorImage) {
  940. //
  941. // The boot sector image might actually be a directory.
  942. // Return to the caller to attempt standard boot.
  943. //
  944. ArcClose(DriveId);
  945. return;
  946. }
  947. BlPrint(BlFindMessage(BL_REBOOT_IO_ERROR),BootPartitionName);
  948. while (1) {
  949. }
  950. }
  951. Status = BlRead( SectorId,
  952. (PVOID)0x7c00,
  953. SECTOR_SIZE,
  954. &Read );
  955. if (Status != ESUCCESS) {
  956. BlPrint(BlFindMessage(BL_REBOOT_IO_ERROR),BootPartitionName);
  957. while (1) {
  958. }
  959. }
  960. //
  961. // The FAT boot code is only one sector long so we just want
  962. // to load it up and jump to it.
  963. //
  964. // For HPFS and NTFS, we can't do this because the first sector
  965. // loads the rest of the boot sectors -- but we want to use
  966. // the boot code in the boot sector image file we loaded.
  967. //
  968. // For HPFS, we load the first 20 sectors (boot code + super and
  969. // space blocks) into d00:200. Fortunately this works for both
  970. // NT and OS/2.
  971. //
  972. // For NTFS, we load the first 16 sectors and jump to d00:256.
  973. // If the OEM field of the boot sector starts with NTFS, we
  974. // assume it's NTFS boot code.
  975. //
  976. //
  977. // Try to read 8K from the boot code image.
  978. // If this succeeds, we have either HPFS or NTFS.
  979. //
  980. SeekPosition.QuadPart = 0;
  981. BlSeek(SectorId,&SeekPosition,SeekAbsolute);
  982. BlRead(SectorId,(PVOID)0xd000,SECTOR_SIZE*16,&Read);
  983. if(Read == SECTOR_SIZE*16) {
  984. if(memcmp((PVOID)0x7c03,"NTFS",4)) {
  985. //
  986. // HPFS -- we need to load the super block.
  987. //
  988. BootType = 1; // HPFS
  989. SeekPosition.QuadPart = 16*SECTOR_SIZE;
  990. ArcSeek(DriveId,&SeekPosition,SeekAbsolute);
  991. ArcRead(DriveId,(PVOID)0xf000,SECTOR_SIZE*4,&Read);
  992. } else {
  993. //
  994. // NTFS -- we've loaded everything we need to load.
  995. //
  996. BootType = 2; // NTFS
  997. }
  998. } else {
  999. BootType = 0; // FAT
  1000. }
  1001. if (LoadOptions) {
  1002. if (_stricmp(LoadOptions,"cmdcons") == 0) {
  1003. strcpy( (PCHAR)(0x7c03), "cmdcons" );
  1004. } else if (strcmp(LoadOptions,"ROLLBACK") == 0) {
  1005. //
  1006. // By definition, when /rollback is specified, it is the only load
  1007. // option. It eventually gets parsed, gets upper-cased, and gets
  1008. // its slash removed. So we check for the exact text "ROLLBACK".
  1009. //
  1010. // When rollback is specified, we have to write a token somewhere
  1011. // in the boot sector. This is our only way to send runtime
  1012. // options to the setup loader.
  1013. //
  1014. // There is a data buffer of 8 bytes at 0000:7C03 in all boot
  1015. // sectors today. Fortunately we can overwrite it. So we hard-code
  1016. // this address here and in the setup loader.
  1017. //
  1018. strcpy( (PCHAR)(0x7c03), "undo" );
  1019. }
  1020. }
  1021. //
  1022. // DX must be the drive to boot from
  1023. //
  1024. _asm {
  1025. mov dx, 0x80
  1026. }
  1027. REBOOT(BootType);
  1028. }
  1029. ULONG
  1030. BlpPresentMenu(
  1031. IN PMENU_OPTION MenuOption,
  1032. IN ULONG NumberSelections,
  1033. IN ULONG Default,
  1034. IN LONG Timeout
  1035. )
  1036. /*++
  1037. Routine Description:
  1038. Displays the menu of boot options and allows the user to select one
  1039. by using the arrow keys.
  1040. Arguments:
  1041. MenuOption - Supplies array of menu options
  1042. NumberSelections - Supplies the number of entries in the MenuOption array.
  1043. Default - Supplies the index of the default operating system choice.
  1044. Timeout - Supplies the timeout (in seconds) before the highlighted
  1045. operating system choice is booted. If this value is -1,
  1046. the menu will never timeout.
  1047. Return Value:
  1048. ULONG - The index of the operating system choice selected.
  1049. --*/
  1050. {
  1051. ULONG i;
  1052. ULONG Selection;
  1053. ULONG StartTime;
  1054. ULONG LastTime;
  1055. ULONG BiasTime=0;
  1056. ULONG CurrentTime;
  1057. LONG SecondsLeft;
  1058. LONG LastSecondsLeft = -1;
  1059. ULONG EndTime;
  1060. ULONG Key;
  1061. ULONG MaxLength;
  1062. ULONG CurrentLength;
  1063. PCHAR DebugSelect;
  1064. PCHAR SelectOs;
  1065. PCHAR MoveHighlight;
  1066. PCHAR TimeoutCountdown;
  1067. PCHAR EnabledKd;
  1068. PCHAR AdvancedBootMessage;
  1069. PCHAR HeadlessRedirect;
  1070. PCHAR p;
  1071. BOOLEAN Moved;
  1072. BOOLEAN ResetDisplay;
  1073. BOOLEAN AllowNewOptions;
  1074. BOOLEAN BlankLineDrawn;
  1075. PCHAR pDebug;
  1076. //
  1077. // Get the strings we'll need to display.
  1078. //
  1079. SelectOs = BlFindMessage(BL_SELECT_OS);
  1080. MoveHighlight = BlFindMessage(BL_MOVE_HIGHLIGHT);
  1081. TimeoutCountdown = BlFindMessage(BL_TIMEOUT_COUNTDOWN);
  1082. EnabledKd = BlFindMessage(BL_ENABLED_KD_TITLE);
  1083. AdvancedBootMessage = BlFindMessage(BL_ADVANCED_BOOT_MESSAGE);
  1084. HeadlessRedirect = BlFindMessage(BL_HEADLESS_REDIRECT_TITLE);
  1085. if ((SelectOs == NULL) ||
  1086. (MoveHighlight == NULL) ||
  1087. (EnabledKd == NULL) ||
  1088. (TimeoutCountdown==NULL)||
  1089. (AdvancedBootMessage == NULL)) {
  1090. return(Default);
  1091. }
  1092. p=strchr(TimeoutCountdown,'\r');
  1093. if (p!=NULL) {
  1094. *p='\0';
  1095. }
  1096. p=strchr(EnabledKd,'\r');
  1097. if (p!=NULL) {
  1098. *p='\0';
  1099. }
  1100. p=strchr(HeadlessRedirect,'\r');
  1101. if (p!=NULL) {
  1102. *p='\0';
  1103. }
  1104. if (NumberSelections<=1) {
  1105. Timeout = 0;
  1106. }
  1107. if (Timeout == 0) {
  1108. //
  1109. // Check for F5 or F8 key
  1110. //
  1111. switch (BlGetKey()) {
  1112. case F5_KEY:
  1113. case F8_KEY:
  1114. Timeout = -1;
  1115. break;
  1116. default:
  1117. //
  1118. // Timeout is zero, and we didn't get a f5 or f8.
  1119. // immediately boot the default
  1120. //
  1121. return(Default);
  1122. }
  1123. }
  1124. //
  1125. // By default, on a free build of the loader only allow the
  1126. // user to specify new options if there is some selection
  1127. // which supports debugging or selection to boot dos. If
  1128. // all the selections are for non-debug versions of NT then
  1129. // do not allow the user to change any of them
  1130. //
  1131. AllowNewOptions = FALSE;
  1132. #if DBG
  1133. AllowNewOptions = TRUE;
  1134. #endif
  1135. //
  1136. // Find the longest string in the selections, so we know how long to
  1137. // make the highlight bar.
  1138. //
  1139. MaxLength=0;
  1140. for (i=0; i<NumberSelections; i++) {
  1141. CurrentLength = strlen(MenuOption[i].Title);
  1142. if (MenuOption[i].HeadlessRedirect == TRUE) {
  1143. CurrentLength += strlen(HeadlessRedirect);
  1144. }
  1145. if (CurrentLength > MAX_TITLE_LENGTH) {
  1146. //
  1147. // This title is too long to fit on one line, so we have to
  1148. // truncate it.
  1149. //
  1150. if (MenuOption[i].HeadlessRedirect == TRUE) {
  1151. AllowNewOptions = TRUE;
  1152. MenuOption[i].Title[MAX_TITLE_LENGTH - strlen(HeadlessRedirect)] = '\0';
  1153. } else {
  1154. MenuOption[i].Title[MAX_TITLE_LENGTH] = '\0';
  1155. }
  1156. CurrentLength = MAX_TITLE_LENGTH;
  1157. }
  1158. if (MenuOption[i].EnableDebug == TRUE) {
  1159. CurrentLength += strlen(EnabledKd);
  1160. if (CurrentLength > MAX_TITLE_LENGTH) {
  1161. //
  1162. // This title is too long to fit on one line, so we have to
  1163. // truncate it.
  1164. //
  1165. AllowNewOptions = TRUE;
  1166. MenuOption[i].Title[strlen(MenuOption[i].Title) - strlen(EnabledKd)] = '\0';
  1167. CurrentLength = MAX_TITLE_LENGTH;
  1168. }
  1169. }
  1170. if (MenuOption[i].EnableDebug == TRUE ||
  1171. MenuOption[i].Win95 != 0 ||
  1172. _stricmp(MenuOption[i].Path, "C:\\") == 0) {
  1173. AllowNewOptions = TRUE;
  1174. }
  1175. if (CurrentLength > MaxLength) {
  1176. MaxLength = CurrentLength;
  1177. }
  1178. }
  1179. Selection = Default;
  1180. CurrentTime = StartTime = GET_COUNTER();
  1181. EndTime = StartTime + (Timeout * 182) / 10;
  1182. pDebug = szDebug;
  1183. DebugSelect = NULL;
  1184. ResetDisplay = TRUE;
  1185. Moved = TRUE;
  1186. BlankLineDrawn = FALSE;
  1187. do {
  1188. if (ResetDisplay) {
  1189. ARC_DISPLAY_ATTRIBUTES_OFF();
  1190. ARC_DISPLAY_CLEAR();
  1191. // ARC_DISPLAY_POSITION_CURSOR(0, 0);
  1192. // BlPrint(OsLoaderVersion);
  1193. ARC_DISPLAY_POSITION_CURSOR(0, 23);
  1194. if (AdvancedBoot != -1) {
  1195. ARC_DISPLAY_SET_COLOR("1;34"); // high-intensity red
  1196. BlPrint(BlGetAdvancedBootDisplayString(AdvancedBoot));
  1197. ARC_DISPLAY_ATTRIBUTES_OFF();
  1198. } else {
  1199. ARC_DISPLAY_CLEAR_TO_EOL();
  1200. }
  1201. ARC_DISPLAY_POSITION_CURSOR(0, 21);
  1202. BlPrint(AdvancedBootMessage);
  1203. ARC_DISPLAY_POSITION_CURSOR(0, 2);
  1204. BlPrint(SelectOs);
  1205. ResetDisplay = FALSE;
  1206. ARC_DISPLAY_POSITION_CURSOR(0, 5+NumberSelections-1);
  1207. BlPrint(MoveHighlight);
  1208. }
  1209. if(Moved) {
  1210. for (i=0; i<NumberSelections; i++) {
  1211. ARC_DISPLAY_POSITION_CURSOR(0, 5+i);
  1212. if (i==Selection) {
  1213. ARC_DISPLAY_INVERSE_VIDEO();
  1214. }
  1215. BlPrint( " %s", MenuOption[i].Title);
  1216. if (MenuOption[i].HeadlessRedirect == TRUE) {
  1217. BlPrint(HeadlessRedirect);
  1218. }
  1219. if (MenuOption[i].EnableDebug == TRUE) {
  1220. BlPrint(EnabledKd);
  1221. }
  1222. ARC_DISPLAY_ATTRIBUTES_OFF();
  1223. }
  1224. if (DebugSelect) {
  1225. ARC_DISPLAY_POSITION_CURSOR(0, 7+NumberSelections-1);
  1226. ARC_DISPLAY_CLEAR_TO_EOD();
  1227. DebugLoadOptions[0] = 0;
  1228. DebugLoadOptions[DEBUG_LOAD_OPTION_LENGTH-1] = 0;
  1229. if (MenuOption[Selection].LoadOptions) {
  1230. i = strlen(MenuOption[Selection].LoadOptions) + 1;
  1231. if (i > DEBUG_LOAD_OPTION_LENGTH-1) {
  1232. i = DEBUG_LOAD_OPTION_LENGTH-1;
  1233. }
  1234. memcpy (DebugLoadOptions, MenuOption[Selection].LoadOptions, i);
  1235. }
  1236. BlPrint (
  1237. DebugSelect,
  1238. MenuOption[Selection].Title,
  1239. MenuOption[Selection].Path,
  1240. DebugLoadOptions
  1241. );
  1242. }
  1243. Moved = FALSE;
  1244. }
  1245. if (!DebugSelect) {
  1246. if (Timeout != -1) {
  1247. LastTime = CurrentTime;
  1248. CurrentTime = GET_COUNTER();
  1249. //
  1250. // deal with wraparound at midnight
  1251. // We can't do it the easy way because there are not exactly
  1252. // 18.2 * 60 * 60 * 24 tics/day. (just approximately)
  1253. //
  1254. if (CurrentTime < StartTime) {
  1255. if (BiasTime == 0) {
  1256. BiasTime = LastTime + 1;
  1257. }
  1258. CurrentTime += BiasTime;
  1259. }
  1260. SecondsLeft = ((LONG)(EndTime - CurrentTime) * 10) / 182;
  1261. if (SecondsLeft < 0) {
  1262. //
  1263. // Note that if the user hits the PAUSE key, the counter stops
  1264. // and, as a result, SecondsLeft can become < 0.
  1265. //
  1266. SecondsLeft = 0;
  1267. }
  1268. if (SecondsLeft != LastSecondsLeft) {
  1269. ARC_DISPLAY_POSITION_CURSOR(0, 5+NumberSelections-1);
  1270. BlPrint(MoveHighlight);
  1271. BlPrint(TimeoutCountdown);
  1272. BlPrint(" %d \n",SecondsLeft);
  1273. LastSecondsLeft = SecondsLeft;
  1274. }
  1275. } else if (!BlankLineDrawn) {
  1276. BlankLineDrawn = TRUE;
  1277. ARC_DISPLAY_POSITION_CURSOR(0, 5+NumberSelections-1);
  1278. BlPrint(MoveHighlight);
  1279. BlPrint(BlankLine);
  1280. }
  1281. }
  1282. //
  1283. // Poll for a key.
  1284. //
  1285. Key = BlGetKey();
  1286. if (Key) {
  1287. //
  1288. // Any key stops timeout
  1289. //
  1290. Timeout = -1;
  1291. //
  1292. // Check for debug string
  1293. //
  1294. if ((UCHAR) Key == *pDebug) {
  1295. pDebug++;
  1296. if (!*pDebug) {
  1297. Moved = TRUE;
  1298. DebugSelect = BlFindMessage(BL_DEBUG_SELECT_OS);
  1299. SelectOs = DebugSelect;
  1300. }
  1301. } else {
  1302. pDebug = szDebug;
  1303. }
  1304. }
  1305. #if defined(ENABLE_LOADER_DEBUG) || DBG
  1306. //
  1307. // for debugging only.
  1308. // lets you break into the debugger
  1309. // with the F10 key.
  1310. //
  1311. if (Key == F10_KEY) {
  1312. extern LOGICAL BdDebuggerEnabled;
  1313. if (BdDebuggerEnabled == TRUE) {
  1314. DbgBreakPoint();
  1315. }
  1316. }
  1317. #endif
  1318. //
  1319. // check for advanced boot options
  1320. //
  1321. if (Key == F8_KEY || Key == F5_KEY) {
  1322. AdvancedBoot = BlDoAdvancedBoot( BL_ADVANCEDBOOT_TITLE, AdvancedBoot, FALSE, 0 );
  1323. #if 0
  1324. if ((AdvancedBoot != -1) &&
  1325. (BlGetAdvancedBootID(AdvancedBoot) == BL_MSG_BOOT_NORMALLY)) {
  1326. AdvancedBoot = -1;
  1327. // break; // the current selection need to be booted (normally)
  1328. }
  1329. #endif
  1330. if ((AdvancedBoot != -1) &&
  1331. (BlGetAdvancedBootID(AdvancedBoot) == BL_MSG_REBOOT)) {
  1332. BlClearScreen();
  1333. REBOOT_PROCESSOR();
  1334. }
  1335. ResetDisplay = TRUE;
  1336. Moved = TRUE;
  1337. } else
  1338. //
  1339. // Check for selection
  1340. //
  1341. if ( (Key==UP_ARROW) ||
  1342. (Key==DOWN_ARROW) ||
  1343. (Key==HOME_KEY) ||
  1344. (Key==END_KEY)
  1345. ) {
  1346. Moved = TRUE;
  1347. ARC_DISPLAY_POSITION_CURSOR(0, 5+Selection);
  1348. ARC_DISPLAY_ATTRIBUTES_OFF();
  1349. BlPrint( " %s", MenuOption[Selection].Title);
  1350. if (Key==DOWN_ARROW) {
  1351. Selection = (Selection+1) % NumberSelections;
  1352. } else if (Key==UP_ARROW) {
  1353. Selection = (Selection == 0) ? (NumberSelections-1)
  1354. : (Selection - 1);
  1355. } else if (Key==HOME_KEY) {
  1356. Selection = 0;
  1357. } else if (Key==END_KEY) {
  1358. Selection = NumberSelections-1;
  1359. }
  1360. }
  1361. } while ( ((Key&(ULONG)0xff) != ENTER_KEY) &&
  1362. ((CurrentTime < EndTime) || (Timeout == -1)) );
  1363. //
  1364. // If debugging, prompt the user for new load options
  1365. //
  1366. if (DebugSelect && AllowNewOptions) {
  1367. ARC_DISPLAY_CLEAR();
  1368. ARC_DISPLAY_POSITION_CURSOR(0, 2);
  1369. ARC_DISPLAY_CLEAR_TO_EOD();
  1370. BlPrint (
  1371. DebugSelect,
  1372. MenuOption[Selection].Title,
  1373. MenuOption[Selection].Path,
  1374. DebugLoadOptions
  1375. );
  1376. BlInputString (
  1377. BL_DEBUG_NEW_OPTIONS,
  1378. 0, 7,
  1379. DebugLoadOptions,
  1380. DEBUG_LOAD_OPTION_LENGTH - 1
  1381. );
  1382. BlParseOsOptions (
  1383. &MenuOption[Selection],
  1384. DebugLoadOptions
  1385. );
  1386. }
  1387. return(Selection);
  1388. }
  1389. ARC_STATUS
  1390. BlpRenameWin95SystemFile(
  1391. IN ULONG DriveId,
  1392. IN ULONG Type,
  1393. IN PCHAR FileName,
  1394. IN PCHAR Ext,
  1395. IN PCHAR NewName
  1396. )
  1397. /*++
  1398. Routine Description:
  1399. Renames a file from one name to another.
  1400. Arguments:
  1401. DriveId - Open drive identifier
  1402. Type - WIN95_DOS or DOS_WIN95
  1403. FileName - Base file name
  1404. Ext - Base extension
  1405. NewName - Non-NULL value causes an override of a generated name
  1406. Return Value:
  1407. Arc status of the failed opperation or E_SUCCESS.
  1408. --*/
  1409. {
  1410. ARC_STATUS Status;
  1411. ULONG FileId;
  1412. ULONG FileIdCur;
  1413. CHAR Fname[16];
  1414. CHAR FnameCur[16];
  1415. CHAR FnameNew[16];
  1416. if (Type == WIN95_DOS) {
  1417. sprintf( Fname, "%s.dos", FileName );
  1418. } else {
  1419. if (NewName) {
  1420. strcpy( Fname, NewName );
  1421. } else {
  1422. sprintf( Fname, "%s.w40", FileName );
  1423. }
  1424. }
  1425. Status = BlOpen(
  1426. DriveId,
  1427. Fname,
  1428. ArcOpenReadOnly,
  1429. &FileId
  1430. );
  1431. if (Status != ESUCCESS) {
  1432. return Status;
  1433. }
  1434. sprintf( FnameCur, "%s.%s", FileName, Ext );
  1435. Status = BlOpen(
  1436. DriveId,
  1437. FnameCur,
  1438. ArcOpenReadOnly,
  1439. &FileIdCur
  1440. );
  1441. if (Status != ESUCCESS) {
  1442. BlClose( FileId );
  1443. return Status;
  1444. }
  1445. if (Type == WIN95_DOS) {
  1446. if (NewName) {
  1447. strcpy( FnameNew, NewName );
  1448. } else {
  1449. sprintf( FnameNew, "%s.w40", FileName );
  1450. }
  1451. } else {
  1452. sprintf( FnameNew, "%s.dos", FileName );
  1453. }
  1454. Status = BlRename(
  1455. FileIdCur,
  1456. FnameNew
  1457. );
  1458. BlClose( FileIdCur );
  1459. if (Status != ESUCCESS) {
  1460. BlClose( FileId );
  1461. return Status;
  1462. }
  1463. Status = BlRename(
  1464. FileId,
  1465. FnameCur
  1466. );
  1467. BlClose( FileId );
  1468. return Status;
  1469. }
  1470. VOID
  1471. BlpRenameWin95Files(
  1472. IN ULONG DriveId,
  1473. IN ULONG Type
  1474. )
  1475. /*++
  1476. Routine Description:
  1477. Renames all Windows 95 system files from either their
  1478. Win95 DOS names to their Win95 name or the reverse.
  1479. Arguments:
  1480. DriveId - Open drive identifier
  1481. Type - 1=dos to win95, 2=win95 to dos
  1482. Return Value:
  1483. None.
  1484. --*/
  1485. {
  1486. BlpRenameWin95SystemFile( DriveId, Type, "command", "com", NULL );
  1487. BlpRenameWin95SystemFile( DriveId, Type, "msdos", "sys", NULL );
  1488. BlpRenameWin95SystemFile( DriveId, Type, "io", "sys", "winboot.sys" );
  1489. BlpRenameWin95SystemFile( DriveId, Type, "autoexec", "bat", NULL );
  1490. BlpRenameWin95SystemFile( DriveId, Type, "config", "sys", NULL );
  1491. }
  1492. ULONG
  1493. BlGetAdvancedBootOption(
  1494. VOID
  1495. )
  1496. {
  1497. return AdvancedBoot;
  1498. }