]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenu.c
MdeModulePkg/BootManagerMenu: Fix bug that boots to undesired option
[mirror_edk2.git] / MdeModulePkg / Application / BootManagerMenuApp / BootManagerMenu.c
CommitLineData
a382952f
RN
1/** @file\r
2 The application to show the Boot Manager Menu.\r
3\r
4Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>\r
5This program and the accompanying materials\r
6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
8http://opensource.org/licenses/bsd-license.php\r
9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "BootManagerMenu.h"\r
16\r
17EFI_HII_HANDLE gStringPackHandle;\r
18\r
19BOOLEAN mModeInitialized = FALSE;\r
20\r
21//\r
22// Boot video resolution and text mode.\r
23//\r
24UINT32 mBootHorizontalResolution = 0;\r
25UINT32 mBootVerticalResolution = 0;\r
26UINT32 mBootTextModeColumn = 0;\r
27UINT32 mBootTextModeRow = 0;\r
28//\r
29// BIOS setup video resolution and text mode.\r
30//\r
31UINT32 mSetupTextModeColumn = 0;\r
32UINT32 mSetupTextModeRow = 0;\r
33UINT32 mSetupHorizontalResolution = 0;\r
34UINT32 mSetupVerticalResolution = 0;\r
35\r
36/**\r
37 Prints a unicode string to the default console, at\r
38 the supplied cursor position, using L"%s" format.\r
39\r
40 @param Column The cursor position to print the string at.\r
41 @param Row The cursor position to print the string at\r
42 @param String String pointer.\r
43\r
44 @return Length of string printed to the console\r
45\r
46**/\r
47UINTN\r
48PrintStringAt (\r
49 IN UINTN Column,\r
50 IN UINTN Row,\r
51 IN CHAR16 *String\r
52 )\r
53{\r
54\r
55 gST->ConOut->SetCursorPosition (gST->ConOut, Column, Row);\r
56 return Print (L"%s", String);\r
57}\r
58\r
59/**\r
60 Prints a chracter to the default console, at\r
61 the supplied cursor position, using L"%c" format.\r
62\r
63 @param Column The cursor position to print the string at.\r
64 @param Row The cursor position to print the string at.\r
65 @param Character Character to print.\r
66\r
67 @return Length of string printed to the console.\r
68\r
69**/\r
70UINTN\r
71PrintCharAt (\r
72 IN UINTN Column,\r
73 IN UINTN Row,\r
74 CHAR16 Character\r
75 )\r
76{\r
77 gST->ConOut->SetCursorPosition (gST->ConOut, Column, Row);\r
78 return Print (L"%c", Character);\r
79}\r
80\r
81/**\r
82 Count the storage space of a Unicode string which uses current lanaguag to get \r
83 from input string ID.\r
84\r
85 @param StringId The input string to be counted.\r
86\r
87 @return Storage space for the input string.\r
88\r
89**/\r
90UINTN\r
91GetLineWidth (\r
92 IN EFI_STRING_ID StringId\r
93 )\r
94{ \r
95 UINTN Index;\r
96 UINTN IncrementValue;\r
97 EFI_STRING String;\r
98 UINTN LineWidth;\r
99 \r
100 LineWidth = 0;\r
101 String = HiiGetString (gStringPackHandle, StringId, NULL); \r
102 \r
103 if (String != NULL) {\r
104 Index = 0;\r
105 IncrementValue = 1;\r
106 \r
107 do {\r
108 //\r
109 // Advance to the null-terminator or to the first width directive\r
110 //\r
111 for (;\r
112 (String[Index] != NARROW_CHAR) && (String[Index] != WIDE_CHAR) && (String[Index] != 0);\r
113 Index++, LineWidth = LineWidth + IncrementValue\r
114 )\r
115 ;\r
116 \r
117 //\r
118 // We hit the null-terminator, we now have a count\r
119 //\r
120 if (String[Index] == 0) {\r
121 break;\r
122 }\r
123 //\r
124 // We encountered a narrow directive - strip it from the size calculation since it doesn't get printed\r
125 // and also set the flag that determines what we increment by.(if narrow, increment by 1, if wide increment by 2)\r
126 //\r
127 if (String[Index] == NARROW_CHAR) {\r
128 //\r
129 // Skip to the next character\r
130 //\r
131 Index++;\r
132 IncrementValue = 1;\r
133 } else {\r
134 //\r
135 // Skip to the next character\r
136 //\r
137 Index++;\r
138 IncrementValue = 2;\r
139 }\r
140 } while (String[Index] != 0); \r
141 FreePool (String);\r
142 }\r
143 \r
144 return LineWidth; \r
145}\r
146\r
147/**\r
148 This function uses calculate the boot menu location, size and scroll bar information.\r
149\r
150 @param BootMenuData The boot menu data to be proccessed.\r
151\r
152 @return EFI_SUCCESS calculate boot menu information successful.\r
153 @retval EFI_INVALID_PARAMETER Input parameter is invalid \r
154\r
155**/\r
156EFI_STATUS \r
157InitializeBootMenuScreen (\r
158 IN OUT BOOT_MENU_POPUP_DATA *BootMenuData\r
159 )\r
160{\r
161 UINTN MaxStrWidth;\r
162 UINTN StrWidth;\r
163 UINTN Index;\r
164 UINTN Column;\r
165 UINTN Row;\r
166 UINTN MaxPrintRows;\r
167 UINTN UnSelectableItmes;\r
168\r
169 if (BootMenuData == NULL) {\r
170 return EFI_INVALID_PARAMETER;\r
171 }\r
172 //\r
173 // Get maximum string width\r
174 //\r
175 MaxStrWidth = 0; \r
176 for (Index = 0; Index < TITLE_TOKEN_COUNT; Index++) { \r
177 StrWidth = GetLineWidth (BootMenuData->TitleToken[Index]);\r
178 MaxStrWidth = MaxStrWidth > StrWidth ? MaxStrWidth : StrWidth;\r
179 }\r
180 \r
181 for (Index = 0; Index < BootMenuData->ItemCount; Index++) {\r
182 StrWidth = GetLineWidth (BootMenuData->PtrTokens[Index]);\r
183 MaxStrWidth = MaxStrWidth > StrWidth ? MaxStrWidth : StrWidth; \r
184 } \r
185 \r
186 for (Index = 0; Index < HELP_TOKEN_COUNT; Index++) { \r
187 StrWidth = GetLineWidth (BootMenuData->HelpToken[Index]);\r
188 MaxStrWidth = MaxStrWidth > StrWidth ? MaxStrWidth : StrWidth;\r
189 } \r
190 //\r
191 // query current row and column to calculate boot menu location\r
192 //\r
193 gST->ConOut->QueryMode (\r
194 gST->ConOut,\r
195 gST->ConOut->Mode->Mode,\r
196 &Column,\r
197 &Row\r
198 ); \r
199 \r
200 MaxPrintRows = Row - 6; \r
201 UnSelectableItmes = TITLE_TOKEN_COUNT + 2 + HELP_TOKEN_COUNT + 2; \r
202 BootMenuData->MenuScreen.Width = MaxStrWidth + 8;\r
203 if (BootMenuData->ItemCount + UnSelectableItmes > MaxPrintRows) {\r
204 BootMenuData->MenuScreen.Height = MaxPrintRows;\r
205 BootMenuData->ScrollBarControl.HasScrollBar = TRUE;\r
206 BootMenuData->ScrollBarControl.ItemCountPerScreen = MaxPrintRows - UnSelectableItmes;\r
207 BootMenuData->ScrollBarControl.FirstItem = 0;\r
208 BootMenuData->ScrollBarControl.LastItem = MaxPrintRows - UnSelectableItmes - 1;\r
209 } else {\r
210 BootMenuData->MenuScreen.Height = BootMenuData->ItemCount + UnSelectableItmes;\r
211 BootMenuData->ScrollBarControl.HasScrollBar = FALSE;\r
212 BootMenuData->ScrollBarControl.ItemCountPerScreen = BootMenuData->ItemCount;\r
213 BootMenuData->ScrollBarControl.FirstItem = 0;\r
214 BootMenuData->ScrollBarControl.LastItem = BootMenuData->ItemCount - 1; \r
215 }\r
216 BootMenuData->MenuScreen.StartCol = (Column - BootMenuData->MenuScreen.Width) / 2; \r
217 BootMenuData->MenuScreen.StartRow = (Row - BootMenuData->MenuScreen.Height) / 2; \r
218\r
219 return EFI_SUCCESS;\r
220}\r
221/**\r
222 This funciton uses check boot option is wheher setup application or no\r
223\r
224 @param BootOption Pointer to EFI_BOOT_MANAGER_LOAD_OPTION array.\r
225 \r
226 @retval TRUE This boot option is setup application.\r
227 @retval FALSE This boot options isn't setup application\r
228\r
229**/\r
230BOOLEAN\r
231IsBootManagerMenu (\r
232 IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOption\r
233 )\r
234{\r
235 EFI_STATUS Status;\r
236 EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu;\r
237\r
238 Status = EfiBootManagerGetBootManagerMenu (&BootManagerMenu);\r
239 if (!EFI_ERROR (Status)) {\r
240 EfiBootManagerFreeLoadOption (&BootManagerMenu);\r
241 }\r
242\r
243 return (BOOLEAN) (!EFI_ERROR (Status) && (BootOption->OptionNumber == BootManagerMenu.OptionNumber));\r
244}\r
7df23f85
RN
245\r
246/**\r
247 Return whether to ignore the boot option.\r
248\r
249 @param BootOption Pointer to EFI_BOOT_MANAGER_LOAD_OPTION to check.\r
250\r
251 @retval TRUE Ignore the boot optin.\r
252 @retval FALSE Do not ignore the boot option.\r
253**/\r
254BOOLEAN\r
255IgnoreBootOption (\r
256 IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOption\r
257 )\r
258{\r
259 EFI_STATUS Status;\r
260 EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath;\r
261\r
262 //\r
263 // Ignore myself.\r
264 //\r
265 Status = gBS->HandleProtocol (gImageHandle, &gEfiLoadedImageDevicePathProtocolGuid, (VOID **) &ImageDevicePath);\r
266 ASSERT_EFI_ERROR (Status);\r
267 if (CompareMem (BootOption->FilePath, ImageDevicePath, GetDevicePathSize (ImageDevicePath)) == 0) {\r
268 return TRUE;\r
269 }\r
270\r
271 //\r
272 // Do not ignore Boot Manager Menu.\r
273 //\r
274 if (IsBootManagerMenu (BootOption)) {\r
275 return FALSE;\r
276 }\r
277\r
278 //\r
279 // Ignore the hidden/inactive boot option.\r
280 //\r
281 if (((BootOption->Attributes & LOAD_OPTION_HIDDEN) != 0) || ((BootOption->Attributes & LOAD_OPTION_ACTIVE) == 0)) {\r
282 return TRUE;\r
283 }\r
284\r
285 return FALSE;\r
286}\r
a382952f
RN
287\r
288/**\r
289 This funciton uses to initialize boot menu data\r
290\r
291 @param BootOption Pointer to EFI_BOOT_MANAGER_LOAD_OPTION array.\r
292 @param BootOptionCount Number of boot option.\r
293 @param BootMenuData The Input BootMenuData to be initialized.\r
294 \r
295 @retval EFI_SUCCESS Initialize boot menu data successful.\r
296 @retval EFI_INVALID_PARAMETER Input parameter is invalid. \r
297\r
298**/\r
299EFI_STATUS\r
300InitializeBootMenuData (\r
301 IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOption,\r
302 IN UINTN BootOptionCount,\r
303 OUT BOOT_MENU_POPUP_DATA *BootMenuData\r
304 )\r
305{\r
306 UINTN Index;\r
307 UINTN StrIndex;\r
308 \r
309 if (BootOption == NULL || BootMenuData == NULL) {\r
310 return EFI_INVALID_PARAMETER;\r
26da0b64
RN
311 }\r
312\r
a382952f
RN
313 BootMenuData->TitleToken[0] = STRING_TOKEN (STR_BOOT_POPUP_MENU_TITLE_STRING);\r
314 BootMenuData->PtrTokens = AllocateZeroPool (BootOptionCount * sizeof (EFI_STRING_ID));\r
315 ASSERT (BootMenuData->PtrTokens != NULL);\r
316\r
317 //\r
318 // Skip boot option which created by BootNext Variable\r
319 //\r
320 for (StrIndex = 0, Index = 0; Index < BootOptionCount; Index++) {\r
7df23f85 321 if (IgnoreBootOption (&BootOption[Index])) {\r
26da0b64
RN
322 continue;\r
323 }\r
324\r
a382952f
RN
325 ASSERT (BootOption[Index].Description != NULL);\r
326 BootMenuData->PtrTokens[StrIndex++] = HiiSetString (\r
327 gStringPackHandle, \r
328 0,\r
329 BootOption[Index].Description,\r
330 NULL\r
331 );\r
332 }\r
333\r
334 BootMenuData->ItemCount = StrIndex; \r
335 BootMenuData->HelpToken[0] = STRING_TOKEN (STR_BOOT_POPUP_MENU_HELP1_STRING);\r
336 BootMenuData->HelpToken[1] = STRING_TOKEN (STR_BOOT_POPUP_MENU_HELP2_STRING);\r
337 BootMenuData->HelpToken[2] = STRING_TOKEN (STR_BOOT_POPUP_MENU_HELP3_STRING);\r
338 InitializeBootMenuScreen (BootMenuData);\r
339 BootMenuData->SelectItem = 0;\r
340 return EFI_SUCCESS;\r
341} \r
342\r
343/**\r
344 This function uses input select item to highlight selected item\r
345 and set current selected item in BootMenuData\r
346\r
347 @param WantSelectItem The user wants to select item.\r
348 @param BootMenuData The boot menu data to be proccessed\r
349\r
350 @return EFI_SUCCESS Highlight selected item and update current selected \r
351 item successful \r
352 @retval EFI_INVALID_PARAMETER Input parameter is invalid \r
353**/\r
354EFI_STATUS\r
355BootMenuSelectItem (\r
356 IN UINTN WantSelectItem,\r
357 IN OUT BOOT_MENU_POPUP_DATA *BootMenuData\r
358 )\r
359{\r
360 INT32 SavedAttribute;\r
361 EFI_STRING String;\r
362 UINTN StartCol; \r
363 UINTN StartRow;\r
364 UINTN PrintCol;\r
365 UINTN PrintRow;\r
366 UINTN TopShadeNum;\r
367 UINTN LowShadeNum;\r
368 UINTN FirstItem;\r
369 UINTN LastItem;\r
370 UINTN ItemCountPerScreen;\r
371 UINTN Index;\r
372 BOOLEAN RePaintItems;\r
373 \r
374 if (BootMenuData == NULL || WantSelectItem >= BootMenuData->ItemCount) {\r
375 return EFI_INVALID_PARAMETER;\r
376 }\r
377 SavedAttribute = gST->ConOut->Mode->Attribute;\r
378 RePaintItems = FALSE;\r
379 StartCol = BootMenuData->MenuScreen.StartCol;\r
380 StartRow = BootMenuData->MenuScreen.StartRow;\r
381 //\r
382 // print selectable items again and adjust scroll bar if need\r
383 // \r
384 if (BootMenuData->ScrollBarControl.HasScrollBar &&\r
385 (WantSelectItem < BootMenuData->ScrollBarControl.FirstItem ||\r
386 WantSelectItem > BootMenuData->ScrollBarControl.LastItem ||\r
387 WantSelectItem == BootMenuData->SelectItem)) { \r
388 ItemCountPerScreen = BootMenuData->ScrollBarControl.ItemCountPerScreen;\r
389 //\r
390 // Set first item and last item\r
391 // \r
392 if (WantSelectItem < BootMenuData->ScrollBarControl.FirstItem) {\r
393 BootMenuData->ScrollBarControl.FirstItem = WantSelectItem;\r
394 BootMenuData->ScrollBarControl.LastItem = WantSelectItem + ItemCountPerScreen - 1; \r
395 } else if (WantSelectItem > BootMenuData->ScrollBarControl.LastItem) {\r
396 BootMenuData->ScrollBarControl.FirstItem = WantSelectItem - ItemCountPerScreen + 1; \r
397 BootMenuData->ScrollBarControl.LastItem = WantSelectItem;\r
398 }\r
399 gST->ConOut->SetAttribute (gST->ConOut, EFI_WHITE | EFI_BACKGROUND_BLUE);\r
400 FirstItem = BootMenuData->ScrollBarControl.FirstItem;\r
401 LastItem = BootMenuData->ScrollBarControl.LastItem;\r
402 TopShadeNum = 0;\r
403 if (FirstItem != 0) {\r
404 TopShadeNum = (FirstItem * ItemCountPerScreen) / BootMenuData->ItemCount;\r
405 if ((FirstItem * ItemCountPerScreen) % BootMenuData->ItemCount != 0) {\r
406 TopShadeNum++;\r
407 }\r
408 PrintCol = StartCol + BootMenuData->MenuScreen.Width - 2;\r
409 PrintRow = StartRow + TITLE_TOKEN_COUNT + 2; \r
410 for (Index = 0; Index < TopShadeNum; Index++, PrintRow++) {\r
411 PrintCharAt (PrintCol, PrintRow, BLOCKELEMENT_LIGHT_SHADE);\r
412 }\r
413 }\r
414 LowShadeNum = 0;\r
415 if (LastItem != BootMenuData->ItemCount - 1) {\r
416 LowShadeNum = ((BootMenuData->ItemCount - 1 - LastItem) * ItemCountPerScreen) / BootMenuData->ItemCount;\r
417 if (((BootMenuData->ItemCount - 1 - LastItem) * ItemCountPerScreen) % BootMenuData->ItemCount != 0) {\r
418 LowShadeNum++;\r
419 }\r
420 PrintCol = StartCol + BootMenuData->MenuScreen.Width - 2;\r
421 PrintRow = StartRow + TITLE_TOKEN_COUNT + 2 + ItemCountPerScreen - LowShadeNum; \r
422 for (Index = 0; Index < LowShadeNum; Index++, PrintRow++) {\r
423 PrintCharAt (PrintCol, PrintRow, BLOCKELEMENT_LIGHT_SHADE);\r
424 } \r
425 }\r
426 PrintCol = StartCol + BootMenuData->MenuScreen.Width - 2;\r
427 PrintRow = StartRow + TITLE_TOKEN_COUNT + 2 + TopShadeNum; \r
428 for (Index = TopShadeNum; Index < ItemCountPerScreen - LowShadeNum; Index++, PrintRow++) {\r
429 PrintCharAt (PrintCol, PrintRow, BLOCKELEMENT_FULL_BLOCK);\r
430 } \r
431\r
432\r
433 //\r
434 // Clear selectable items first\r
435 //\r
436 PrintCol = StartCol + 1;\r
437 PrintRow = StartRow + TITLE_TOKEN_COUNT + 2; \r
438 String = AllocateZeroPool ((BootMenuData->MenuScreen.Width - 2) * sizeof (CHAR16));\r
439 ASSERT (String != NULL);\r
440 for (Index = 0; Index < BootMenuData->MenuScreen.Width - 3; Index++) {\r
441 String[Index] = 0x20;\r
442 } \r
443 for (Index = 0; Index < ItemCountPerScreen; Index++) { \r
444 PrintStringAt (PrintCol, PrintRow + Index, String); \r
445 }\r
446 FreePool (String);\r
447 //\r
448 // print selectable items \r
449 //\r
450 for (Index = 0; Index < ItemCountPerScreen; Index++, PrintRow++) {\r
451 String = HiiGetString (gStringPackHandle, BootMenuData->PtrTokens[Index + FirstItem], NULL);\r
452 PrintStringAt (PrintCol, PrintRow, String);\r
453 FreePool (String); \r
454 }\r
455 RePaintItems = TRUE;\r
456 }\r
457 \r
458 //\r
459 // Print want to select item \r
460 //\r
461 FirstItem = BootMenuData->ScrollBarControl.FirstItem;\r
462 gST->ConOut->SetAttribute (gST->ConOut, EFI_WHITE | EFI_BACKGROUND_BLACK);\r
463 String = HiiGetString (gStringPackHandle, BootMenuData->PtrTokens[WantSelectItem], NULL);\r
464 PrintCol = StartCol + 1; \r
465 PrintRow = StartRow + TITLE_TOKEN_COUNT + 2 + WantSelectItem - FirstItem; \r
466 PrintStringAt (PrintCol, PrintRow, String);\r
467 FreePool (String);\r
468 \r
469 //\r
470 // if Want Select and selected item isn't the same and doesn't re-draw selectable \r
471 // items, clear select item\r
472 //\r
473 if (WantSelectItem != BootMenuData->SelectItem && !RePaintItems) {\r
474 gST->ConOut->SetAttribute (gST->ConOut, EFI_WHITE | EFI_BACKGROUND_BLUE);\r
475 String = HiiGetString (gStringPackHandle, BootMenuData->PtrTokens[BootMenuData->SelectItem], NULL);\r
476 PrintCol = StartCol + 1; \r
477 PrintRow = StartRow + 3 + BootMenuData->SelectItem - FirstItem; \r
478 PrintStringAt (PrintCol, PrintRow, String);\r
479 FreePool (String); \r
480 }\r
481\r
482 gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);\r
483 BootMenuData->SelectItem = WantSelectItem;\r
484 return EFI_SUCCESS;\r
485}\r
486\r
487/**\r
488 This funciton uses to draw boot popup menu\r
489\r
490 @param BootMenuData The Input BootMenuData to be processed.\r
491 \r
492 @retval EFI_SUCCESS Draw boot popup menu successful.\r
493\r
494**/\r
495EFI_STATUS \r
496DrawBootPopupMenu (\r
497 IN BOOT_MENU_POPUP_DATA *BootMenuData\r
498 )\r
499{\r
500 EFI_STRING String;\r
501 UINTN Index;\r
502 UINTN Width; \r
503 UINTN Height;\r
504 UINTN StartCol;\r
505 UINTN StartRow;\r
506 UINTN PrintRow;\r
507 UINTN PrintCol;\r
508 UINTN LineWidth;\r
509 INT32 SavedAttribute; \r
510 UINTN ItemCountPerScreen; \r
511\r
512 gST->ConOut->ClearScreen (gST->ConOut);\r
513 \r
514 SavedAttribute = gST->ConOut->Mode->Attribute;\r
515 gST->ConOut->SetAttribute (gST->ConOut, EFI_WHITE | EFI_BACKGROUND_BLUE);\r
516 Width = BootMenuData->MenuScreen.Width;\r
517 Height = BootMenuData->MenuScreen.Height;\r
518 StartCol = BootMenuData->MenuScreen.StartCol;\r
519 StartRow = BootMenuData->MenuScreen.StartRow;\r
520 ItemCountPerScreen = BootMenuData->ScrollBarControl.ItemCountPerScreen;\r
521 PrintRow = StartRow;\r
522 \r
523 gST->ConOut->EnableCursor (gST->ConOut, FALSE);\r
524 //\r
525 // Draw Boot popup menu screen\r
526 //\r
527 PrintCharAt (StartCol, PrintRow, BOXDRAW_DOWN_RIGHT);\r
528 for (Index = 1; Index < Width - 1; Index++) {\r
529 PrintCharAt (StartCol + Index, PrintRow, BOXDRAW_HORIZONTAL); \r
530 }\r
531 PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_DOWN_LEFT);\r
532 \r
533 //\r
534 // Draw the screen for title\r
535 //\r
536 String = AllocateZeroPool ((Width - 1) * sizeof (CHAR16));\r
537 ASSERT (String != NULL);\r
538 for (Index = 0; Index < Width - 2; Index++) {\r
539 String[Index] = 0x20;\r
540 }\r
541\r
542 for (Index = 0; Index < TITLE_TOKEN_COUNT; Index++) {\r
543 PrintRow++;\r
544 PrintCharAt (StartCol, PrintRow, BOXDRAW_VERTICAL); \r
545 PrintStringAt (StartCol + 1, PrintRow, String);\r
546 PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_VERTICAL);\r
547 }\r
548 \r
549 PrintRow++;\r
550 PrintCharAt (StartCol, PrintRow, BOXDRAW_VERTICAL_RIGHT);\r
551 for (Index = 1; Index < Width - 1; Index++) {\r
552 PrintCharAt (StartCol + Index, PrintRow, BOXDRAW_HORIZONTAL); \r
553 }\r
554 PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_VERTICAL_LEFT); \r
555 \r
556 //\r
557 // Draw screen for selectable items\r
558 //\r
559 for (Index = 0; Index < ItemCountPerScreen; Index++) {\r
560 PrintRow++;\r
561 PrintCharAt (StartCol, PrintRow, BOXDRAW_VERTICAL);\r
562 PrintStringAt (StartCol + 1, PrintRow, String);\r
563 PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_VERTICAL);\r
564 } \r
565\r
566 PrintRow++;\r
567 PrintCharAt (StartCol, PrintRow, BOXDRAW_VERTICAL_RIGHT);\r
568 for (Index = 1; Index < Width - 1; Index++) {\r
569 PrintCharAt (StartCol + Index, PrintRow, BOXDRAW_HORIZONTAL); \r
570 }\r
571 PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_VERTICAL_LEFT);\r
572 \r
573 //\r
574 // Draw screen for Help\r
575 //\r
576 for (Index = 0; Index < HELP_TOKEN_COUNT; Index++) {\r
577 PrintRow++;\r
578 PrintCharAt (StartCol, PrintRow, BOXDRAW_VERTICAL);\r
579 PrintStringAt (StartCol + 1, PrintRow, String);\r
580 PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_VERTICAL);\r
581 }\r
582 FreePool (String); \r
583 \r
584 PrintRow++; \r
585 PrintCharAt (StartCol, PrintRow, BOXDRAW_UP_RIGHT);\r
586 for (Index = 1; Index < Width - 1; Index++) {\r
587 PrintCharAt (StartCol + Index, PrintRow, BOXDRAW_HORIZONTAL); \r
588 }\r
589 PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_UP_LEFT); \r
590 \r
591 \r
592 //\r
593 // print title strings\r
594 //\r
595 PrintRow = StartRow + 1;\r
596 for (Index = 0; Index < TITLE_TOKEN_COUNT; Index++, PrintRow++) {\r
597 String = HiiGetString (gStringPackHandle, BootMenuData->TitleToken[Index], NULL);\r
598 LineWidth = GetLineWidth (BootMenuData->TitleToken[Index]); \r
599 PrintCol = StartCol + (Width - LineWidth) / 2;\r
600 PrintStringAt (PrintCol, PrintRow, String);\r
601 FreePool (String);\r
602 }\r
603 \r
604 //\r
605 // print selectable items\r
606 //\r
607 PrintCol = StartCol + 1;\r
608 PrintRow = StartRow + TITLE_TOKEN_COUNT + 2; \r
609 for (Index = 0; Index < ItemCountPerScreen; Index++, PrintRow++) {\r
610 String = HiiGetString (gStringPackHandle, BootMenuData->PtrTokens[Index], NULL);\r
611 PrintStringAt (PrintCol, PrintRow, String);\r
612 FreePool (String); \r
613 }\r
614 \r
615 //\r
616 // Print Help strings\r
617 //\r
618 PrintRow++;\r
619 for (Index = 0; Index < HELP_TOKEN_COUNT; Index++, PrintRow++) {\r
620 String = HiiGetString (gStringPackHandle, BootMenuData->HelpToken[Index], NULL);\r
621 LineWidth = GetLineWidth (BootMenuData->HelpToken[Index]);\r
622 PrintCol = StartCol + (Width - LineWidth) / 2;\r
623 PrintStringAt (PrintCol, PrintRow, String);\r
624 FreePool (String);\r
625 }\r
626 \r
627 //\r
628 // Print scroll bar if has scroll bar\r
629 //\r
630 if (BootMenuData->ScrollBarControl.HasScrollBar) {\r
631 PrintCol = StartCol + Width - 2;\r
632 PrintRow = StartRow + 2; \r
633 PrintCharAt (PrintCol, PrintRow, GEOMETRICSHAPE_UP_TRIANGLE); \r
634 PrintCharAt (PrintCol + 1, PrintRow, BOXDRAW_VERTICAL); \r
635 PrintRow += (ItemCountPerScreen + 1); \r
636 PrintCharAt (PrintCol, PrintRow, GEOMETRICSHAPE_DOWN_TRIANGLE);\r
637 PrintCharAt (PrintCol + 1, PrintRow, BOXDRAW_VERTICAL); \r
638 } \r
639 \r
640 gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);\r
641 //\r
642 // Print Selected item\r
643 //\r
644 BootMenuSelectItem (BootMenuData->SelectItem, BootMenuData);\r
645 return EFI_SUCCESS;\r
646}\r
647\r
648/**\r
649 This funciton uses to boot from selected item \r
650\r
651 @param BootOptions Pointer to EFI_BOOT_MANAGER_LOAD_OPTION array.\r
652 @param BootOptionCount Number of boot option.\r
653 @param SelectItem Current selected item.\r
654**/\r
655VOID\r
656BootFromSelectOption (\r
657 IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions,\r
658 IN UINTN BootOptionCount, \r
659 IN UINTN SelectItem\r
660 )\r
661{\r
662 UINTN ItemNum;\r
663 UINTN Index;\r
664\r
665 ASSERT (BootOptions != NULL);\r
666\r
667 for (ItemNum = 0, Index = 0; Index < BootOptionCount; Index++) {\r
7df23f85 668 if (IgnoreBootOption (&BootOptions[Index])) {\r
a382952f
RN
669 continue;\r
670 }\r
7df23f85 671\r
a382952f
RN
672 if (ItemNum++ == SelectItem) {\r
673 EfiBootManagerBoot (&BootOptions[Index]);\r
674 break;\r
675 }\r
676 }\r
677}\r
678\r
679/**\r
680 This function will change video resolution and text mode\r
681 according to defined setup mode or defined boot mode \r
682\r
683 @param IsSetupMode Indicate mode is changed to setup mode or boot mode. \r
684\r
685 @retval EFI_SUCCESS Mode is changed successfully.\r
686 @retval Others Mode failed to be changed.\r
687\r
688**/\r
689EFI_STATUS\r
690EFIAPI\r
691BdsSetConsoleMode (\r
692 BOOLEAN IsSetupMode\r
693 )\r
694{\r
695 EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;\r
696 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOut;\r
697 UINTN SizeOfInfo;\r
698 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;\r
699 UINT32 MaxGopMode;\r
700 UINT32 MaxTextMode;\r
701 UINT32 ModeNumber;\r
702 UINT32 NewHorizontalResolution;\r
703 UINT32 NewVerticalResolution;\r
704 UINT32 NewColumns;\r
705 UINT32 NewRows;\r
706 UINTN HandleCount;\r
707 EFI_HANDLE *HandleBuffer;\r
708 EFI_STATUS Status;\r
709 UINTN Index;\r
710 UINTN CurrentColumn;\r
711 UINTN CurrentRow; \r
712\r
713 MaxGopMode = 0;\r
714 MaxTextMode = 0;\r
715\r
716 //\r
717 // Get current video resolution and text mode \r
718 //\r
719 Status = gBS->HandleProtocol (\r
720 gST->ConsoleOutHandle,\r
721 &gEfiGraphicsOutputProtocolGuid,\r
722 (VOID**)&GraphicsOutput\r
723 );\r
724 if (EFI_ERROR (Status)) {\r
725 GraphicsOutput = NULL;\r
726 }\r
727\r
728 Status = gBS->HandleProtocol (\r
729 gST->ConsoleOutHandle,\r
730 &gEfiSimpleTextOutProtocolGuid,\r
731 (VOID**)&SimpleTextOut\r
732 );\r
733 if (EFI_ERROR (Status)) {\r
734 SimpleTextOut = NULL;\r
735 } \r
736\r
737 if ((GraphicsOutput == NULL) || (SimpleTextOut == NULL)) {\r
738 return EFI_UNSUPPORTED;\r
739 }\r
740\r
741 if (IsSetupMode) {\r
742 //\r
743 // The requried resolution and text mode is setup mode.\r
744 //\r
745 NewHorizontalResolution = mSetupHorizontalResolution;\r
746 NewVerticalResolution = mSetupVerticalResolution;\r
747 NewColumns = mSetupTextModeColumn;\r
748 NewRows = mSetupTextModeRow;\r
749 } else {\r
750 //\r
751 // The required resolution and text mode is boot mode.\r
752 //\r
753 NewHorizontalResolution = mBootHorizontalResolution;\r
754 NewVerticalResolution = mBootVerticalResolution;\r
755 NewColumns = mBootTextModeColumn;\r
756 NewRows = mBootTextModeRow; \r
757 }\r
758 \r
759 if (GraphicsOutput != NULL) {\r
760 MaxGopMode = GraphicsOutput->Mode->MaxMode;\r
761 } \r
762\r
763 if (SimpleTextOut != NULL) {\r
764 MaxTextMode = SimpleTextOut->Mode->MaxMode;\r
765 }\r
766\r
767 //\r
768 // 1. If current video resolution is same with required video resolution,\r
769 // video resolution need not be changed.\r
770 // 1.1. If current text mode is same with required text mode, text mode need not be changed.\r
771 // 1.2. If current text mode is different from required text mode, text mode need be changed.\r
772 // 2. If current video resolution is different from required video resolution, we need restart whole console drivers.\r
773 //\r
774 for (ModeNumber = 0; ModeNumber < MaxGopMode; ModeNumber++) {\r
775 Status = GraphicsOutput->QueryMode (\r
776 GraphicsOutput,\r
777 ModeNumber,\r
778 &SizeOfInfo,\r
779 &Info\r
780 );\r
781 if (!EFI_ERROR (Status)) {\r
782 if ((Info->HorizontalResolution == NewHorizontalResolution) &&\r
783 (Info->VerticalResolution == NewVerticalResolution)) {\r
784 if ((GraphicsOutput->Mode->Info->HorizontalResolution == NewHorizontalResolution) &&\r
785 (GraphicsOutput->Mode->Info->VerticalResolution == NewVerticalResolution)) {\r
786 //\r
787 // Current resolution is same with required resolution, check if text mode need be set\r
788 //\r
789 Status = SimpleTextOut->QueryMode (SimpleTextOut, SimpleTextOut->Mode->Mode, &CurrentColumn, &CurrentRow);\r
790 ASSERT_EFI_ERROR (Status);\r
791 if (CurrentColumn == NewColumns && CurrentRow == NewRows) {\r
792 //\r
793 // If current text mode is same with required text mode. Do nothing\r
794 //\r
795 FreePool (Info);\r
796 return EFI_SUCCESS;\r
797 } else {\r
798 //\r
799 // If current text mode is different from requried text mode. Set new video mode\r
800 //\r
801 for (Index = 0; Index < MaxTextMode; Index++) {\r
802 Status = SimpleTextOut->QueryMode (SimpleTextOut, Index, &CurrentColumn, &CurrentRow);\r
803 if (!EFI_ERROR(Status)) {\r
804 if ((CurrentColumn == NewColumns) && (CurrentRow == NewRows)) {\r
805 //\r
806 // Required text mode is supported, set it.\r
807 //\r
808 Status = SimpleTextOut->SetMode (SimpleTextOut, Index);\r
809 ASSERT_EFI_ERROR (Status);\r
810 //\r
811 // Update text mode PCD.\r
812 //\r
377680ae
ED
813 Status = PcdSet32S (PcdConOutColumn, mSetupTextModeColumn);\r
814 ASSERT_EFI_ERROR (Status);\r
815 Status = PcdSet32S (PcdConOutRow, mSetupTextModeRow);\r
816 ASSERT_EFI_ERROR (Status);\r
a382952f
RN
817 FreePool (Info);\r
818 return EFI_SUCCESS;\r
819 }\r
820 }\r
821 }\r
822 if (Index == MaxTextMode) {\r
823 //\r
824 // If requried text mode is not supported, return error.\r
825 //\r
826 FreePool (Info);\r
827 return EFI_UNSUPPORTED;\r
828 }\r
829 }\r
830 } else {\r
831 //\r
832 // If current video resolution is not same with the new one, set new video resolution.\r
833 // In this case, the driver which produces simple text out need be restarted.\r
834 //\r
835 Status = GraphicsOutput->SetMode (GraphicsOutput, ModeNumber);\r
836 if (!EFI_ERROR (Status)) {\r
837 FreePool (Info);\r
838 break;\r
839 }\r
840 }\r
841 }\r
842 FreePool (Info);\r
843 }\r
844 }\r
845\r
846 if (ModeNumber == MaxGopMode) {\r
847 //\r
848 // If the resolution is not supported, return error.\r
849 //\r
850 return EFI_UNSUPPORTED;\r
851 }\r
852\r
853 //\r
854 // Set PCD to Inform GraphicsConsole to change video resolution.\r
855 // Set PCD to Inform Consplitter to change text mode.\r
856 //\r
377680ae
ED
857 Status = PcdSet32S (PcdVideoHorizontalResolution, NewHorizontalResolution);\r
858 ASSERT_EFI_ERROR (Status);\r
859 Status = PcdSet32S (PcdVideoVerticalResolution, NewVerticalResolution);\r
860 ASSERT_EFI_ERROR (Status);\r
861 Status = PcdSet32S (PcdConOutColumn, NewColumns);\r
862 ASSERT_EFI_ERROR (Status);\r
863 Status = PcdSet32S (PcdConOutRow, NewRows);\r
864 ASSERT_EFI_ERROR (Status);\r
a382952f
RN
865 \r
866 //\r
867 // Video mode is changed, so restart graphics console driver and higher level driver.\r
868 // Reconnect graphics console driver and higher level driver.\r
869 // Locate all the handles with GOP protocol and reconnect it.\r
870 //\r
871 Status = gBS->LocateHandleBuffer (\r
872 ByProtocol,\r
873 &gEfiSimpleTextOutProtocolGuid,\r
874 NULL,\r
875 &HandleCount,\r
876 &HandleBuffer\r
877 );\r
878 if (!EFI_ERROR (Status)) {\r
879 for (Index = 0; Index < HandleCount; Index++) {\r
880 gBS->DisconnectController (HandleBuffer[Index], NULL, NULL);\r
881 }\r
882 for (Index = 0; Index < HandleCount; Index++) {\r
883 gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);\r
884 }\r
885 if (HandleBuffer != NULL) {\r
886 FreePool (HandleBuffer);\r
887 }\r
888 }\r
889\r
890 return EFI_SUCCESS;\r
891}\r
892\r
893/**\r
894 Display the boot popup menu and allow user select boot item.\r
895\r
896 @param ImageHandle The image handle.\r
897 @param SystemTable The system table.\r
898 \r
899 @retval EFI_SUCCESS Boot from selected boot option, and return success from boot option\r
900 @retval EFI_NOT_FOUND User select to enter setup or can not find boot option\r
901 \r
902**/\r
903EFI_STATUS\r
904EFIAPI\r
905BootManagerMenuEntry (\r
906 IN EFI_HANDLE ImageHandle,\r
907 IN EFI_SYSTEM_TABLE *SystemTable\r
908 )\r
909{\r
910 EFI_BOOT_MANAGER_LOAD_OPTION *BootOption;\r
911 UINTN BootOptionCount; \r
912 EFI_STATUS Status;\r
913 BOOT_MENU_POPUP_DATA BootMenuData;\r
914 UINTN Index;\r
915 EFI_INPUT_KEY Key;\r
916 BOOLEAN ExitApplication;\r
917 UINTN SelectItem;\r
918 EFI_BOOT_LOGO_PROTOCOL *BootLogo;\r
919 EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;\r
920 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOut;\r
921 UINTN BootTextColumn;\r
922 UINTN BootTextRow;\r
923\r
924 //\r
925 // Set Logo status invalid when boot manager menu is launched\r
926 //\r
927 BootLogo = NULL;\r
928 Status = gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo);\r
929 if (!EFI_ERROR (Status) && (BootLogo != NULL)) {\r
930 Status = BootLogo->SetBootLogo (BootLogo, NULL, 0, 0, 0, 0);\r
931 ASSERT_EFI_ERROR (Status);\r
932 }\r
933\r
934 gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);\r
935\r
936 gStringPackHandle = HiiAddPackages (\r
937 &gEfiCallerIdGuid,\r
938 gImageHandle,\r
939 BootManagerMenuAppStrings,\r
940 NULL\r
941 );\r
942 ASSERT (gStringPackHandle != NULL);\r
943\r
944 //\r
945 // Connect all prior to entering the platform setup menu.\r
946 //\r
947 EfiBootManagerConnectAll ();\r
948 EfiBootManagerRefreshAllBootOption ();\r
949\r
950 BootOption = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);\r
951\r
952 if (!mModeInitialized) {\r
953 //\r
954 // After the console is ready, get current video resolution \r
955 // and text mode before launching setup at first time.\r
956 //\r
957 Status = gBS->HandleProtocol (\r
958 gST->ConsoleOutHandle,\r
959 &gEfiGraphicsOutputProtocolGuid,\r
960 (VOID**)&GraphicsOutput\r
961 );\r
962 if (EFI_ERROR (Status)) {\r
963 GraphicsOutput = NULL;\r
964 }\r
965 \r
966 Status = gBS->HandleProtocol (\r
967 gST->ConsoleOutHandle,\r
968 &gEfiSimpleTextOutProtocolGuid,\r
969 (VOID**)&SimpleTextOut\r
970 );\r
971 if (EFI_ERROR (Status)) {\r
972 SimpleTextOut = NULL;\r
973 } \r
974\r
975 if (GraphicsOutput != NULL) {\r
976 //\r
977 // Get current video resolution and text mode.\r
978 //\r
979 mBootHorizontalResolution = GraphicsOutput->Mode->Info->HorizontalResolution;\r
980 mBootVerticalResolution = GraphicsOutput->Mode->Info->VerticalResolution;\r
981 }\r
982\r
983 if (SimpleTextOut != NULL) {\r
984 Status = SimpleTextOut->QueryMode (\r
985 SimpleTextOut,\r
986 SimpleTextOut->Mode->Mode,\r
987 &BootTextColumn,\r
988 &BootTextRow\r
989 );\r
990 mBootTextModeColumn = (UINT32)BootTextColumn;\r
991 mBootTextModeRow = (UINT32)BootTextRow;\r
992 }\r
993\r
994 //\r
995 // Get user defined text mode for setup.\r
996 // \r
997 mSetupHorizontalResolution = PcdGet32 (PcdSetupVideoHorizontalResolution);\r
998 mSetupVerticalResolution = PcdGet32 (PcdSetupVideoVerticalResolution); \r
999 mSetupTextModeColumn = PcdGet32 (PcdSetupConOutColumn);\r
1000 mSetupTextModeRow = PcdGet32 (PcdSetupConOutRow);\r
1001 mModeInitialized = TRUE;\r
1002 }\r
1003 \r
1004 //\r
1005 // Set back to conventional setup resolution\r
1006 //\r
1007 BdsSetConsoleMode (TRUE);\r
1008\r
1009 //\r
1010 // Initialize Boot menu data\r
1011 //\r
1012 Status = InitializeBootMenuData (BootOption, BootOptionCount, &BootMenuData);\r
1013 //\r
1014 // According to boot menu data to draw boot popup menu\r
1015 //\r
1016 DrawBootPopupMenu (&BootMenuData);\r
1017 \r
1018 //\r
1019 // check user input to determine want to re-draw or boot from user selected item\r
1020 //\r
1021 ExitApplication = FALSE;\r
1022 while (!ExitApplication) {\r
1023 gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &Index);\r
1024 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
1025 if (!EFI_ERROR (Status)) {\r
1026 switch (Key.UnicodeChar) {\r
1027 \r
1028 case CHAR_NULL: \r
1029 switch (Key.ScanCode) { \r
1030 \r
1031 case SCAN_UP:\r
1032 SelectItem = BootMenuData.SelectItem == 0 ? BootMenuData.ItemCount - 1 : BootMenuData.SelectItem - 1;\r
1033 BootMenuSelectItem (SelectItem, &BootMenuData); \r
1034 break;\r
1035 \r
1036 case SCAN_DOWN:\r
1037 SelectItem = BootMenuData.SelectItem == BootMenuData.ItemCount - 1 ? 0 : BootMenuData.SelectItem + 1;\r
1038 BootMenuSelectItem (SelectItem, &BootMenuData); \r
1039 break;\r
1040\r
1041 case SCAN_ESC:\r
1042 gST->ConOut->ClearScreen (gST->ConOut);\r
1043 ExitApplication = TRUE;\r
1044 //\r
1045 // Set boot resolution for normal boot\r
1046 //\r
1047 BdsSetConsoleMode (FALSE);\r
1048 break;\r
1049 \r
1050 default:\r
1051 break;\r
1052 }\r
1053 break;\r
1054 \r
1055 case CHAR_CARRIAGE_RETURN:\r
1056 gST->ConOut->ClearScreen (gST->ConOut);\r
1057 //\r
1058 // Set boot resolution for normal boot\r
1059 //\r
1060 BdsSetConsoleMode (FALSE);\r
1061 BootFromSelectOption (BootOption, BootOptionCount, BootMenuData.SelectItem);\r
1062 //\r
1063 // Back to boot manager menu again, set back to setup resolution\r
1064 //\r
1065 BdsSetConsoleMode (TRUE);\r
1066 DrawBootPopupMenu (&BootMenuData);\r
1067 break;\r
1068 \r
1069 default:\r
1070 break;\r
1071 }\r
1072 }\r
1073 }\r
1074 EfiBootManagerFreeLoadOptions (BootOption, BootOptionCount);\r
1075 FreePool (BootMenuData.PtrTokens);\r
1076\r
1077 HiiRemovePackages (gStringPackHandle);\r
1078\r
1079 return Status;\r
1080 \r
1081}\r