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.

879 lines
20 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. advboot.c
  5. Abstract:
  6. Handles the advanced options boot menu screen.
  7. Author:
  8. Wesley Wittt (wesw) 12-Dec-1997
  9. Revision History:
  10. --*/
  11. #ifdef i386
  12. #include "bldrx86.h"
  13. #endif
  14. #if defined(_IA64_)
  15. #include "bldria64.h"
  16. #endif
  17. #include <netboot.h>
  18. #include "msg.h"
  19. #include "ntdddisk.h"
  20. #include <string.h>
  21. #include <stdlib.h>
  22. #include <stdio.h>
  23. #include "bldrint.h"
  24. #if 0
  25. ULONG VerboseDebugging = 0;
  26. #define dbg(x) \
  27. if(VerboseDebugging) { \
  28. DbgPrint x; \
  29. }
  30. #define dbgbrk() \
  31. if(VerboseDebugging) { \
  32. DbgBreakPoint(); \
  33. }
  34. #else
  35. #define dbg(x) /* x */
  36. #define dbgbrk() /* */
  37. #endif
  38. //
  39. // used to force the boot loader into
  40. // using LKG even though the LKG menu
  41. // wasn't used.
  42. //
  43. extern BOOLEAN ForceLastKnownGood;
  44. #define ATTR_TEXT 0x07
  45. #define ATTR_TEXT_REVERSE 0x70
  46. #define HEADER_START_Y 0x01
  47. //
  48. // menu data structures and defines
  49. //
  50. #define MENU_ITEM 1
  51. #define MENU_BLANK_LINE 2
  52. typedef void (*PADVANCED_BOOT_PROCESSING)(void);
  53. typedef int (*PADVANCED_BOOT_ISVALID)(void);
  54. typedef struct _ADVANCEDBOOT_OPTIONS {
  55. ULONG MenuType;
  56. ULONG MsgId;
  57. PTSTR DisplayStr;
  58. PSTR LoadOptions;
  59. LONG RemoveIfPresent;
  60. ULONG UseEntry;
  61. ULONG AutoAdvancedBootOption;
  62. PADVANCED_BOOT_PROCESSING ProcessFunc;
  63. PADVANCED_BOOT_ISVALID IsValid;
  64. BOOLEAN IsDefault;
  65. } ADVANCEDBOOT_OPTIONS, PADVANCEDBOOT_OPTIONS;
  66. //
  67. // some prototypes that are needed for
  68. // the menu definitions.
  69. //
  70. void
  71. BlProcessLastKnownGoodOption(
  72. void
  73. );
  74. int
  75. BlIsReturnToOSChoicesValid(
  76. VOID
  77. );
  78. #if defined(REMOTE_BOOT)
  79. void
  80. BlProcessOschooserOption(
  81. void
  82. );
  83. void
  84. BlProcessRepinOption(
  85. void
  86. );
  87. void
  88. BlDisableCSC(
  89. void
  90. );
  91. void
  92. BlBootNormally(
  93. void
  94. );
  95. void
  96. BlReturnToOSChoiceMenu(
  97. void
  98. );
  99. int
  100. BlIsRemoteBootValid(
  101. void
  102. );
  103. #endif // defined(REMOTE_BOOT)
  104. //
  105. // this table drives the advanced boot menu screen.
  106. // of you need to add something to the screen then
  107. // this is what you need to modify.
  108. //
  109. ADVANCEDBOOT_OPTIONS AdvancedBootOptions[] =
  110. {
  111. { MENU_ITEM, BL_SAFEBOOT_OPTION1, NULL, "SAFEBOOT:MINIMAL SOS BOOTLOG NOGUIBOOT", -1, 0, 1, NULL, NULL, FALSE},
  112. { MENU_ITEM, BL_SAFEBOOT_OPTION2, NULL, "SAFEBOOT:NETWORK SOS BOOTLOG NOGUIBOOT", -1, 0, 1, NULL, NULL, FALSE},
  113. { MENU_ITEM, BL_SAFEBOOT_OPTION4, NULL, "SAFEBOOT:MINIMAL(ALTERNATESHELL) SOS BOOTLOG NOGUIBOOT", -1, 0, 1, NULL, NULL, FALSE},
  114. // { MENU_ITEM, BL_SAFEBOOT_OPTION3, NULL, "SAFEBOOT:STEPBYSTEP SOS BOOTLOG", -1, 0, 1, NULL, NULL, FALSE},
  115. { MENU_BLANK_LINE, 0, NULL, NULL, -1, 0, 1, NULL, NULL, FALSE},
  116. { MENU_ITEM, BL_BOOTLOG, NULL, "BOOTLOG", -1, 0, 0, NULL, NULL, FALSE},
  117. { MENU_ITEM, BL_BASEVIDEO, NULL, "BASEVIDEO", -1, 0, 0, NULL, NULL, FALSE},
  118. { MENU_ITEM, BL_LASTKNOWNGOOD_OPTION, NULL, NULL, -1, 0, 1, BlProcessLastKnownGoodOption, NULL, FALSE},
  119. { MENU_ITEM, BL_SAFEBOOT_OPTION6, NULL, "SAFEBOOT:DSREPAIR SOS", -1, 0, 0, NULL, NULL, FALSE},
  120. { MENU_ITEM, BL_DEBUG_OPTION, NULL, "DEBUG", -1, 0, 0, NULL, NULL, FALSE},
  121. #if defined(REMOTE_BOOT)
  122. { MENU_BLANK_LINE, 0, NULL, NULL, -1, 0, 0, NULL, BlIsRemoteBootValid, FALSE},
  123. { MENU_ITEM, BL_REMOTEBOOT_OPTION1, NULL, NULL, -1, 0, 0, BlProcessOschooserOption, BlIsRemoteBootValid, FALSE},
  124. { MENU_ITEM, BL_REMOTEBOOT_OPTION2, NULL, NULL, -1, 0, 0, BlProcessRepinOption, BlIsRemoteBootValid, FALSE},
  125. { MENU_ITEM, BL_REMOTEBOOT_OPTION3, NULL, NULL, -1, 0, 0, BlDisableCSC, BlIsRemoteBootValid, FALSE},
  126. #endif // defined(REMOTE_BOOT)
  127. { MENU_BLANK_LINE, 0, NULL, NULL, -1, 0, 1, NULL, NULL, FALSE},
  128. { MENU_ITEM, BL_MSG_BOOT_NORMALLY, NULL, NULL, -1, 0, 1, NULL, NULL, TRUE},
  129. { MENU_ITEM, BL_MSG_REBOOT, NULL, NULL, -1, 0, 0, NULL, NULL, FALSE},
  130. { MENU_ITEM, BL_MSG_OSCHOICES_MENU, NULL, NULL, -1, 0, 0, NULL, BlIsReturnToOSChoicesValid, FALSE}
  131. };
  132. #define MaxAdvancedBootOptions (sizeof(AdvancedBootOptions)/sizeof(ADVANCEDBOOT_OPTIONS))
  133. PTSTR
  134. BlGetAdvancedBootDisplayString(
  135. LONG BootOption
  136. )
  137. /*++
  138. Routine Description:
  139. Returns a pointer to the display string for a specific
  140. boot option.
  141. Arguments:
  142. BootOption - Desired boot option. Must correspond to an entry
  143. in the AdvancedBootOptions table.
  144. Return Value:
  145. PSTR - Pointer to the display string for the specified boot option.
  146. --*/
  147. {
  148. if (BootOption > MaxAdvancedBootOptions-1) {
  149. return TEXT("");
  150. }
  151. return AdvancedBootOptions[BootOption].DisplayStr;
  152. }
  153. ULONG
  154. BlGetAdvancedBootID(
  155. LONG BootOption
  156. )
  157. /*++
  158. Routine Description:
  159. Returns a ULONG indicating the string ID for a specific
  160. boot option.
  161. Arguments:
  162. BootOption - Desired boot option. Must correspond to an entry
  163. in the AdvancedBootOptions table.
  164. Return Value:
  165. MessageID for the string which is displayed for the
  166. the advanced boot option in the menu (unique ID).
  167. --*/
  168. {
  169. if (BootOption > MaxAdvancedBootOptions-1) {
  170. return -1;
  171. }
  172. return AdvancedBootOptions[BootOption].MsgId;
  173. }
  174. PSTR
  175. BlGetAdvancedBootLoadOptions(
  176. LONG BootOption
  177. )
  178. /*++
  179. Routine Description:
  180. Returns a pointer to the load options string for a specific
  181. boot option.
  182. Arguments:
  183. BootOption - Desired boot option. Must correspond to an entry
  184. in the AdvancedBootOptions table.
  185. Return Value:
  186. PSTR - Pointer to the load options string for the specified boot option.
  187. --*/
  188. {
  189. if (BootOption > MaxAdvancedBootOptions-1) {
  190. return "";
  191. }
  192. return AdvancedBootOptions[BootOption].LoadOptions;
  193. }
  194. void
  195. BlDoAdvancedBootLoadProcessing(
  196. LONG BootOption
  197. )
  198. /*++
  199. Routine Description:
  200. Performs any processing necessary for a
  201. boot option. This is used if the necessary action
  202. needed for a specific boot option cannot be
  203. expressed in terms of a load option string.
  204. Arguments:
  205. BootOption - Desired boot option. Must correspond to an entry
  206. in the AdvancedBootOptions table.
  207. Return Value:
  208. Nothing.
  209. --*/
  210. {
  211. if (BootOption > MaxAdvancedBootOptions-1 || AdvancedBootOptions[BootOption].ProcessFunc == NULL) {
  212. return;
  213. }
  214. AdvancedBootOptions[BootOption].ProcessFunc();
  215. }
  216. void
  217. BlProcessLastKnownGoodOption(
  218. void
  219. )
  220. /*++
  221. Routine Description:
  222. Performs LKG processing by simply setting a
  223. global boolean to TRUE.
  224. Arguments:
  225. None.
  226. Return Value:
  227. Nothing.
  228. --*/
  229. {
  230. ForceLastKnownGood = TRUE;
  231. }
  232. #if defined(REMOTE_BOOT)
  233. void
  234. BlProcessOschooserOption(
  235. void
  236. )
  237. /*++
  238. Routine Description:
  239. Brings up OSchooser so user can do remote boot maintenance.
  240. Arguments:
  241. None.
  242. Return Value:
  243. Nothing.
  244. --*/
  245. {
  246. return; // not yet implemented
  247. }
  248. void
  249. BlProcessRepinOption(
  250. void
  251. )
  252. /*++
  253. Routine Description:
  254. Sets NetBootRepin to cause the CSC to be repinned.
  255. Arguments:
  256. None.
  257. Return Value:
  258. Nothing.
  259. --*/
  260. {
  261. NetBootRepin = TRUE;
  262. NetBootCSC = FALSE;
  263. }
  264. void
  265. BlDisableCSC(
  266. void
  267. )
  268. /*++
  269. Routine Description:
  270. Clears NetBootCSC to cause the CSC to be disabled so that the local CSC
  271. can be inspected.
  272. Arguments:
  273. None.
  274. Return Value:
  275. Nothing.
  276. --*/
  277. {
  278. NetBootCSC = FALSE;
  279. }
  280. int
  281. BlIsRemoteBootValid(
  282. void
  283. )
  284. /*++
  285. Routine Description:
  286. Used for the remote boot options so that they
  287. can be displayed dynamically.
  288. Arguments:
  289. None.
  290. Return Value:
  291. TRUE or FALSE.
  292. --*/
  293. {
  294. return BlBootingFromNet;
  295. }
  296. #endif // defined(REMOTE_BOOT)
  297. LONG
  298. BlDoAdvancedBoot(
  299. IN ULONG MenuTitleId,
  300. IN LONG DefaultBootOption,
  301. IN BOOLEAN AutoAdvancedBoot,
  302. IN UCHAR Timeout
  303. )
  304. /*++
  305. Routine Description:
  306. Displays the menu of boot options and allows the user to select one
  307. by using the arrow keys.
  308. Arguments:
  309. MenuTitleId - the message ID of the title for the menu. The title
  310. will be different depending on whether the user
  311. selected advanced boot or whether the loader has
  312. determined that the system didn't boot or shutdown
  313. correctly (auto advanced boot)
  314. DefaultBootOption - menu selection to set the highligh on
  315. when the menu is drawn the first time.
  316. AutoAdvancedBoot - the menu is being displayed by the auto-advanced boot
  317. code. In this case a simplified menu is displayed
  318. containing the options relevant to recovering from a
  319. detected crash.
  320. Timeout - the number of seconds to wait for input before
  321. simply returning the default boot option.
  322. A timeout value of 0 means no timeout (the menu will
  323. stay up until an option is chosen)
  324. Return Value:
  325. LONG - The index of the advanced boot option that was selected
  326. or -1 to reset the selection to "nothing".
  327. --*/
  328. {
  329. PTCHAR Title;
  330. PTCHAR MoveHighlight;
  331. ULONG i,j;
  332. ULONG MaxLength;
  333. ULONG CurrentLength;
  334. ULONG Selection;
  335. ULONG Key;
  336. ULONG NumValidEntries = 0;
  337. BOOLEAN DisplayMenu;
  338. UCHAR ch;
  339. ULONG Count;
  340. PTCHAR TimeoutMessage;
  341. ULONG LastTime;
  342. ULONG TicksRemaining = -1;
  343. ULONG SecondsRemaining = -1;
  344. ULONG OptionStartY;
  345. ULONG CurrentX;
  346. ULONG CurrentY;
  347. ULONG MenuDefault;
  348. //
  349. // load any resource strings
  350. //
  351. Title = BlFindMessage(MenuTitleId);
  352. MoveHighlight = BlFindMessage(BL_MOVE_HIGHLIGHT);
  353. TimeoutMessage = BlFindMessage(BL_ADVANCEDBOOT_TIMEOUT);
  354. if (Title == NULL || MoveHighlight == NULL || TimeoutMessage == NULL) {
  355. return -1;
  356. }
  357. //
  358. // Remove the newline at the end of the timeout message.
  359. //
  360. {
  361. PTCHAR p;
  362. p=_tcschr(TimeoutMessage,TEXT('\r'));
  363. if (p!=NULL) {
  364. *p=TEXT('\0');
  365. }
  366. }
  367. //
  368. // print the screen header, etc.
  369. //
  370. #ifdef EFI
  371. BlEfiSetAttribute( DEFATT );
  372. BlClearScreen();
  373. BlEfiPositionCursor(0, HEADER_START_Y);
  374. #else
  375. ARC_DISPLAY_CLEAR();
  376. ARC_DISPLAY_ATTRIBUTES_OFF();
  377. ARC_DISPLAY_POSITION_CURSOR(0, HEADER_START_Y);
  378. #endif
  379. BlPrint(Title);
  380. #ifdef EFI
  381. BlEfiGetCursorPosition(&CurrentX, &CurrentY);
  382. #else
  383. TextGetCursorPosition(&CurrentX, &CurrentY);
  384. #endif
  385. OptionStartY = CurrentY;
  386. //
  387. // check to see which boot options are valid. While we're scanning save
  388. // the index of the default option.
  389. //
  390. for (i=0,MaxLength=0; i<MaxAdvancedBootOptions; i++) {
  391. if (AutoAdvancedBoot && !AdvancedBootOptions[i].AutoAdvancedBootOption) {
  392. AdvancedBootOptions[i].UseEntry = FALSE;
  393. } else if (AdvancedBootOptions[i].IsValid) {
  394. AdvancedBootOptions[i].UseEntry = AdvancedBootOptions[i].IsValid();
  395. } else {
  396. AdvancedBootOptions[i].UseEntry = TRUE;
  397. }
  398. if(AdvancedBootOptions[i].IsDefault) {
  399. MenuDefault = i;
  400. }
  401. }
  402. //
  403. // check to see which boot options are invalid based
  404. // on the presence of other boot options
  405. //
  406. for (i=0,MaxLength=0; i<MaxAdvancedBootOptions; i++) {
  407. if (AdvancedBootOptions[i].RemoveIfPresent != -1) {
  408. if (AdvancedBootOptions[AdvancedBootOptions[i].RemoveIfPresent].UseEntry) {
  409. AdvancedBootOptions[i].UseEntry = FALSE;
  410. }
  411. }
  412. }
  413. //
  414. // count the number of valid entries
  415. //
  416. for (i=0,MaxLength=0; i<MaxAdvancedBootOptions; i++) {
  417. if (AdvancedBootOptions[i].UseEntry) {
  418. NumValidEntries += 1;
  419. }
  420. }
  421. //
  422. // load all the string for the various boot options
  423. // Find the longest string in the selections, so we know how long to
  424. // make the highlight bar.
  425. //
  426. for (i=0,MaxLength=0; i<MaxAdvancedBootOptions; i++) {
  427. if (AdvancedBootOptions[i].MenuType == MENU_ITEM && AdvancedBootOptions[i].UseEntry) {
  428. if (AdvancedBootOptions[i].DisplayStr == NULL) {
  429. AdvancedBootOptions[i].DisplayStr = BlFindMessage(AdvancedBootOptions[i].MsgId);
  430. if (AdvancedBootOptions[i].DisplayStr == NULL) {
  431. return -1;
  432. }
  433. }
  434. CurrentLength = _tcslen(AdvancedBootOptions[i].DisplayStr);
  435. if (CurrentLength > MaxLength) {
  436. MaxLength = CurrentLength;
  437. }
  438. }
  439. }
  440. //
  441. // print the trailer message
  442. //
  443. #ifdef EFI
  444. BlEfiPositionCursor(0, OptionStartY + NumValidEntries);
  445. #else
  446. ARC_DISPLAY_POSITION_CURSOR(0, OptionStartY + NumValidEntries);
  447. #endif
  448. BlPrint(MoveHighlight);
  449. //
  450. // process the menu
  451. //
  452. Selection = ((DefaultBootOption == -1) ?
  453. MenuDefault :
  454. DefaultBootOption);
  455. while (AdvancedBootOptions[Selection].UseEntry == FALSE) {
  456. Selection += 1;
  457. }
  458. DisplayMenu = TRUE;
  459. if(Timeout) {
  460. //
  461. // according to the code in the boot loader there are roughly 18.2
  462. // ticks per second from the counter.
  463. //
  464. TicksRemaining = Timeout * 182 / 10;
  465. //
  466. // Now that we've rounded, compute the number of seconds remaining as
  467. // well. We'll use this to determine if the menu needs updated.
  468. //
  469. SecondsRemaining = (TicksRemaining * 10) / 182;
  470. dbg(("Timeout = %#x, Ticks = %#x, Seconds = %#x\n", Timeout, TicksRemaining, SecondsRemaining));
  471. }
  472. //
  473. // Save the current time as the last time.
  474. //
  475. LastTime = GET_COUNTER();
  476. do {
  477. ULONG CurrentTime = 0;
  478. dbg(("*****"));
  479. //
  480. // Decrement the number of ticks remaining. Compare the current time
  481. // to the last time and subtract that many ticks.
  482. //
  483. if (Timeout) {
  484. ULONG CurrentTime;
  485. ULONG s;
  486. ULONG Delta;
  487. CurrentTime = GET_COUNTER();
  488. dbg(("%x - %x", CurrentTime, LastTime));
  489. //
  490. // The counter wraps at midnight. However if current time is
  491. // less than or equal to last time we'll just ignore this
  492. // iteration.
  493. //
  494. if (CurrentTime >= LastTime) {
  495. Delta = CurrentTime - LastTime;
  496. } else {
  497. Delta = 1;
  498. }
  499. dbg(("= %x. %x - %x = ", Delta, TicksRemaining, Delta));
  500. TicksRemaining -= min(TicksRemaining, Delta);
  501. LastTime = CurrentTime;
  502. dbg(("%x. ", TicksRemaining));
  503. //
  504. // If there are no ticks left then terminate the loop.
  505. //
  506. if(TicksRemaining == 0) {
  507. dbg(("timeout\n"));
  508. dbgbrk();
  509. Selection = -1;
  510. break;
  511. }
  512. //
  513. // Compute the current number of seconds remaining. If it's not
  514. // equal to what it was before then we'll need to update the
  515. // menu.
  516. //
  517. s = (TicksRemaining * 10) / 182;
  518. dbg(("-> s %x/%x ", SecondsRemaining, s));
  519. if(SecondsRemaining > s) {
  520. SecondsRemaining = s;
  521. DisplayMenu = TRUE;
  522. dbg(("update "));
  523. }
  524. dbg(("\n"));
  525. }
  526. //
  527. // print the menu
  528. //
  529. if (DisplayMenu) {
  530. dbg(("Printing Menu: ticks = %#08lx. Sec = %d. Last = %#08lx Current = %08lx\n",
  531. TicksRemaining,
  532. SecondsRemaining,
  533. LastTime,
  534. CurrentTime
  535. ));
  536. for (i=0,j=1; i<MaxAdvancedBootOptions; i++) {
  537. if (AdvancedBootOptions[i].UseEntry) {
  538. #ifdef EFI
  539. BlEfiPositionCursor(0, OptionStartY + j);
  540. #else
  541. ARC_DISPLAY_POSITION_CURSOR(0, OptionStartY + j);
  542. #endif
  543. if (i==Selection) {
  544. #ifdef EFI
  545. //BlEfiSetInverseMode( TRUE );
  546. BlEfiSetAttribute( INVATT );
  547. #else
  548. ARC_DISPLAY_INVERSE_VIDEO();
  549. #endif
  550. } else {
  551. #ifdef EFI
  552. //BlEfiSetInverseMode( FALSE );
  553. BlEfiSetAttribute( DEFATT );
  554. #else
  555. ARC_DISPLAY_ATTRIBUTES_OFF();
  556. #endif
  557. }
  558. if (AdvancedBootOptions[i].MenuType == MENU_ITEM) {
  559. BlPrint( TEXT(" %s"), AdvancedBootOptions[i].DisplayStr);
  560. }
  561. #ifdef EFI
  562. if (i == Selection) {
  563. //BlEfiSetInverseMode( FALSE );
  564. BlEfiSetAttribute( DEFATT );
  565. }
  566. #else
  567. ARC_DISPLAY_ATTRIBUTES_OFF();
  568. #endif
  569. j += 1;
  570. }
  571. }
  572. #ifdef EFI
  573. BlEfiPositionCursor(0, OptionStartY + NumValidEntries + 3);
  574. #else
  575. ARC_DISPLAY_POSITION_CURSOR(0, OptionStartY + NumValidEntries + 3);
  576. #endif
  577. if(Timeout) {
  578. BlPrint( TEXT("%s"), TimeoutMessage);
  579. BlPrint(TEXT(" %d \n"),SecondsRemaining);
  580. } else {
  581. #ifdef EFI
  582. BlEfiClearToEndOfLine();
  583. #else
  584. ARC_DISPLAY_CLEAR_TO_EOL();
  585. #endif
  586. }
  587. DisplayMenu = FALSE;
  588. }
  589. //
  590. // Poll for a key.
  591. //
  592. Key = BlGetKey();
  593. //
  594. // Any input cancels the timeout.
  595. //
  596. if(Key) {
  597. Timeout = 0;
  598. }
  599. //
  600. // Check for selection.
  601. //
  602. //
  603. // The ESCAPE_KEY does nothing if this is an auto advanced boot.
  604. //
  605. if ((AutoAdvancedBoot == FALSE) && (Key == ESCAPE_KEY)) {
  606. //
  607. // reset the selection to "nothing"
  608. //
  609. return -1;
  610. }
  611. if ( (Key==UP_ARROW) || (Key==DOWN_ARROW) || (Key==HOME_KEY) || (Key==END_KEY)) {
  612. DisplayMenu = TRUE;
  613. if (Key==DOWN_ARROW) {
  614. Selection = (Selection+1) % MaxAdvancedBootOptions;
  615. } else if (Key==UP_ARROW) {
  616. Selection = (Selection == 0) ? (MaxAdvancedBootOptions-1) : (Selection - 1);
  617. } else if (Key==HOME_KEY) {
  618. Selection = 0;
  619. } else if (Key==END_KEY) {
  620. Selection = MaxAdvancedBootOptions-1;
  621. //
  622. // search for the last valid entry
  623. //
  624. i = Selection;
  625. while (AdvancedBootOptions[i].UseEntry == FALSE) {
  626. i -= 1;
  627. }
  628. Selection = i;
  629. }
  630. //
  631. // don't let the highlight line rest on a blank line
  632. //
  633. while((AdvancedBootOptions[Selection].UseEntry == FALSE) ||
  634. (AdvancedBootOptions[Selection].MenuType == MENU_BLANK_LINE)) {
  635. if(Key == DOWN_ARROW) {
  636. Selection = (Selection + 1) % MaxAdvancedBootOptions;
  637. } else if (Key == UP_ARROW) {
  638. Selection = (Selection == 0) ? (MaxAdvancedBootOptions - 1) : (Selection - 1);
  639. }
  640. }
  641. }
  642. } while ( ((Key&(ULONG)0xff) != ENTER_KEY) );
  643. //
  644. // If Return to OS Choices selected, go back to main menu
  645. //
  646. if ((Selection != -1) &&
  647. (AdvancedBootOptions[Selection].MsgId == BL_MSG_OSCHOICES_MENU)) {
  648. Selection = -1;
  649. }
  650. return Selection;
  651. }