Leaked source code of windows server 2003
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

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