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 "BootMaint.h"
16 #include "FormGuid.h"
17 #include "Bds.h"
18 #include "FrontPage.h"
19 
20 EFI_DEVICE_PATH_PROTOCOL  EndDevicePath[] = {
21   {
22     END_DEVICE_PATH_TYPE,
23     END_ENTIRE_DEVICE_PATH_SUBTYPE,
24     {
25       END_DEVICE_PATH_LENGTH,
26       0
27     }
28   }
29 };
30 
31 HII_VENDOR_DEVICE_PATH  mBmmHiiVendorDevicePath = {
32   {
33     {
34       HARDWARE_DEVICE_PATH,
35       HW_VENDOR_DP,
36       {
37         (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
38         (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
39       }
40     },
41     BOOT_MAINT_FORMSET_GUID
42   },
43   {
44     END_DEVICE_PATH_TYPE,
45     END_ENTIRE_DEVICE_PATH_SUBTYPE,
46     {
47       (UINT8) (END_DEVICE_PATH_LENGTH),
48       (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
49     }
50   }
51 };
52 
53 HII_VENDOR_DEVICE_PATH  mFeHiiVendorDevicePath = {
54   {
55     {
56       HARDWARE_DEVICE_PATH,
57       HW_VENDOR_DP,
58       {
59         (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
60         (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
61       }
62     },
63     FILE_EXPLORE_FORMSET_GUID
64   },
65   {
66     END_DEVICE_PATH_TYPE,
67     END_ENTIRE_DEVICE_PATH_SUBTYPE,
68     {
69       (UINT8) (END_DEVICE_PATH_LENGTH),
70       (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
71     }
72   }
73 };
74 
75 CHAR16  mBootMaintStorageName[]     = L"BmmData";
76 CHAR16  mFileExplorerStorageName[]  = L"FeData";
77 BMM_CALLBACK_DATA *mBmmCallbackInfo = NULL;
78 
79 /**
80   Init all memu.
81 
82   @param CallbackData    The BMM context data.
83 
84 **/
85 VOID
86 InitAllMenu (
87   IN  BMM_CALLBACK_DATA    *CallbackData
88   );
89 
90 /**
91   Free up all Menu Option list.
92 
93 **/
94 VOID
95 FreeAllMenu (
96   VOID
97   );
98 
99 /**
100   Initialize all of BMM configuration data in BmmFakeNvData and BmmOldFakeNVData member
101   in BMM context data and create all of dynamic OP code for BMM.
102 
103   @param CallbackData    The BMM context data.
104 
105 **/
106 VOID
InitializeBmmConfig(IN BMM_CALLBACK_DATA * CallbackData)107 InitializeBmmConfig (
108   IN  BMM_CALLBACK_DATA    *CallbackData
109   )
110 {
111   BM_MENU_ENTRY   *NewMenuEntry;
112   BM_LOAD_CONTEXT *NewLoadContext;
113   UINT16          Index;
114 
115   ASSERT (CallbackData != NULL);
116 
117   //
118   // Initialize data which located in BMM main page
119   //
120   CallbackData->BmmFakeNvData.BootNext = (UINT16) (BootOptionMenu.MenuNumber);
121   for (Index = 0; Index < BootOptionMenu.MenuNumber; Index++) {
122     NewMenuEntry    = BOpt_GetMenuEntry (&BootOptionMenu, Index);
123     NewLoadContext  = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
124 
125     if (NewLoadContext->IsBootNext) {
126       CallbackData->BmmFakeNvData.BootNext = Index;
127       break;
128     }
129   }
130 
131   CallbackData->BmmFakeNvData.BootTimeOut = PcdGet16 (PcdPlatformBootTimeOut);
132 
133   //
134   // Initialize data which located in Boot Options Menu
135   //
136   GetBootOrder (CallbackData);
137   GetLegacyDeviceOrder (CallbackData);
138 
139   //
140   // Initialize data which located in Driver Options Menu
141   //
142   GetDriverOrder (CallbackData);
143 
144   //
145   // Initialize data which located in Console Options Menu
146   //
147   GetConsoleOutMode (CallbackData);
148   GetConsoleInCheck (CallbackData);
149   GetConsoleOutCheck (CallbackData);
150   GetConsoleErrCheck (CallbackData);
151   GetTerminalAttribute (CallbackData);
152 
153   //
154   // Backup Initialize BMM configuartion data to BmmOldFakeNVData
155   //
156   CopyMem (&CallbackData->BmmOldFakeNVData, &CallbackData->BmmFakeNvData, sizeof (BMM_FAKE_NV_DATA));
157 }
158 
159 /**
160   Create string tokens for a menu from its help strings and display strings
161 
162   @param CallbackData       The BMM context data.
163   @param HiiHandle          Hii Handle of the package to be updated.
164   @param MenuOption         The Menu whose string tokens need to be created
165 
166   @retval  EFI_SUCCESS      String tokens created successfully
167   @retval  others           contain some errors
168 **/
169 EFI_STATUS
CreateMenuStringToken(IN BMM_CALLBACK_DATA * CallbackData,IN EFI_HII_HANDLE HiiHandle,IN BM_MENU_OPTION * MenuOption)170 CreateMenuStringToken (
171   IN BMM_CALLBACK_DATA                *CallbackData,
172   IN EFI_HII_HANDLE                   HiiHandle,
173   IN BM_MENU_OPTION                   *MenuOption
174   )
175 {
176   BM_MENU_ENTRY *NewMenuEntry;
177   UINTN         Index;
178 
179   for (Index = 0; Index < MenuOption->MenuNumber; Index++) {
180     NewMenuEntry = BOpt_GetMenuEntry (MenuOption, Index);
181 
182     NewMenuEntry->DisplayStringToken = HiiSetString (
183                                          HiiHandle,
184                                          0,
185                                          NewMenuEntry->DisplayString,
186                                          NULL
187                                          );
188 
189     if (NULL == NewMenuEntry->HelpString) {
190       NewMenuEntry->HelpStringToken = NewMenuEntry->DisplayStringToken;
191     } else {
192       NewMenuEntry->HelpStringToken = HiiSetString (
193                                         HiiHandle,
194                                         0,
195                                         NewMenuEntry->HelpString,
196                                         NULL
197                                         );
198     }
199   }
200 
201   return EFI_SUCCESS;
202 }
203 
204 /**
205   This function allows a caller to extract the current configuration for one
206   or more named elements from the target driver.
207 
208 
209   @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
210   @param Request         A null-terminated Unicode string in <ConfigRequest> format.
211   @param Progress        On return, points to a character in the Request string.
212                          Points to the string's null terminator if request was successful.
213                          Points to the most recent '&' before the first failing name/value
214                          pair (or the beginning of the string if the failure is in the
215                          first name/value pair) if the request was not successful.
216   @param Results         A null-terminated Unicode string in <ConfigAltResp> format which
217                          has all values filled in for the names in the Request string.
218                          String to be allocated by the called function.
219 
220   @retval  EFI_SUCCESS            The Results is filled with the requested values.
221   @retval  EFI_OUT_OF_RESOURCES   Not enough memory to store the results.
222   @retval  EFI_INVALID_PARAMETER  Request is NULL, illegal syntax, or unknown name.
223   @retval  EFI_NOT_FOUND          Routing data doesn't match any storage in this driver.
224 
225 **/
226 EFI_STATUS
227 EFIAPI
BootMaintExtractConfig(IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL * This,IN CONST EFI_STRING Request,OUT EFI_STRING * Progress,OUT EFI_STRING * Results)228 BootMaintExtractConfig (
229   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
230   IN  CONST EFI_STRING                       Request,
231   OUT EFI_STRING                             *Progress,
232   OUT EFI_STRING                             *Results
233   )
234 {
235   EFI_STATUS         Status;
236   UINTN              BufferSize;
237   BMM_CALLBACK_DATA  *Private;
238   EFI_STRING                       ConfigRequestHdr;
239   EFI_STRING                       ConfigRequest;
240   BOOLEAN                          AllocatedRequest;
241   UINTN                            Size;
242 
243   if (Progress == NULL || Results == NULL) {
244     return EFI_INVALID_PARAMETER;
245   }
246 
247   *Progress = Request;
248   if ((Request != NULL) && !HiiIsConfigHdrMatch (Request, &gBootMaintFormSetGuid, mBootMaintStorageName)) {
249     return EFI_NOT_FOUND;
250   }
251 
252   ConfigRequestHdr = NULL;
253   ConfigRequest    = NULL;
254   AllocatedRequest = FALSE;
255   Size             = 0;
256 
257   Private = BMM_CALLBACK_DATA_FROM_THIS (This);
258   //
259   // Convert buffer data to <ConfigResp> by helper function BlockToConfig()
260   //
261   BufferSize = sizeof (BMM_FAKE_NV_DATA);
262   ConfigRequest = Request;
263   if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) {
264     //
265     // Request has no request element, construct full request string.
266     // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
267     // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator
268     //
269     ConfigRequestHdr = HiiConstructConfigHdr (&gBootMaintFormSetGuid, mBootMaintStorageName, Private->BmmDriverHandle);
270     Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);
271     ConfigRequest = AllocateZeroPool (Size);
272     ASSERT (ConfigRequest != NULL);
273     AllocatedRequest = TRUE;
274     UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64)BufferSize);
275     FreePool (ConfigRequestHdr);
276   }
277 
278   Status = gHiiConfigRouting->BlockToConfig (
279                                 gHiiConfigRouting,
280                                 ConfigRequest,
281                                 (UINT8 *) &Private->BmmFakeNvData,
282                                 BufferSize,
283                                 Results,
284                                 Progress
285                                 );
286   //
287   // Free the allocated config request string.
288   //
289   if (AllocatedRequest) {
290     FreePool (ConfigRequest);
291     ConfigRequest = NULL;
292   }
293   //
294   // Set Progress string to the original request string.
295   //
296   if (Request == NULL) {
297     *Progress = NULL;
298   } else if (StrStr (Request, L"OFFSET") == NULL) {
299     *Progress = Request + StrLen (Request);
300   }
301 
302   return Status;
303 }
304 
305 /**
306   This function applies changes in a driver's configuration.
307   Input is a Configuration, which has the routing data for this
308   driver followed by name / value configuration pairs. The driver
309   must apply those pairs to its configurable storage. If the
310   driver's configuration is stored in a linear block of data
311   and the driver's name / value pairs are in <BlockConfig>
312   format, it may use the ConfigToBlock helper function (above) to
313   simplify the job. Currently not implemented.
314 
315   @param[in]  This                Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
316   @param[in]  Configuration       A null-terminated Unicode string in
317                                   <ConfigString> format.
318   @param[out] Progress            A pointer to a string filled in with the
319                                   offset of the most recent '&' before the
320                                   first failing name / value pair (or the
321                                   beginn ing of the string if the failure
322                                   is in the first name / value pair) or
323                                   the terminating NULL if all was
324                                   successful.
325 
326   @retval EFI_SUCCESS             The results have been distributed or are
327                                   awaiting distribution.
328   @retval EFI_OUT_OF_RESOURCES    Not enough memory to store the
329                                   parts of the results that must be
330                                   stored awaiting possible future
331                                   protocols.
332   @retval EFI_INVALID_PARAMETERS  Passing in a NULL for the
333                                   Results parameter would result
334                                   in this type of error.
335   @retval EFI_NOT_FOUND           Target for the specified routing data
336                                   was not found.
337 **/
338 EFI_STATUS
339 EFIAPI
BootMaintRouteConfig(IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL * This,IN CONST EFI_STRING Configuration,OUT EFI_STRING * Progress)340 BootMaintRouteConfig (
341   IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
342   IN CONST EFI_STRING                     Configuration,
343   OUT EFI_STRING                          *Progress
344   )
345 {
346   EFI_STATUS                      Status;
347   UINTN                           BufferSize;
348   EFI_HII_CONFIG_ROUTING_PROTOCOL *ConfigRouting;
349   BMM_FAKE_NV_DATA                *NewBmmData;
350   BMM_FAKE_NV_DATA                *OldBmmData;
351   BM_CONSOLE_CONTEXT              *NewConsoleContext;
352   BM_TERMINAL_CONTEXT             *NewTerminalContext;
353   BM_MENU_ENTRY                   *NewMenuEntry;
354   BM_LOAD_CONTEXT                 *NewLoadContext;
355   UINT16                          Index;
356   BOOLEAN                         TerminalAttChange;
357   BMM_CALLBACK_DATA               *Private;
358 
359   if (Progress == NULL) {
360     return EFI_INVALID_PARAMETER;
361   }
362   *Progress = Configuration;
363 
364   if (Configuration == NULL) {
365     return EFI_INVALID_PARAMETER;
366   }
367 
368   //
369   // Check routing data in <ConfigHdr>.
370   // Note: there is no name for Name/Value storage, only GUID will be checked
371   //
372   if (!HiiIsConfigHdrMatch (Configuration, &gBootMaintFormSetGuid, mBootMaintStorageName)) {
373     return EFI_NOT_FOUND;
374   }
375 
376   Status = gBS->LocateProtocol (
377                   &gEfiHiiConfigRoutingProtocolGuid,
378                   NULL,
379                   (VOID**) &ConfigRouting
380                   );
381   if (EFI_ERROR (Status)) {
382     return Status;
383   }
384 
385   Private = BMM_CALLBACK_DATA_FROM_THIS (This);
386   //
387   // Get Buffer Storage data from EFI variable
388   //
389   BufferSize = sizeof (BMM_FAKE_NV_DATA);
390   OldBmmData = &Private->BmmOldFakeNVData;
391   NewBmmData = &Private->BmmFakeNvData;
392   //
393   // Convert <ConfigResp> to buffer data by helper function ConfigToBlock()
394   //
395   Status = ConfigRouting->ConfigToBlock (
396                             ConfigRouting,
397                             Configuration,
398                             (UINT8 *) NewBmmData,
399                             &BufferSize,
400                             Progress
401                             );
402   ASSERT_EFI_ERROR (Status);
403   //
404   // Compare new and old BMM configuration data and only do action for modified item to
405   // avoid setting unnecessary non-volatile variable
406   //
407 
408   //
409   // Check data which located in BMM main page and save the settings if need
410   //
411   if (CompareMem (NewBmmData->LegacyFD, OldBmmData->LegacyFD, sizeof (NewBmmData->LegacyFD)) != 0) {
412     Var_UpdateBBSOption (Private, FORM_SET_FD_ORDER_ID);
413   }
414 
415   if (CompareMem (NewBmmData->LegacyHD, OldBmmData->LegacyHD, sizeof (NewBmmData->LegacyHD)) != 0) {
416     Var_UpdateBBSOption (Private, FORM_SET_HD_ORDER_ID);
417   }
418 
419   if (CompareMem (NewBmmData->LegacyCD, OldBmmData->LegacyCD, sizeof (NewBmmData->LegacyCD)) != 0) {
420     Var_UpdateBBSOption (Private, FORM_SET_CD_ORDER_ID);
421   }
422 
423   if (CompareMem (NewBmmData->LegacyNET, OldBmmData->LegacyNET, sizeof (NewBmmData->LegacyNET)) != 0) {
424     Var_UpdateBBSOption (Private, FORM_SET_NET_ORDER_ID);
425   }
426 
427   if (CompareMem (NewBmmData->LegacyBEV, OldBmmData->LegacyBEV, sizeof (NewBmmData->LegacyBEV)) != 0) {
428     Var_UpdateBBSOption (Private, FORM_SET_BEV_ORDER_ID);
429   }
430 
431   //
432   // Change for "delete boot option" page need update NewBmmData->BootOptionOrder, so process
433   // NewBmmData->BootOptionOrder before NewBmmData->BootOptionDel
434   //
435   if (CompareMem (NewBmmData->BootOptionOrder, OldBmmData->BootOptionOrder, sizeof (NewBmmData->BootOptionOrder)) != 0) {
436     Status = Var_UpdateBootOrder (Private);
437   }
438 
439   //
440   // Change for "delete driver option" page need update NewBmmData->DriverOptionOrder, so process
441   // NewBmmData->DriverOptionOrder before NewBmmData->DriverOptionDel
442   //
443   if (CompareMem (NewBmmData->DriverOptionOrder, OldBmmData->DriverOptionOrder, sizeof (NewBmmData->DriverOptionOrder)) != 0) {
444     Status = Var_UpdateDriverOrder (Private);
445   }
446 
447   //
448   // Check data which located in Boot Options Menu and save the settings if need
449   //
450   if (CompareMem (NewBmmData->BootOptionDel, OldBmmData->BootOptionDel, sizeof (NewBmmData->BootOptionDel)) != 0) {
451     for (Index = 0;
452          ((Index < BootOptionMenu.MenuNumber) && (Index < (sizeof (NewBmmData->BootOptionDel) / sizeof (NewBmmData->BootOptionDel[0]))));
453          Index ++) {
454       NewMenuEntry            = BOpt_GetMenuEntry (&BootOptionMenu, Index);
455       NewLoadContext          = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
456       NewLoadContext->Deleted = NewBmmData->BootOptionDel[Index];
457       NewBmmData->BootOptionDel[Index] = FALSE;
458       NewBmmData->BootOptionDelMark[Index] = FALSE;
459     }
460 
461     Var_DelBootOption ();
462   }
463 
464   //
465   // Check data which located in Driver Options Menu and save the settings if need
466   //
467   if (CompareMem (NewBmmData->DriverOptionDel, OldBmmData->DriverOptionDel, sizeof (NewBmmData->DriverOptionDel)) != 0) {
468     for (Index = 0;
469          ((Index < DriverOptionMenu.MenuNumber) && (Index < (sizeof (NewBmmData->DriverOptionDel) / sizeof (NewBmmData->DriverOptionDel[0]))));
470          Index++) {
471       NewMenuEntry            = BOpt_GetMenuEntry (&DriverOptionMenu, Index);
472       NewLoadContext          = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
473       NewLoadContext->Deleted = NewBmmData->DriverOptionDel[Index];
474       NewBmmData->DriverOptionDel[Index] = FALSE;
475       NewBmmData->DriverOptionDelMark[Index] = FALSE;
476     }
477     Var_DelDriverOption ();
478   }
479 
480   if (CompareMem (&NewBmmData->BootTimeOut, &OldBmmData->BootTimeOut, sizeof (NewBmmData->BootTimeOut)) != 0) {
481     Status = gRT->SetVariable (
482                     L"Timeout",
483                     &gEfiGlobalVariableGuid,
484                     EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
485                     sizeof (UINT16),
486                     &(NewBmmData->BootTimeOut)
487                     );
488     ASSERT_EFI_ERROR(Status);
489 
490     //
491     // Bugbug: code not exit in UiApp but in IntelFrameworkModulePkg, need do more check.
492     //
493     Private->BmmOldFakeNVData.BootTimeOut = NewBmmData->BootTimeOut;
494   }
495 
496   if (CompareMem (&NewBmmData->BootNext, &OldBmmData->BootNext, sizeof (NewBmmData->BootNext)) != 0) {
497     Status = Var_UpdateBootNext (Private);
498   }
499 
500   if (CompareMem (&NewBmmData->ConsoleOutMode, &OldBmmData->ConsoleOutMode, sizeof (NewBmmData->ConsoleOutMode)) != 0) {
501     Var_UpdateConMode (Private);
502   }
503 
504   TerminalAttChange = FALSE;
505   for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) {
506 
507     //
508     // only need update modified items
509     //
510     if (CompareMem (&NewBmmData->COMBaudRate[Index], &OldBmmData->COMBaudRate[Index], sizeof (NewBmmData->COMBaudRate[Index])) == 0 &&
511          CompareMem (&NewBmmData->COMDataRate[Index], &OldBmmData->COMDataRate[Index], sizeof (NewBmmData->COMDataRate[Index])) == 0 &&
512          CompareMem (&NewBmmData->COMStopBits[Index], &OldBmmData->COMStopBits[Index], sizeof (NewBmmData->COMStopBits[Index])) == 0 &&
513          CompareMem (&NewBmmData->COMParity[Index], &OldBmmData->COMParity[Index], sizeof (NewBmmData->COMParity[Index])) == 0 &&
514          CompareMem (&NewBmmData->COMTerminalType[Index], &OldBmmData->COMTerminalType[Index], sizeof (NewBmmData->COMTerminalType[Index])) == 0 &&
515          CompareMem (&NewBmmData->COMFlowControl[Index], &OldBmmData->COMFlowControl[Index], sizeof (NewBmmData->COMFlowControl[Index])) == 0) {
516       continue;
517     }
518 
519     NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Index);
520     ASSERT (NewMenuEntry != NULL);
521     NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
522     NewTerminalContext->BaudRateIndex = NewBmmData->COMBaudRate[Index];
523     ASSERT (NewBmmData->COMBaudRate[Index] < (sizeof (BaudRateList) / sizeof (BaudRateList[0])));
524     NewTerminalContext->BaudRate      = BaudRateList[NewBmmData->COMBaudRate[Index]].Value;
525     NewTerminalContext->DataBitsIndex = NewBmmData->COMDataRate[Index];
526     ASSERT (NewBmmData->COMDataRate[Index] < (sizeof (DataBitsList) / sizeof (DataBitsList[0])));
527     NewTerminalContext->DataBits      = (UINT8) DataBitsList[NewBmmData->COMDataRate[Index]].Value;
528     NewTerminalContext->StopBitsIndex = NewBmmData->COMStopBits[Index];
529     ASSERT (NewBmmData->COMStopBits[Index] < (sizeof (StopBitsList) / sizeof (StopBitsList[0])));
530     NewTerminalContext->StopBits      = (UINT8) StopBitsList[NewBmmData->COMStopBits[Index]].Value;
531     NewTerminalContext->ParityIndex   = NewBmmData->COMParity[Index];
532     ASSERT (NewBmmData->COMParity[Index] < (sizeof (ParityList) / sizeof (ParityList[0])));
533     NewTerminalContext->Parity        = (UINT8) ParityList[NewBmmData->COMParity[Index]].Value;
534     NewTerminalContext->TerminalType  = NewBmmData->COMTerminalType[Index];
535     NewTerminalContext->FlowControl   = NewBmmData->COMFlowControl[Index];
536     ChangeTerminalDevicePath (
537       &(NewTerminalContext->DevicePath),
538       FALSE
539       );
540     TerminalAttChange = TRUE;
541   }
542   if (TerminalAttChange) {
543     Var_UpdateConsoleInpOption ();
544     Var_UpdateConsoleOutOption ();
545     Var_UpdateErrorOutOption ();
546   }
547 
548   //
549   // Check data which located in Console Options Menu and save the settings if need
550   //
551   if (CompareMem (NewBmmData->ConsoleInCheck, OldBmmData->ConsoleInCheck, sizeof (NewBmmData->ConsoleInCheck)) != 0) {
552     for (Index = 0; Index < ConsoleInpMenu.MenuNumber; Index++) {
553       NewMenuEntry                = BOpt_GetMenuEntry (&ConsoleInpMenu, Index);
554       NewConsoleContext           = (BM_CONSOLE_CONTEXT *) NewMenuEntry->VariableContext;
555       ASSERT (Index < MAX_MENU_NUMBER);
556       NewConsoleContext->IsActive = NewBmmData->ConsoleInCheck[Index];
557     }
558 
559     Var_UpdateConsoleInpOption ();
560   }
561 
562   if (CompareMem (NewBmmData->ConsoleOutCheck, OldBmmData->ConsoleOutCheck, sizeof (NewBmmData->ConsoleOutCheck)) != 0) {
563     for (Index = 0; Index < ConsoleOutMenu.MenuNumber; Index++) {
564       NewMenuEntry                = BOpt_GetMenuEntry (&ConsoleOutMenu, Index);
565       NewConsoleContext           = (BM_CONSOLE_CONTEXT *) NewMenuEntry->VariableContext;
566       ASSERT (Index < MAX_MENU_NUMBER);
567       NewConsoleContext->IsActive = NewBmmData->ConsoleOutCheck[Index];
568     }
569 
570     Var_UpdateConsoleOutOption ();
571   }
572 
573   if (CompareMem (NewBmmData->ConsoleErrCheck, OldBmmData->ConsoleErrCheck, sizeof (NewBmmData->ConsoleErrCheck)) != 0) {
574     for (Index = 0; Index < ConsoleErrMenu.MenuNumber; Index++) {
575       NewMenuEntry                = BOpt_GetMenuEntry (&ConsoleErrMenu, Index);
576       NewConsoleContext           = (BM_CONSOLE_CONTEXT *) NewMenuEntry->VariableContext;
577       ASSERT (Index < MAX_MENU_NUMBER);
578       NewConsoleContext->IsActive = NewBmmData->ConsoleErrCheck[Index];
579     }
580 
581     Var_UpdateErrorOutOption ();
582   }
583 
584   //
585   // After user do the save action, need to update OldBmmData.
586   //
587   CopyMem (OldBmmData, NewBmmData, sizeof (BMM_FAKE_NV_DATA));
588 
589   return EFI_SUCCESS;
590 }
591 
592 /**
593   Create GoTo OP code into FORM_BOOT_LEGACY_DEVICE label for legacy boot option.
594 
595 **/
596 EFI_STATUS
InitializeLegacyBootOption(VOID)597 InitializeLegacyBootOption (
598   VOID
599   )
600 {
601   RefreshUpdateData ();
602   mStartLabel->Number = FORM_BOOT_LEGACY_DEVICE_ID;
603 
604   //
605   // If LegacyBios Protocol is installed, add 3 tags about legacy boot option
606   // in BootOption form: legacy FD/HD/CD/NET/BEV
607   //
608   HiiCreateGotoOpCode (
609     mStartOpCodeHandle,
610     FORM_SET_FD_ORDER_ID,
611     STRING_TOKEN (STR_FORM_SET_FD_ORDER_TITLE),
612     STRING_TOKEN (STR_FORM_SET_FD_ORDER_TITLE),
613     EFI_IFR_FLAG_CALLBACK,
614     FORM_SET_FD_ORDER_ID
615     );
616 
617   HiiCreateGotoOpCode (
618     mStartOpCodeHandle,
619     FORM_SET_HD_ORDER_ID,
620     STRING_TOKEN (STR_FORM_SET_HD_ORDER_TITLE),
621     STRING_TOKEN (STR_FORM_SET_HD_ORDER_TITLE),
622     EFI_IFR_FLAG_CALLBACK,
623     FORM_SET_HD_ORDER_ID
624     );
625 
626   HiiCreateGotoOpCode (
627     mStartOpCodeHandle,
628     FORM_SET_CD_ORDER_ID,
629     STRING_TOKEN (STR_FORM_SET_CD_ORDER_TITLE),
630     STRING_TOKEN (STR_FORM_SET_CD_ORDER_TITLE),
631     EFI_IFR_FLAG_CALLBACK,
632     FORM_SET_CD_ORDER_ID
633     );
634 
635   HiiCreateGotoOpCode (
636     mStartOpCodeHandle,
637     FORM_SET_NET_ORDER_ID,
638     STRING_TOKEN (STR_FORM_SET_NET_ORDER_TITLE),
639     STRING_TOKEN (STR_FORM_SET_NET_ORDER_TITLE),
640     EFI_IFR_FLAG_CALLBACK,
641     FORM_SET_NET_ORDER_ID
642     );
643 
644   HiiCreateGotoOpCode (
645     mStartOpCodeHandle,
646     FORM_SET_BEV_ORDER_ID,
647     STRING_TOKEN (STR_FORM_SET_BEV_ORDER_TITLE),
648     STRING_TOKEN (STR_FORM_SET_BEV_ORDER_TITLE),
649     EFI_IFR_FLAG_CALLBACK,
650     FORM_SET_BEV_ORDER_ID
651     );
652 
653   HiiUpdateForm (
654     mBmmCallbackInfo->BmmHiiHandle,
655     &gBootMaintFormSetGuid,
656     FORM_BOOT_SETUP_ID,
657     mStartOpCodeHandle, // Label FORM_BOOT_LEGACY_DEVICE_ID
658     mEndOpCodeHandle    // LABEL_END
659     );
660 
661   return EFI_SUCCESS;
662 }
663 
664 /**
665   This function processes the results of changes in configuration.
666 
667 
668   @param This               Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
669   @param Action             Specifies the type of action taken by the browser.
670   @param QuestionId         A unique value which is sent to the original exporting driver
671                             so that it can identify the type of data to expect.
672   @param Type               The type of value for the question.
673   @param Value              A pointer to the data being sent to the original exporting driver.
674   @param ActionRequest      On return, points to the action requested by the callback function.
675 
676   @retval EFI_SUCCESS           The callback successfully handled the action.
677   @retval EFI_OUT_OF_RESOURCES  Not enough storage is available to hold the variable and its data.
678   @retval EFI_DEVICE_ERROR      The variable could not be saved.
679   @retval EFI_UNSUPPORTED       The specified Action is not supported by the callback.
680   @retval EFI_INVALID_PARAMETER The parameter of Value or ActionRequest is invalid.
681 **/
682 EFI_STATUS
683 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)684 BootMaintCallback (
685   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL         *This,
686   IN        EFI_BROWSER_ACTION                     Action,
687   IN        EFI_QUESTION_ID                        QuestionId,
688   IN        UINT8                                  Type,
689   IN        EFI_IFR_TYPE_VALUE                     *Value,
690   OUT       EFI_BROWSER_ACTION_REQUEST             *ActionRequest
691   )
692 {
693   BMM_CALLBACK_DATA *Private;
694   BM_MENU_ENTRY     *NewMenuEntry;
695   BMM_FAKE_NV_DATA  *CurrentFakeNVMap;
696   EFI_STATUS        Status;
697   UINTN             OldValue;
698   UINTN             NewValue;
699   UINTN             Number;
700   UINTN             Pos;
701   UINTN             Bit;
702   UINT16            NewValuePos;
703   UINT16            Index3;
704   UINT16            Index2;
705   UINT16            Index;
706   UINT8             *OldLegacyDev;
707   UINT8             *NewLegacyDev;
708   UINT8             *DisMap;
709   EFI_LEGACY_BIOS_PROTOCOL    *LegacyBios;
710 
711   Private = BMM_CALLBACK_DATA_FROM_THIS (This);
712   if (Action == EFI_BROWSER_ACTION_FORM_OPEN && QuestionId == FORM_BOOT_SETUP_ID) {
713     //
714     // Initilize Form for legacy boot option.
715     //
716     Status = EfiLibLocateProtocol (&gEfiLegacyBiosProtocolGuid, (VOID **) &LegacyBios);
717     if (!EFI_ERROR (Status)) {
718       InitializeLegacyBootOption ();
719     }
720 
721     return EFI_SUCCESS;
722   }
723 
724   if (Action != EFI_BROWSER_ACTION_CHANGING && Action != EFI_BROWSER_ACTION_CHANGED) {
725     //
726     // All other action return unsupported.
727     //
728     return EFI_UNSUPPORTED;
729   }
730 
731   Status       = EFI_SUCCESS;
732   OldValue     = 0;
733   NewValue     = 0;
734   Number       = 0;
735   OldLegacyDev = NULL;
736   NewLegacyDev = NULL;
737   NewValuePos  = 0;
738   DisMap       = NULL;
739 
740   Private      = BMM_CALLBACK_DATA_FROM_THIS (This);
741   //
742   // Retrive uncommitted data from Form Browser
743   //
744   CurrentFakeNVMap = &Private->BmmFakeNvData;
745   HiiGetBrowserData (&gBootMaintFormSetGuid, mBootMaintStorageName, sizeof (BMM_FAKE_NV_DATA), (UINT8 *) CurrentFakeNVMap);
746   if (Action == EFI_BROWSER_ACTION_CHANGING) {
747     if (Value == NULL) {
748       return EFI_INVALID_PARAMETER;
749     }
750 
751     UpdatePageId (Private, QuestionId);
752 
753     if (QuestionId < FILE_OPTION_OFFSET) {
754       if (QuestionId < CONFIG_OPTION_OFFSET) {
755         switch (QuestionId) {
756         case KEY_VALUE_BOOT_FROM_FILE:
757           Private->FeCurrentState = FileExplorerStateBootFromFile;
758           break;
759 
760         case FORM_BOOT_ADD_ID:
761           Private->FeCurrentState = FileExplorerStateAddBootOption;
762           break;
763 
764         case FORM_DRV_ADD_FILE_ID:
765           Private->FeCurrentState = FileExplorerStateAddDriverOptionState;
766           break;
767 
768         case FORM_DRV_ADD_HANDLE_ID:
769           CleanUpPage (FORM_DRV_ADD_HANDLE_ID, Private);
770           UpdateDrvAddHandlePage (Private);
771           break;
772 
773         case FORM_BOOT_DEL_ID:
774           CleanUpPage (FORM_BOOT_DEL_ID, Private);
775           UpdateBootDelPage (Private);
776           break;
777 
778         case FORM_BOOT_CHG_ID:
779         case FORM_DRV_CHG_ID:
780           UpdatePageBody (QuestionId, Private);
781           break;
782 
783         case FORM_DRV_DEL_ID:
784           CleanUpPage (FORM_DRV_DEL_ID, Private);
785           UpdateDrvDelPage (Private);
786           break;
787 
788         case FORM_BOOT_NEXT_ID:
789           CleanUpPage (FORM_BOOT_NEXT_ID, Private);
790           UpdateBootNextPage (Private);
791           break;
792 
793         case FORM_TIME_OUT_ID:
794           CleanUpPage (FORM_TIME_OUT_ID, Private);
795           UpdateTimeOutPage (Private);
796           break;
797 
798         case FORM_CON_IN_ID:
799         case FORM_CON_OUT_ID:
800         case FORM_CON_ERR_ID:
801           UpdatePageBody (QuestionId, Private);
802           break;
803 
804         case FORM_CON_MODE_ID:
805           CleanUpPage (FORM_CON_MODE_ID, Private);
806           UpdateConModePage (Private);
807           break;
808 
809         case FORM_CON_COM_ID:
810           CleanUpPage (FORM_CON_COM_ID, Private);
811           UpdateConCOMPage (Private);
812           break;
813 
814         case FORM_SET_FD_ORDER_ID:
815         case FORM_SET_HD_ORDER_ID:
816         case FORM_SET_CD_ORDER_ID:
817         case FORM_SET_NET_ORDER_ID:
818         case FORM_SET_BEV_ORDER_ID:
819           CleanUpPage (QuestionId, Private);
820           UpdateSetLegacyDeviceOrderPage (QuestionId, Private);
821           break;
822 
823         default:
824           break;
825         }
826       } else if ((QuestionId >= TERMINAL_OPTION_OFFSET) && (QuestionId < CONSOLE_OPTION_OFFSET)) {
827         Index2                    = (UINT16) (QuestionId - TERMINAL_OPTION_OFFSET);
828         Private->CurrentTerminal  = Index2;
829 
830         CleanUpPage (FORM_CON_COM_SETUP_ID, Private);
831         UpdateTerminalPage (Private);
832 
833       } else if (QuestionId >= HANDLE_OPTION_OFFSET) {
834         Index2                  = (UINT16) (QuestionId - HANDLE_OPTION_OFFSET);
835 
836         NewMenuEntry            = BOpt_GetMenuEntry (&DriverMenu, Index2);
837         ASSERT (NewMenuEntry != NULL);
838         Private->HandleContext  = (BM_HANDLE_CONTEXT *) NewMenuEntry->VariableContext;
839 
840         CleanUpPage (FORM_DRV_ADD_HANDLE_DESC_ID, Private);
841 
842         Private->MenuEntry                  = NewMenuEntry;
843         Private->LoadContext->FilePathList  = Private->HandleContext->DevicePath;
844 
845         UpdateDriverAddHandleDescPage (Private);
846       }
847     }
848   } else if (Action == EFI_BROWSER_ACTION_CHANGED) {
849     if ((Value == NULL) || (ActionRequest == NULL)) {
850       return EFI_INVALID_PARAMETER;
851     }
852     if ((QuestionId >= BOOT_OPTION_DEL_QUESTION_ID) && (QuestionId < BOOT_OPTION_DEL_QUESTION_ID + MAX_MENU_NUMBER)) {
853       if (Value->b){
854         //
855         // Means user try to delete this boot option but not press F10 or "Commit Changes and Exit" menu.
856         //
857         CurrentFakeNVMap->BootOptionDelMark[QuestionId - BOOT_OPTION_DEL_QUESTION_ID] = TRUE;
858       } else {
859         //
860         // Means user remove the old check status.
861         //
862         CurrentFakeNVMap->BootOptionDelMark[QuestionId - BOOT_OPTION_DEL_QUESTION_ID] = FALSE;
863       }
864     } else if ((QuestionId >= DRIVER_OPTION_DEL_QUESTION_ID) && (QuestionId < DRIVER_OPTION_DEL_QUESTION_ID + MAX_MENU_NUMBER)) {
865       if (Value->b){
866         CurrentFakeNVMap->DriverOptionDelMark[QuestionId - DRIVER_OPTION_DEL_QUESTION_ID] = TRUE;
867       } else {
868         CurrentFakeNVMap->DriverOptionDelMark[QuestionId - DRIVER_OPTION_DEL_QUESTION_ID] = FALSE;
869       }
870     } else if ((QuestionId >= LEGACY_FD_QUESTION_ID) && (QuestionId < LEGACY_BEV_QUESTION_ID + MAX_MENU_NUMBER)) {
871       //
872       // Update Select FD/HD/CD/NET/BEV Order Form
873       //
874 
875       DisMap  = Private->BmmOldFakeNVData.DisableMap;
876 
877       if (QuestionId >= LEGACY_FD_QUESTION_ID && QuestionId < LEGACY_FD_QUESTION_ID + MAX_MENU_NUMBER) {
878         Number        = (UINT16) LegacyFDMenu.MenuNumber;
879         OldLegacyDev  = Private->BmmOldFakeNVData.LegacyFD;
880         NewLegacyDev  = CurrentFakeNVMap->LegacyFD;
881       } else if (QuestionId >= LEGACY_HD_QUESTION_ID && QuestionId < LEGACY_HD_QUESTION_ID + MAX_MENU_NUMBER) {
882         Number        = (UINT16) LegacyHDMenu.MenuNumber;
883         OldLegacyDev  = Private->BmmOldFakeNVData.LegacyHD;
884         NewLegacyDev  = CurrentFakeNVMap->LegacyHD;
885       } else if (QuestionId >= LEGACY_CD_QUESTION_ID && QuestionId < LEGACY_CD_QUESTION_ID + MAX_MENU_NUMBER) {
886         Number        = (UINT16) LegacyCDMenu.MenuNumber;
887         OldLegacyDev  = Private->BmmOldFakeNVData.LegacyCD;
888         NewLegacyDev  = CurrentFakeNVMap->LegacyCD;
889       } else if (QuestionId >= LEGACY_NET_QUESTION_ID && QuestionId < LEGACY_NET_QUESTION_ID + MAX_MENU_NUMBER) {
890         Number        = (UINT16) LegacyNETMenu.MenuNumber;
891         OldLegacyDev  = Private->BmmOldFakeNVData.LegacyNET;
892         NewLegacyDev  = CurrentFakeNVMap->LegacyNET;
893       } else if (QuestionId >= LEGACY_BEV_QUESTION_ID && QuestionId < LEGACY_BEV_QUESTION_ID + MAX_MENU_NUMBER) {
894         Number        = (UINT16) LegacyBEVMenu.MenuNumber;
895         OldLegacyDev  = Private->BmmOldFakeNVData.LegacyBEV;
896         NewLegacyDev  = CurrentFakeNVMap->LegacyBEV;
897       }
898       //
899       //  First, find the different position
900       //  if there is change, it should be only one
901       //
902       for (Index = 0; Index < Number; Index++) {
903         if (OldLegacyDev[Index] != NewLegacyDev[Index]) {
904           OldValue  = OldLegacyDev[Index];
905           NewValue  = NewLegacyDev[Index];
906           break;
907         }
908       }
909 
910       if (Index != Number) {
911         //
912         // there is change, now process
913         //
914         if (0xFF == NewValue) {
915           //
916           // This item will be disable
917           // Just move the items behind this forward to overlap it
918           //
919           Pos = OldValue / 8;
920           Bit = 7 - (OldValue % 8);
921           DisMap[Pos] = (UINT8) (DisMap[Pos] | (UINT8) (1 << Bit));
922           for (Index2 = Index; Index2 < Number - 1; Index2++) {
923             NewLegacyDev[Index2] = NewLegacyDev[Index2 + 1];
924           }
925 
926           NewLegacyDev[Index2] = 0xFF;
927         } else {
928           for (Index2 = 0; Index2 < Number; Index2++) {
929             if (Index2 == Index) {
930               continue;
931             }
932 
933             if (OldLegacyDev[Index2] == NewValue) {
934               //
935               // If NewValue is in OldLegacyDev array
936               // remember its old position
937               //
938               NewValuePos = Index2;
939               break;
940             }
941           }
942 
943           if (Index2 != Number) {
944             //
945             // We will change current item to an existing item
946             // (It's hard to describe here, please read code, it's like a cycle-moving)
947             //
948             for (Index2 = NewValuePos; Index2 != Index;) {
949               if (NewValuePos < Index) {
950                 NewLegacyDev[Index2] = OldLegacyDev[Index2 + 1];
951                 Index2++;
952               } else {
953                 NewLegacyDev[Index2] = OldLegacyDev[Index2 - 1];
954                 Index2--;
955               }
956             }
957           } else {
958             //
959             // If NewValue is not in OldlegacyDev array, we are changing to a disabled item
960             // so we should modify DisMap to reflect the change
961             //
962             Pos = NewValue / 8;
963             Bit = 7 - (NewValue % 8);
964             DisMap[Pos] = (UINT8) (DisMap[Pos] & (~ (UINT8) (1 << Bit)));
965             if (0xFF != OldValue) {
966               //
967               // Because NewValue is a item that was disabled before
968               // so after changing the OldValue should be disabled
969               // actually we are doing a swap of enable-disable states of two items
970               //
971               Pos = OldValue / 8;
972               Bit = 7 - (OldValue % 8);
973               DisMap[Pos] = (UINT8) (DisMap[Pos] | (UINT8) (1 << Bit));
974             }
975           }
976         }
977         //
978         // To prevent DISABLE appears in the middle of the list
979         // we should perform a re-ordering
980         //
981         Index3 = Index;
982         Index = 0;
983         while (Index < Number) {
984           if (0xFF != NewLegacyDev[Index]) {
985             Index++;
986             continue;
987           }
988 
989           Index2 = Index;
990           Index2++;
991           while (Index2 < Number) {
992             if (0xFF != NewLegacyDev[Index2]) {
993               break;
994             }
995 
996             Index2++;
997           }
998 
999           if (Index2 < Number) {
1000             NewLegacyDev[Index]   = NewLegacyDev[Index2];
1001             NewLegacyDev[Index2]  = 0xFF;
1002           }
1003 
1004           Index++;
1005         }
1006 
1007         //
1008         //  Return correct question value.
1009         //
1010         Value->u8 = NewLegacyDev[Index3];
1011       }
1012     } else {
1013       switch (QuestionId) {
1014       case KEY_VALUE_SAVE_AND_EXIT:
1015         *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT;
1016         break;
1017 
1018       case KEY_VALUE_NO_SAVE_AND_EXIT:
1019         //
1020         // Restore local maintain data.
1021         //
1022         DiscardChangeHandler (Private, CurrentFakeNVMap);
1023         *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT;
1024         break;
1025 
1026       case FORM_RESET:
1027         gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
1028         return EFI_UNSUPPORTED;
1029 
1030       default:
1031         break;
1032       }
1033     }
1034   }
1035 
1036   //
1037   // Pass changed uncommitted data back to Form Browser
1038   //
1039   HiiSetBrowserData (&gBootMaintFormSetGuid, mBootMaintStorageName, sizeof (BMM_FAKE_NV_DATA), (UINT8 *) CurrentFakeNVMap, NULL);
1040   return EFI_SUCCESS;
1041 }
1042 
1043 /**
1044   Discard all changes done to the BMM pages such as Boot Order change,
1045   Driver order change.
1046 
1047   @param Private            The BMM context data.
1048   @param CurrentFakeNVMap   The current Fack NV Map.
1049 
1050 **/
1051 VOID
DiscardChangeHandler(IN BMM_CALLBACK_DATA * Private,IN BMM_FAKE_NV_DATA * CurrentFakeNVMap)1052 DiscardChangeHandler (
1053   IN  BMM_CALLBACK_DATA               *Private,
1054   IN  BMM_FAKE_NV_DATA                *CurrentFakeNVMap
1055   )
1056 {
1057   UINT16  Index;
1058 
1059   switch (Private->BmmPreviousPageId) {
1060   case FORM_BOOT_CHG_ID:
1061     CopyMem (CurrentFakeNVMap->BootOptionOrder, Private->BmmOldFakeNVData.BootOptionOrder, sizeof (CurrentFakeNVMap->BootOptionOrder));
1062     break;
1063 
1064   case FORM_DRV_CHG_ID:
1065     CopyMem (CurrentFakeNVMap->DriverOptionOrder, Private->BmmOldFakeNVData.DriverOptionOrder, sizeof (CurrentFakeNVMap->DriverOptionOrder));
1066     break;
1067 
1068   case FORM_BOOT_DEL_ID:
1069     ASSERT (BootOptionMenu.MenuNumber <= (sizeof (CurrentFakeNVMap->BootOptionDel) / sizeof (CurrentFakeNVMap->BootOptionDel[0])));
1070     for (Index = 0; Index < BootOptionMenu.MenuNumber; Index++) {
1071       CurrentFakeNVMap->BootOptionDel[Index] = FALSE;
1072       CurrentFakeNVMap->BootOptionDelMark[Index] = FALSE;
1073     }
1074     break;
1075 
1076   case FORM_DRV_DEL_ID:
1077     ASSERT (DriverOptionMenu.MenuNumber <= (sizeof (CurrentFakeNVMap->DriverOptionDel) / sizeof (CurrentFakeNVMap->DriverOptionDel[0])));
1078     for (Index = 0; Index < DriverOptionMenu.MenuNumber; Index++) {
1079       CurrentFakeNVMap->DriverOptionDel[Index] = FALSE;
1080       CurrentFakeNVMap->DriverOptionDelMark[Index] = FALSE;
1081     }
1082     break;
1083 
1084   case FORM_BOOT_NEXT_ID:
1085     CurrentFakeNVMap->BootNext = Private->BmmOldFakeNVData.BootNext;
1086     break;
1087 
1088   case FORM_TIME_OUT_ID:
1089     CurrentFakeNVMap->BootTimeOut = Private->BmmOldFakeNVData.BootTimeOut;
1090     break;
1091 
1092   case FORM_DRV_ADD_HANDLE_DESC_ID:
1093   case FORM_DRV_ADD_FILE_ID:
1094   case FORM_DRV_ADD_HANDLE_ID:
1095     CurrentFakeNVMap->DriverAddHandleDesc[0]          = 0x0000;
1096     CurrentFakeNVMap->DriverAddHandleOptionalData[0]  = 0x0000;
1097     break;
1098 
1099   default:
1100     break;
1101   }
1102 }
1103 
1104 /**
1105   Initialize the Boot Maintenance Utitliy.
1106 
1107 
1108   @retval  EFI_SUCCESS      utility ended successfully
1109   @retval  others           contain some errors
1110 
1111 **/
1112 EFI_STATUS
InitializeBM(VOID)1113 InitializeBM (
1114   VOID
1115   )
1116 {
1117   BMM_CALLBACK_DATA           *BmmCallbackInfo;
1118   EFI_STATUS                  Status;
1119   EFI_HII_PACKAGE_LIST_HEADER *PackageListHeader;
1120   UINT32                      Length;
1121   UINT8                       *Data;
1122 
1123   Status = EFI_SUCCESS;
1124   BmmCallbackInfo = mBmmCallbackInfo;
1125 
1126   BmmCallbackInfo->BmmPreviousPageId             = FORM_MAIN_ID;
1127   BmmCallbackInfo->BmmCurrentPageId              = FORM_MAIN_ID;
1128   BmmCallbackInfo->FeCurrentState                = FileExplorerStateInActive;
1129   BmmCallbackInfo->FeDisplayContext              = FileExplorerDisplayUnknown;
1130 
1131   //
1132   // Reinstall String packages to include more new strings.
1133   //
1134 
1135   //
1136   // String package size
1137   //
1138   Length = ReadUnaligned32 ((UINT32 *) BdsDxeStrings) - sizeof (UINT32);
1139 
1140   //
1141   // Add the length of the Package List Header and the terminating Package Header
1142   //
1143   Length += sizeof (EFI_HII_PACKAGE_LIST_HEADER) + sizeof (EFI_HII_PACKAGE_HEADER);
1144 
1145   //
1146   // Allocate the storage for the entire Package List
1147   //
1148   PackageListHeader = AllocateZeroPool (Length);
1149 
1150   //
1151   // If the Package List can not be allocated, then return a NULL HII Handle
1152   //
1153   if (PackageListHeader == NULL) {
1154     return EFI_OUT_OF_RESOURCES;
1155   }
1156 
1157   //
1158   // Fill in the GUID and Length of the Package List Header
1159   //
1160   PackageListHeader->PackageLength = Length;
1161 
1162   //
1163   // Copy String Data into Package list.
1164   //
1165   Data = (UINT8 *)(PackageListHeader + 1);
1166   Length = ReadUnaligned32 ((UINT32 *) BdsDxeStrings) - sizeof (UINT32);
1167   CopyMem (Data, (UINT8 *) BdsDxeStrings + sizeof (UINT32), Length);
1168 
1169   //
1170   // Add End type HII package.
1171   //
1172   Data += Length;
1173   ((EFI_HII_PACKAGE_HEADER *) Data)->Type   = EFI_HII_PACKAGE_END;
1174   ((EFI_HII_PACKAGE_HEADER *) Data)->Length = sizeof (EFI_HII_PACKAGE_HEADER);
1175 
1176   //
1177   // Update String package for BM
1178   //
1179   CopyGuid (&PackageListHeader->PackageListGuid, &gBootMaintFormSetGuid);
1180   Status = gHiiDatabase->UpdatePackageList (gHiiDatabase, BmmCallbackInfo->BmmHiiHandle, PackageListHeader);
1181 
1182   //
1183   // Update String package for FE.
1184   //
1185   CopyGuid (&PackageListHeader->PackageListGuid, &gFileExploreFormSetGuid);
1186   Status = gHiiDatabase->UpdatePackageList (gHiiDatabase, BmmCallbackInfo->FeHiiHandle, PackageListHeader);
1187 
1188   FreePool (PackageListHeader);
1189 
1190   //
1191   // Init OpCode Handle and Allocate space for creation of Buffer
1192   //
1193   mStartOpCodeHandle = HiiAllocateOpCodeHandle ();
1194   if (mStartOpCodeHandle == NULL) {
1195     Status = EFI_OUT_OF_RESOURCES;
1196     goto Exit;
1197   }
1198 
1199   mEndOpCodeHandle = HiiAllocateOpCodeHandle ();
1200   if (mEndOpCodeHandle == NULL) {
1201     Status = EFI_OUT_OF_RESOURCES;
1202     goto Exit;
1203   }
1204 
1205   //
1206   // Create Hii Extend Label OpCode as the start opcode
1207   //
1208   mStartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (mStartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
1209   mStartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
1210 
1211   //
1212   // Create Hii Extend Label OpCode as the end opcode
1213   //
1214   mEndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (mEndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
1215   mEndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
1216   mEndLabel->Number       = LABEL_END;
1217 
1218   InitializeStringDepository ();
1219 
1220   InitAllMenu (BmmCallbackInfo);
1221 
1222   CreateMenuStringToken (BmmCallbackInfo, BmmCallbackInfo->BmmHiiHandle, &ConsoleInpMenu);
1223   CreateMenuStringToken (BmmCallbackInfo, BmmCallbackInfo->BmmHiiHandle, &ConsoleOutMenu);
1224   CreateMenuStringToken (BmmCallbackInfo, BmmCallbackInfo->BmmHiiHandle, &ConsoleErrMenu);
1225   CreateMenuStringToken (BmmCallbackInfo, BmmCallbackInfo->BmmHiiHandle, &BootOptionMenu);
1226   CreateMenuStringToken (BmmCallbackInfo, BmmCallbackInfo->BmmHiiHandle, &DriverOptionMenu);
1227   CreateMenuStringToken (BmmCallbackInfo, BmmCallbackInfo->BmmHiiHandle, &TerminalMenu);
1228   CreateMenuStringToken (BmmCallbackInfo, BmmCallbackInfo->BmmHiiHandle, &DriverMenu);
1229 
1230   InitializeBmmConfig (BmmCallbackInfo);
1231 
1232   //
1233   // Dispatch BMM main formset and File Explorer formset.
1234   //
1235   FormSetDispatcher (BmmCallbackInfo);
1236 
1237   //
1238   // Clean up.
1239   //
1240   CleanUpStringDepository ();
1241 
1242   FreeAllMenu ();
1243 
1244 Exit:
1245   if (mStartOpCodeHandle != NULL) {
1246     HiiFreeOpCodeHandle (mStartOpCodeHandle);
1247   }
1248 
1249   if (mEndOpCodeHandle != NULL) {
1250     HiiFreeOpCodeHandle (mEndOpCodeHandle);
1251   }
1252 
1253   return Status;
1254 }
1255 
1256 
1257 /**
1258   Initialized all Menu Option List.
1259 
1260   @param CallbackData    The BMM context data.
1261 
1262 **/
1263 VOID
InitAllMenu(IN BMM_CALLBACK_DATA * CallbackData)1264 InitAllMenu (
1265   IN  BMM_CALLBACK_DATA    *CallbackData
1266   )
1267 {
1268   InitializeListHead (&BootOptionMenu.Head);
1269   InitializeListHead (&DriverOptionMenu.Head);
1270   BOpt_GetBootOptions (CallbackData);
1271   BOpt_GetDriverOptions (CallbackData);
1272   BOpt_GetLegacyOptions ();
1273   InitializeListHead (&FsOptionMenu.Head);
1274   BOpt_FindDrivers ();
1275   InitializeListHead (&DirectoryMenu.Head);
1276   InitializeListHead (&ConsoleInpMenu.Head);
1277   InitializeListHead (&ConsoleOutMenu.Head);
1278   InitializeListHead (&ConsoleErrMenu.Head);
1279   InitializeListHead (&TerminalMenu.Head);
1280   LocateSerialIo ();
1281   GetAllConsoles ();
1282 }
1283 
1284 /**
1285   Free up all Menu Option list.
1286 
1287 **/
1288 VOID
FreeAllMenu(VOID)1289 FreeAllMenu (
1290   VOID
1291   )
1292 {
1293   BOpt_FreeMenu (&DirectoryMenu);
1294   BOpt_FreeMenu (&FsOptionMenu);
1295   BOpt_FreeMenu (&BootOptionMenu);
1296   BOpt_FreeMenu (&DriverOptionMenu);
1297   BOpt_FreeMenu (&DriverMenu);
1298   BOpt_FreeLegacyOptions ();
1299   FreeAllConsoles ();
1300 }
1301 
1302 /**
1303   Initialize all the string depositories.
1304 
1305 **/
1306 VOID
InitializeStringDepository(VOID)1307 InitializeStringDepository (
1308   VOID
1309   )
1310 {
1311   STRING_DEPOSITORY *StringDepository;
1312   StringDepository              = AllocateZeroPool (sizeof (STRING_DEPOSITORY) * STRING_DEPOSITORY_NUMBER);
1313   FileOptionStrDepository       = StringDepository++;
1314   ConsoleOptionStrDepository    = StringDepository++;
1315   BootOptionStrDepository       = StringDepository++;
1316   BootOptionHelpStrDepository   = StringDepository++;
1317   DriverOptionStrDepository     = StringDepository++;
1318   DriverOptionHelpStrDepository = StringDepository++;
1319   TerminalStrDepository         = StringDepository;
1320 }
1321 
1322 /**
1323   Fetch a usable string node from the string depository and return the string token.
1324 
1325   @param CallbackData       The BMM context data.
1326   @param StringDepository   The string repository.
1327 
1328   @retval  EFI_STRING_ID           String token.
1329 
1330 **/
1331 EFI_STRING_ID
GetStringTokenFromDepository(IN BMM_CALLBACK_DATA * CallbackData,IN STRING_DEPOSITORY * StringDepository)1332 GetStringTokenFromDepository (
1333   IN   BMM_CALLBACK_DATA     *CallbackData,
1334   IN   STRING_DEPOSITORY     *StringDepository
1335   )
1336 {
1337   STRING_LIST_NODE  *CurrentListNode;
1338   STRING_LIST_NODE  *NextListNode;
1339 
1340   CurrentListNode = StringDepository->CurrentNode;
1341 
1342   if ((NULL != CurrentListNode) && (NULL != CurrentListNode->Next)) {
1343     //
1344     // Fetch one reclaimed node from the list.
1345     //
1346     NextListNode = StringDepository->CurrentNode->Next;
1347   } else {
1348     //
1349     // If there is no usable node in the list, update the list.
1350     //
1351     NextListNode = AllocateZeroPool (sizeof (STRING_LIST_NODE));
1352     ASSERT (NextListNode != NULL);
1353     NextListNode->StringToken = HiiSetString (CallbackData->BmmHiiHandle, 0, L" ", NULL);
1354     ASSERT (NextListNode->StringToken != 0);
1355 
1356     StringDepository->TotalNodeNumber++;
1357 
1358     if (NULL == CurrentListNode) {
1359       StringDepository->ListHead = NextListNode;
1360     } else {
1361       CurrentListNode->Next = NextListNode;
1362     }
1363   }
1364 
1365   StringDepository->CurrentNode = NextListNode;
1366 
1367   return StringDepository->CurrentNode->StringToken;
1368 }
1369 
1370 /**
1371   Reclaim string depositories by moving the current node pointer to list head..
1372 
1373 **/
1374 VOID
ReclaimStringDepository(VOID)1375 ReclaimStringDepository (
1376   VOID
1377   )
1378 {
1379   UINTN             DepositoryIndex;
1380   STRING_DEPOSITORY *StringDepository;
1381 
1382   StringDepository = FileOptionStrDepository;
1383   for (DepositoryIndex = 0; DepositoryIndex < STRING_DEPOSITORY_NUMBER; DepositoryIndex++) {
1384     StringDepository->CurrentNode = StringDepository->ListHead;
1385     StringDepository++;
1386   }
1387 }
1388 
1389 /**
1390   Release resource for all the string depositories.
1391 
1392 **/
1393 VOID
CleanUpStringDepository(VOID)1394 CleanUpStringDepository (
1395   VOID
1396   )
1397 {
1398   UINTN             NodeIndex;
1399   UINTN             DepositoryIndex;
1400   STRING_LIST_NODE  *CurrentListNode;
1401   STRING_LIST_NODE  *NextListNode;
1402   STRING_DEPOSITORY *StringDepository;
1403 
1404   //
1405   // Release string list nodes.
1406   //
1407   StringDepository = FileOptionStrDepository;
1408   for (DepositoryIndex = 0; DepositoryIndex < STRING_DEPOSITORY_NUMBER; DepositoryIndex++) {
1409     CurrentListNode = StringDepository->ListHead;
1410     for (NodeIndex = 0; NodeIndex < StringDepository->TotalNodeNumber; NodeIndex++) {
1411       NextListNode = CurrentListNode->Next;
1412       FreePool (CurrentListNode);
1413       CurrentListNode = NextListNode;
1414     }
1415 
1416     StringDepository++;
1417   }
1418   //
1419   // Release string depository.
1420   //
1421   FreePool (FileOptionStrDepository);
1422 }
1423 
1424 /**
1425   Start boot maintenance manager
1426 
1427   @retval EFI_SUCCESS If BMM is invoked successfully.
1428   @return Other value if BMM return unsuccessfully.
1429 
1430 **/
1431 EFI_STATUS
BdsStartBootMaint(VOID)1432 BdsStartBootMaint (
1433   VOID
1434   )
1435 {
1436   EFI_STATUS      Status;
1437   LIST_ENTRY      BdsBootOptionList;
1438 
1439   InitializeListHead (&BdsBootOptionList);
1440 
1441   //
1442   // Connect all prior to entering the platform setup menu.
1443   //
1444   if (!gConnectAllHappened) {
1445     BdsLibConnectAllDriversToAllControllers ();
1446     gConnectAllHappened = TRUE;
1447   }
1448   //
1449   // Have chance to enumerate boot device
1450   //
1451   BdsLibEnumerateAllBootOption (&BdsBootOptionList);
1452 
1453   //
1454   // Group the legacy boot options for the same device type
1455   //
1456   GroupMultipleLegacyBootOption4SameType ();
1457 
1458   //
1459   // Init the BMM
1460   //
1461   Status = InitializeBM ();
1462 
1463   return Status;
1464 }
1465 
1466 /**
1467   Dispatch BMM formset and FileExplorer formset.
1468 
1469 
1470   @param CallbackData    The BMM context data.
1471 
1472   @retval EFI_SUCCESS If function complete successfully.
1473   @return Other value if the Setup Browser process BMM's pages and
1474            return unsuccessfully.
1475 
1476 **/
1477 EFI_STATUS
FormSetDispatcher(IN BMM_CALLBACK_DATA * CallbackData)1478 FormSetDispatcher (
1479   IN  BMM_CALLBACK_DATA    *CallbackData
1480   )
1481 {
1482   EFI_STATUS                 Status;
1483   EFI_BROWSER_ACTION_REQUEST ActionRequest;
1484 
1485   while (TRUE) {
1486     UpdatePageId (CallbackData, FORM_MAIN_ID);
1487 
1488     ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
1489     Status = gFormBrowser2->SendForm (
1490                              gFormBrowser2,
1491                              &CallbackData->BmmHiiHandle,
1492                              1,
1493                              &gBootMaintFormSetGuid,
1494                              0,
1495                              NULL,
1496                              &ActionRequest
1497                              );
1498     if (ActionRequest == EFI_BROWSER_ACTION_REQUEST_RESET) {
1499       EnableResetRequired ();
1500     }
1501 
1502     ReclaimStringDepository ();
1503 
1504     //
1505     // When this Formset returns, check if we are going to explore files.
1506     //
1507     if (FileExplorerStateInActive != CallbackData->FeCurrentState) {
1508       UpdateFileExplorer (CallbackData, 0);
1509 
1510       ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
1511       Status = gFormBrowser2->SendForm (
1512                                gFormBrowser2,
1513                                &CallbackData->FeHiiHandle,
1514                                1,
1515                                &gFileExploreFormSetGuid,
1516                                0,
1517                                NULL,
1518                                &ActionRequest
1519                                );
1520       if (ActionRequest == EFI_BROWSER_ACTION_REQUEST_RESET) {
1521         EnableResetRequired ();
1522       }
1523 
1524       CallbackData->FeCurrentState    = FileExplorerStateInActive;
1525       CallbackData->FeDisplayContext  = FileExplorerDisplayUnknown;
1526       ReclaimStringDepository ();
1527     } else {
1528       break;
1529     }
1530   }
1531 
1532   return Status;
1533 }
1534 
1535 /**
1536   Intall BootMaint and FileExplorer HiiPackages.
1537 
1538 **/
1539 EFI_STATUS
InitBMPackage(VOID)1540 InitBMPackage (
1541   VOID
1542   )
1543 {
1544   BMM_CALLBACK_DATA           *BmmCallbackInfo;
1545   EFI_STATUS                  Status;
1546   UINT8                       *Ptr;
1547 
1548   //
1549   // Create CallbackData structures for Driver Callback
1550   //
1551   BmmCallbackInfo = AllocateZeroPool (sizeof (BMM_CALLBACK_DATA));
1552   if (BmmCallbackInfo == NULL) {
1553     return EFI_OUT_OF_RESOURCES;
1554   }
1555 
1556   //
1557   // Create LoadOption in BmmCallbackInfo for Driver Callback
1558   //
1559   Ptr = AllocateZeroPool (sizeof (BM_LOAD_CONTEXT) + sizeof (BM_FILE_CONTEXT) + sizeof (BM_HANDLE_CONTEXT) + sizeof (BM_MENU_ENTRY));
1560   if (Ptr == NULL) {
1561     FreePool (BmmCallbackInfo);
1562     BmmCallbackInfo = NULL;
1563     return EFI_OUT_OF_RESOURCES;
1564   }
1565   //
1566   // Initialize Bmm callback data.
1567   //
1568   BmmCallbackInfo->LoadContext = (BM_LOAD_CONTEXT *) Ptr;
1569   Ptr += sizeof (BM_LOAD_CONTEXT);
1570 
1571   BmmCallbackInfo->FileContext = (BM_FILE_CONTEXT *) Ptr;
1572   Ptr += sizeof (BM_FILE_CONTEXT);
1573 
1574   BmmCallbackInfo->HandleContext = (BM_HANDLE_CONTEXT *) Ptr;
1575   Ptr += sizeof (BM_HANDLE_CONTEXT);
1576 
1577   BmmCallbackInfo->MenuEntry      = (BM_MENU_ENTRY *) Ptr;
1578 
1579   BmmCallbackInfo->Signature                     = BMM_CALLBACK_DATA_SIGNATURE;
1580   BmmCallbackInfo->BmmConfigAccess.ExtractConfig = BootMaintExtractConfig;
1581   BmmCallbackInfo->BmmConfigAccess.RouteConfig   = BootMaintRouteConfig;
1582   BmmCallbackInfo->BmmConfigAccess.Callback      = BootMaintCallback;
1583   BmmCallbackInfo->FeConfigAccess.ExtractConfig  = FakeExtractConfig;
1584   BmmCallbackInfo->FeConfigAccess.RouteConfig    = FileExplorerRouteConfig;
1585   BmmCallbackInfo->FeConfigAccess.Callback       = FileExplorerCallback;
1586 
1587   //
1588   // Install Device Path Protocol and Config Access protocol to driver handle
1589   //
1590   Status = gBS->InstallMultipleProtocolInterfaces (
1591                   &BmmCallbackInfo->BmmDriverHandle,
1592                   &gEfiDevicePathProtocolGuid,
1593                   &mBmmHiiVendorDevicePath,
1594                   &gEfiHiiConfigAccessProtocolGuid,
1595                   &BmmCallbackInfo->BmmConfigAccess,
1596                   NULL
1597                   );
1598   ASSERT_EFI_ERROR (Status);
1599 
1600   //
1601   // Install Device Path Protocol and Config Access protocol to driver handle
1602   //
1603   Status = gBS->InstallMultipleProtocolInterfaces (
1604                   &BmmCallbackInfo->FeDriverHandle,
1605                   &gEfiDevicePathProtocolGuid,
1606                   &mFeHiiVendorDevicePath,
1607                   &gEfiHiiConfigAccessProtocolGuid,
1608                   &BmmCallbackInfo->FeConfigAccess,
1609                   NULL
1610                   );
1611   ASSERT_EFI_ERROR (Status);
1612 
1613   //
1614   // Post our Boot Maint VFR binary to the HII database.
1615   //
1616   BmmCallbackInfo->BmmHiiHandle = HiiAddPackages (
1617                                     &gBootMaintFormSetGuid,
1618                                     BmmCallbackInfo->BmmDriverHandle,
1619                                     BmBin,
1620                                     BdsDxeStrings,
1621                                     NULL
1622                                     );
1623   ASSERT (BmmCallbackInfo->BmmHiiHandle != NULL);
1624 
1625   //
1626   // Post our File Explorer VFR binary to the HII database.
1627   //
1628   BmmCallbackInfo->FeHiiHandle = HiiAddPackages (
1629                                    &gFileExploreFormSetGuid,
1630                                    BmmCallbackInfo->FeDriverHandle,
1631                                    FEBin,
1632                                    BdsDxeStrings,
1633                                    NULL
1634                                    );
1635   ASSERT (BmmCallbackInfo->FeHiiHandle != NULL);
1636 
1637   mBmmCallbackInfo = BmmCallbackInfo;
1638 
1639   return EFI_SUCCESS;
1640 }
1641 
1642 /**
1643   Remvoe the intalled BootMaint and FileExplorer HiiPackages.
1644 
1645 **/
1646 VOID
FreeBMPackage(VOID)1647 FreeBMPackage (
1648   VOID
1649   )
1650 {
1651   BMM_CALLBACK_DATA           *BmmCallbackInfo;
1652 
1653   BmmCallbackInfo = mBmmCallbackInfo;
1654 
1655   //
1656   // Remove our IFR data from HII database
1657   //
1658   HiiRemovePackages (BmmCallbackInfo->BmmHiiHandle);
1659   HiiRemovePackages (BmmCallbackInfo->FeHiiHandle);
1660 
1661   if (BmmCallbackInfo->FeDriverHandle != NULL) {
1662     gBS->UninstallMultipleProtocolInterfaces (
1663            BmmCallbackInfo->FeDriverHandle,
1664            &gEfiDevicePathProtocolGuid,
1665            &mFeHiiVendorDevicePath,
1666            &gEfiHiiConfigAccessProtocolGuid,
1667            &BmmCallbackInfo->FeConfigAccess,
1668            NULL
1669            );
1670   }
1671 
1672   if (BmmCallbackInfo->BmmDriverHandle != NULL) {
1673     gBS->UninstallMultipleProtocolInterfaces (
1674            BmmCallbackInfo->BmmDriverHandle,
1675            &gEfiDevicePathProtocolGuid,
1676            &mBmmHiiVendorDevicePath,
1677            &gEfiHiiConfigAccessProtocolGuid,
1678            &BmmCallbackInfo->BmmConfigAccess,
1679            NULL
1680            );
1681   }
1682 
1683   FreePool (BmmCallbackInfo->LoadContext);
1684   FreePool (BmmCallbackInfo);
1685 
1686   mBmmCallbackInfo = NULL;
1687 
1688   return;
1689 }
1690 
1691