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.

898 lines
22 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. #define BL_INVALID_ADVANCED_BOOT_OPTION (ULONG)-1
  53. #define BL_INVALID_TIME (ULONG)-1
  54. typedef void (*PADVANCED_BOOT_PROCESSING)(void);
  55. typedef int (*PADVANCED_BOOT_ISVALID)(void);
  56. typedef struct _ADVANCEDBOOT_OPTIONS {
  57. ULONG MenuType;
  58. ULONG MsgId;
  59. PTSTR DisplayStr;
  60. PSTR LoadOptions;
  61. LONG RemoveIfPresent;
  62. ULONG UseEntry;
  63. ULONG AutoAdvancedBootOption;
  64. PADVANCED_BOOT_PROCESSING ProcessFunc;
  65. PADVANCED_BOOT_ISVALID IsValid;
  66. BOOLEAN IsDefault;
  67. } ADVANCEDBOOT_OPTIONS, PADVANCEDBOOT_OPTIONS;
  68. //
  69. // some prototypes that are needed for
  70. // the menu definitions.
  71. //
  72. void
  73. BlProcessLastKnownGoodOption(
  74. void
  75. );
  76. int
  77. BlIsReturnToOSChoicesValid(
  78. VOID
  79. );
  80. #if defined(REMOTE_BOOT)
  81. void
  82. BlProcessOschooserOption(
  83. void
  84. );
  85. void
  86. BlProcessRepinOption(
  87. void
  88. );
  89. void
  90. BlDisableCSC(
  91. void
  92. );
  93. void
  94. BlBootNormally(
  95. void
  96. );
  97. void
  98. BlReturnToOSChoiceMenu(
  99. void
  100. );
  101. int
  102. BlIsRemoteBootValid(
  103. void
  104. );
  105. #endif // defined(REMOTE_BOOT)
  106. //
  107. // this table drives the advanced boot menu screen.
  108. // of you need to add something to the screen then
  109. // this is what you need to modify.
  110. //
  111. ADVANCEDBOOT_OPTIONS AdvancedBootOptions[] =
  112. {
  113. { MENU_ITEM, BL_SAFEBOOT_OPTION1, NULL, "SAFEBOOT:MINIMAL SOS BOOTLOG NOGUIBOOT", -1, 0, 1, NULL, NULL, FALSE},
  114. { MENU_ITEM, BL_SAFEBOOT_OPTION2, NULL, "SAFEBOOT:NETWORK SOS BOOTLOG NOGUIBOOT", -1, 0, 1, NULL, NULL, FALSE},
  115. { MENU_ITEM, BL_SAFEBOOT_OPTION4, NULL, "SAFEBOOT:MINIMAL(ALTERNATESHELL) SOS BOOTLOG NOGUIBOOT", -1, 0, 1, NULL, NULL, FALSE},
  116. // { MENU_ITEM, BL_SAFEBOOT_OPTION3, NULL, "SAFEBOOT:STEPBYSTEP SOS BOOTLOG", -1, 0, 1, NULL, NULL, FALSE},
  117. { MENU_BLANK_LINE, 0, NULL, NULL, -1, 0, 1, NULL, NULL, FALSE},
  118. { MENU_ITEM, BL_BOOTLOG, NULL, "BOOTLOG", -1, 0, 0, NULL, NULL, FALSE},
  119. { MENU_ITEM, BL_BASEVIDEO, NULL, "BASEVIDEO", -1, 0, 0, NULL, NULL, FALSE},
  120. { MENU_ITEM, BL_LASTKNOWNGOOD_OPTION, NULL, NULL, -1, 0, 1, BlProcessLastKnownGoodOption, NULL, FALSE},
  121. { MENU_ITEM, BL_SAFEBOOT_OPTION6, NULL, "SAFEBOOT:DSREPAIR SOS", -1, 0, 0, NULL, NULL, FALSE},
  122. { MENU_ITEM, BL_DEBUG_OPTION, NULL, "DEBUG", -1, 0, 0, NULL, NULL, FALSE},
  123. #if defined(REMOTE_BOOT)
  124. { MENU_BLANK_LINE, 0, NULL, NULL, -1, 0, 0, NULL, BlIsRemoteBootValid, FALSE},
  125. { MENU_ITEM, BL_REMOTEBOOT_OPTION1, NULL, NULL, -1, 0, 0, BlProcessOschooserOption, BlIsRemoteBootValid, FALSE},
  126. { MENU_ITEM, BL_REMOTEBOOT_OPTION2, NULL, NULL, -1, 0, 0, BlProcessRepinOption, BlIsRemoteBootValid, FALSE},
  127. { MENU_ITEM, BL_REMOTEBOOT_OPTION3, NULL, NULL, -1, 0, 0, BlDisableCSC, BlIsRemoteBootValid, FALSE},
  128. #endif // defined(REMOTE_BOOT)
  129. { MENU_BLANK_LINE, 0, NULL, NULL, -1, 0, 1, NULL, NULL, FALSE},
  130. { MENU_ITEM, BL_MSG_BOOT_NORMALLY, NULL, NULL, -1, 0, 1, NULL, NULL, TRUE},
  131. { MENU_ITEM, BL_MSG_REBOOT, NULL, NULL, -1, 0, 0, NULL, NULL, FALSE},
  132. { MENU_ITEM, BL_MSG_OSCHOICES_MENU, NULL, NULL, -1, 0, 0, NULL, BlIsReturnToOSChoicesValid, FALSE}
  133. };
  134. #define MaxAdvancedBootOptions (sizeof(AdvancedBootOptions)/sizeof(ADVANCEDBOOT_OPTIONS))
  135. PTSTR
  136. BlGetAdvancedBootDisplayString(
  137. LONG BootOption
  138. )
  139. /*++
  140. Routine Description:
  141. Returns a pointer to the display string for a specific
  142. boot option.
  143. Arguments:
  144. BootOption - Desired boot option. Must correspond to an entry
  145. in the AdvancedBootOptions table.
  146. Return Value:
  147. PSTR - Pointer to the display string for the specified boot option.
  148. --*/
  149. {
  150. if (BootOption > MaxAdvancedBootOptions-1) {
  151. return TEXT("");
  152. }
  153. return AdvancedBootOptions[BootOption].DisplayStr;
  154. }
  155. ULONG
  156. BlGetAdvancedBootID(
  157. LONG BootOption
  158. )
  159. /*++
  160. Routine Description:
  161. Returns a ULONG indicating the string ID for a specific
  162. boot option.
  163. Arguments:
  164. BootOption - Desired boot option. Must correspond to an entry
  165. in the AdvancedBootOptions table.
  166. Return Value:
  167. MessageID for the string which is displayed for the
  168. the advanced boot option in the menu (unique ID).
  169. --*/
  170. {
  171. if (BootOption > MaxAdvancedBootOptions-1) {
  172. return BL_INVALID_ADVANCED_BOOT_OPTION;
  173. }
  174. return AdvancedBootOptions[BootOption].MsgId;
  175. }
  176. PSTR
  177. BlGetAdvancedBootLoadOptions(
  178. LONG BootOption
  179. )
  180. /*++
  181. Routine Description:
  182. Returns a pointer to the load options string for a specific
  183. boot option.
  184. Arguments:
  185. BootOption - Desired boot option. Must correspond to an entry
  186. in the AdvancedBootOptions table.
  187. Return Value:
  188. PSTR - Pointer to the load options string for the specified boot option.
  189. --*/
  190. {
  191. if (BootOption > MaxAdvancedBootOptions-1) {
  192. return "";
  193. }
  194. return AdvancedBootOptions[BootOption].LoadOptions;
  195. }
  196. void
  197. BlDoAdvancedBootLoadProcessing(
  198. LONG BootOption
  199. )
  200. /*++
  201. Routine Description:
  202. Performs any processing necessary for a
  203. boot option. This is used if the necessary action
  204. needed for a specific boot option cannot be
  205. expressed in terms of a load option string.
  206. Arguments:
  207. BootOption - Desired boot option. Must correspond to an entry
  208. in the AdvancedBootOptions table.
  209. Return Value:
  210. Nothing.
  211. --*/
  212. {
  213. if (BootOption > MaxAdvancedBootOptions-1 || AdvancedBootOptions[BootOption].ProcessFunc == NULL) {
  214. return;
  215. }
  216. AdvancedBootOptions[BootOption].ProcessFunc();
  217. }
  218. void
  219. BlProcessLastKnownGoodOption(
  220. void
  221. )
  222. /*++
  223. Routine Description:
  224. Performs LKG processing by simply setting a
  225. global boolean to TRUE.
  226. Arguments:
  227. None.
  228. Return Value:
  229. Nothing.
  230. --*/
  231. {
  232. ForceLastKnownGood = TRUE;
  233. }
  234. #if defined(REMOTE_BOOT)
  235. void
  236. BlProcessOschooserOption(
  237. void
  238. )
  239. /*++
  240. Routine Description:
  241. Brings up OSchooser so user can do remote boot maintenance.
  242. Arguments:
  243. None.
  244. Return Value:
  245. Nothing.
  246. --*/
  247. {
  248. return; // not yet implemented
  249. }
  250. void
  251. BlProcessRepinOption(
  252. void
  253. )
  254. /*++
  255. Routine Description:
  256. Sets NetBootRepin to cause the CSC to be repinned.
  257. Arguments:
  258. None.
  259. Return Value:
  260. Nothing.
  261. --*/
  262. {
  263. NetBootRepin = TRUE;
  264. NetBootCSC = FALSE;
  265. }
  266. void
  267. BlDisableCSC(
  268. void
  269. )
  270. /*++
  271. Routine Description:
  272. Clears NetBootCSC to cause the CSC to be disabled so that the local CSC
  273. can be inspected.
  274. Arguments:
  275. None.
  276. Return Value:
  277. Nothing.
  278. --*/
  279. {
  280. NetBootCSC = FALSE;
  281. }
  282. int
  283. BlIsRemoteBootValid(
  284. void
  285. )
  286. /*++
  287. Routine Description:
  288. Used for the remote boot options so that they
  289. can be displayed dynamically.
  290. Arguments:
  291. None.
  292. Return Value:
  293. TRUE or FALSE.
  294. --*/
  295. {
  296. return BlBootingFromNet;
  297. }
  298. #endif // defined(REMOTE_BOOT)
  299. LONG
  300. BlDoAdvancedBoot(
  301. IN ULONG MenuTitleId,
  302. IN LONG DefaultBootOption,
  303. IN BOOLEAN AutoAdvancedBoot,
  304. IN UCHAR Timeout
  305. )
  306. /*++
  307. Routine Description:
  308. Displays the menu of boot options and allows the user to select one
  309. by using the arrow keys.
  310. Arguments:
  311. MenuTitleId - the message ID of the title for the menu. The title
  312. will be different depending on whether the user
  313. selected advanced boot or whether the loader has
  314. determined that the system didn't boot or shutdown
  315. correctly (auto advanced boot)
  316. DefaultBootOption - menu selection to set the highligh on
  317. when the menu is drawn the first time.
  318. AutoAdvancedBoot - the menu is being displayed by the auto-advanced boot
  319. code. In this case a simplified menu is displayed
  320. containing the options relevant to recovering from a
  321. detected crash.
  322. Timeout - the number of seconds to wait for input before
  323. simply returning the default boot option.
  324. A timeout value of 0 means no timeout (the menu will
  325. stay up until an option is chosen)
  326. Return Value:
  327. LONG - The index of the advanced boot option that was selected
  328. or -1 to reset the selection to "nothing".
  329. --*/
  330. {
  331. PTCHAR Title;
  332. PTCHAR MoveHighlight;
  333. ULONG i,j;
  334. ULONG MaxLength;
  335. ULONG CurrentLength;
  336. ULONG Selection;
  337. ULONG Key;
  338. ULONG NumValidEntries = 0;
  339. BOOLEAN DisplayMenu;
  340. PTCHAR TimeoutMessage;
  341. ULONG LastTime;
  342. ULONG TicksRemaining = BL_INVALID_TIME;
  343. ULONG SecondsRemaining = BL_INVALID_TIME;
  344. ULONG OptionStartY;
  345. ULONG CurrentX;
  346. ULONG CurrentY;
  347. ULONG MenuDefault = 0;
  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 BL_INVALID_TIME;
  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 = (ULONG)_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 == BL_INVALID_ADVANCED_BOOT_OPTION) ?
  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. #ifdef EFI
  477. //
  478. // diable the EFI watchdog while waiting for user response
  479. //
  480. DisableEFIWatchDog();
  481. #endif
  482. do {
  483. ULONG CurrentTime = 0;
  484. dbg(("*****"));
  485. //
  486. // Decrement the number of ticks remaining. Compare the current time
  487. // to the last time and subtract that many ticks.
  488. //
  489. if (Timeout) {
  490. ULONG s;
  491. ULONG Delta;
  492. CurrentTime = GET_COUNTER();
  493. dbg(("%x - %x", CurrentTime, LastTime));
  494. //
  495. // The counter wraps at midnight. However if current time is
  496. // less than or equal to last time we'll just ignore this
  497. // iteration.
  498. //
  499. if (CurrentTime >= LastTime) {
  500. Delta = CurrentTime - LastTime;
  501. } else {
  502. Delta = 1;
  503. }
  504. dbg(("= %x. %x - %x = ", Delta, TicksRemaining, Delta));
  505. TicksRemaining -= min(TicksRemaining, Delta);
  506. LastTime = CurrentTime;
  507. dbg(("%x. ", TicksRemaining));
  508. //
  509. // If there are no ticks left then terminate the loop.
  510. //
  511. if(TicksRemaining == 0) {
  512. dbg(("timeout\n"));
  513. dbgbrk();
  514. Selection = BL_INVALID_ADVANCED_BOOT_OPTION;
  515. break;
  516. }
  517. //
  518. // Compute the current number of seconds remaining. If it's not
  519. // equal to what it was before then we'll need to update the
  520. // menu.
  521. //
  522. s = (TicksRemaining * 10) / 182;
  523. dbg(("-> s %x/%x ", SecondsRemaining, s));
  524. if(SecondsRemaining > s) {
  525. SecondsRemaining = s;
  526. DisplayMenu = TRUE;
  527. dbg(("update "));
  528. }
  529. dbg(("\n"));
  530. }
  531. //
  532. // print the menu
  533. //
  534. if (DisplayMenu) {
  535. dbg(("Printing Menu: ticks = %#08lx. Sec = %d. Last = %#08lx Current = %08lx\n",
  536. TicksRemaining,
  537. SecondsRemaining,
  538. LastTime,
  539. CurrentTime
  540. ));
  541. for (i=0,j=1; i<MaxAdvancedBootOptions; i++) {
  542. if (AdvancedBootOptions[i].UseEntry) {
  543. #ifdef EFI
  544. BlEfiPositionCursor(0, OptionStartY + j);
  545. #else
  546. ARC_DISPLAY_POSITION_CURSOR(0, OptionStartY + j);
  547. #endif
  548. if (i==Selection) {
  549. #ifdef EFI
  550. //BlEfiSetInverseMode( TRUE );
  551. BlEfiSetAttribute( INVATT );
  552. #else
  553. ARC_DISPLAY_INVERSE_VIDEO();
  554. #endif
  555. } else {
  556. #ifdef EFI
  557. //BlEfiSetInverseMode( FALSE );
  558. BlEfiSetAttribute( DEFATT );
  559. #else
  560. ARC_DISPLAY_ATTRIBUTES_OFF();
  561. #endif
  562. }
  563. if (AdvancedBootOptions[i].MenuType == MENU_ITEM) {
  564. BlPrint( TEXT(" %s"), AdvancedBootOptions[i].DisplayStr);
  565. }
  566. #ifdef EFI
  567. if (i == Selection) {
  568. //BlEfiSetInverseMode( FALSE );
  569. BlEfiSetAttribute( DEFATT );
  570. }
  571. #else
  572. ARC_DISPLAY_ATTRIBUTES_OFF();
  573. #endif
  574. j += 1;
  575. }
  576. }
  577. #ifdef EFI
  578. BlEfiPositionCursor(0, OptionStartY + NumValidEntries + 3);
  579. #else
  580. ARC_DISPLAY_POSITION_CURSOR(0, OptionStartY + NumValidEntries + 3);
  581. #endif
  582. if(Timeout) {
  583. BlPrint( TEXT("%s"), TimeoutMessage);
  584. BlPrint(TEXT(" %d \n"),SecondsRemaining);
  585. } else {
  586. #ifdef EFI
  587. BlEfiClearToEndOfLine();
  588. #else
  589. ARC_DISPLAY_CLEAR_TO_EOL();
  590. #endif
  591. }
  592. DisplayMenu = FALSE;
  593. }
  594. //
  595. // Poll for a key.
  596. //
  597. Key = BlGetKey();
  598. //
  599. // Any input cancels the timeout.
  600. //
  601. if(Key) {
  602. Timeout = 0;
  603. }
  604. //
  605. // Check for selection.
  606. //
  607. //
  608. // The ESCAPE_KEY does nothing if this is an auto advanced boot.
  609. //
  610. if ((AutoAdvancedBoot == FALSE) && (Key == ESCAPE_KEY)) {
  611. //
  612. // reset the selection to "nothing"
  613. //
  614. #ifdef EFI
  615. //
  616. // reset EFI watchdog before exiting
  617. //
  618. SetEFIWatchDog(EFI_WATCHDOG_TIMEOUT);
  619. #endif
  620. return -1;
  621. }
  622. if ( (Key==UP_ARROW) || (Key==DOWN_ARROW) || (Key==HOME_KEY) || (Key==END_KEY)) {
  623. DisplayMenu = TRUE;
  624. if (Key==DOWN_ARROW) {
  625. Selection = (Selection+1) % MaxAdvancedBootOptions;
  626. } else if (Key==UP_ARROW) {
  627. Selection = (Selection == 0) ? (MaxAdvancedBootOptions-1) : (Selection - 1);
  628. } else if (Key==HOME_KEY) {
  629. Selection = 0;
  630. } else if (Key==END_KEY) {
  631. Selection = MaxAdvancedBootOptions-1;
  632. //
  633. // search for the last valid entry
  634. //
  635. i = Selection;
  636. while (AdvancedBootOptions[i].UseEntry == FALSE) {
  637. i -= 1;
  638. }
  639. Selection = i;
  640. }
  641. //
  642. // don't let the highlight line rest on a blank line
  643. //
  644. while((AdvancedBootOptions[Selection].UseEntry == FALSE) ||
  645. (AdvancedBootOptions[Selection].MenuType == MENU_BLANK_LINE)) {
  646. if(Key == DOWN_ARROW) {
  647. Selection = (Selection + 1) % MaxAdvancedBootOptions;
  648. } else if (Key == UP_ARROW) {
  649. Selection = (Selection == 0) ? (MaxAdvancedBootOptions - 1) : (Selection - 1);
  650. }
  651. }
  652. }
  653. } while ( ((Key&(ULONG)0xff) != ENTER_KEY) );
  654. #ifdef EFI
  655. //
  656. // reset EFI watchdog before exiting
  657. //
  658. SetEFIWatchDog(EFI_WATCHDOG_TIMEOUT);
  659. #endif
  660. //
  661. // If Return to OS Choices selected, go back to main menu
  662. //
  663. if ((Selection != BL_INVALID_ADVANCED_BOOT_OPTION) &&
  664. (AdvancedBootOptions[Selection].MsgId == BL_MSG_OSCHOICES_MENU)) {
  665. Selection = BL_INVALID_ADVANCED_BOOT_OPTION;
  666. }
  667. return Selection;
  668. }