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