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