1 /** @file
2 The functions for Boot Maintainence Main menu.
3 
4 Copyright (c) 2004 - 2019, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 **/
8 
9 #include "BootMaintenanceManager.h"
10 
11 #define FRONT_PAGE_KEY_OFFSET          0x4000
12 //
13 // Boot video resolution and text mode.
14 //
15 UINT32    mBmmBootHorizontalResolution    = 0;
16 UINT32    mBmmBootVerticalResolution      = 0;
17 UINT32    mBmmBootTextModeColumn          = 0;
18 UINT32    mBmmBootTextModeRow             = 0;
19 //
20 // BIOS setup video resolution and text mode.
21 //
22 UINT32    mBmmSetupTextModeColumn         = 0;
23 UINT32    mBmmSetupTextModeRow            = 0;
24 UINT32    mBmmSetupHorizontalResolution   = 0;
25 UINT32    mBmmSetupVerticalResolution     = 0;
26 
27 BOOLEAN   mBmmModeInitialized             = FALSE;
28 
29 EFI_DEVICE_PATH_PROTOCOL  EndDevicePath[] = {
30   {
31     END_DEVICE_PATH_TYPE,
32     END_ENTIRE_DEVICE_PATH_SUBTYPE,
33     {
34       END_DEVICE_PATH_LENGTH,
35       0
36     }
37   }
38 };
39 
40 HII_VENDOR_DEVICE_PATH  mBmmHiiVendorDevicePath = {
41   {
42     {
43       HARDWARE_DEVICE_PATH,
44       HW_VENDOR_DP,
45       {
46         (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
47         (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
48       }
49     },
50     //
51     // {165A028F-0BB2-4b5f-8747-77592E3F6499}
52     //
53     { 0x165a028f, 0xbb2, 0x4b5f, { 0x87, 0x47, 0x77, 0x59, 0x2e, 0x3f, 0x64, 0x99 } }
54   },
55   {
56     END_DEVICE_PATH_TYPE,
57     END_ENTIRE_DEVICE_PATH_SUBTYPE,
58     {
59       (UINT8) (END_DEVICE_PATH_LENGTH),
60       (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
61     }
62   }
63 };
64 
65 EFI_GUID mBootMaintGuid          = BOOT_MAINT_FORMSET_GUID;
66 
67 CHAR16  mBootMaintStorageName[]     = L"BmmData";
68 BMM_CALLBACK_DATA  gBootMaintenancePrivate = {
69   BMM_CALLBACK_DATA_SIGNATURE,
70   NULL,
71   NULL,
72   {
73     BootMaintExtractConfig,
74     BootMaintRouteConfig,
75     BootMaintCallback
76   }
77 };
78 
79 BMM_CALLBACK_DATA *mBmmCallbackInfo = &gBootMaintenancePrivate;
80 BOOLEAN  mAllMenuInit               = FALSE;
81 BOOLEAN  mFirstEnterBMMForm         = FALSE;
82 
83 /**
84   Init all memu.
85 
86   @param CallbackData    The BMM context data.
87 
88 **/
89 VOID
90 InitAllMenu (
91   IN  BMM_CALLBACK_DATA    *CallbackData
92   );
93 
94 /**
95   Free up all Menu Option list.
96 
97 **/
98 VOID
99 FreeAllMenu (
100   VOID
101   );
102 
103 /**
104 
105   Update the menus in the BMM page.
106 
107 **/
108 VOID
109 CustomizeMenus (
110   VOID
111   );
112 
113 /**
114   This function will change video resolution and text mode
115   according to defined setup mode or defined boot mode
116 
117   @param  IsSetupMode   Indicate mode is changed to setup mode or boot mode.
118 
119   @retval  EFI_SUCCESS  Mode is changed successfully.
120   @retval  Others       Mode failed to be changed.
121 
122 **/
123 EFI_STATUS
BmmSetConsoleMode(BOOLEAN IsSetupMode)124 BmmSetConsoleMode (
125   BOOLEAN  IsSetupMode
126   )
127 {
128   EFI_GRAPHICS_OUTPUT_PROTOCOL          *GraphicsOutput;
129   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL       *SimpleTextOut;
130   UINTN                                 SizeOfInfo;
131   EFI_GRAPHICS_OUTPUT_MODE_INFORMATION  *Info;
132   UINT32                                MaxGopMode;
133   UINT32                                MaxTextMode;
134   UINT32                                ModeNumber;
135   UINT32                                NewHorizontalResolution;
136   UINT32                                NewVerticalResolution;
137   UINT32                                NewColumns;
138   UINT32                                NewRows;
139   UINTN                                 HandleCount;
140   EFI_HANDLE                            *HandleBuffer;
141   EFI_STATUS                            Status;
142   UINTN                                 Index;
143   UINTN                                 CurrentColumn;
144   UINTN                                 CurrentRow;
145 
146   MaxGopMode  = 0;
147   MaxTextMode = 0;
148 
149   //
150   // Get current video resolution and text mode
151   //
152   Status = gBS->HandleProtocol (
153                   gST->ConsoleOutHandle,
154                   &gEfiGraphicsOutputProtocolGuid,
155                   (VOID**)&GraphicsOutput
156                   );
157   if (EFI_ERROR (Status)) {
158     GraphicsOutput = NULL;
159   }
160 
161   Status = gBS->HandleProtocol (
162                   gST->ConsoleOutHandle,
163                   &gEfiSimpleTextOutProtocolGuid,
164                   (VOID**)&SimpleTextOut
165                   );
166   if (EFI_ERROR (Status)) {
167     SimpleTextOut = NULL;
168   }
169 
170   if ((GraphicsOutput == NULL) || (SimpleTextOut == NULL)) {
171     return EFI_UNSUPPORTED;
172   }
173 
174   if (IsSetupMode) {
175     //
176     // The required resolution and text mode is setup mode.
177     //
178     NewHorizontalResolution = mBmmSetupHorizontalResolution;
179     NewVerticalResolution   = mBmmSetupVerticalResolution;
180     NewColumns              = mBmmSetupTextModeColumn;
181     NewRows                 = mBmmSetupTextModeRow;
182   } else {
183     //
184     // The required resolution and text mode is boot mode.
185     //
186     NewHorizontalResolution = mBmmBootHorizontalResolution;
187     NewVerticalResolution   = mBmmBootVerticalResolution;
188     NewColumns              = mBmmBootTextModeColumn;
189     NewRows                 = mBmmBootTextModeRow;
190   }
191 
192   if (GraphicsOutput != NULL) {
193     MaxGopMode  = GraphicsOutput->Mode->MaxMode;
194   }
195 
196   if (SimpleTextOut != NULL) {
197     MaxTextMode = SimpleTextOut->Mode->MaxMode;
198   }
199 
200   //
201   // 1. If current video resolution is same with required video resolution,
202   //    video resolution need not be changed.
203   //    1.1. If current text mode is same with required text mode, text mode need not be changed.
204   //    1.2. If current text mode is different from required text mode, text mode need be changed.
205   // 2. If current video resolution is different from required video resolution, we need restart whole console drivers.
206   //
207   for (ModeNumber = 0; ModeNumber < MaxGopMode; ModeNumber++) {
208     Status = GraphicsOutput->QueryMode (
209                        GraphicsOutput,
210                        ModeNumber,
211                        &SizeOfInfo,
212                        &Info
213                        );
214     if (!EFI_ERROR (Status)) {
215       if ((Info->HorizontalResolution == NewHorizontalResolution) &&
216           (Info->VerticalResolution == NewVerticalResolution)) {
217         if ((GraphicsOutput->Mode->Info->HorizontalResolution == NewHorizontalResolution) &&
218             (GraphicsOutput->Mode->Info->VerticalResolution == NewVerticalResolution)) {
219           //
220           // Current resolution is same with required resolution, check if text mode need be set
221           //
222           Status = SimpleTextOut->QueryMode (SimpleTextOut, SimpleTextOut->Mode->Mode, &CurrentColumn, &CurrentRow);
223           ASSERT_EFI_ERROR (Status);
224           if (CurrentColumn == NewColumns && CurrentRow == NewRows) {
225             //
226             // If current text mode is same with required text mode. Do nothing
227             //
228             FreePool (Info);
229             return EFI_SUCCESS;
230           } else {
231             //
232             // If current text mode is different from required text mode.  Set new video mode
233             //
234             for (Index = 0; Index < MaxTextMode; Index++) {
235               Status = SimpleTextOut->QueryMode (SimpleTextOut, Index, &CurrentColumn, &CurrentRow);
236               if (!EFI_ERROR(Status)) {
237                 if ((CurrentColumn == NewColumns) && (CurrentRow == NewRows)) {
238                   //
239                   // Required text mode is supported, set it.
240                   //
241                   Status = SimpleTextOut->SetMode (SimpleTextOut, Index);
242                   ASSERT_EFI_ERROR (Status);
243                   //
244                   // Update text mode PCD.
245                   //
246                   Status = PcdSet32S (PcdConOutColumn, mBmmSetupTextModeColumn);
247                   ASSERT_EFI_ERROR (Status);
248                   Status = PcdSet32S (PcdConOutRow, mBmmSetupTextModeRow);
249                   ASSERT_EFI_ERROR (Status);
250                   FreePool (Info);
251                   return EFI_SUCCESS;
252                 }
253               }
254             }
255             if (Index == MaxTextMode) {
256               //
257               // If required text mode is not supported, return error.
258               //
259               FreePool (Info);
260               return EFI_UNSUPPORTED;
261             }
262           }
263         } else {
264           //
265           // If current video resolution is not same with the new one, set new video resolution.
266           // In this case, the driver which produces simple text out need be restarted.
267           //
268           Status = GraphicsOutput->SetMode (GraphicsOutput, ModeNumber);
269           if (!EFI_ERROR (Status)) {
270             FreePool (Info);
271             break;
272           }
273         }
274       }
275       FreePool (Info);
276     }
277   }
278 
279   if (ModeNumber == MaxGopMode) {
280     //
281     // If the resolution is not supported, return error.
282     //
283     return EFI_UNSUPPORTED;
284   }
285 
286   //
287   // Set PCD to Inform GraphicsConsole to change video resolution.
288   // Set PCD to Inform Consplitter to change text mode.
289   //
290   Status = PcdSet32S (PcdVideoHorizontalResolution, NewHorizontalResolution);
291   ASSERT_EFI_ERROR (Status);
292   Status = PcdSet32S (PcdVideoVerticalResolution, NewVerticalResolution);
293   ASSERT_EFI_ERROR (Status);
294   Status = PcdSet32S (PcdConOutColumn, NewColumns);
295   ASSERT_EFI_ERROR (Status);
296   Status = PcdSet32S (PcdConOutRow, NewRows);
297   ASSERT_EFI_ERROR (Status);
298 
299   //
300   // Video mode is changed, so restart graphics console driver and higher level driver.
301   // Reconnect graphics console driver and higher level driver.
302   // Locate all the handles with GOP protocol and reconnect it.
303   //
304   Status = gBS->LocateHandleBuffer (
305                    ByProtocol,
306                    &gEfiSimpleTextOutProtocolGuid,
307                    NULL,
308                    &HandleCount,
309                    &HandleBuffer
310                    );
311   if (!EFI_ERROR (Status)) {
312     for (Index = 0; Index < HandleCount; Index++) {
313       gBS->DisconnectController (HandleBuffer[Index], NULL, NULL);
314     }
315     for (Index = 0; Index < HandleCount; Index++) {
316       gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
317     }
318     if (HandleBuffer != NULL) {
319       FreePool (HandleBuffer);
320     }
321   }
322 
323   return EFI_SUCCESS;
324 }
325 
326 /**
327   This function converts an input device structure to a Unicode string.
328 
329   @param DevPath      A pointer to the device path structure.
330 
331   @return             A new allocated Unicode string that represents the device path.
332 
333 **/
334 CHAR16 *
UiDevicePathToStr(IN EFI_DEVICE_PATH_PROTOCOL * DevPath)335 UiDevicePathToStr (
336   IN EFI_DEVICE_PATH_PROTOCOL     *DevPath
337   )
338 {
339   EFI_STATUS                       Status;
340   CHAR16                           *ToText;
341   EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevPathToText;
342 
343   if (DevPath == NULL) {
344     return NULL;
345   }
346 
347   Status = gBS->LocateProtocol (
348                   &gEfiDevicePathToTextProtocolGuid,
349                   NULL,
350                   (VOID **) &DevPathToText
351                   );
352   ASSERT_EFI_ERROR (Status);
353   ToText = DevPathToText->ConvertDevicePathToText (
354                             DevPath,
355                             FALSE,
356                             TRUE
357                             );
358   ASSERT (ToText != NULL);
359   return ToText;
360 }
361 
362 /**
363   Extract filename from device path. The returned buffer is allocated using AllocateCopyPool.
364   The caller is responsible for freeing the allocated buffer using FreePool().
365 
366   @param DevicePath       Device path.
367 
368   @return                 A new allocated string that represents the file name.
369 
370 **/
371 CHAR16 *
ExtractFileNameFromDevicePath(IN EFI_DEVICE_PATH_PROTOCOL * DevicePath)372 ExtractFileNameFromDevicePath (
373   IN   EFI_DEVICE_PATH_PROTOCOL *DevicePath
374   )
375 {
376   CHAR16          *String;
377   CHAR16          *MatchString;
378   CHAR16          *LastMatch;
379   CHAR16          *FileName;
380   UINTN           Length;
381 
382   ASSERT(DevicePath != NULL);
383 
384   String = UiDevicePathToStr(DevicePath);
385   MatchString = String;
386   LastMatch   = String;
387   FileName    = NULL;
388 
389   while(MatchString != NULL){
390     LastMatch   = MatchString + 1;
391     MatchString = StrStr(LastMatch,L"\\");
392   }
393 
394   Length = StrLen(LastMatch);
395   FileName = AllocateCopyPool ((Length + 1) * sizeof(CHAR16), LastMatch);
396   if (FileName != NULL) {
397     *(FileName + Length) = 0;
398   }
399 
400   FreePool(String);
401 
402   return FileName;
403 }
404 
405 /**
406   Extract device path for given HII handle and class guid.
407 
408   @param Handle          The HII handle.
409 
410   @retval  NULL          Fail to get the device path string.
411   @return  PathString    Get the device path string.
412 
413 **/
414 CHAR16 *
BmmExtractDevicePathFromHiiHandle(IN EFI_HII_HANDLE Handle)415 BmmExtractDevicePathFromHiiHandle (
416   IN      EFI_HII_HANDLE      Handle
417   )
418 {
419   EFI_STATUS                       Status;
420   EFI_HANDLE                       DriverHandle;
421 
422   ASSERT (Handle != NULL);
423 
424   if (Handle == NULL) {
425     return NULL;
426   }
427 
428   Status = gHiiDatabase->GetPackageListHandle (gHiiDatabase, Handle, &DriverHandle);
429   if (EFI_ERROR (Status)) {
430     return NULL;
431   }
432 
433   //
434   // Get device path string.
435   //
436   return ConvertDevicePathToText(DevicePathFromHandle (DriverHandle), FALSE, FALSE);
437 
438 }
439 
440 /**
441   Converts the unicode character of the string from uppercase to lowercase.
442   This is a internal function.
443 
444   @param ConfigString  String to be converted
445 
446 **/
447 VOID
HiiToLower(IN EFI_STRING ConfigString)448 HiiToLower (
449   IN EFI_STRING  ConfigString
450   )
451 {
452   EFI_STRING  String;
453   BOOLEAN     Lower;
454 
455   ASSERT (ConfigString != NULL);
456 
457   //
458   // Convert all hex digits in range [A-F] in the configuration header to [a-f]
459   //
460   for (String = ConfigString, Lower = FALSE; *String != L'\0'; String++) {
461     if (*String == L'=') {
462       Lower = TRUE;
463     } else if (*String == L'&') {
464       Lower = FALSE;
465     } else if (Lower && *String >= L'A' && *String <= L'F') {
466       *String = (CHAR16) (*String - L'A' + L'a');
467     }
468   }
469 }
470 
471 /**
472   Update the progress string through the offset value.
473 
474   @param Offset           The offset value
475   @param Configuration    Point to the configuration string.
476 
477 **/
478 EFI_STRING
UpdateProgress(IN UINTN Offset,IN EFI_STRING Configuration)479 UpdateProgress(
480   IN  UINTN       Offset,
481   IN  EFI_STRING  Configuration
482 )
483 {
484   UINTN       Length;
485   EFI_STRING  StringPtr;
486   EFI_STRING  ReturnString;
487 
488   StringPtr    = NULL;
489   ReturnString = NULL;
490 
491   //
492   // &OFFSET=XXXX followed by a Null-terminator.
493   // Length = StrLen (L"&OFFSET=") + 4 + 1
494   //
495   Length    = StrLen (L"&OFFSET=") + 4 + 1;
496 
497   StringPtr = AllocateZeroPool (Length * sizeof (CHAR16));
498 
499   if (StringPtr == NULL) {
500     return  NULL;
501   }
502 
503   UnicodeSPrint (
504     StringPtr,
505     (8 + 4 + 1) * sizeof (CHAR16),
506     L"&OFFSET=%04x",
507     Offset
508     );
509 
510   ReturnString = StrStr (Configuration, StringPtr);
511 
512   if (ReturnString == NULL) {
513     //
514     // If doesn't find the string in Configuration, convert the string to lower case then search again.
515     //
516     HiiToLower (StringPtr);
517     ReturnString = StrStr (Configuration, StringPtr);
518   }
519 
520   FreePool (StringPtr);
521 
522   return ReturnString;
523 }
524 
525 /**
526   Update the terminal content in TerminalMenu.
527 
528   @param BmmData           The BMM fake NV data.
529 
530 **/
531 VOID
UpdateTerminalContent(IN BMM_FAKE_NV_DATA * BmmData)532 UpdateTerminalContent (
533   IN BMM_FAKE_NV_DATA       *BmmData
534   )
535 {
536   UINT16                          Index;
537   BM_TERMINAL_CONTEXT             *NewTerminalContext;
538   BM_MENU_ENTRY                   *NewMenuEntry;
539 
540   for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) {
541     NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Index);
542     ASSERT (NewMenuEntry != NULL);
543     NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
544     NewTerminalContext->BaudRateIndex = BmmData->COMBaudRate[Index];
545     ASSERT (BmmData->COMBaudRate[Index] < (ARRAY_SIZE (BaudRateList)));
546     NewTerminalContext->BaudRate      = BaudRateList[BmmData->COMBaudRate[Index]].Value;
547     NewTerminalContext->DataBitsIndex = BmmData->COMDataRate[Index];
548     ASSERT (BmmData->COMDataRate[Index] < (ARRAY_SIZE (DataBitsList)));
549     NewTerminalContext->DataBits      = (UINT8) DataBitsList[BmmData->COMDataRate[Index]].Value;
550     NewTerminalContext->StopBitsIndex = BmmData->COMStopBits[Index];
551     ASSERT (BmmData->COMStopBits[Index] < (ARRAY_SIZE (StopBitsList)));
552     NewTerminalContext->StopBits      = (UINT8) StopBitsList[BmmData->COMStopBits[Index]].Value;
553     NewTerminalContext->ParityIndex   = BmmData->COMParity[Index];
554     ASSERT (BmmData->COMParity[Index] < (ARRAY_SIZE (ParityList)));
555     NewTerminalContext->Parity        = (UINT8) ParityList[BmmData->COMParity[Index]].Value;
556     NewTerminalContext->TerminalType  = BmmData->COMTerminalType[Index];
557     NewTerminalContext->FlowControl   = BmmData->COMFlowControl[Index];
558     ChangeTerminalDevicePath (
559       NewTerminalContext->DevicePath,
560       FALSE
561       );
562   }
563 }
564 
565 /**
566   Update the console content in ConsoleMenu.
567 
568   @param ConsoleName       The name for the console device type.
569   @param BmmData           The BMM fake NV data.
570 
571 **/
572 VOID
UpdateConsoleContent(IN CHAR16 * ConsoleName,IN BMM_FAKE_NV_DATA * BmmData)573 UpdateConsoleContent(
574   IN CHAR16                 *ConsoleName,
575   IN BMM_FAKE_NV_DATA       *BmmData
576   )
577 {
578   UINT16                          Index;
579   BM_CONSOLE_CONTEXT              *NewConsoleContext;
580   BM_TERMINAL_CONTEXT             *NewTerminalContext;
581   BM_MENU_ENTRY                   *NewMenuEntry;
582 
583   if (StrCmp (ConsoleName, L"ConIn") == 0) {
584     for (Index = 0; Index < ConsoleInpMenu.MenuNumber; Index++){
585       NewMenuEntry                = BOpt_GetMenuEntry(&ConsoleInpMenu, Index);
586       NewConsoleContext           = (BM_CONSOLE_CONTEXT *)NewMenuEntry->VariableContext;
587       ASSERT (Index < MAX_MENU_NUMBER);
588       NewConsoleContext->IsActive = BmmData->ConsoleInCheck[Index];
589     }
590     for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) {
591       NewMenuEntry                = BOpt_GetMenuEntry (&TerminalMenu, Index);
592       NewTerminalContext          = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
593       ASSERT (Index + ConsoleInpMenu.MenuNumber < MAX_MENU_NUMBER);
594       NewTerminalContext->IsConIn = BmmData->ConsoleInCheck[Index + ConsoleInpMenu.MenuNumber];
595     }
596   }
597 
598   if (StrCmp (ConsoleName, L"ConOut") == 0) {
599     for (Index = 0; Index < ConsoleOutMenu.MenuNumber; Index++){
600       NewMenuEntry                = BOpt_GetMenuEntry(&ConsoleOutMenu, Index);
601       NewConsoleContext           = (BM_CONSOLE_CONTEXT *)NewMenuEntry->VariableContext;
602       ASSERT (Index < MAX_MENU_NUMBER);
603       NewConsoleContext->IsActive = BmmData->ConsoleOutCheck[Index];
604     }
605     for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) {
606       NewMenuEntry                = BOpt_GetMenuEntry (&TerminalMenu, Index);
607       NewTerminalContext          = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
608       ASSERT (Index + ConsoleOutMenu.MenuNumber < MAX_MENU_NUMBER);
609       NewTerminalContext->IsConOut = BmmData->ConsoleOutCheck[Index + ConsoleOutMenu.MenuNumber];
610     }
611   }
612   if (StrCmp (ConsoleName, L"ErrOut") == 0) {
613     for (Index = 0; Index < ConsoleErrMenu.MenuNumber; Index++){
614       NewMenuEntry                = BOpt_GetMenuEntry(&ConsoleErrMenu, Index);
615       NewConsoleContext           = (BM_CONSOLE_CONTEXT *)NewMenuEntry->VariableContext;
616       ASSERT (Index < MAX_MENU_NUMBER);
617       NewConsoleContext->IsActive = BmmData->ConsoleErrCheck[Index];
618     }
619     for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) {
620       NewMenuEntry                = BOpt_GetMenuEntry (&TerminalMenu, Index);
621       NewTerminalContext          = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
622       ASSERT (Index + ConsoleErrMenu.MenuNumber < MAX_MENU_NUMBER);
623       NewTerminalContext->IsStdErr = BmmData->ConsoleErrCheck[Index + ConsoleErrMenu.MenuNumber];
624     }
625   }
626 }
627 
628 /**
629   This function allows a caller to extract the current configuration for one
630   or more named elements from the target driver.
631 
632   @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
633   @param Request         A null-terminated Unicode string in <ConfigRequest> format.
634   @param Progress        On return, points to a character in the Request string.
635                          Points to the string's null terminator if request was successful.
636                          Points to the most recent '&' before the first failing name/value
637                          pair (or the beginning of the string if the failure is in the
638                          first name/value pair) if the request was not successful.
639   @param Results         A null-terminated Unicode string in <ConfigAltResp> format which
640                          has all values filled in for the names in the Request string.
641                          String to be allocated by the called function.
642 
643   @retval  EFI_SUCCESS            The Results is filled with the requested values.
644   @retval  EFI_OUT_OF_RESOURCES   Not enough memory to store the results.
645   @retval  EFI_INVALID_PARAMETER  Request is NULL, illegal syntax, or unknown name.
646   @retval  EFI_NOT_FOUND          Routing data doesn't match any storage in this driver.
647 
648 **/
649 EFI_STATUS
650 EFIAPI
BootMaintExtractConfig(IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL * This,IN CONST EFI_STRING Request,OUT EFI_STRING * Progress,OUT EFI_STRING * Results)651 BootMaintExtractConfig (
652   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
653   IN  CONST EFI_STRING                       Request,
654   OUT EFI_STRING                             *Progress,
655   OUT EFI_STRING                             *Results
656   )
657 {
658   EFI_STATUS         Status;
659   UINTN              BufferSize;
660   BMM_CALLBACK_DATA  *Private;
661   EFI_STRING                       ConfigRequestHdr;
662   EFI_STRING                       ConfigRequest;
663   BOOLEAN                          AllocatedRequest;
664   UINTN                            Size;
665 
666   if (Progress == NULL || Results == NULL) {
667     return EFI_INVALID_PARAMETER;
668   }
669 
670   *Progress = Request;
671   if ((Request != NULL) && !HiiIsConfigHdrMatch (Request, &mBootMaintGuid, mBootMaintStorageName)) {
672     return EFI_NOT_FOUND;
673   }
674 
675   ConfigRequestHdr = NULL;
676   ConfigRequest    = NULL;
677   AllocatedRequest = FALSE;
678   Size             = 0;
679 
680   Private = BMM_CALLBACK_DATA_FROM_THIS (This);
681   //
682   // Convert buffer data to <ConfigResp> by helper function BlockToConfig()
683   //
684   BufferSize = sizeof (BMM_FAKE_NV_DATA);
685   ConfigRequest = Request;
686   if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) {
687     //
688     // Request has no request element, construct full request string.
689     // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
690     // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator
691     //
692     ConfigRequestHdr = HiiConstructConfigHdr (&mBootMaintGuid, mBootMaintStorageName, Private->BmmDriverHandle);
693     Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);
694     ConfigRequest = AllocateZeroPool (Size);
695     ASSERT (ConfigRequest != NULL);
696     AllocatedRequest = TRUE;
697     UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64)BufferSize);
698     FreePool (ConfigRequestHdr);
699   }
700 
701   Status = gHiiConfigRouting->BlockToConfig (
702                                 gHiiConfigRouting,
703                                 ConfigRequest,
704                                 (UINT8 *) &Private->BmmFakeNvData,
705                                 BufferSize,
706                                 Results,
707                                 Progress
708                                 );
709   //
710   // Free the allocated config request string.
711   //
712   if (AllocatedRequest) {
713     FreePool (ConfigRequest);
714     ConfigRequest = NULL;
715   }
716   //
717   // Set Progress string to the original request string.
718   //
719   if (Request == NULL) {
720     *Progress = NULL;
721   } else if (StrStr (Request, L"OFFSET") == NULL) {
722     *Progress = Request + StrLen (Request);
723   }
724 
725   return Status;
726 }
727 
728 /**
729   This function applies changes in a driver's configuration.
730   Input is a Configuration, which has the routing data for this
731   driver followed by name / value configuration pairs. The driver
732   must apply those pairs to its configurable storage. If the
733   driver's configuration is stored in a linear block of data
734   and the driver's name / value pairs are in <BlockConfig>
735   format, it may use the ConfigToBlock helper function (above) to
736   simplify the job. Currently not implemented.
737 
738   @param[in]  This                Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
739   @param[in]  Configuration       A null-terminated Unicode string in
740                                   <ConfigString> format.
741   @param[out] Progress            A pointer to a string filled in with the
742                                   offset of the most recent '&' before the
743                                   first failing name / value pair (or the
744                                   beginn ing of the string if the failure
745                                   is in the first name / value pair) or
746                                   the terminating NULL if all was
747                                   successful.
748 
749   @retval EFI_SUCCESS             The results have been distributed or are
750                                   awaiting distribution.
751   @retval EFI_OUT_OF_RESOURCES    Not enough memory to store the
752                                   parts of the results that must be
753                                   stored awaiting possible future
754                                   protocols.
755   @retval EFI_INVALID_PARAMETERS  Passing in a NULL for the
756                                   Results parameter would result
757                                   in this type of error.
758   @retval EFI_NOT_FOUND           Target for the specified routing data
759                                   was not found.
760 **/
761 EFI_STATUS
762 EFIAPI
BootMaintRouteConfig(IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL * This,IN CONST EFI_STRING Configuration,OUT EFI_STRING * Progress)763 BootMaintRouteConfig (
764   IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
765   IN CONST EFI_STRING                     Configuration,
766   OUT EFI_STRING                          *Progress
767   )
768 {
769   EFI_STATUS                      Status;
770   UINTN                           BufferSize;
771   EFI_HII_CONFIG_ROUTING_PROTOCOL *ConfigRouting;
772   BMM_FAKE_NV_DATA                *NewBmmData;
773   BMM_FAKE_NV_DATA                *OldBmmData;
774   BM_MENU_ENTRY                   *NewMenuEntry;
775   BM_LOAD_CONTEXT                 *NewLoadContext;
776   UINT16                          Index;
777   BOOLEAN                         TerminalAttChange;
778   BMM_CALLBACK_DATA               *Private;
779   UINTN                           Offset;
780 
781   if (Progress == NULL) {
782     return EFI_INVALID_PARAMETER;
783   }
784   *Progress = Configuration;
785 
786   if (Configuration == NULL) {
787     return EFI_INVALID_PARAMETER;
788   }
789 
790   //
791   // Check routing data in <ConfigHdr>.
792   // Note: there is no name for Name/Value storage, only GUID will be checked
793   //
794   if (!HiiIsConfigHdrMatch (Configuration, &mBootMaintGuid, mBootMaintStorageName)) {
795     return EFI_NOT_FOUND;
796   }
797 
798   Status = gBS->LocateProtocol (
799                   &gEfiHiiConfigRoutingProtocolGuid,
800                   NULL,
801                   (VOID **)&ConfigRouting
802                   );
803   if (EFI_ERROR (Status)) {
804     return Status;
805   }
806 
807   Private = BMM_CALLBACK_DATA_FROM_THIS (This);
808   //
809   // Get Buffer Storage data from EFI variable
810   //
811   BufferSize = sizeof (BMM_FAKE_NV_DATA);
812   OldBmmData = &Private->BmmOldFakeNVData;
813   NewBmmData = &Private->BmmFakeNvData;
814   Offset     = 0;
815   //
816   // Convert <ConfigResp> to buffer data by helper function ConfigToBlock()
817   //
818   Status = ConfigRouting->ConfigToBlock (
819                             ConfigRouting,
820                             Configuration,
821                             (UINT8 *) NewBmmData,
822                             &BufferSize,
823                             Progress
824                             );
825   ASSERT_EFI_ERROR (Status);
826   //
827   // Compare new and old BMM configuration data and only do action for modified item to
828   // avoid setting unnecessary non-volatile variable
829   //
830 
831   //
832   // Check data which located in BMM main page and save the settings if need
833   //
834   if (CompareMem (&NewBmmData->BootNext, &OldBmmData->BootNext, sizeof (NewBmmData->BootNext)) != 0) {
835     Status = Var_UpdateBootNext (Private);
836     if (EFI_ERROR (Status)) {
837       Offset = OFFSET_OF (BMM_FAKE_NV_DATA, BootNext);
838       goto Exit;
839     }
840   }
841 
842   //
843   // Check data which located in Boot Options Menu and save the settings if need
844   //
845   if (CompareMem (NewBmmData->BootOptionDel, OldBmmData->BootOptionDel, sizeof (NewBmmData->BootOptionDel)) != 0) {
846     for (Index = 0;
847          ((Index < BootOptionMenu.MenuNumber) && (Index < (sizeof (NewBmmData->BootOptionDel) / sizeof (NewBmmData->BootOptionDel[0]))));
848          Index ++) {
849       NewMenuEntry            = BOpt_GetMenuEntry (&BootOptionMenu, Index);
850       NewLoadContext          = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
851       NewLoadContext->Deleted = NewBmmData->BootOptionDel[Index];
852       NewBmmData->BootOptionDel[Index] = FALSE;
853       NewBmmData->BootOptionDelMark[Index] = FALSE;
854     }
855 
856     Status = Var_DelBootOption ();
857     if (EFI_ERROR (Status)) {
858       Offset = OFFSET_OF (BMM_FAKE_NV_DATA, BootOptionDel);
859       goto Exit;
860     }
861   }
862 
863   if (CompareMem (NewBmmData->BootOptionOrder, OldBmmData->BootOptionOrder, sizeof (NewBmmData->BootOptionOrder)) != 0) {
864     Status = Var_UpdateBootOrder (Private);
865     if (EFI_ERROR (Status)) {
866       Offset = OFFSET_OF (BMM_FAKE_NV_DATA, BootOptionOrder);
867       goto Exit;
868     }
869   }
870 
871   if (CompareMem (&NewBmmData->BootTimeOut, &OldBmmData->BootTimeOut, sizeof (NewBmmData->BootTimeOut)) != 0){
872     Status = gRT->SetVariable(
873                     L"Timeout",
874                     &gEfiGlobalVariableGuid,
875                     EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
876                     sizeof(UINT16),
877                     &(NewBmmData->BootTimeOut)
878                     );
879     if (EFI_ERROR (Status)) {
880       Offset = OFFSET_OF (BMM_FAKE_NV_DATA, BootTimeOut);
881       goto Exit;
882     }
883     Private->BmmOldFakeNVData.BootTimeOut = NewBmmData->BootTimeOut;
884   }
885 
886   //
887   // Check data which located in Driver Options Menu and save the settings if need
888   //
889   if (CompareMem (NewBmmData->DriverOptionDel, OldBmmData->DriverOptionDel, sizeof (NewBmmData->DriverOptionDel)) != 0) {
890     for (Index = 0;
891          ((Index < DriverOptionMenu.MenuNumber) && (Index < (sizeof (NewBmmData->DriverOptionDel) / sizeof (NewBmmData->DriverOptionDel[0]))));
892          Index++) {
893       NewMenuEntry            = BOpt_GetMenuEntry (&DriverOptionMenu, Index);
894       NewLoadContext          = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
895       NewLoadContext->Deleted = NewBmmData->DriverOptionDel[Index];
896       NewBmmData->DriverOptionDel[Index] = FALSE;
897       NewBmmData->DriverOptionDelMark[Index] = FALSE;
898     }
899     Status = Var_DelDriverOption ();
900     if (EFI_ERROR (Status)) {
901       Offset = OFFSET_OF (BMM_FAKE_NV_DATA, DriverOptionDel);
902       goto Exit;
903     }
904   }
905 
906   if (CompareMem (NewBmmData->DriverOptionOrder, OldBmmData->DriverOptionOrder, sizeof (NewBmmData->DriverOptionOrder)) != 0) {
907     Status = Var_UpdateDriverOrder (Private);
908     if (EFI_ERROR (Status)) {
909       Offset = OFFSET_OF (BMM_FAKE_NV_DATA, DriverOptionOrder);
910       goto Exit;
911     }
912   }
913 
914   if (CompareMem (&NewBmmData->ConsoleOutMode, &OldBmmData->ConsoleOutMode, sizeof (NewBmmData->ConsoleOutMode)) != 0){
915     Status = Var_UpdateConMode(Private);
916     if (EFI_ERROR (Status)) {
917       Offset = OFFSET_OF (BMM_FAKE_NV_DATA, ConsoleOutMode);
918       goto Exit;
919     }
920   }
921 
922   TerminalAttChange = FALSE;
923   for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) {
924 
925     //
926     // only need update modified items
927     //
928     if (CompareMem (&NewBmmData->COMBaudRate[Index], &OldBmmData->COMBaudRate[Index], sizeof (NewBmmData->COMBaudRate[Index])) == 0 &&
929          CompareMem (&NewBmmData->COMDataRate[Index], &OldBmmData->COMDataRate[Index], sizeof (NewBmmData->COMDataRate[Index])) == 0 &&
930          CompareMem (&NewBmmData->COMStopBits[Index], &OldBmmData->COMStopBits[Index], sizeof (NewBmmData->COMStopBits[Index])) == 0 &&
931          CompareMem (&NewBmmData->COMParity[Index], &OldBmmData->COMParity[Index], sizeof (NewBmmData->COMParity[Index])) == 0 &&
932          CompareMem (&NewBmmData->COMTerminalType[Index], &OldBmmData->COMTerminalType[Index], sizeof (NewBmmData->COMTerminalType[Index])) == 0 &&
933          CompareMem (&NewBmmData->COMFlowControl[Index], &OldBmmData->COMFlowControl[Index], sizeof (NewBmmData->COMFlowControl[Index])) == 0) {
934       continue;
935     }
936 
937     TerminalAttChange = TRUE;
938   }
939   if (TerminalAttChange) {
940     if (CompareMem (&NewBmmData->COMBaudRate[Index], &OldBmmData->COMBaudRate[Index], sizeof (NewBmmData->COMBaudRate[Index])) != 0) {
941       Offset = OFFSET_OF (BMM_FAKE_NV_DATA, COMBaudRate);
942     } else if (CompareMem (&NewBmmData->COMDataRate[Index], &OldBmmData->COMDataRate[Index], sizeof (NewBmmData->COMDataRate[Index])) != 0) {
943       Offset = OFFSET_OF (BMM_FAKE_NV_DATA, COMDataRate);
944     } else if (CompareMem (&NewBmmData->COMStopBits[Index], &OldBmmData->COMStopBits[Index], sizeof (NewBmmData->COMStopBits[Index])) != 0) {
945       Offset = OFFSET_OF (BMM_FAKE_NV_DATA, COMStopBits);
946     } else if (CompareMem (&NewBmmData->COMParity[Index], &OldBmmData->COMParity[Index], sizeof (NewBmmData->COMParity[Index])) != 0) {
947       Offset = OFFSET_OF (BMM_FAKE_NV_DATA, COMParity);
948     } else if (CompareMem (&NewBmmData->COMTerminalType[Index], &OldBmmData->COMTerminalType[Index], sizeof (NewBmmData->COMTerminalType[Index])) != 0) {
949       Offset = OFFSET_OF (BMM_FAKE_NV_DATA, COMTerminalType);
950     } else if (CompareMem (&NewBmmData->COMFlowControl[Index], &OldBmmData->COMFlowControl[Index], sizeof (NewBmmData->COMFlowControl[Index])) != 0) {
951       Offset = OFFSET_OF (BMM_FAKE_NV_DATA, COMFlowControl);
952     }
953     Status = Var_UpdateConsoleInpOption ();
954     if (EFI_ERROR (Status)) {
955       goto Exit;
956     }
957     Status = Var_UpdateConsoleOutOption ();
958     if (EFI_ERROR (Status)) {
959       goto Exit;
960     }
961     Status = Var_UpdateErrorOutOption ();
962     if (EFI_ERROR (Status)) {
963       goto Exit;
964     }
965   }
966   //
967   // Check data which located in Console Options Menu and save the settings if need
968   //
969   if (CompareMem (NewBmmData->ConsoleInCheck, OldBmmData->ConsoleInCheck, sizeof (NewBmmData->ConsoleInCheck)) != 0){
970     Status = Var_UpdateConsoleInpOption();
971     if (EFI_ERROR (Status)) {
972       Offset = OFFSET_OF (BMM_FAKE_NV_DATA, ConsoleInCheck);
973       goto Exit;
974     }
975   }
976 
977   if (CompareMem (NewBmmData->ConsoleOutCheck, OldBmmData->ConsoleOutCheck, sizeof (NewBmmData->ConsoleOutCheck)) != 0){
978     Status = Var_UpdateConsoleOutOption();
979     if (EFI_ERROR (Status)) {
980       Offset = OFFSET_OF (BMM_FAKE_NV_DATA, ConsoleOutCheck);
981       goto Exit;
982     }
983   }
984 
985   if (CompareMem (NewBmmData->ConsoleErrCheck, OldBmmData->ConsoleErrCheck, sizeof (NewBmmData->ConsoleErrCheck)) != 0){
986     Status = Var_UpdateErrorOutOption();
987     if (EFI_ERROR (Status)) {
988       Offset = OFFSET_OF (BMM_FAKE_NV_DATA, ConsoleErrCheck);
989       goto Exit;
990     }
991   }
992 
993   if (CompareMem (NewBmmData->BootDescriptionData, OldBmmData->BootDescriptionData, sizeof (NewBmmData->BootDescriptionData)) != 0 ||
994        CompareMem (NewBmmData->BootOptionalData, OldBmmData->BootOptionalData, sizeof (NewBmmData->BootOptionalData)) != 0) {
995     Status = Var_UpdateBootOption (Private);
996     NewBmmData->BootOptionChanged = FALSE;
997     if (EFI_ERROR (Status)) {
998       if (CompareMem (NewBmmData->BootDescriptionData, OldBmmData->BootDescriptionData, sizeof (NewBmmData->BootDescriptionData)) != 0) {
999         Offset = OFFSET_OF (BMM_FAKE_NV_DATA, BootDescriptionData);
1000       } else {
1001         Offset = OFFSET_OF (BMM_FAKE_NV_DATA, BootOptionalData);
1002       }
1003       goto Exit;
1004     }
1005     BOpt_GetBootOptions (Private);
1006   }
1007 
1008   if (CompareMem (NewBmmData->DriverDescriptionData, OldBmmData->DriverDescriptionData, sizeof (NewBmmData->DriverDescriptionData)) != 0 ||
1009        CompareMem (NewBmmData->DriverOptionalData, OldBmmData->DriverOptionalData, sizeof (NewBmmData->DriverOptionalData)) != 0) {
1010     Status = Var_UpdateDriverOption (
1011               Private,
1012               Private->BmmHiiHandle,
1013               NewBmmData->DriverDescriptionData,
1014               NewBmmData->DriverOptionalData,
1015               NewBmmData->ForceReconnect
1016               );
1017     NewBmmData->DriverOptionChanged = FALSE;
1018     NewBmmData->ForceReconnect      = TRUE;
1019     if (EFI_ERROR (Status)) {
1020       if (CompareMem (NewBmmData->DriverDescriptionData, OldBmmData->DriverDescriptionData, sizeof (NewBmmData->DriverDescriptionData)) != 0) {
1021         Offset = OFFSET_OF (BMM_FAKE_NV_DATA, DriverDescriptionData);
1022       } else {
1023         Offset = OFFSET_OF (BMM_FAKE_NV_DATA, DriverOptionalData);
1024       }
1025       goto Exit;
1026     }
1027 
1028     BOpt_GetDriverOptions (Private);
1029   }
1030 
1031   //
1032   // After user do the save action, need to update OldBmmData.
1033   //
1034   CopyMem (OldBmmData, NewBmmData, sizeof (BMM_FAKE_NV_DATA));
1035 
1036   return EFI_SUCCESS;
1037 
1038 Exit:
1039   //
1040   // Fail to save the data, update the progress string.
1041   //
1042   *Progress = UpdateProgress (Offset, Configuration);
1043   if (Status == EFI_OUT_OF_RESOURCES) {
1044     return Status;
1045   } else {
1046     return EFI_NOT_FOUND;
1047   }
1048 }
1049 
1050 /**
1051   This function processes the results of changes in configuration.
1052 
1053 
1054   @param This               Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
1055   @param Action             Specifies the type of action taken by the browser.
1056   @param QuestionId         A unique value which is sent to the original exporting driver
1057                             so that it can identify the type of data to expect.
1058   @param Type               The type of value for the question.
1059   @param Value              A pointer to the data being sent to the original exporting driver.
1060   @param ActionRequest      On return, points to the action requested by the callback function.
1061 
1062   @retval EFI_SUCCESS           The callback successfully handled the action.
1063   @retval EFI_OUT_OF_RESOURCES  Not enough storage is available to hold the variable and its data.
1064   @retval EFI_DEVICE_ERROR      The variable could not be saved.
1065   @retval EFI_UNSUPPORTED       The specified Action is not supported by the callback.
1066   @retval EFI_INVALID_PARAMETER The parameter of Value or ActionRequest is invalid.
1067 **/
1068 EFI_STATUS
1069 EFIAPI
BootMaintCallback(IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL * This,IN EFI_BROWSER_ACTION Action,IN EFI_QUESTION_ID QuestionId,IN UINT8 Type,IN EFI_IFR_TYPE_VALUE * Value,OUT EFI_BROWSER_ACTION_REQUEST * ActionRequest)1070 BootMaintCallback (
1071   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL         *This,
1072   IN        EFI_BROWSER_ACTION                     Action,
1073   IN        EFI_QUESTION_ID                        QuestionId,
1074   IN        UINT8                                  Type,
1075   IN        EFI_IFR_TYPE_VALUE                     *Value,
1076   OUT       EFI_BROWSER_ACTION_REQUEST             *ActionRequest
1077   )
1078 {
1079   BMM_CALLBACK_DATA *Private;
1080   BM_MENU_ENTRY     *NewMenuEntry;
1081   BMM_FAKE_NV_DATA  *CurrentFakeNVMap;
1082   BMM_FAKE_NV_DATA  *OldFakeNVMap;
1083   UINTN             Index;
1084   EFI_DEVICE_PATH_PROTOCOL * File;
1085 
1086   if (Action != EFI_BROWSER_ACTION_CHANGING && Action != EFI_BROWSER_ACTION_CHANGED && Action != EFI_BROWSER_ACTION_FORM_OPEN) {
1087     //
1088     // Do nothing for other UEFI Action. Only do call back when data is changed or the form is open.
1089     //
1090     return EFI_UNSUPPORTED;
1091   }
1092 
1093   Private        = BMM_CALLBACK_DATA_FROM_THIS (This);
1094 
1095   if (Action == EFI_BROWSER_ACTION_FORM_OPEN) {
1096     if (QuestionId == KEY_VALUE_TRIGGER_FORM_OPEN_ACTION) {
1097       if (!mFirstEnterBMMForm) {
1098         //
1099         // BMMUiLib depends on LegacyUi library to show legacy menus.
1100         // If we want to show Legacy menus correctly in BMM page,
1101         // we must do it after the LegacyUi library has already been initialized.
1102         // Opening the BMM form is the appropriate time that the LegacyUi library has already been initialized.
1103         // So we do the tasks which are related to legacy menus here.
1104         // 1. Update the menus (including legacy munu) show in BootMiantenanceManager page.
1105         // 2. Re-scan the BootOption menus (including the legacy boot option).
1106         //
1107         CustomizeMenus ();
1108         EfiBootManagerRefreshAllBootOption ();
1109         BOpt_GetBootOptions (Private);
1110         mFirstEnterBMMForm = TRUE;
1111       }
1112     }
1113   }
1114   //
1115   // Retrieve uncommitted data from Form Browser
1116   //
1117   CurrentFakeNVMap = &Private->BmmFakeNvData;
1118   OldFakeNVMap     = &Private->BmmOldFakeNVData;
1119   HiiGetBrowserData (&mBootMaintGuid, mBootMaintStorageName, sizeof (BMM_FAKE_NV_DATA), (UINT8 *) CurrentFakeNVMap);
1120 
1121   if (Action == EFI_BROWSER_ACTION_CHANGING) {
1122     if (Value == NULL) {
1123       return EFI_INVALID_PARAMETER;
1124     }
1125 
1126     UpdatePageId (Private, QuestionId);
1127 
1128     if (QuestionId < FILE_OPTION_OFFSET) {
1129       if (QuestionId < CONFIG_OPTION_OFFSET) {
1130         switch (QuestionId) {
1131         case FORM_BOOT_ADD_ID:
1132           // Leave BMM and enter FileExplorer.
1133           ChooseFile (NULL, L".efi", CreateBootOptionFromFile, &File);
1134           break;
1135 
1136         case FORM_DRV_ADD_FILE_ID:
1137           // Leave BMM and enter FileExplorer.
1138           ChooseFile (NULL, L".efi", CreateDriverOptionFromFile, &File);
1139           break;
1140 
1141         case FORM_DRV_ADD_HANDLE_ID:
1142           CleanUpPage (FORM_DRV_ADD_HANDLE_ID, Private);
1143           UpdateDrvAddHandlePage (Private);
1144           break;
1145 
1146         case FORM_BOOT_DEL_ID:
1147           CleanUpPage (FORM_BOOT_DEL_ID, Private);
1148           UpdateBootDelPage (Private);
1149           break;
1150 
1151         case FORM_BOOT_CHG_ID:
1152         case FORM_DRV_CHG_ID:
1153           UpdatePageBody (QuestionId, Private);
1154           break;
1155 
1156         case FORM_DRV_DEL_ID:
1157           CleanUpPage (FORM_DRV_DEL_ID, Private);
1158           UpdateDrvDelPage (Private);
1159           break;
1160 
1161         case FORM_CON_IN_ID:
1162         case FORM_CON_OUT_ID:
1163         case FORM_CON_ERR_ID:
1164           UpdatePageBody (QuestionId, Private);
1165           break;
1166 
1167         case FORM_CON_MODE_ID:
1168           CleanUpPage (FORM_CON_MODE_ID, Private);
1169           UpdateConModePage (Private);
1170           break;
1171 
1172         case FORM_CON_COM_ID:
1173           CleanUpPage (FORM_CON_COM_ID, Private);
1174           UpdateConCOMPage (Private);
1175           break;
1176 
1177         default:
1178           break;
1179         }
1180       } else if ((QuestionId >= TERMINAL_OPTION_OFFSET) && (QuestionId < CONSOLE_OPTION_OFFSET)) {
1181         Index                  = (UINT16) (QuestionId - TERMINAL_OPTION_OFFSET);
1182         Private->CurrentTerminal  = Index;
1183 
1184         CleanUpPage (FORM_CON_COM_SETUP_ID, Private);
1185         UpdateTerminalPage (Private);
1186 
1187       } else if (QuestionId >= HANDLE_OPTION_OFFSET) {
1188         Index                  = (UINT16) (QuestionId - HANDLE_OPTION_OFFSET);
1189 
1190         NewMenuEntry            = BOpt_GetMenuEntry (&DriverMenu, Index);
1191         ASSERT (NewMenuEntry != NULL);
1192         Private->HandleContext  = (BM_HANDLE_CONTEXT *) NewMenuEntry->VariableContext;
1193 
1194         CleanUpPage (FORM_DRV_ADD_HANDLE_DESC_ID, Private);
1195 
1196         Private->MenuEntry                  = NewMenuEntry;
1197         Private->LoadContext->FilePathList  = Private->HandleContext->DevicePath;
1198 
1199         UpdateDriverAddHandleDescPage (Private);
1200       }
1201     }
1202     if (QuestionId == KEY_VALUE_BOOT_FROM_FILE){
1203       // Leave BMM and enter FileExplorer.
1204       ChooseFile (NULL, L".efi", BootFromFile, &File);
1205     }
1206   } else if (Action == EFI_BROWSER_ACTION_CHANGED) {
1207     if ((Value == NULL) || (ActionRequest == NULL)) {
1208       return EFI_INVALID_PARAMETER;
1209     }
1210 
1211     if (QuestionId == KEY_VALUE_SAVE_AND_EXIT_BOOT) {
1212       CleanUselessBeforeSubmit (Private);
1213       CurrentFakeNVMap->BootOptionChanged = FALSE;
1214       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT;
1215     } else if (QuestionId == KEY_VALUE_SAVE_AND_EXIT_DRIVER) {
1216       CleanUselessBeforeSubmit (Private);
1217       CurrentFakeNVMap->DriverOptionChanged = FALSE;
1218       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT;
1219     } else if (QuestionId == KEY_VALUE_NO_SAVE_AND_EXIT_DRIVER) {
1220       //
1221       // Discard changes and exit formset
1222       //
1223       ZeroMem (CurrentFakeNVMap->DriverOptionalData, sizeof (CurrentFakeNVMap->DriverOptionalData));
1224       ZeroMem (CurrentFakeNVMap->BootDescriptionData, sizeof (CurrentFakeNVMap->BootDescriptionData));
1225       ZeroMem (OldFakeNVMap->DriverOptionalData, sizeof (OldFakeNVMap->DriverOptionalData));
1226       ZeroMem (OldFakeNVMap->DriverDescriptionData, sizeof (OldFakeNVMap->DriverDescriptionData));
1227       CurrentFakeNVMap->DriverOptionChanged = FALSE;
1228       CurrentFakeNVMap->ForceReconnect      = TRUE;
1229       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT;
1230     } else if (QuestionId == KEY_VALUE_NO_SAVE_AND_EXIT_BOOT) {
1231       //
1232       // Discard changes and exit formset
1233       //
1234       ZeroMem (CurrentFakeNVMap->BootOptionalData, sizeof (CurrentFakeNVMap->BootOptionalData));
1235       ZeroMem (CurrentFakeNVMap->BootDescriptionData, sizeof (CurrentFakeNVMap->BootDescriptionData));
1236       ZeroMem (OldFakeNVMap->BootOptionalData, sizeof (OldFakeNVMap->BootOptionalData));
1237       ZeroMem (OldFakeNVMap->BootDescriptionData, sizeof (OldFakeNVMap->BootDescriptionData));
1238       CurrentFakeNVMap->BootOptionChanged = FALSE;
1239       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT;
1240     } else if (QuestionId == KEY_VALUE_BOOT_DESCRIPTION || QuestionId == KEY_VALUE_BOOT_OPTION) {
1241       CurrentFakeNVMap->BootOptionChanged = TRUE;
1242     } else if (QuestionId == KEY_VALUE_DRIVER_DESCRIPTION || QuestionId == KEY_VALUE_DRIVER_OPTION) {
1243       CurrentFakeNVMap->DriverOptionChanged = TRUE;
1244     }
1245 
1246     if ((QuestionId >= BOOT_OPTION_DEL_QUESTION_ID) && (QuestionId < BOOT_OPTION_DEL_QUESTION_ID + MAX_MENU_NUMBER)) {
1247       if (Value->b){
1248         //
1249         // Means user try to delete this boot option but not press F10 or "Commit Changes and Exit" menu.
1250         //
1251         CurrentFakeNVMap->BootOptionDelMark[QuestionId - BOOT_OPTION_DEL_QUESTION_ID] = TRUE;
1252       } else {
1253         //
1254         // Means user remove the old check status.
1255         //
1256         CurrentFakeNVMap->BootOptionDelMark[QuestionId - BOOT_OPTION_DEL_QUESTION_ID] = FALSE;
1257       }
1258     } else if ((QuestionId >= DRIVER_OPTION_DEL_QUESTION_ID) && (QuestionId < DRIVER_OPTION_DEL_QUESTION_ID + MAX_MENU_NUMBER)) {
1259       if (Value->b){
1260         CurrentFakeNVMap->DriverOptionDelMark[QuestionId - DRIVER_OPTION_DEL_QUESTION_ID] = TRUE;
1261       } else {
1262         CurrentFakeNVMap->DriverOptionDelMark[QuestionId - DRIVER_OPTION_DEL_QUESTION_ID] = FALSE;
1263       }
1264     } else {
1265       switch (QuestionId) {
1266       case KEY_VALUE_SAVE_AND_EXIT:
1267       case KEY_VALUE_NO_SAVE_AND_EXIT:
1268         if (QuestionId == KEY_VALUE_SAVE_AND_EXIT) {
1269           CleanUselessBeforeSubmit (Private);
1270           *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT;
1271         } else if (QuestionId == KEY_VALUE_NO_SAVE_AND_EXIT) {
1272           DiscardChangeHandler (Private, CurrentFakeNVMap);
1273           *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT;
1274         }
1275 
1276         break;
1277 
1278       case FORM_RESET:
1279         gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
1280         return EFI_UNSUPPORTED;
1281 
1282       default:
1283         break;
1284       }
1285     }
1286     //
1287     // Update the content in Terminal menu and Console menu here.
1288     //
1289     if (QuestionId == COM_BAUD_RATE_QUESTION_ID + Private->CurrentTerminal || QuestionId == COM_DATA_RATE_QUESTION_ID + Private->CurrentTerminal ||
1290       QuestionId == COM_PARITY_QUESTION_ID + Private->CurrentTerminal || QuestionId == COM_STOP_BITS_QUESTION_ID + Private->CurrentTerminal ||
1291       QuestionId == COM_TERMINAL_QUESTION_ID + Private->CurrentTerminal || QuestionId == COM_FLOWCONTROL_QUESTION_ID + Private->CurrentTerminal
1292     ) {
1293       UpdateTerminalContent(CurrentFakeNVMap);
1294     }
1295     if ((QuestionId >= CON_IN_DEVICE_QUESTION_ID) && (QuestionId < CON_IN_DEVICE_QUESTION_ID + MAX_MENU_NUMBER)) {
1296       UpdateConsoleContent (L"ConIn",CurrentFakeNVMap);
1297     } else if ((QuestionId >= CON_OUT_DEVICE_QUESTION_ID) && (QuestionId < CON_OUT_DEVICE_QUESTION_ID + MAX_MENU_NUMBER)) {
1298       UpdateConsoleContent (L"ConOut", CurrentFakeNVMap);
1299     } else if ((QuestionId >= CON_ERR_DEVICE_QUESTION_ID) && (QuestionId < CON_ERR_DEVICE_QUESTION_ID + MAX_MENU_NUMBER)) {
1300       UpdateConsoleContent (L"ErrOut", CurrentFakeNVMap);
1301     }
1302   }
1303 
1304   //
1305   // Pass changed uncommitted data back to Form Browser
1306   //
1307   HiiSetBrowserData (&mBootMaintGuid, mBootMaintStorageName, sizeof (BMM_FAKE_NV_DATA), (UINT8 *) CurrentFakeNVMap, NULL);
1308 
1309   return EFI_SUCCESS;
1310 }
1311 
1312 /**
1313   Discard all changes done to the BMM pages such as Boot Order change,
1314   Driver order change.
1315 
1316   @param Private            The BMM context data.
1317   @param CurrentFakeNVMap   The current Fack NV Map.
1318 
1319 **/
1320 VOID
DiscardChangeHandler(IN BMM_CALLBACK_DATA * Private,IN BMM_FAKE_NV_DATA * CurrentFakeNVMap)1321 DiscardChangeHandler (
1322   IN  BMM_CALLBACK_DATA               *Private,
1323   IN  BMM_FAKE_NV_DATA                *CurrentFakeNVMap
1324   )
1325 {
1326   UINT16  Index;
1327 
1328   switch (Private->BmmPreviousPageId) {
1329   case FORM_BOOT_CHG_ID:
1330     CopyMem (CurrentFakeNVMap->BootOptionOrder, Private->BmmOldFakeNVData.BootOptionOrder, sizeof (CurrentFakeNVMap->BootOptionOrder));
1331     break;
1332 
1333   case FORM_DRV_CHG_ID:
1334     CopyMem (CurrentFakeNVMap->DriverOptionOrder, Private->BmmOldFakeNVData.DriverOptionOrder, sizeof (CurrentFakeNVMap->DriverOptionOrder));
1335     break;
1336 
1337   case FORM_BOOT_DEL_ID:
1338     ASSERT (BootOptionMenu.MenuNumber <= (sizeof (CurrentFakeNVMap->BootOptionDel) / sizeof (CurrentFakeNVMap->BootOptionDel[0])));
1339     for (Index = 0; Index < BootOptionMenu.MenuNumber; Index++) {
1340       CurrentFakeNVMap->BootOptionDel[Index] = FALSE;
1341     }
1342     break;
1343 
1344   case FORM_DRV_DEL_ID:
1345     ASSERT (DriverOptionMenu.MenuNumber <= (sizeof (CurrentFakeNVMap->DriverOptionDel) / sizeof (CurrentFakeNVMap->DriverOptionDel[0])));
1346     for (Index = 0; Index < DriverOptionMenu.MenuNumber; Index++) {
1347       CurrentFakeNVMap->DriverOptionDel[Index] = FALSE;
1348     }
1349     break;
1350 
1351   case FORM_BOOT_NEXT_ID:
1352     CurrentFakeNVMap->BootNext = Private->BmmOldFakeNVData.BootNext;
1353     break;
1354 
1355   case FORM_TIME_OUT_ID:
1356     CurrentFakeNVMap->BootTimeOut = Private->BmmOldFakeNVData.BootTimeOut;
1357     break;
1358 
1359   case FORM_DRV_ADD_HANDLE_DESC_ID:
1360   case FORM_DRV_ADD_FILE_ID:
1361   case FORM_DRV_ADD_HANDLE_ID:
1362     CurrentFakeNVMap->DriverAddHandleDesc[0]          = 0x0000;
1363     CurrentFakeNVMap->DriverAddHandleOptionalData[0]  = 0x0000;
1364     break;
1365 
1366   default:
1367     break;
1368   }
1369 }
1370 
1371 /**
1372   This function is to clean some useless data before submit changes.
1373 
1374   @param Private            The BMM context data.
1375 
1376 **/
1377 VOID
CleanUselessBeforeSubmit(IN BMM_CALLBACK_DATA * Private)1378 CleanUselessBeforeSubmit (
1379   IN  BMM_CALLBACK_DATA               *Private
1380   )
1381 {
1382   UINT16  Index;
1383   if (Private->BmmPreviousPageId != FORM_BOOT_DEL_ID) {
1384     for (Index = 0; Index < BootOptionMenu.MenuNumber; Index++) {
1385       if (Private->BmmFakeNvData.BootOptionDel[Index] && !Private->BmmFakeNvData.BootOptionDelMark[Index]) {
1386         Private->BmmFakeNvData.BootOptionDel[Index] = FALSE;
1387         Private->BmmOldFakeNVData.BootOptionDel[Index] = FALSE;
1388       }
1389     }
1390   }
1391   if (Private->BmmPreviousPageId != FORM_DRV_DEL_ID) {
1392     for (Index = 0; Index < DriverOptionMenu.MenuNumber; Index++) {
1393       if (Private->BmmFakeNvData.DriverOptionDel[Index] && !Private->BmmFakeNvData.DriverOptionDelMark[Index]) {
1394         Private->BmmFakeNvData.DriverOptionDel[Index] = FALSE;
1395         Private->BmmOldFakeNVData.DriverOptionDel[Index] = FALSE;
1396       }
1397     }
1398   }
1399 }
1400 
1401 /**
1402 
1403   Update the menus in the BMM page.
1404 
1405 **/
1406 VOID
CustomizeMenus(VOID)1407 CustomizeMenus (
1408   VOID
1409   )
1410 {
1411   VOID                        *StartOpCodeHandle;
1412   VOID                        *EndOpCodeHandle;
1413   EFI_IFR_GUID_LABEL          *StartGuidLabel;
1414   EFI_IFR_GUID_LABEL          *EndGuidLabel;
1415 
1416   //
1417   // Allocate space for creation of UpdateData Buffer
1418   //
1419   StartOpCodeHandle = HiiAllocateOpCodeHandle ();
1420   ASSERT (StartOpCodeHandle != NULL);
1421 
1422   EndOpCodeHandle = HiiAllocateOpCodeHandle ();
1423   ASSERT (EndOpCodeHandle != NULL);
1424   //
1425   // Create Hii Extend Label OpCode as the start opcode
1426   //
1427   StartGuidLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
1428   StartGuidLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
1429   StartGuidLabel->Number       = LABEL_FORM_MAIN_START;
1430   //
1431   // Create Hii Extend Label OpCode as the end opcode
1432   //
1433   EndGuidLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
1434   EndGuidLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
1435   EndGuidLabel->Number       = LABEL_FORM_MAIN_END;
1436 
1437   //
1438   //Updata Front Page form
1439   //
1440   UiCustomizeBMMPage (
1441     mBmmCallbackInfo->BmmHiiHandle,
1442     StartOpCodeHandle
1443     );
1444 
1445   HiiUpdateForm (
1446     mBmmCallbackInfo->BmmHiiHandle,
1447     &mBootMaintGuid,
1448     FORM_MAIN_ID,
1449     StartOpCodeHandle,
1450     EndOpCodeHandle
1451     );
1452 
1453   HiiFreeOpCodeHandle (StartOpCodeHandle);
1454   HiiFreeOpCodeHandle (EndOpCodeHandle);
1455 }
1456 
1457 /**
1458    Create dynamic code for BMM and initialize all of BMM configuration data in BmmFakeNvData and
1459    BmmOldFakeNVData member in BMM context data.
1460 
1461   @param CallbackData    The BMM context data.
1462 
1463 **/
1464 VOID
InitializeBmmConfig(IN BMM_CALLBACK_DATA * CallbackData)1465 InitializeBmmConfig (
1466   IN  BMM_CALLBACK_DATA    *CallbackData
1467   )
1468 {
1469   BM_MENU_ENTRY   *NewMenuEntry;
1470   BM_LOAD_CONTEXT *NewLoadContext;
1471   UINT16          Index;
1472 
1473   ASSERT (CallbackData != NULL);
1474 
1475   //
1476   // Initialize data which located in BMM main page
1477   //
1478   CallbackData->BmmFakeNvData.BootNext = NONE_BOOTNEXT_VALUE;
1479   for (Index = 0; Index < BootOptionMenu.MenuNumber; Index++) {
1480     NewMenuEntry    = BOpt_GetMenuEntry (&BootOptionMenu, Index);
1481     NewLoadContext  = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
1482 
1483     if (NewLoadContext->IsBootNext) {
1484       CallbackData->BmmFakeNvData.BootNext = Index;
1485       break;
1486     }
1487   }
1488 
1489   CallbackData->BmmFakeNvData.BootTimeOut = PcdGet16 (PcdPlatformBootTimeOut);
1490 
1491   //
1492   // Initialize data which located in Boot Options Menu
1493   //
1494   GetBootOrder (CallbackData);
1495 
1496   //
1497   // Initialize data which located in Driver Options Menu
1498   //
1499   GetDriverOrder (CallbackData);
1500 
1501   //
1502   // Initialize data which located in Console Options Menu
1503   //
1504   GetConsoleOutMode (CallbackData);
1505   GetConsoleInCheck (CallbackData);
1506   GetConsoleOutCheck (CallbackData);
1507   GetConsoleErrCheck (CallbackData);
1508   GetTerminalAttribute (CallbackData);
1509 
1510   CallbackData->BmmFakeNvData.ForceReconnect = TRUE;
1511 
1512   //
1513   // Backup Initialize BMM configuartion data to BmmOldFakeNVData
1514   //
1515   CopyMem (&CallbackData->BmmOldFakeNVData, &CallbackData->BmmFakeNvData, sizeof (BMM_FAKE_NV_DATA));
1516 }
1517 
1518 /**
1519   Initialized all Menu Option List.
1520 
1521   @param CallbackData    The BMM context data.
1522 
1523 **/
1524 VOID
InitAllMenu(IN BMM_CALLBACK_DATA * CallbackData)1525 InitAllMenu (
1526   IN  BMM_CALLBACK_DATA    *CallbackData
1527   )
1528 {
1529   InitializeListHead (&BootOptionMenu.Head);
1530   InitializeListHead (&DriverOptionMenu.Head);
1531   BOpt_GetBootOptions (CallbackData);
1532   BOpt_GetDriverOptions (CallbackData);
1533   BOpt_FindDrivers ();
1534   InitializeListHead (&ConsoleInpMenu.Head);
1535   InitializeListHead (&ConsoleOutMenu.Head);
1536   InitializeListHead (&ConsoleErrMenu.Head);
1537   InitializeListHead (&TerminalMenu.Head);
1538   LocateSerialIo ();
1539   GetAllConsoles ();
1540   mAllMenuInit = TRUE;
1541 }
1542 
1543 /**
1544   Free up all Menu Option list.
1545 
1546 **/
1547 VOID
FreeAllMenu(VOID)1548 FreeAllMenu (
1549   VOID
1550   )
1551 {
1552   if (!mAllMenuInit){
1553     return;
1554   }
1555   BOpt_FreeMenu (&BootOptionMenu);
1556   BOpt_FreeMenu (&DriverOptionMenu);
1557   BOpt_FreeMenu (&DriverMenu);
1558   FreeAllConsoles ();
1559   mAllMenuInit = FALSE;
1560 }
1561 
1562 /**
1563   Initial the boot mode related parameters.
1564 
1565 **/
1566 VOID
BmmInitialBootModeInfo(VOID)1567 BmmInitialBootModeInfo (
1568   VOID
1569   )
1570 {
1571   EFI_STATUS                         Status;
1572   EFI_GRAPHICS_OUTPUT_PROTOCOL       *GraphicsOutput;
1573   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *SimpleTextOut;
1574   UINTN                              BootTextColumn;
1575   UINTN                              BootTextRow;
1576 
1577   if (mBmmModeInitialized) {
1578     return;
1579   }
1580 
1581   //
1582   // After the console is ready, get current video resolution
1583   // and text mode before launching setup at first time.
1584   //
1585   Status = gBS->HandleProtocol (
1586                   gST->ConsoleOutHandle,
1587                   &gEfiGraphicsOutputProtocolGuid,
1588                   (VOID**)&GraphicsOutput
1589                   );
1590   if (EFI_ERROR (Status)) {
1591     GraphicsOutput = NULL;
1592   }
1593 
1594   Status = gBS->HandleProtocol (
1595                   gST->ConsoleOutHandle,
1596                   &gEfiSimpleTextOutProtocolGuid,
1597                   (VOID**)&SimpleTextOut
1598                   );
1599   if (EFI_ERROR (Status)) {
1600     SimpleTextOut = NULL;
1601   }
1602 
1603   if (GraphicsOutput != NULL) {
1604     //
1605     // Get current video resolution and text mode.
1606     //
1607     mBmmBootHorizontalResolution = GraphicsOutput->Mode->Info->HorizontalResolution;
1608     mBmmBootVerticalResolution   = GraphicsOutput->Mode->Info->VerticalResolution;
1609   }
1610 
1611   if (SimpleTextOut != NULL) {
1612     Status = SimpleTextOut->QueryMode (
1613                               SimpleTextOut,
1614                               SimpleTextOut->Mode->Mode,
1615                               &BootTextColumn,
1616                               &BootTextRow
1617                               );
1618     mBmmBootTextModeColumn = (UINT32)BootTextColumn;
1619     mBmmBootTextModeRow    = (UINT32)BootTextRow;
1620   }
1621 
1622   //
1623   // Get user defined text mode for setup.
1624   //
1625   mBmmSetupHorizontalResolution = PcdGet32 (PcdSetupVideoHorizontalResolution);
1626   mBmmSetupVerticalResolution   = PcdGet32 (PcdSetupVideoVerticalResolution);
1627   mBmmSetupTextModeColumn       = PcdGet32 (PcdSetupConOutColumn);
1628   mBmmSetupTextModeRow          = PcdGet32 (PcdSetupConOutRow);
1629 
1630   mBmmModeInitialized           = TRUE;
1631 }
1632 
1633 /**
1634 
1635   Install Boot Maintenance Manager Menu driver.
1636 
1637   @param ImageHandle     The image handle.
1638   @param SystemTable     The system table.
1639 
1640   @retval  EFI_SUCEESS  Install Boot manager menu success.
1641   @retval  Other        Return error status.
1642 
1643 **/
1644 EFI_STATUS
1645 EFIAPI
BootMaintenanceManagerUiLibConstructor(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)1646 BootMaintenanceManagerUiLibConstructor (
1647   IN EFI_HANDLE                            ImageHandle,
1648   IN EFI_SYSTEM_TABLE                      *SystemTable
1649   )
1650 
1651 {
1652   EFI_STATUS               Status;
1653   UINT8                    *Ptr;
1654 
1655   Status = EFI_SUCCESS;
1656 
1657   //
1658   // Install Device Path Protocol and Config Access protocol to driver handle
1659   //
1660   Status = gBS->InstallMultipleProtocolInterfaces (
1661                   &mBmmCallbackInfo->BmmDriverHandle,
1662                   &gEfiDevicePathProtocolGuid,
1663                   &mBmmHiiVendorDevicePath,
1664                   &gEfiHiiConfigAccessProtocolGuid,
1665                   &mBmmCallbackInfo->BmmConfigAccess,
1666                   NULL
1667                   );
1668   ASSERT_EFI_ERROR (Status);
1669 
1670   //
1671   // Post our Boot Maint VFR binary to the HII database.
1672   //
1673   mBmmCallbackInfo->BmmHiiHandle = HiiAddPackages (
1674                                     &mBootMaintGuid,
1675                                     mBmmCallbackInfo->BmmDriverHandle,
1676                                     BootMaintenanceManagerBin,
1677                                     BootMaintenanceManagerUiLibStrings,
1678                                     NULL
1679                                     );
1680   ASSERT (mBmmCallbackInfo->BmmHiiHandle != NULL);
1681 
1682   //
1683   // Locate Formbrowser2 protocol
1684   //
1685   Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &mBmmCallbackInfo->FormBrowser2);
1686   ASSERT_EFI_ERROR (Status);
1687 
1688   //
1689   // Create LoadOption in BmmCallbackInfo for Driver Callback
1690   //
1691   Ptr = AllocateZeroPool (sizeof (BM_LOAD_CONTEXT) + sizeof (BM_FILE_CONTEXT) + sizeof (BM_HANDLE_CONTEXT) + sizeof (BM_MENU_ENTRY));
1692   ASSERT (Ptr != NULL);
1693 
1694   //
1695   // Initialize Bmm callback data.
1696   //
1697   mBmmCallbackInfo->LoadContext = (BM_LOAD_CONTEXT *) Ptr;
1698   Ptr += sizeof (BM_LOAD_CONTEXT);
1699 
1700   mBmmCallbackInfo->FileContext = (BM_FILE_CONTEXT *) Ptr;
1701   Ptr += sizeof (BM_FILE_CONTEXT);
1702 
1703   mBmmCallbackInfo->HandleContext = (BM_HANDLE_CONTEXT *) Ptr;
1704   Ptr += sizeof (BM_HANDLE_CONTEXT);
1705 
1706   mBmmCallbackInfo->MenuEntry     = (BM_MENU_ENTRY *) Ptr;
1707 
1708   mBmmCallbackInfo->BmmPreviousPageId  = FORM_MAIN_ID;
1709   mBmmCallbackInfo->BmmCurrentPageId   = FORM_MAIN_ID;
1710 
1711   InitAllMenu (mBmmCallbackInfo);
1712 
1713   CreateUpdateData();
1714   //
1715   // Update boot maintenance manager page
1716   //
1717   InitializeBmmConfig(mBmmCallbackInfo);
1718 
1719   BmmInitialBootModeInfo();
1720 
1721   return EFI_SUCCESS;
1722 }
1723 
1724 /**
1725   Unloads the application and its installed protocol.
1726 
1727   @param ImageHandle       Handle that identifies the image to be unloaded.
1728   @param  SystemTable      The system table.
1729 
1730   @retval EFI_SUCCESS      The image has been unloaded.
1731 
1732 **/
1733 EFI_STATUS
1734 EFIAPI
BootMaintenanceManagerUiLibDestructor(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)1735 BootMaintenanceManagerUiLibDestructor (
1736   IN EFI_HANDLE                            ImageHandle,
1737   IN EFI_SYSTEM_TABLE                      *SystemTable
1738   )
1739 
1740 {
1741   if (mStartOpCodeHandle != NULL) {
1742     HiiFreeOpCodeHandle (mStartOpCodeHandle);
1743   }
1744 
1745   if (mEndOpCodeHandle != NULL) {
1746     HiiFreeOpCodeHandle (mEndOpCodeHandle);
1747   }
1748 
1749   FreeAllMenu ();
1750 
1751   //
1752   // Remove our IFR data from HII database
1753   //
1754   HiiRemovePackages (mBmmCallbackInfo->BmmHiiHandle);
1755 
1756   gBS->UninstallMultipleProtocolInterfaces (
1757          mBmmCallbackInfo->BmmDriverHandle,
1758          &gEfiDevicePathProtocolGuid,
1759          &mBmmHiiVendorDevicePath,
1760          &gEfiHiiConfigAccessProtocolGuid,
1761          &mBmmCallbackInfo->BmmConfigAccess,
1762          NULL
1763          );
1764 
1765   FreePool (mBmmCallbackInfo->LoadContext);
1766   mBmmCallbackInfo->BmmDriverHandle = NULL;
1767 
1768   return EFI_SUCCESS;
1769 }
1770 
1771