]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenu.c
MdeModulePkg/BootManagerMenu: Add assertion to indicate no DIV by 0
[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
51a1db9b 4Copyright (c) 2011 - 2017, Intel Corporation. All rights reserved.<BR>\r
a382952f
RN
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
04b34efb 60 Prints a character to the default console, at\r
a382952f
RN
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
04b34efb 82 Count the storage space of a Unicode string which uses current language to get\r
a382952f
RN
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
04b34efb 150 @param BootMenuData The boot menu data to be processed.\r
a382952f
RN
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
04b34efb 222 This function uses check boot option is wheher setup application or no\r
a382952f
RN
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
04b34efb 251 @retval TRUE Ignore the boot option.\r
7df23f85
RN
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
04b34efb 289 This function uses to initialize boot menu data\r
a382952f
RN
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
04b34efb 348 @param BootMenuData The boot menu data to be processed\r
a382952f
RN
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
51a1db9b 377 ASSERT (BootMenuData->ItemCount != 0);\r
a382952f
RN
378 SavedAttribute = gST->ConOut->Mode->Attribute;\r
379 RePaintItems = FALSE;\r
380 StartCol = BootMenuData->MenuScreen.StartCol;\r
381 StartRow = BootMenuData->MenuScreen.StartRow;\r
382 //\r
383 // print selectable items again and adjust scroll bar if need\r
384 // \r
385 if (BootMenuData->ScrollBarControl.HasScrollBar &&\r
386 (WantSelectItem < BootMenuData->ScrollBarControl.FirstItem ||\r
387 WantSelectItem > BootMenuData->ScrollBarControl.LastItem ||\r
388 WantSelectItem == BootMenuData->SelectItem)) { \r
389 ItemCountPerScreen = BootMenuData->ScrollBarControl.ItemCountPerScreen;\r
390 //\r
391 // Set first item and last item\r
392 // \r
393 if (WantSelectItem < BootMenuData->ScrollBarControl.FirstItem) {\r
394 BootMenuData->ScrollBarControl.FirstItem = WantSelectItem;\r
395 BootMenuData->ScrollBarControl.LastItem = WantSelectItem + ItemCountPerScreen - 1; \r
396 } else if (WantSelectItem > BootMenuData->ScrollBarControl.LastItem) {\r
397 BootMenuData->ScrollBarControl.FirstItem = WantSelectItem - ItemCountPerScreen + 1; \r
398 BootMenuData->ScrollBarControl.LastItem = WantSelectItem;\r
399 }\r
400 gST->ConOut->SetAttribute (gST->ConOut, EFI_WHITE | EFI_BACKGROUND_BLUE);\r
401 FirstItem = BootMenuData->ScrollBarControl.FirstItem;\r
402 LastItem = BootMenuData->ScrollBarControl.LastItem;\r
403 TopShadeNum = 0;\r
404 if (FirstItem != 0) {\r
405 TopShadeNum = (FirstItem * ItemCountPerScreen) / BootMenuData->ItemCount;\r
406 if ((FirstItem * ItemCountPerScreen) % BootMenuData->ItemCount != 0) {\r
407 TopShadeNum++;\r
408 }\r
409 PrintCol = StartCol + BootMenuData->MenuScreen.Width - 2;\r
410 PrintRow = StartRow + TITLE_TOKEN_COUNT + 2; \r
411 for (Index = 0; Index < TopShadeNum; Index++, PrintRow++) {\r
412 PrintCharAt (PrintCol, PrintRow, BLOCKELEMENT_LIGHT_SHADE);\r
413 }\r
414 }\r
415 LowShadeNum = 0;\r
416 if (LastItem != BootMenuData->ItemCount - 1) {\r
417 LowShadeNum = ((BootMenuData->ItemCount - 1 - LastItem) * ItemCountPerScreen) / BootMenuData->ItemCount;\r
418 if (((BootMenuData->ItemCount - 1 - LastItem) * ItemCountPerScreen) % BootMenuData->ItemCount != 0) {\r
419 LowShadeNum++;\r
420 }\r
421 PrintCol = StartCol + BootMenuData->MenuScreen.Width - 2;\r
422 PrintRow = StartRow + TITLE_TOKEN_COUNT + 2 + ItemCountPerScreen - LowShadeNum; \r
423 for (Index = 0; Index < LowShadeNum; Index++, PrintRow++) {\r
424 PrintCharAt (PrintCol, PrintRow, BLOCKELEMENT_LIGHT_SHADE);\r
425 } \r
426 }\r
427 PrintCol = StartCol + BootMenuData->MenuScreen.Width - 2;\r
428 PrintRow = StartRow + TITLE_TOKEN_COUNT + 2 + TopShadeNum; \r
429 for (Index = TopShadeNum; Index < ItemCountPerScreen - LowShadeNum; Index++, PrintRow++) {\r
430 PrintCharAt (PrintCol, PrintRow, BLOCKELEMENT_FULL_BLOCK);\r
431 } \r
432\r
433\r
434 //\r
435 // Clear selectable items first\r
436 //\r
437 PrintCol = StartCol + 1;\r
438 PrintRow = StartRow + TITLE_TOKEN_COUNT + 2; \r
439 String = AllocateZeroPool ((BootMenuData->MenuScreen.Width - 2) * sizeof (CHAR16));\r
440 ASSERT (String != NULL);\r
441 for (Index = 0; Index < BootMenuData->MenuScreen.Width - 3; Index++) {\r
442 String[Index] = 0x20;\r
443 } \r
444 for (Index = 0; Index < ItemCountPerScreen; Index++) { \r
445 PrintStringAt (PrintCol, PrintRow + Index, String); \r
446 }\r
447 FreePool (String);\r
448 //\r
449 // print selectable items \r
450 //\r
451 for (Index = 0; Index < ItemCountPerScreen; Index++, PrintRow++) {\r
452 String = HiiGetString (gStringPackHandle, BootMenuData->PtrTokens[Index + FirstItem], NULL);\r
453 PrintStringAt (PrintCol, PrintRow, String);\r
454 FreePool (String); \r
455 }\r
456 RePaintItems = TRUE;\r
457 }\r
458 \r
459 //\r
460 // Print want to select item \r
461 //\r
462 FirstItem = BootMenuData->ScrollBarControl.FirstItem;\r
463 gST->ConOut->SetAttribute (gST->ConOut, EFI_WHITE | EFI_BACKGROUND_BLACK);\r
464 String = HiiGetString (gStringPackHandle, BootMenuData->PtrTokens[WantSelectItem], NULL);\r
465 PrintCol = StartCol + 1; \r
466 PrintRow = StartRow + TITLE_TOKEN_COUNT + 2 + WantSelectItem - FirstItem; \r
467 PrintStringAt (PrintCol, PrintRow, String);\r
468 FreePool (String);\r
469 \r
470 //\r
471 // if Want Select and selected item isn't the same and doesn't re-draw selectable \r
472 // items, clear select item\r
473 //\r
474 if (WantSelectItem != BootMenuData->SelectItem && !RePaintItems) {\r
475 gST->ConOut->SetAttribute (gST->ConOut, EFI_WHITE | EFI_BACKGROUND_BLUE);\r
476 String = HiiGetString (gStringPackHandle, BootMenuData->PtrTokens[BootMenuData->SelectItem], NULL);\r
477 PrintCol = StartCol + 1; \r
478 PrintRow = StartRow + 3 + BootMenuData->SelectItem - FirstItem; \r
479 PrintStringAt (PrintCol, PrintRow, String);\r
480 FreePool (String); \r
481 }\r
482\r
483 gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);\r
484 BootMenuData->SelectItem = WantSelectItem;\r
485 return EFI_SUCCESS;\r
486}\r
487\r
488/**\r
04b34efb 489 This function uses to draw boot popup menu\r
a382952f
RN
490\r
491 @param BootMenuData The Input BootMenuData to be processed.\r
492 \r
493 @retval EFI_SUCCESS Draw boot popup menu successful.\r
494\r
495**/\r
496EFI_STATUS \r
497DrawBootPopupMenu (\r
498 IN BOOT_MENU_POPUP_DATA *BootMenuData\r
499 )\r
500{\r
501 EFI_STRING String;\r
502 UINTN Index;\r
503 UINTN Width; \r
a382952f
RN
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
a382952f
RN
517 StartCol = BootMenuData->MenuScreen.StartCol;\r
518 StartRow = BootMenuData->MenuScreen.StartRow;\r
519 ItemCountPerScreen = BootMenuData->ScrollBarControl.ItemCountPerScreen;\r
520 PrintRow = StartRow;\r
521 \r
522 gST->ConOut->EnableCursor (gST->ConOut, FALSE);\r
523 //\r
524 // Draw Boot popup menu screen\r
525 //\r
526 PrintCharAt (StartCol, PrintRow, BOXDRAW_DOWN_RIGHT);\r
527 for (Index = 1; Index < Width - 1; Index++) {\r
528 PrintCharAt (StartCol + Index, PrintRow, BOXDRAW_HORIZONTAL); \r
529 }\r
530 PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_DOWN_LEFT);\r
531 \r
532 //\r
533 // Draw the screen for title\r
534 //\r
535 String = AllocateZeroPool ((Width - 1) * sizeof (CHAR16));\r
536 ASSERT (String != NULL);\r
537 for (Index = 0; Index < Width - 2; Index++) {\r
538 String[Index] = 0x20;\r
539 }\r
540\r
541 for (Index = 0; Index < TITLE_TOKEN_COUNT; Index++) {\r
542 PrintRow++;\r
543 PrintCharAt (StartCol, PrintRow, BOXDRAW_VERTICAL); \r
544 PrintStringAt (StartCol + 1, PrintRow, String);\r
545 PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_VERTICAL);\r
546 }\r
547 \r
548 PrintRow++;\r
549 PrintCharAt (StartCol, PrintRow, BOXDRAW_VERTICAL_RIGHT);\r
550 for (Index = 1; Index < Width - 1; Index++) {\r
551 PrintCharAt (StartCol + Index, PrintRow, BOXDRAW_HORIZONTAL); \r
552 }\r
553 PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_VERTICAL_LEFT); \r
554 \r
555 //\r
556 // Draw screen for selectable items\r
557 //\r
558 for (Index = 0; Index < ItemCountPerScreen; Index++) {\r
559 PrintRow++;\r
560 PrintCharAt (StartCol, PrintRow, BOXDRAW_VERTICAL);\r
561 PrintStringAt (StartCol + 1, PrintRow, String);\r
562 PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_VERTICAL);\r
563 } \r
564\r
565 PrintRow++;\r
566 PrintCharAt (StartCol, PrintRow, BOXDRAW_VERTICAL_RIGHT);\r
567 for (Index = 1; Index < Width - 1; Index++) {\r
568 PrintCharAt (StartCol + Index, PrintRow, BOXDRAW_HORIZONTAL); \r
569 }\r
570 PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_VERTICAL_LEFT);\r
571 \r
572 //\r
573 // Draw screen for Help\r
574 //\r
575 for (Index = 0; Index < HELP_TOKEN_COUNT; Index++) {\r
576 PrintRow++;\r
577 PrintCharAt (StartCol, PrintRow, BOXDRAW_VERTICAL);\r
578 PrintStringAt (StartCol + 1, PrintRow, String);\r
579 PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_VERTICAL);\r
580 }\r
581 FreePool (String); \r
582 \r
583 PrintRow++; \r
584 PrintCharAt (StartCol, PrintRow, BOXDRAW_UP_RIGHT);\r
585 for (Index = 1; Index < Width - 1; Index++) {\r
586 PrintCharAt (StartCol + Index, PrintRow, BOXDRAW_HORIZONTAL); \r
587 }\r
588 PrintCharAt (StartCol + Width - 1, PrintRow, BOXDRAW_UP_LEFT); \r
589 \r
590 \r
591 //\r
592 // print title strings\r
593 //\r
594 PrintRow = StartRow + 1;\r
595 for (Index = 0; Index < TITLE_TOKEN_COUNT; Index++, PrintRow++) {\r
596 String = HiiGetString (gStringPackHandle, BootMenuData->TitleToken[Index], NULL);\r
597 LineWidth = GetLineWidth (BootMenuData->TitleToken[Index]); \r
598 PrintCol = StartCol + (Width - LineWidth) / 2;\r
599 PrintStringAt (PrintCol, PrintRow, String);\r
600 FreePool (String);\r
601 }\r
602 \r
603 //\r
604 // print selectable items\r
605 //\r
606 PrintCol = StartCol + 1;\r
607 PrintRow = StartRow + TITLE_TOKEN_COUNT + 2; \r
608 for (Index = 0; Index < ItemCountPerScreen; Index++, PrintRow++) {\r
609 String = HiiGetString (gStringPackHandle, BootMenuData->PtrTokens[Index], NULL);\r
610 PrintStringAt (PrintCol, PrintRow, String);\r
611 FreePool (String); \r
612 }\r
613 \r
614 //\r
615 // Print Help strings\r
616 //\r
617 PrintRow++;\r
618 for (Index = 0; Index < HELP_TOKEN_COUNT; Index++, PrintRow++) {\r
619 String = HiiGetString (gStringPackHandle, BootMenuData->HelpToken[Index], NULL);\r
620 LineWidth = GetLineWidth (BootMenuData->HelpToken[Index]);\r
621 PrintCol = StartCol + (Width - LineWidth) / 2;\r
622 PrintStringAt (PrintCol, PrintRow, String);\r
623 FreePool (String);\r
624 }\r
625 \r
626 //\r
627 // Print scroll bar if has scroll bar\r
628 //\r
629 if (BootMenuData->ScrollBarControl.HasScrollBar) {\r
630 PrintCol = StartCol + Width - 2;\r
631 PrintRow = StartRow + 2; \r
632 PrintCharAt (PrintCol, PrintRow, GEOMETRICSHAPE_UP_TRIANGLE); \r
633 PrintCharAt (PrintCol + 1, PrintRow, BOXDRAW_VERTICAL); \r
634 PrintRow += (ItemCountPerScreen + 1); \r
635 PrintCharAt (PrintCol, PrintRow, GEOMETRICSHAPE_DOWN_TRIANGLE);\r
636 PrintCharAt (PrintCol + 1, PrintRow, BOXDRAW_VERTICAL); \r
637 } \r
638 \r
639 gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);\r
640 //\r
641 // Print Selected item\r
642 //\r
643 BootMenuSelectItem (BootMenuData->SelectItem, BootMenuData);\r
644 return EFI_SUCCESS;\r
645}\r
646\r
647/**\r
04b34efb 648 This function uses to boot from selected item \r
a382952f
RN
649\r
650 @param BootOptions Pointer to EFI_BOOT_MANAGER_LOAD_OPTION array.\r
651 @param BootOptionCount Number of boot option.\r
652 @param SelectItem Current selected item.\r
653**/\r
654VOID\r
655BootFromSelectOption (\r
656 IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions,\r
657 IN UINTN BootOptionCount, \r
658 IN UINTN SelectItem\r
659 )\r
660{\r
661 UINTN ItemNum;\r
662 UINTN Index;\r
663\r
664 ASSERT (BootOptions != NULL);\r
665\r
666 for (ItemNum = 0, Index = 0; Index < BootOptionCount; Index++) {\r
7df23f85 667 if (IgnoreBootOption (&BootOptions[Index])) {\r
a382952f
RN
668 continue;\r
669 }\r
7df23f85 670\r
a382952f
RN
671 if (ItemNum++ == SelectItem) {\r
672 EfiBootManagerBoot (&BootOptions[Index]);\r
673 break;\r
674 }\r
675 }\r
676}\r
677\r
678/**\r
679 This function will change video resolution and text mode\r
680 according to defined setup mode or defined boot mode \r
681\r
682 @param IsSetupMode Indicate mode is changed to setup mode or boot mode. \r
683\r
684 @retval EFI_SUCCESS Mode is changed successfully.\r
685 @retval Others Mode failed to be changed.\r
686\r
687**/\r
688EFI_STATUS\r
689EFIAPI\r
690BdsSetConsoleMode (\r
691 BOOLEAN IsSetupMode\r
692 )\r
693{\r
694 EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;\r
695 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOut;\r
696 UINTN SizeOfInfo;\r
697 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;\r
698 UINT32 MaxGopMode;\r
699 UINT32 MaxTextMode;\r
700 UINT32 ModeNumber;\r
701 UINT32 NewHorizontalResolution;\r
702 UINT32 NewVerticalResolution;\r
703 UINT32 NewColumns;\r
704 UINT32 NewRows;\r
705 UINTN HandleCount;\r
706 EFI_HANDLE *HandleBuffer;\r
707 EFI_STATUS Status;\r
708 UINTN Index;\r
709 UINTN CurrentColumn;\r
710 UINTN CurrentRow; \r
711\r
712 MaxGopMode = 0;\r
713 MaxTextMode = 0;\r
714\r
715 //\r
716 // Get current video resolution and text mode \r
717 //\r
718 Status = gBS->HandleProtocol (\r
719 gST->ConsoleOutHandle,\r
720 &gEfiGraphicsOutputProtocolGuid,\r
721 (VOID**)&GraphicsOutput\r
722 );\r
723 if (EFI_ERROR (Status)) {\r
724 GraphicsOutput = NULL;\r
725 }\r
726\r
727 Status = gBS->HandleProtocol (\r
728 gST->ConsoleOutHandle,\r
729 &gEfiSimpleTextOutProtocolGuid,\r
730 (VOID**)&SimpleTextOut\r
731 );\r
732 if (EFI_ERROR (Status)) {\r
733 SimpleTextOut = NULL;\r
734 } \r
735\r
736 if ((GraphicsOutput == NULL) || (SimpleTextOut == NULL)) {\r
737 return EFI_UNSUPPORTED;\r
738 }\r
739\r
740 if (IsSetupMode) {\r
741 //\r
2048c585 742 // The required resolution and text mode is setup mode.\r
a382952f
RN
743 //\r
744 NewHorizontalResolution = mSetupHorizontalResolution;\r
745 NewVerticalResolution = mSetupVerticalResolution;\r
746 NewColumns = mSetupTextModeColumn;\r
747 NewRows = mSetupTextModeRow;\r
748 } else {\r
749 //\r
750 // The required resolution and text mode is boot mode.\r
751 //\r
752 NewHorizontalResolution = mBootHorizontalResolution;\r
753 NewVerticalResolution = mBootVerticalResolution;\r
754 NewColumns = mBootTextModeColumn;\r
755 NewRows = mBootTextModeRow; \r
756 }\r
757 \r
758 if (GraphicsOutput != NULL) {\r
759 MaxGopMode = GraphicsOutput->Mode->MaxMode;\r
760 } \r
761\r
762 if (SimpleTextOut != NULL) {\r
763 MaxTextMode = SimpleTextOut->Mode->MaxMode;\r
764 }\r
765\r
766 //\r
767 // 1. If current video resolution is same with required video resolution,\r
768 // video resolution need not be changed.\r
769 // 1.1. If current text mode is same with required text mode, text mode need not be changed.\r
770 // 1.2. If current text mode is different from required text mode, text mode need be changed.\r
771 // 2. If current video resolution is different from required video resolution, we need restart whole console drivers.\r
772 //\r
773 for (ModeNumber = 0; ModeNumber < MaxGopMode; ModeNumber++) {\r
774 Status = GraphicsOutput->QueryMode (\r
775 GraphicsOutput,\r
776 ModeNumber,\r
777 &SizeOfInfo,\r
778 &Info\r
779 );\r
780 if (!EFI_ERROR (Status)) {\r
781 if ((Info->HorizontalResolution == NewHorizontalResolution) &&\r
782 (Info->VerticalResolution == NewVerticalResolution)) {\r
783 if ((GraphicsOutput->Mode->Info->HorizontalResolution == NewHorizontalResolution) &&\r
784 (GraphicsOutput->Mode->Info->VerticalResolution == NewVerticalResolution)) {\r
785 //\r
786 // Current resolution is same with required resolution, check if text mode need be set\r
787 //\r
788 Status = SimpleTextOut->QueryMode (SimpleTextOut, SimpleTextOut->Mode->Mode, &CurrentColumn, &CurrentRow);\r
789 ASSERT_EFI_ERROR (Status);\r
790 if (CurrentColumn == NewColumns && CurrentRow == NewRows) {\r
791 //\r
792 // If current text mode is same with required text mode. Do nothing\r
793 //\r
794 FreePool (Info);\r
795 return EFI_SUCCESS;\r
796 } else {\r
797 //\r
2048c585 798 // If current text mode is different from required text mode. Set new video mode\r
a382952f
RN
799 //\r
800 for (Index = 0; Index < MaxTextMode; Index++) {\r
801 Status = SimpleTextOut->QueryMode (SimpleTextOut, Index, &CurrentColumn, &CurrentRow);\r
802 if (!EFI_ERROR(Status)) {\r
803 if ((CurrentColumn == NewColumns) && (CurrentRow == NewRows)) {\r
804 //\r
805 // Required text mode is supported, set it.\r
806 //\r
807 Status = SimpleTextOut->SetMode (SimpleTextOut, Index);\r
808 ASSERT_EFI_ERROR (Status);\r
809 //\r
810 // Update text mode PCD.\r
811 //\r
377680ae
ED
812 Status = PcdSet32S (PcdConOutColumn, mSetupTextModeColumn);\r
813 ASSERT_EFI_ERROR (Status);\r
814 Status = PcdSet32S (PcdConOutRow, mSetupTextModeRow);\r
815 ASSERT_EFI_ERROR (Status);\r
a382952f
RN
816 FreePool (Info);\r
817 return EFI_SUCCESS;\r
818 }\r
819 }\r
820 }\r
821 if (Index == MaxTextMode) {\r
822 //\r
2048c585 823 // If required text mode is not supported, return error.\r
a382952f
RN
824 //\r
825 FreePool (Info);\r
826 return EFI_UNSUPPORTED;\r
827 }\r
828 }\r
829 } else {\r
830 //\r
831 // If current video resolution is not same with the new one, set new video resolution.\r
832 // In this case, the driver which produces simple text out need be restarted.\r
833 //\r
834 Status = GraphicsOutput->SetMode (GraphicsOutput, ModeNumber);\r
835 if (!EFI_ERROR (Status)) {\r
836 FreePool (Info);\r
837 break;\r
838 }\r
839 }\r
840 }\r
841 FreePool (Info);\r
842 }\r
843 }\r
844\r
845 if (ModeNumber == MaxGopMode) {\r
846 //\r
847 // If the resolution is not supported, return error.\r
848 //\r
849 return EFI_UNSUPPORTED;\r
850 }\r
851\r
852 //\r
853 // Set PCD to Inform GraphicsConsole to change video resolution.\r
854 // Set PCD to Inform Consplitter to change text mode.\r
855 //\r
377680ae
ED
856 Status = PcdSet32S (PcdVideoHorizontalResolution, NewHorizontalResolution);\r
857 ASSERT_EFI_ERROR (Status);\r
858 Status = PcdSet32S (PcdVideoVerticalResolution, NewVerticalResolution);\r
859 ASSERT_EFI_ERROR (Status);\r
860 Status = PcdSet32S (PcdConOutColumn, NewColumns);\r
861 ASSERT_EFI_ERROR (Status);\r
862 Status = PcdSet32S (PcdConOutRow, NewRows);\r
863 ASSERT_EFI_ERROR (Status);\r
a382952f
RN
864 \r
865 //\r
866 // Video mode is changed, so restart graphics console driver and higher level driver.\r
867 // Reconnect graphics console driver and higher level driver.\r
868 // Locate all the handles with GOP protocol and reconnect it.\r
869 //\r
870 Status = gBS->LocateHandleBuffer (\r
871 ByProtocol,\r
872 &gEfiSimpleTextOutProtocolGuid,\r
873 NULL,\r
874 &HandleCount,\r
875 &HandleBuffer\r
876 );\r
877 if (!EFI_ERROR (Status)) {\r
878 for (Index = 0; Index < HandleCount; Index++) {\r
879 gBS->DisconnectController (HandleBuffer[Index], NULL, NULL);\r
880 }\r
881 for (Index = 0; Index < HandleCount; Index++) {\r
882 gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);\r
883 }\r
884 if (HandleBuffer != NULL) {\r
885 FreePool (HandleBuffer);\r
886 }\r
887 }\r
888\r
889 return EFI_SUCCESS;\r
890}\r
891\r
892/**\r
893 Display the boot popup menu and allow user select boot item.\r
894\r
895 @param ImageHandle The image handle.\r
896 @param SystemTable The system table.\r
897 \r
898 @retval EFI_SUCCESS Boot from selected boot option, and return success from boot option\r
899 @retval EFI_NOT_FOUND User select to enter setup or can not find boot option\r
900 \r
901**/\r
902EFI_STATUS\r
903EFIAPI\r
904BootManagerMenuEntry (\r
905 IN EFI_HANDLE ImageHandle,\r
906 IN EFI_SYSTEM_TABLE *SystemTable\r
907 )\r
908{\r
909 EFI_BOOT_MANAGER_LOAD_OPTION *BootOption;\r
910 UINTN BootOptionCount; \r
911 EFI_STATUS Status;\r
912 BOOT_MENU_POPUP_DATA BootMenuData;\r
913 UINTN Index;\r
914 EFI_INPUT_KEY Key;\r
915 BOOLEAN ExitApplication;\r
916 UINTN SelectItem;\r
917 EFI_BOOT_LOGO_PROTOCOL *BootLogo;\r
918 EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;\r
919 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOut;\r
920 UINTN BootTextColumn;\r
921 UINTN BootTextRow;\r
922\r
923 //\r
924 // Set Logo status invalid when boot manager menu is launched\r
925 //\r
926 BootLogo = NULL;\r
927 Status = gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo);\r
928 if (!EFI_ERROR (Status) && (BootLogo != NULL)) {\r
929 Status = BootLogo->SetBootLogo (BootLogo, NULL, 0, 0, 0, 0);\r
930 ASSERT_EFI_ERROR (Status);\r
931 }\r
932\r
933 gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);\r
934\r
935 gStringPackHandle = HiiAddPackages (\r
936 &gEfiCallerIdGuid,\r
937 gImageHandle,\r
938 BootManagerMenuAppStrings,\r
939 NULL\r
940 );\r
941 ASSERT (gStringPackHandle != NULL);\r
942\r
943 //\r
944 // Connect all prior to entering the platform setup menu.\r
945 //\r
946 EfiBootManagerConnectAll ();\r
947 EfiBootManagerRefreshAllBootOption ();\r
948\r
949 BootOption = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);\r
950\r
951 if (!mModeInitialized) {\r
952 //\r
953 // After the console is ready, get current video resolution \r
954 // and text mode before launching setup at first time.\r
955 //\r
956 Status = gBS->HandleProtocol (\r
957 gST->ConsoleOutHandle,\r
958 &gEfiGraphicsOutputProtocolGuid,\r
959 (VOID**)&GraphicsOutput\r
960 );\r
961 if (EFI_ERROR (Status)) {\r
962 GraphicsOutput = NULL;\r
963 }\r
964 \r
965 Status = gBS->HandleProtocol (\r
966 gST->ConsoleOutHandle,\r
967 &gEfiSimpleTextOutProtocolGuid,\r
968 (VOID**)&SimpleTextOut\r
969 );\r
970 if (EFI_ERROR (Status)) {\r
971 SimpleTextOut = NULL;\r
972 } \r
973\r
974 if (GraphicsOutput != NULL) {\r
975 //\r
976 // Get current video resolution and text mode.\r
977 //\r
978 mBootHorizontalResolution = GraphicsOutput->Mode->Info->HorizontalResolution;\r
979 mBootVerticalResolution = GraphicsOutput->Mode->Info->VerticalResolution;\r
980 }\r
981\r
982 if (SimpleTextOut != NULL) {\r
983 Status = SimpleTextOut->QueryMode (\r
984 SimpleTextOut,\r
985 SimpleTextOut->Mode->Mode,\r
986 &BootTextColumn,\r
987 &BootTextRow\r
988 );\r
989 mBootTextModeColumn = (UINT32)BootTextColumn;\r
990 mBootTextModeRow = (UINT32)BootTextRow;\r
991 }\r
992\r
993 //\r
994 // Get user defined text mode for setup.\r
995 // \r
996 mSetupHorizontalResolution = PcdGet32 (PcdSetupVideoHorizontalResolution);\r
997 mSetupVerticalResolution = PcdGet32 (PcdSetupVideoVerticalResolution); \r
998 mSetupTextModeColumn = PcdGet32 (PcdSetupConOutColumn);\r
999 mSetupTextModeRow = PcdGet32 (PcdSetupConOutRow);\r
1000 mModeInitialized = TRUE;\r
1001 }\r
1002 \r
1003 //\r
1004 // Set back to conventional setup resolution\r
1005 //\r
1006 BdsSetConsoleMode (TRUE);\r
1007\r
1008 //\r
1009 // Initialize Boot menu data\r
1010 //\r
1011 Status = InitializeBootMenuData (BootOption, BootOptionCount, &BootMenuData);\r
1012 //\r
1013 // According to boot menu data to draw boot popup menu\r
1014 //\r
1015 DrawBootPopupMenu (&BootMenuData);\r
1016 \r
1017 //\r
1018 // check user input to determine want to re-draw or boot from user selected item\r
1019 //\r
1020 ExitApplication = FALSE;\r
1021 while (!ExitApplication) {\r
1022 gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &Index);\r
1023 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
1024 if (!EFI_ERROR (Status)) {\r
1025 switch (Key.UnicodeChar) {\r
1026 \r
1027 case CHAR_NULL: \r
1028 switch (Key.ScanCode) { \r
1029 \r
1030 case SCAN_UP:\r
1031 SelectItem = BootMenuData.SelectItem == 0 ? BootMenuData.ItemCount - 1 : BootMenuData.SelectItem - 1;\r
1032 BootMenuSelectItem (SelectItem, &BootMenuData); \r
1033 break;\r
1034 \r
1035 case SCAN_DOWN:\r
1036 SelectItem = BootMenuData.SelectItem == BootMenuData.ItemCount - 1 ? 0 : BootMenuData.SelectItem + 1;\r
1037 BootMenuSelectItem (SelectItem, &BootMenuData); \r
1038 break;\r
1039\r
1040 case SCAN_ESC:\r
1041 gST->ConOut->ClearScreen (gST->ConOut);\r
1042 ExitApplication = TRUE;\r
1043 //\r
1044 // Set boot resolution for normal boot\r
1045 //\r
1046 BdsSetConsoleMode (FALSE);\r
1047 break;\r
1048 \r
1049 default:\r
1050 break;\r
1051 }\r
1052 break;\r
1053 \r
1054 case CHAR_CARRIAGE_RETURN:\r
1055 gST->ConOut->ClearScreen (gST->ConOut);\r
1056 //\r
1057 // Set boot resolution for normal boot\r
1058 //\r
1059 BdsSetConsoleMode (FALSE);\r
1060 BootFromSelectOption (BootOption, BootOptionCount, BootMenuData.SelectItem);\r
1061 //\r
1062 // Back to boot manager menu again, set back to setup resolution\r
1063 //\r
1064 BdsSetConsoleMode (TRUE);\r
1065 DrawBootPopupMenu (&BootMenuData);\r
1066 break;\r
1067 \r
1068 default:\r
1069 break;\r
1070 }\r
1071 }\r
1072 }\r
1073 EfiBootManagerFreeLoadOptions (BootOption, BootOptionCount);\r
1074 FreePool (BootMenuData.PtrTokens);\r
1075\r
1076 HiiRemovePackages (gStringPackHandle);\r
1077\r
1078 return Status;\r
1079 \r
1080}\r