1 /** @file
2   Legacy Boot Maintainence UI implementation.
3 
4 Copyright (c) 2004 - 2016, 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 
16 #include "LegacyBootMaintUi.h"
17 
18 LEGACY_BOOT_OPTION_CALLBACK_DATA  *mLegacyBootOptionPrivate;
19 EFI_GUID  mLegacyBootOptionGuid     = LEGACY_BOOT_OPTION_FORMSET_GUID;
20 CHAR16    mLegacyBootStorageName[]  = L"LegacyBootData";
21 BBS_TYPE  mBbsType[] = {BBS_FLOPPY, BBS_HARDDISK, BBS_CDROM, BBS_EMBED_NETWORK, BBS_BEV_DEVICE, BBS_UNKNOWN};
22 BOOLEAN   mFirstEnterLegacyForm = FALSE;
23 
24 
25 ///
26 /// Legacy FD Info from LegacyBios.GetBbsInfo()
27 ///
28 LEGACY_MENU_OPTION      LegacyFDMenu = {
29   LEGACY_MENU_OPTION_SIGNATURE,
30   {NULL},
31   0
32 };
33 
34 ///
35 /// Legacy HD Info from LegacyBios.GetBbsInfo()
36 ///
37 LEGACY_MENU_OPTION      LegacyHDMenu = {
38   LEGACY_MENU_OPTION_SIGNATURE,
39   {NULL},
40   0
41 };
42 
43 ///
44 /// Legacy CD Info from LegacyBios.GetBbsInfo()
45 ///
46 LEGACY_MENU_OPTION      LegacyCDMenu = {
47   LEGACY_MENU_OPTION_SIGNATURE,
48   {NULL},
49   0
50 };
51 
52 ///
53 /// Legacy NET Info from LegacyBios.GetBbsInfo()
54 ///
55 LEGACY_MENU_OPTION      LegacyNETMenu = {
56   LEGACY_MENU_OPTION_SIGNATURE,
57   {NULL},
58   0
59 };
60 
61 ///
62 /// Legacy NET Info from LegacyBios.GetBbsInfo()
63 ///
64 LEGACY_MENU_OPTION      LegacyBEVMenu = {
65   LEGACY_MENU_OPTION_SIGNATURE,
66   {NULL},
67   0
68 };
69 
70 
71 VOID                *mLegacyStartOpCodeHandle = NULL;
72 VOID                *mLegacyEndOpCodeHandle = NULL;
73 EFI_IFR_GUID_LABEL  *mLegacyStartLabel = NULL;
74 EFI_IFR_GUID_LABEL  *mLegacyEndLabel = NULL;
75 
76 
77 HII_VENDOR_DEVICE_PATH  mLegacyBootOptionHiiVendorDevicePath = {
78   {
79     {
80       HARDWARE_DEVICE_PATH,
81       HW_VENDOR_DP,
82       {
83         (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
84         (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
85       }
86     },
87     { 0x6bc75598, 0x89b4, 0x483d, { 0x91, 0x60, 0x7f, 0x46, 0x9a, 0x96, 0x35, 0x31 } }
88   },
89   {
90     END_DEVICE_PATH_TYPE,
91     END_ENTIRE_DEVICE_PATH_SUBTYPE,
92     {
93       (UINT8) (END_DEVICE_PATH_LENGTH),
94       (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
95     }
96   }
97 };
98 
99 /**
100 
101   Build the LegacyFDMenu LegacyHDMenu LegacyCDMenu according to LegacyBios.GetBbsInfo().
102 
103 **/
104 VOID
105 GetLegacyOptions (
106   VOID
107   );
108 
109 
110 /**
111 
112   Base on the L"LegacyDevOrder" variable to build the current order data.
113 
114 **/
115 VOID
116 GetLegacyOptionsOrder (
117   VOID
118   );
119 
120 /**
121   Re-order the Boot Option according to the DevOrder.
122 
123   The routine re-orders the Boot Option in BootOption array according to
124   the order specified by DevOrder.
125 
126   @param DevOrder           Pointer to buffer containing the BBS Index,
127                             high 8-bit value 0xFF indicating a disabled boot option
128   @param DevOrderCount      Count of the BBS Index
129   @param EnBootOption       Callee allocated buffer containing the enabled Boot Option Numbers
130   @param EnBootOptionCount  Count of the enabled Boot Option Numbers
131   @param DisBootOption      Callee allocated buffer containing the disabled Boot Option Numbers
132   @param DisBootOptionCount Count of the disabled Boot Option Numbers
133 
134   @return EFI_SUCCESS       The function completed successfully.
135   @retval other             Contain some error, details see  the status return by gRT->SetVariable.
136 **/
137 EFI_STATUS
OrderLegacyBootOption4SameType(UINT16 * DevOrder,UINTN DevOrderCount,UINT16 ** EnBootOption,UINTN * EnBootOptionCount,UINT16 ** DisBootOption,UINTN * DisBootOptionCount)138 OrderLegacyBootOption4SameType (
139   UINT16                   *DevOrder,
140   UINTN                    DevOrderCount,
141   UINT16                   **EnBootOption,
142   UINTN                    *EnBootOptionCount,
143   UINT16                   **DisBootOption,
144   UINTN                    *DisBootOptionCount
145   )
146 {
147   EFI_STATUS               Status;
148   UINT16                   *NewBootOption;
149   UINT16                   *BootOrder;
150   UINTN                    BootOrderSize;
151   UINTN                    Index;
152   UINTN                    StartPosition;
153 
154   EFI_BOOT_MANAGER_LOAD_OPTION    BootOption;
155 
156   CHAR16                           OptionName[sizeof ("Boot####")];
157   UINT16                   *BbsIndexArray;
158   UINT16                   *DeviceTypeArray;
159 
160   GetEfiGlobalVariable2 (L"BootOrder", (VOID **) &BootOrder, &BootOrderSize);
161   ASSERT (BootOrder != NULL);
162 
163   BbsIndexArray       = AllocatePool (BootOrderSize);
164   DeviceTypeArray     = AllocatePool (BootOrderSize);
165   *EnBootOption       = AllocatePool (BootOrderSize);
166   *DisBootOption      = AllocatePool (BootOrderSize);
167   *DisBootOptionCount = 0;
168   *EnBootOptionCount  = 0;
169   Index               = 0;
170   Status              = EFI_SUCCESS;
171 
172   ASSERT (BbsIndexArray != NULL);
173   ASSERT (DeviceTypeArray != NULL);
174   ASSERT (*EnBootOption != NULL);
175   ASSERT (*DisBootOption != NULL);
176 
177   for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {
178 
179     UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", BootOrder[Index]);
180     Status = EfiBootManagerVariableToLoadOption (OptionName, &BootOption);
181     ASSERT_EFI_ERROR (Status);
182 
183     if ((DevicePathType (BootOption.FilePath) == BBS_DEVICE_PATH) &&
184         (DevicePathSubType (BootOption.FilePath) == BBS_BBS_DP)) {
185       //
186       // Legacy Boot Option
187       //
188       ASSERT (BootOption.OptionalDataSize == sizeof (LEGACY_BOOT_OPTION_BBS_DATA));
189 
190       DeviceTypeArray[Index] = ((BBS_BBS_DEVICE_PATH *) BootOption.FilePath)->DeviceType;
191       BbsIndexArray  [Index] = ((LEGACY_BOOT_OPTION_BBS_DATA *) BootOption.OptionalData)->BbsIndex;
192     } else {
193       DeviceTypeArray[Index] = BBS_TYPE_UNKNOWN;
194       BbsIndexArray  [Index] = 0xFFFF;
195     }
196     EfiBootManagerFreeLoadOption (&BootOption);
197   }
198 
199   //
200   // Record the corresponding Boot Option Numbers according to the DevOrder
201   // Record the EnBootOption and DisBootOption according to the DevOrder
202   //
203   StartPosition = BootOrderSize / sizeof (UINT16);
204   NewBootOption = AllocatePool (DevOrderCount * sizeof (UINT16));
205   ASSERT (NewBootOption != NULL);
206   while (DevOrderCount-- != 0) {
207     for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {
208       if (BbsIndexArray[Index] == (DevOrder[DevOrderCount] & 0xFF)) {
209         StartPosition = MIN (StartPosition, Index);
210         NewBootOption[DevOrderCount] = BootOrder[Index];
211 
212         if ((DevOrder[DevOrderCount] & 0xFF00) == 0xFF00) {
213           (*DisBootOption)[*DisBootOptionCount] = BootOrder[Index];
214           (*DisBootOptionCount)++;
215         } else {
216           (*EnBootOption)[*EnBootOptionCount] = BootOrder[Index];
217           (*EnBootOptionCount)++;
218         }
219         break;
220       }
221     }
222   }
223 
224   //
225   // Overwrite the old BootOption
226   //
227   CopyMem (&BootOrder[StartPosition], NewBootOption, (*DisBootOptionCount + *EnBootOptionCount) * sizeof (UINT16));
228   Status = gRT->SetVariable (
229                   L"BootOrder",
230                   &gEfiGlobalVariableGuid,
231                   VAR_FLAG,
232                   BootOrderSize,
233                   BootOrder
234                   );
235 
236   FreePool (NewBootOption);
237   FreePool (DeviceTypeArray);
238   FreePool (BbsIndexArray);
239 
240   return Status;
241 }
242 
243 /**
244   Update the legacy BBS boot option. L"LegacyDevOrder" and gEfiLegacyDevOrderVariableGuid EFI Variable
245   is udpated with the new Legacy Boot order. The EFI Variable of "Boot####" and gEfiGlobalVariableGuid
246   is also updated.
247 
248   @param NVMapData   The data for egacy BBS boot.
249 
250   @return EFI_SUCCESS           The function completed successfully.
251   @retval EFI_NOT_FOUND         If L"LegacyDevOrder" and gEfiLegacyDevOrderVariableGuid EFI Variable can not be found.
252   @retval EFI_OUT_OF_RESOURCES  Fail to allocate memory resource
253   @retval other                 Contain some error, details see  the status return by gRT->SetVariable.
254 **/
255 EFI_STATUS
UpdateBBSOption(IN LEGACY_BOOT_NV_DATA * NVMapData)256 UpdateBBSOption (
257   IN LEGACY_BOOT_NV_DATA            *NVMapData
258   )
259 {
260   UINTN                       Index;
261   UINTN                       Index2;
262   UINTN                       CurrentType;
263   VOID                        *BootOptionVar;
264   CHAR16                      VarName[100];
265   UINTN                       OptionSize;
266   EFI_STATUS                  Status;
267   UINT32                      *Attribute;
268   LEGACY_MENU_OPTION          *OptionMenu;
269   UINT16                      *LegacyDev;
270   UINT16                      *InitialLegacyDev;
271   UINT8                       *VarData;
272   UINTN                       VarSize;
273   LEGACY_DEV_ORDER_ENTRY      *DevOrder;
274   UINT8                       *OriginalPtr;
275   UINT8                       *DisMap;
276   UINTN                       Pos;
277   UINTN                       Bit;
278   UINT16                      *NewOrder;
279   UINT16                      Tmp;
280   UINT16                      *EnBootOption;
281   UINTN                       EnBootOptionCount;
282   UINT16                      *DisBootOption;
283   UINTN                       DisBootOptionCount;
284   UINTN                       BufferSize;
285 
286 
287   DisMap              = NULL;
288   NewOrder            = NULL;
289   CurrentType         = 0;
290   EnBootOption        = NULL;
291   DisBootOption       = NULL;
292 
293 
294   DisMap  = mLegacyBootOptionPrivate->MaintainMapData->DisableMap;
295   Status  = EFI_SUCCESS;
296 
297   //
298   // Update the Variable "LegacyDevOrder"
299   //
300   GetVariable2 (VAR_LEGACY_DEV_ORDER, &gEfiLegacyDevOrderVariableGuid, (VOID **) &VarData, &VarSize);
301   if (VarData == NULL) {
302     return EFI_NOT_FOUND;
303   }
304   OriginalPtr = VarData;
305 
306   while (mBbsType[CurrentType] != BBS_UNKNOWN) {
307     switch (mBbsType[CurrentType]) {
308     case BBS_FLOPPY:
309       OptionMenu            = (LEGACY_MENU_OPTION *) &LegacyFDMenu;
310       LegacyDev             = NVMapData->LegacyFD;
311       InitialLegacyDev     = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyFD;
312       BufferSize            = sizeof (NVMapData->LegacyFD);
313       break;
314 
315     case BBS_HARDDISK:
316       OptionMenu            = (LEGACY_MENU_OPTION *) &LegacyHDMenu;
317       LegacyDev             = NVMapData->LegacyHD;
318       InitialLegacyDev     = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyHD;
319 
320       BufferSize            = sizeof (NVMapData->LegacyHD);
321       break;
322 
323     case BBS_CDROM:
324       OptionMenu            = (LEGACY_MENU_OPTION *) &LegacyCDMenu;
325       LegacyDev             = NVMapData->LegacyCD;
326       InitialLegacyDev     = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyCD;
327       BufferSize            = sizeof (NVMapData->LegacyCD);
328       break;
329 
330     case BBS_EMBED_NETWORK:
331       OptionMenu            = (LEGACY_MENU_OPTION *) &LegacyNETMenu;
332       LegacyDev             = NVMapData->LegacyNET;
333       InitialLegacyDev     = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyNET;
334       BufferSize            = sizeof (NVMapData->LegacyNET);
335       break;
336 
337     default:
338       ASSERT (mBbsType[CurrentType] == BBS_BEV_DEVICE);
339       OptionMenu            = (LEGACY_MENU_OPTION *) &LegacyBEVMenu;
340       LegacyDev             = NVMapData->LegacyBEV;
341       InitialLegacyDev     = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyBEV;
342       BufferSize            = sizeof (NVMapData->LegacyBEV);
343       break;
344     }
345 
346     //
347     // Check whether has value changed.
348     //
349     if (CompareMem (LegacyDev, InitialLegacyDev, BufferSize) == 0) {
350       CurrentType++;
351       continue;
352     }
353 
354     DevOrder    = (LEGACY_DEV_ORDER_ENTRY *) OriginalPtr;
355     while (VarData < OriginalPtr + VarSize) {
356       if (DevOrder->BbsType == mBbsType[CurrentType]) {
357         break;
358       }
359 
360       VarData += sizeof (BBS_TYPE) + DevOrder->Length;
361       DevOrder = (LEGACY_DEV_ORDER_ENTRY *) VarData;
362     }
363 
364     if (VarData >= OriginalPtr + VarSize) {
365       FreePool (OriginalPtr);
366       return EFI_NOT_FOUND;
367     }
368 
369     NewOrder = AllocateZeroPool (DevOrder->Length - sizeof (DevOrder->Length));
370     if (NewOrder == NULL) {
371       FreePool (OriginalPtr);
372       return EFI_OUT_OF_RESOURCES;
373     }
374 
375     for (Index = 0; Index < OptionMenu->MenuNumber; Index++) {
376       if (0xFF == LegacyDev[Index]) {
377         break;
378       }
379 
380       NewOrder[Index] = LegacyDev[Index];
381     }
382 
383     //
384     // Only the enable/disable state of each boot device with same device type can be changed,
385     // so we can count on the index information in DevOrder.
386     // DisMap bit array is the only reliable source to check a device's en/dis state,
387     // so we use DisMap to set en/dis state of each item in NewOrder array
388     //
389     for (Index2 = 0; Index2 < OptionMenu->MenuNumber; Index2++) {
390       Tmp = (UINT16) (DevOrder->Data[Index2] & 0xFF);
391       Pos = Tmp / 8;
392       Bit = 7 - (Tmp % 8);
393       if ((DisMap[Pos] & (1 << Bit)) != 0) {
394         NewOrder[Index] = (UINT16) (0xFF00 | Tmp);
395         Index++;
396       }
397     }
398 
399     CopyMem (
400       DevOrder->Data,
401       NewOrder,
402       DevOrder->Length - sizeof (DevOrder->Length)
403       );
404     FreePool (NewOrder);
405 
406     //
407     // Update BootOrder and Boot####.Attribute
408     //
409     // 1. Re-order the Option Number in BootOrder according to Legacy Dev Order
410     //
411     ASSERT (OptionMenu->MenuNumber == DevOrder->Length / sizeof (UINT16) - 1);
412 
413     Status = OrderLegacyBootOption4SameType (
414       DevOrder->Data,
415       DevOrder->Length / sizeof (UINT16) - 1,
416       &EnBootOption,
417       &EnBootOptionCount,
418       &DisBootOption,
419       &DisBootOptionCount
420       );
421      if (EFI_ERROR(Status)) {
422        goto Fail;
423      }
424 
425     //
426     // 2. Deactivate the DisBootOption and activate the EnBootOption
427     //
428     for (Index = 0; Index < DisBootOptionCount; Index++) {
429       UnicodeSPrint (VarName, sizeof (VarName), L"Boot%04x", DisBootOption[Index]);
430       GetEfiGlobalVariable2 (VarName, (VOID **) &BootOptionVar, &OptionSize);
431       if (BootOptionVar != NULL) {
432         Attribute   = (UINT32 *) BootOptionVar;
433         *Attribute &= ~LOAD_OPTION_ACTIVE;
434 
435         Status = gRT->SetVariable (
436                         VarName,
437                         &gEfiGlobalVariableGuid,
438                         VAR_FLAG,
439                         OptionSize,
440                         BootOptionVar
441                         );
442 
443         FreePool (BootOptionVar);
444       }
445     }
446 
447     for (Index = 0; Index < EnBootOptionCount; Index++) {
448       UnicodeSPrint (VarName, sizeof (VarName), L"Boot%04x", EnBootOption[Index]);
449       GetEfiGlobalVariable2 (VarName, (VOID **) &BootOptionVar, &OptionSize);
450       if (BootOptionVar != NULL) {
451         Attribute   = (UINT32 *) BootOptionVar;
452         *Attribute |= LOAD_OPTION_ACTIVE;
453 
454         Status = gRT->SetVariable (
455                         VarName,
456                         &gEfiGlobalVariableGuid,
457                         VAR_FLAG,
458                         OptionSize,
459                         BootOptionVar
460                         );
461 
462         FreePool (BootOptionVar);
463       }
464     }
465 
466 
467     FreePool (EnBootOption);
468     FreePool (DisBootOption);
469 
470     CurrentType++;
471   }
472 
473   Status = gRT->SetVariable (
474                   VAR_LEGACY_DEV_ORDER,
475                   &gEfiLegacyDevOrderVariableGuid,
476                   EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
477                   VarSize,
478                   OriginalPtr
479                   );
480 
481 Fail:
482   if (EnBootOption != NULL) {
483     FreePool (EnBootOption);
484   }
485 
486   if (DisBootOption != NULL) {
487     FreePool (DisBootOption);
488   }
489 
490   FreePool (OriginalPtr);
491   return Status;
492 }
493 
494 /**
495   This function allows a caller to extract the current configuration for one
496   or more named elements from the target driver.
497 
498 
499   @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
500   @param Request         A null-terminated Unicode string in <ConfigRequest> format.
501   @param Progress        On return, points to a character in the Request string.
502                          Points to the string's null terminator if request was successful.
503                          Points to the most recent '&' before the first failing name/value
504                          pair (or the beginning of the string if the failure is in the
505                          first name/value pair) if the request was not successful.
506   @param Results         A null-terminated Unicode string in <ConfigAltResp> format which
507                          has all values filled in for the names in the Request string.
508                          String to be allocated by the called function.
509 
510   @retval  EFI_SUCCESS            The Results is filled with the requested values.
511   @retval  EFI_OUT_OF_RESOURCES   Not enough memory to store the results.
512   @retval  EFI_INVALID_PARAMETER  Request is illegal syntax, or unknown name.
513   @retval  EFI_NOT_FOUND          Routing data doesn't match any storage in this driver.
514 
515 **/
516 EFI_STATUS
517 EFIAPI
LegacyBootOptionExtractConfig(IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL * This,IN CONST EFI_STRING Request,OUT EFI_STRING * Progress,OUT EFI_STRING * Results)518 LegacyBootOptionExtractConfig (
519   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
520   IN  CONST EFI_STRING                       Request,
521   OUT EFI_STRING                             *Progress,
522   OUT EFI_STRING                             *Results
523   )
524 {
525   if (Progress == NULL || Results == NULL) {
526     return EFI_INVALID_PARAMETER;
527   }
528   *Progress = Request;
529   return EFI_NOT_FOUND;
530 }
531 
532 /**
533   This function processes the results of changes in configuration.
534 
535 
536   @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
537   @param Configuration   A null-terminated Unicode string in <ConfigResp> format.
538   @param Progress        A pointer to a string filled in with the offset of the most
539                          recent '&' before the first failing name/value pair (or the
540                          beginning of the string if the failure is in the first
541                          name/value pair) or the terminating NULL if all was successful.
542 
543   @retval  EFI_SUCCESS            The Results is processed successfully.
544   @retval  EFI_INVALID_PARAMETER  Configuration is NULL.
545   @retval  EFI_NOT_FOUND          Routing data doesn't match any storage in this driver.
546 
547 **/
548 EFI_STATUS
549 EFIAPI
LegacyBootOptionRouteConfig(IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL * This,IN CONST EFI_STRING Configuration,OUT EFI_STRING * Progress)550 LegacyBootOptionRouteConfig (
551   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
552   IN  CONST EFI_STRING                       Configuration,
553   OUT       EFI_STRING                       *Progress
554   )
555 {
556   EFI_STATUS                      Status;
557   EFI_HII_CONFIG_ROUTING_PROTOCOL *ConfigRouting;
558   LEGACY_BOOT_NV_DATA             *CurrentNVMapData;
559   UINTN                           BufferSize;
560 
561 
562   if (Configuration == NULL || Progress == NULL) {
563     return EFI_INVALID_PARAMETER;
564   }
565 
566   //
567   // Check routing data in <ConfigHdr>.
568   // Note: there is no name for Name/Value storage, only GUID will be checked
569   //
570   if (!HiiIsConfigHdrMatch (Configuration, &mLegacyBootOptionGuid, mLegacyBootStorageName)) {
571     return EFI_NOT_FOUND;
572   }
573 
574   Status = gBS->LocateProtocol (
575                   &gEfiHiiConfigRoutingProtocolGuid,
576                   NULL,
577                   (VOID **) &ConfigRouting
578                   );
579   if (EFI_ERROR (Status)) {
580     return Status;
581   }
582 
583   //
584   // Convert <ConfigResp> to buffer data by helper function ConfigToBlock()
585   //
586   CurrentNVMapData = &mLegacyBootOptionPrivate->MaintainMapData->CurrentNvData;
587   Status = ConfigRouting->ConfigToBlock (
588                             ConfigRouting,
589                             Configuration,
590                             (UINT8 *) CurrentNVMapData,
591                             &BufferSize,
592                             Progress
593                             );
594   ASSERT_EFI_ERROR (Status);
595 
596   Status = UpdateBBSOption (CurrentNVMapData);
597 
598   return Status;
599 }
600 
601 /**
602   Refresh the global UpdateData structure.
603 
604 **/
605 VOID
RefreshLegacyUpdateData(VOID)606 RefreshLegacyUpdateData (
607   VOID
608   )
609 {
610   //
611   // Free current updated date
612   //
613   if (mLegacyStartOpCodeHandle != NULL) {
614     HiiFreeOpCodeHandle (mLegacyStartOpCodeHandle);
615   }
616   if (mLegacyEndOpCodeHandle != NULL) {
617     HiiFreeOpCodeHandle (mLegacyEndOpCodeHandle);
618   }
619 
620   //
621   // Create new OpCode Handle
622   //
623   mLegacyStartOpCodeHandle = HiiAllocateOpCodeHandle ();
624   mLegacyEndOpCodeHandle = HiiAllocateOpCodeHandle ();
625 
626   //
627   // Create Hii Extend Label OpCode as the start opcode
628   //
629   mLegacyStartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
630                                          mLegacyStartOpCodeHandle,
631                                          &gEfiIfrTianoGuid,
632                                          NULL,
633                                          sizeof (EFI_IFR_GUID_LABEL)
634                                          );
635   mLegacyStartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
636 
637   mLegacyStartLabel->Number = FORM_BOOT_LEGACY_DEVICE_ID;
638 
639   //
640   // Create Hii Extend Label OpCode as the start opcode
641   //
642   mLegacyEndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
643                                          mLegacyEndOpCodeHandle,
644                                          &gEfiIfrTianoGuid,
645                                          NULL,
646                                          sizeof (EFI_IFR_GUID_LABEL)
647                                          );
648   mLegacyEndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
649 
650   mLegacyEndLabel->Number = FORM_BOOT_LEGACY_LABEL_END;
651 
652 }
653 
654 /**
655   Get the Menu Entry from the list in Menu Entry List.
656 
657   If MenuNumber is great or equal to the number of Menu
658   Entry in the list, then ASSERT.
659 
660   @param MenuOption      The Menu Entry List to read the menu entry.
661   @param MenuNumber      The index of Menu Entry.
662 
663   @return The Menu Entry.
664 
665 **/
666 LEGACY_MENU_ENTRY *
GetMenuEntry(LEGACY_MENU_OPTION * MenuOption,UINTN MenuNumber)667 GetMenuEntry (
668   LEGACY_MENU_OPTION      *MenuOption,
669   UINTN                   MenuNumber
670   )
671 {
672   LEGACY_MENU_ENTRY   *NewMenuEntry;
673   UINTN               Index;
674   LIST_ENTRY          *List;
675 
676   ASSERT (MenuNumber < MenuOption->MenuNumber);
677 
678   List = MenuOption->Head.ForwardLink;
679   for (Index = 0; Index < MenuNumber; Index++) {
680     List = List->ForwardLink;
681   }
682 
683   NewMenuEntry = CR (List, LEGACY_MENU_ENTRY, Link, LEGACY_MENU_ENTRY_SIGNATURE);
684 
685   return NewMenuEntry;
686 }
687 
688 /**
689   Create string tokens for a menu from its help strings and display strings
690 
691   @param HiiHandle          Hii Handle of the package to be updated.
692   @param MenuOption         The Menu whose string tokens need to be created
693 
694 **/
695 VOID
CreateLegacyMenuStringToken(IN EFI_HII_HANDLE HiiHandle,IN LEGACY_MENU_OPTION * MenuOption)696 CreateLegacyMenuStringToken (
697   IN EFI_HII_HANDLE                   HiiHandle,
698   IN LEGACY_MENU_OPTION               *MenuOption
699   )
700 {
701   LEGACY_MENU_ENTRY *NewMenuEntry;
702   UINTN             Index;
703 
704   for (Index = 0; Index < MenuOption->MenuNumber; Index++) {
705     NewMenuEntry = GetMenuEntry (MenuOption, Index);
706 
707     NewMenuEntry->DisplayStringToken = HiiSetString (
708                                          HiiHandle,
709                                          0,
710                                          NewMenuEntry->DisplayString,
711                                          NULL
712                                          );
713 
714     if (NULL == NewMenuEntry->HelpString) {
715       NewMenuEntry->HelpStringToken = NewMenuEntry->DisplayStringToken;
716     } else {
717       NewMenuEntry->HelpStringToken = HiiSetString (
718                                         HiiHandle,
719                                         0,
720                                         NewMenuEntry->HelpString,
721                                         NULL
722                                         );
723     }
724   }
725 }
726 
727 /**
728   Create a dynamic page so that Legacy Device boot order
729   can be set for specified device type.
730 
731   @param UpdatePageId    The form ID. It also spefies the legacy device type.
732 
733 
734 **/
735 VOID
UpdateLegacyDeviceOrderPage(IN UINT16 UpdatePageId)736 UpdateLegacyDeviceOrderPage (
737   IN UINT16                           UpdatePageId
738   )
739 {
740   LEGACY_MENU_OPTION          *OptionMenu;
741   LEGACY_MENU_ENTRY           *NewMenuEntry;
742   EFI_STRING_ID               StrRef;
743   EFI_STRING_ID               StrRefHelp;
744   UINT16                      *Default;
745   UINT16                      Index;
746   UINT16                      Key;
747   CHAR16                      String[100];
748   CHAR16                      *TypeStr;
749   CHAR16                      *TypeStrHelp;
750   CHAR16                      *FormTitle;
751   VOID                        *OptionsOpCodeHandle;
752   VOID                        *DefaultOpCodeHandle;
753 
754   Key         = 0;
755   StrRef      = 0;
756   StrRefHelp  = 0;
757   OptionMenu  = NULL;
758   TypeStr     = NULL;
759   TypeStrHelp = NULL;
760   Default     = NULL;
761 
762   RefreshLegacyUpdateData();
763 
764   //
765   // Create oneof option list
766   //
767   switch (UpdatePageId) {
768   case FORM_FLOPPY_BOOT_ID:
769     OptionMenu  = (LEGACY_MENU_OPTION *) &LegacyFDMenu;
770     Key         = (UINT16) LEGACY_FD_QUESTION_ID;
771     TypeStr     = STR_FLOPPY;
772     TypeStrHelp = STR_FLOPPY_HELP;
773     FormTitle   = STR_FLOPPY_TITLE;
774     Default     = mLegacyBootOptionPrivate->MaintainMapData->CurrentNvData.LegacyFD;
775     break;
776 
777   case FORM_HARDDISK_BOOT_ID:
778     OptionMenu  = (LEGACY_MENU_OPTION *) &LegacyHDMenu;
779     Key         = (UINT16) LEGACY_HD_QUESTION_ID;
780     TypeStr     = STR_HARDDISK;
781     TypeStrHelp = STR_HARDDISK_HELP;
782     FormTitle   = STR_HARDDISK_TITLE;
783     Default     = mLegacyBootOptionPrivate->MaintainMapData->CurrentNvData.LegacyHD;
784     break;
785 
786   case FORM_CDROM_BOOT_ID:
787     OptionMenu  = (LEGACY_MENU_OPTION *) &LegacyCDMenu;
788     Key         = (UINT16) LEGACY_CD_QUESTION_ID;
789     TypeStr     = STR_CDROM;
790     TypeStrHelp = STR_CDROM_HELP;
791     FormTitle   = STR_CDROM_TITLE;
792     Default     = mLegacyBootOptionPrivate->MaintainMapData->CurrentNvData.LegacyCD;
793     break;
794 
795   case FORM_NET_BOOT_ID:
796     OptionMenu  = (LEGACY_MENU_OPTION *) &LegacyNETMenu;
797     Key         = (UINT16) LEGACY_NET_QUESTION_ID;
798     TypeStr     = STR_NET;
799     TypeStrHelp = STR_NET_HELP;
800     FormTitle   = STR_NET_TITLE;
801     Default     = mLegacyBootOptionPrivate->MaintainMapData->CurrentNvData.LegacyNET;
802     break;
803 
804   case FORM_BEV_BOOT_ID:
805     OptionMenu  = (LEGACY_MENU_OPTION *) &LegacyBEVMenu;
806     Key         = (UINT16) LEGACY_BEV_QUESTION_ID;
807     TypeStr     = STR_BEV;
808     TypeStrHelp = STR_BEV_HELP;
809     FormTitle   = STR_BEV_TITLE;
810     Default     = mLegacyBootOptionPrivate->MaintainMapData->CurrentNvData.LegacyBEV;
811     break;
812 
813   default:
814     DEBUG ((EFI_D_ERROR, "Invalid command ID for updating page!\n"));
815     return;
816   }
817 
818   HiiSetString (mLegacyBootOptionPrivate->HiiHandle, STRING_TOKEN(STR_ORDER_CHANGE_PROMPT), FormTitle, NULL);
819 
820   CreateLegacyMenuStringToken (mLegacyBootOptionPrivate->HiiHandle, OptionMenu);
821 
822   OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();
823   ASSERT (OptionsOpCodeHandle != NULL);
824 
825 
826   for (Index = 0; Index < OptionMenu->MenuNumber; Index++) {
827     NewMenuEntry = GetMenuEntry (OptionMenu, Index);
828     //
829     // Create OneOf for each legacy device
830     //
831     HiiCreateOneOfOptionOpCode (
832       OptionsOpCodeHandle,
833       NewMenuEntry->DisplayStringToken,
834       0,
835       EFI_IFR_TYPE_NUM_SIZE_16,
836       ((LEGACY_DEVICE_CONTEXT *) NewMenuEntry->VariableContext)->BbsIndex
837       );
838   }
839 
840   //
841   // Create OneOf for item "Disabled"
842   //
843   HiiCreateOneOfOptionOpCode (
844     OptionsOpCodeHandle,
845     STRING_TOKEN (STR_DISABLE_LEGACY_DEVICE),
846     0,
847     EFI_IFR_TYPE_NUM_SIZE_16,
848     0xFF
849     );
850 
851   //
852   // Create oneof tag here for FD/HD/CD #1 #2
853   //
854   for (Index = 0; Index < OptionMenu->MenuNumber; Index++) {
855     DefaultOpCodeHandle = HiiAllocateOpCodeHandle ();
856     ASSERT (DefaultOpCodeHandle != NULL);
857 
858     HiiCreateDefaultOpCode (
859       DefaultOpCodeHandle,
860       EFI_HII_DEFAULT_CLASS_STANDARD,
861       EFI_IFR_TYPE_NUM_SIZE_16,
862       *Default++
863       );
864 
865     //
866     // Create the string for oneof tag
867     //
868     UnicodeSPrint (String, sizeof (String), TypeStr, Index);
869     StrRef = HiiSetString (mLegacyBootOptionPrivate->HiiHandle, 0, String, NULL);
870 
871     UnicodeSPrint (String, sizeof (String), TypeStrHelp, Index);
872     StrRefHelp = HiiSetString (mLegacyBootOptionPrivate->HiiHandle, 0, String, NULL);
873 
874     HiiCreateOneOfOpCode (
875       mLegacyStartOpCodeHandle,
876       (EFI_QUESTION_ID) (Key + Index),
877       VARSTORE_ID_LEGACY_BOOT,
878       (UINT16) (Key + Index * 2 - CONFIG_OPTION_OFFSET),
879       StrRef,
880       StrRefHelp,
881       EFI_IFR_FLAG_CALLBACK,
882       EFI_IFR_NUMERIC_SIZE_2,
883       OptionsOpCodeHandle,
884       DefaultOpCodeHandle //NULL //
885       );
886 
887     HiiFreeOpCodeHandle (DefaultOpCodeHandle);
888   }
889 
890   HiiUpdateForm (
891     mLegacyBootOptionPrivate->HiiHandle,
892     &mLegacyBootOptionGuid,
893     LEGACY_ORDER_CHANGE_FORM_ID,
894     mLegacyStartOpCodeHandle,
895     mLegacyEndOpCodeHandle
896     );
897 
898   HiiFreeOpCodeHandle (OptionsOpCodeHandle);
899 }
900 
901 
902 /**
903   Adjust question value when one question value has been changed.
904 
905   @param QuestionId    The question id for the value changed question.
906   @param Value         The value for the changed question.
907 
908 **/
909 VOID
AdjustOptionValue(IN UINT16 QuestionId,IN EFI_IFR_TYPE_VALUE * Value)910 AdjustOptionValue (
911   IN  UINT16                                 QuestionId,
912   IN  EFI_IFR_TYPE_VALUE                     *Value
913   )
914 {
915   UINTN                       Number;
916   UINT16                      *Default;
917   LEGACY_BOOT_NV_DATA         *CurrentNVMap;
918   UINT16                      *CurrentVal;
919   UINTN                       Index;
920   UINTN                       Index2;
921   UINTN                       Index3;
922   UINTN                       NewValuePos;
923   UINTN                       OldValue;
924   UINTN                       NewValue;
925   UINT8                       *DisMap;
926   UINTN                       Pos;
927   UINTN                       Bit;
928 
929   Number = 0;
930   CurrentVal = 0;
931   Default = NULL;
932   NewValue = 0;
933   NewValuePos = 0;
934   OldValue = 0;
935 
936   //
937   // Update Select FD/HD/CD/NET/BEV Order Form
938   //
939   ASSERT ((QuestionId >= LEGACY_FD_QUESTION_ID) && (QuestionId < LEGACY_BEV_QUESTION_ID + MAX_MENU_NUMBER));
940 
941   CurrentNVMap = &mLegacyBootOptionPrivate->MaintainMapData->CurrentNvData;
942   HiiGetBrowserData (&mLegacyBootOptionGuid, mLegacyBootStorageName, sizeof (LEGACY_BOOT_NV_DATA), (UINT8 *) CurrentNVMap);
943   DisMap  = mLegacyBootOptionPrivate->MaintainMapData->DisableMap;
944 
945   if (QuestionId >= LEGACY_FD_QUESTION_ID && QuestionId < LEGACY_FD_QUESTION_ID + MAX_MENU_NUMBER) {
946     Number      = (UINT16) LegacyFDMenu.MenuNumber;
947     CurrentVal  = CurrentNVMap->LegacyFD;
948     Default     = mLegacyBootOptionPrivate->MaintainMapData->LastTimeNvData.LegacyFD;
949   } else if (QuestionId >= LEGACY_HD_QUESTION_ID && QuestionId < LEGACY_HD_QUESTION_ID + MAX_MENU_NUMBER) {
950     Number      = (UINT16) LegacyHDMenu.MenuNumber;
951     CurrentVal  = CurrentNVMap->LegacyHD;
952     Default     = mLegacyBootOptionPrivate->MaintainMapData->LastTimeNvData.LegacyHD;
953   } else if (QuestionId >= LEGACY_CD_QUESTION_ID && QuestionId < LEGACY_CD_QUESTION_ID + MAX_MENU_NUMBER) {
954     Number      = (UINT16) LegacyCDMenu.MenuNumber;
955     CurrentVal  = CurrentNVMap->LegacyCD;
956     Default     = mLegacyBootOptionPrivate->MaintainMapData->LastTimeNvData.LegacyCD;
957   } else if (QuestionId >= LEGACY_NET_QUESTION_ID && QuestionId < LEGACY_NET_QUESTION_ID + MAX_MENU_NUMBER) {
958     Number      = (UINT16) LegacyNETMenu.MenuNumber;
959     CurrentVal  = CurrentNVMap->LegacyNET;
960     Default     = mLegacyBootOptionPrivate->MaintainMapData->LastTimeNvData.LegacyNET;
961   } else if (QuestionId >= LEGACY_BEV_QUESTION_ID && QuestionId < LEGACY_BEV_QUESTION_ID + MAX_MENU_NUMBER) {
962     Number      = (UINT16) LegacyBEVMenu.MenuNumber;
963     CurrentVal  = CurrentNVMap->LegacyBEV;
964     Default     = mLegacyBootOptionPrivate->MaintainMapData->LastTimeNvData.LegacyBEV;
965   }
966 
967   //
968   //  First, find the different position
969   //  if there is change, it should be only one
970   //
971   for (Index = 0; Index < Number; Index++) {
972     if (CurrentVal[Index] != Default[Index]) {
973       OldValue  = Default[Index];
974       NewValue  = CurrentVal[Index];
975       break;
976     }
977   }
978 
979   if (Index != Number) {
980     //
981     // there is change, now process
982     //
983     if (0xFF == NewValue) {
984       //
985       // This item will be disable
986       // Just move the items behind this forward to overlap it
987       //
988       Pos = OldValue / 8;
989       Bit = 7 - (OldValue % 8);
990       DisMap[Pos] = (UINT8) (DisMap[Pos] | (UINT8) (1 << Bit));
991       for (Index2 = Index; Index2 < Number - 1; Index2++) {
992         CurrentVal[Index2] = CurrentVal[Index2 + 1];
993       }
994 
995       CurrentVal[Index2] = 0xFF;
996     } else {
997       for (Index2 = 0; Index2 < Number; Index2++) {
998         if (Index2 == Index) {
999           continue;
1000         }
1001 
1002         if (Default[Index2] == NewValue) {
1003           //
1004           // If NewValue is in OldLegacyDev array
1005           // remember its old position
1006           //
1007           NewValuePos = Index2;
1008           break;
1009         }
1010       }
1011 
1012       if (Index2 != Number) {
1013         //
1014         // We will change current item to an existing item
1015         // (It's hard to describe here, please read code, it's like a cycle-moving)
1016         //
1017         for (Index2 = NewValuePos; Index2 != Index;) {
1018           if (NewValuePos < Index) {
1019             CurrentVal[Index2] = Default[Index2 + 1];
1020             Index2++;
1021           } else {
1022             CurrentVal[Index2] = Default[Index2 - 1];
1023             Index2--;
1024           }
1025         }
1026       } else {
1027         //
1028         // If NewValue is not in OldlegacyDev array, we are changing to a disabled item
1029         // so we should modify DisMap to reflect the change
1030         //
1031         Pos = NewValue / 8;
1032         Bit = 7 - (NewValue % 8);
1033         DisMap[Pos] = (UINT8) (DisMap[Pos] & (~ (UINT8) (1 << Bit)));
1034         if (0xFF != OldValue) {
1035           //
1036           // Because NewValue is a item that was disabled before
1037           // so after changing the OldValue should be disabled
1038           // actually we are doing a swap of enable-disable states of two items
1039           //
1040           Pos = OldValue / 8;
1041           Bit = 7 - (OldValue % 8);
1042           DisMap[Pos] = (UINT8) (DisMap[Pos] | (UINT8) (1 << Bit));
1043         }
1044       }
1045     }
1046     //
1047     // To prevent DISABLE appears in the middle of the list
1048     // we should perform a re-ordering
1049     //
1050     Index3 = Index;
1051     Index = 0;
1052     while (Index < Number) {
1053       if (0xFF != CurrentVal[Index]) {
1054         Index++;
1055         continue;
1056       }
1057 
1058       Index2 = Index;
1059       Index2++;
1060       while (Index2 < Number) {
1061         if (0xFF != CurrentVal[Index2]) {
1062           break;
1063         }
1064 
1065         Index2++;
1066       }
1067 
1068       if (Index2 < Number) {
1069         CurrentVal[Index]   = CurrentVal[Index2];
1070         CurrentVal[Index2]  = 0xFF;
1071       }
1072 
1073       Index++;
1074     }
1075 
1076     //
1077     // Return correct question value.
1078     //
1079     Value->u16 = CurrentVal[Index3];
1080     CopyMem (Default, CurrentVal, sizeof (UINT16) * Number);
1081   }
1082 
1083   //
1084   // Pass changed uncommitted data back to Form Browser
1085   //
1086   HiiSetBrowserData (&mLegacyBootOptionGuid, mLegacyBootStorageName, sizeof (LEGACY_BOOT_NV_DATA), (UINT8 *) CurrentNVMap, NULL);
1087 }
1088 
1089 /**
1090   This call back function is registered with Boot Manager formset.
1091   When user selects a boot option, this call back function will
1092   be triggered. The boot option is saved for later processing.
1093 
1094 
1095   @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
1096   @param Action          Specifies the type of action taken by the browser.
1097   @param QuestionId      A unique value which is sent to the original exporting driver
1098                          so that it can identify the type of data to expect.
1099   @param Type            The type of value for the question.
1100   @param Value           A pointer to the data being sent to the original exporting driver.
1101   @param ActionRequest   On return, points to the action requested by the callback function.
1102 
1103   @retval  EFI_SUCCESS           The callback successfully handled the action.
1104   @retval  EFI_INVALID_PARAMETER The setup browser call this function with invalid parameters.
1105 
1106 **/
1107 EFI_STATUS
1108 EFIAPI
LegacyBootOptionCallback(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)1109 LegacyBootOptionCallback (
1110   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
1111   IN  EFI_BROWSER_ACTION                     Action,
1112   IN  EFI_QUESTION_ID                        QuestionId,
1113   IN  UINT8                                  Type,
1114   IN  EFI_IFR_TYPE_VALUE                     *Value,
1115   OUT EFI_BROWSER_ACTION_REQUEST             *ActionRequest
1116   )
1117 {
1118   if (Action != EFI_BROWSER_ACTION_CHANGED && Action != EFI_BROWSER_ACTION_CHANGING && Action != EFI_BROWSER_ACTION_FORM_OPEN) {
1119     //
1120     // Do nothing for other UEFI Action. Only do call back when data is changed or the form is open.
1121     //
1122     return EFI_UNSUPPORTED;
1123   }
1124 
1125   if ((Value == NULL) || (ActionRequest == NULL)) {
1126     return EFI_INVALID_PARAMETER;
1127   }
1128 
1129   if (Action == EFI_BROWSER_ACTION_FORM_OPEN) {
1130     if (QuestionId == FORM_FLOPPY_BOOT_ID) {
1131       if (!mFirstEnterLegacyForm) {
1132         //
1133         // The leagcyBootMaintUiLib depends on the LegacyBootManagerLib to realize its functionality.
1134         // We need to do the leagcy boot options related actions after the LegacyBootManagerLib has been initialized.
1135         // Opening the legacy menus is the appropriate time that the LegacyBootManagerLib has already been initialized.
1136         //
1137         mFirstEnterLegacyForm = TRUE;
1138         GetLegacyOptions ();
1139         GetLegacyOptionsOrder ();
1140       }
1141     }
1142   }
1143 
1144   if (Action == EFI_BROWSER_ACTION_CHANGING) {
1145     switch (QuestionId) {
1146     case FORM_FLOPPY_BOOT_ID:
1147     case FORM_HARDDISK_BOOT_ID:
1148     case FORM_CDROM_BOOT_ID:
1149     case FORM_NET_BOOT_ID:
1150     case FORM_BEV_BOOT_ID:
1151       UpdateLegacyDeviceOrderPage (QuestionId);
1152       break;
1153 
1154     default:
1155       break;
1156     }
1157   } else if (Action == EFI_BROWSER_ACTION_CHANGED) {
1158     if ((Value == NULL) || (ActionRequest == NULL)) {
1159       return EFI_INVALID_PARAMETER;
1160     }
1161 
1162     if ((QuestionId >= LEGACY_FD_QUESTION_ID) && (QuestionId < LEGACY_BEV_QUESTION_ID + MAX_MENU_NUMBER)) {
1163       AdjustOptionValue(QuestionId, Value);
1164     }
1165   }
1166   return EFI_SUCCESS;
1167 }
1168 
1169 
1170 /**
1171   Create a menu entry by given menu type.
1172 
1173   @param MenuType        The Menu type to be created.
1174 
1175   @retval NULL           If failed to create the menu.
1176   @return the new menu entry.
1177 
1178 **/
1179 LEGACY_MENU_ENTRY *
CreateMenuEntry(VOID)1180 CreateMenuEntry (
1181   VOID
1182   )
1183 {
1184   LEGACY_MENU_ENTRY *MenuEntry;
1185 
1186   //
1187   // Create new menu entry
1188   //
1189   MenuEntry = AllocateZeroPool (sizeof (LEGACY_MENU_ENTRY));
1190   if (MenuEntry == NULL) {
1191     return NULL;
1192   }
1193 
1194   MenuEntry->VariableContext = AllocateZeroPool (sizeof (LEGACY_DEVICE_CONTEXT));
1195   if (MenuEntry->VariableContext == NULL) {
1196     FreePool (MenuEntry);
1197     return NULL;
1198   }
1199 
1200   MenuEntry->Signature        = LEGACY_MENU_ENTRY_SIGNATURE;
1201   return MenuEntry;
1202 }
1203 
1204 /**
1205 
1206   Base on the L"LegacyDevOrder" variable to build the current order data.
1207 
1208 **/
1209 VOID
GetLegacyOptionsOrder(VOID)1210 GetLegacyOptionsOrder (
1211   VOID
1212   )
1213 {
1214   UINTN                       VarSize;
1215   UINT8                       *VarData;
1216   UINT8                       *VarTmp;
1217   LEGACY_DEV_ORDER_ENTRY      *DevOrder;
1218   UINT16                      *LegacyDev;
1219   UINTN                       Index;
1220   LEGACY_MENU_OPTION          *OptionMenu;
1221   UINT16                      VarDevOrder;
1222   UINTN                       Pos;
1223   UINTN                       Bit;
1224   UINT8                       *DisMap;
1225   UINTN                       TotalLength;
1226 
1227   LegacyDev = NULL;
1228   OptionMenu = NULL;
1229 
1230   DisMap = ZeroMem (mLegacyBootOptionPrivate->MaintainMapData->DisableMap, sizeof (mLegacyBootOptionPrivate->MaintainMapData->DisableMap));
1231 
1232   //
1233   // Get Device Order from variable
1234   //
1235   GetVariable2 (VAR_LEGACY_DEV_ORDER, &gEfiLegacyDevOrderVariableGuid, (VOID **) &VarData, &VarSize);
1236   VarTmp = VarData;
1237   if (NULL != VarData) {
1238     DevOrder    = (LEGACY_DEV_ORDER_ENTRY *) VarData;
1239     while (VarData < VarTmp + VarSize) {
1240       switch (DevOrder->BbsType) {
1241       case BBS_FLOPPY:
1242         LegacyDev = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyFD;
1243         OptionMenu = &LegacyFDMenu;
1244         break;
1245 
1246       case BBS_HARDDISK:
1247         LegacyDev = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyHD;
1248         OptionMenu = &LegacyHDMenu;
1249         break;
1250 
1251       case BBS_CDROM:
1252         LegacyDev = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyCD;
1253         OptionMenu = &LegacyCDMenu;
1254         break;
1255 
1256       case BBS_EMBED_NETWORK:
1257         LegacyDev = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyNET;
1258         OptionMenu = &LegacyNETMenu;
1259         break;
1260 
1261       case BBS_BEV_DEVICE:
1262         LegacyDev = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyBEV;
1263         OptionMenu = &LegacyBEVMenu;
1264         break;
1265 
1266       case BBS_UNKNOWN:
1267       default:
1268         ASSERT (FALSE);
1269         DEBUG ((DEBUG_ERROR, "Unsupported device type found!\n"));
1270         break;
1271       }
1272 
1273       //
1274       // Create oneof tag here for FD/HD/CD #1 #2
1275       //
1276       for (Index = 0; Index < OptionMenu->MenuNumber; Index++) {
1277         TotalLength = sizeof (BBS_TYPE) + sizeof (UINT16) + Index * sizeof (UINT16);
1278         VarDevOrder = *(UINT16 *) ((UINT8 *) DevOrder + TotalLength);
1279 
1280         if (0xFF00 == (VarDevOrder & 0xFF00)) {
1281           LegacyDev[Index]  = 0xFF;
1282           Pos               = (VarDevOrder & 0xFF) / 8;
1283           Bit               = 7 - ((VarDevOrder & 0xFF) % 8);
1284           DisMap[Pos]       = (UINT8) (DisMap[Pos] | (UINT8) (1 << Bit));
1285         } else {
1286           LegacyDev[Index] = VarDevOrder & 0xFF;
1287         }
1288       }
1289 
1290       VarData ++;
1291       VarData += *(UINT16 *) VarData;
1292       DevOrder = (LEGACY_DEV_ORDER_ENTRY *) VarData;
1293     }
1294   }
1295 
1296   CopyMem (&mLegacyBootOptionPrivate->MaintainMapData->LastTimeNvData, &mLegacyBootOptionPrivate->MaintainMapData->InitialNvData, sizeof (LEGACY_BOOT_NV_DATA));
1297   CopyMem (&mLegacyBootOptionPrivate->MaintainMapData->CurrentNvData, &mLegacyBootOptionPrivate->MaintainMapData->InitialNvData, sizeof (LEGACY_BOOT_NV_DATA));
1298 }
1299 
1300 /**
1301 
1302   Build the LegacyFDMenu LegacyHDMenu LegacyCDMenu according to LegacyBios.GetBbsInfo().
1303 
1304 **/
1305 VOID
GetLegacyOptions(VOID)1306 GetLegacyOptions (
1307   VOID
1308   )
1309 {
1310   LEGACY_MENU_ENTRY             *NewMenuEntry;
1311   LEGACY_DEVICE_CONTEXT         *NewLegacyDevContext;
1312   EFI_BOOT_MANAGER_LOAD_OPTION  *BootOption;
1313   UINTN                         BootOptionCount;
1314   UINT16                        Index;
1315   UINTN                         FDNum;
1316   UINTN                         HDNum;
1317   UINTN                         CDNum;
1318   UINTN                         NETNum;
1319   UINTN                         BEVNum;
1320 
1321   //
1322   // Initialize Bbs Table Context from BBS info data
1323   //
1324   InitializeListHead (&LegacyFDMenu.Head);
1325   InitializeListHead (&LegacyHDMenu.Head);
1326   InitializeListHead (&LegacyCDMenu.Head);
1327   InitializeListHead (&LegacyNETMenu.Head);
1328   InitializeListHead (&LegacyBEVMenu.Head);
1329 
1330   FDNum   = 0;
1331   HDNum   = 0;
1332   CDNum   = 0;
1333   NETNum  = 0;
1334   BEVNum  = 0;
1335 
1336   EfiBootManagerConnectAll ();
1337 
1338   //
1339   // for better user experience
1340   // 1. User changes HD configuration (e.g.: unplug HDD), here we have a chance to remove the HDD boot option
1341   // 2. User enables/disables UEFI PXE, here we have a chance to add/remove EFI Network boot option
1342   //
1343   EfiBootManagerRefreshAllBootOption ();
1344 
1345   BootOption = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
1346   for (Index = 0; Index < BootOptionCount; Index++) {
1347     if ((DevicePathType (BootOption[Index].FilePath) != BBS_DEVICE_PATH) ||
1348         (DevicePathSubType (BootOption[Index].FilePath) != BBS_BBS_DP)
1349        ) {
1350       continue;
1351     }
1352     ASSERT (BootOption[Index].OptionalDataSize == sizeof (LEGACY_BOOT_OPTION_BBS_DATA));
1353     NewMenuEntry = CreateMenuEntry ();
1354     ASSERT (NewMenuEntry != NULL);
1355 
1356     NewLegacyDevContext              = (LEGACY_DEVICE_CONTEXT *) NewMenuEntry->VariableContext;
1357     NewLegacyDevContext->BbsIndex    = ((LEGACY_BOOT_OPTION_BBS_DATA *) BootOption[Index].OptionalData)->BbsIndex;
1358     NewLegacyDevContext->Description = AllocateCopyPool (StrSize (BootOption[Index].Description), BootOption[Index].Description);
1359     ASSERT (NewLegacyDevContext->Description != NULL);
1360 
1361     NewMenuEntry->DisplayString = NewLegacyDevContext->Description;
1362     NewMenuEntry->HelpString    = NULL;
1363 
1364     switch (((BBS_BBS_DEVICE_PATH *) BootOption[Index].FilePath)->DeviceType) {
1365     case BBS_TYPE_FLOPPY:
1366       InsertTailList (&LegacyFDMenu.Head, &NewMenuEntry->Link);
1367       FDNum++;
1368       break;
1369 
1370     case BBS_TYPE_HARDDRIVE:
1371       InsertTailList (&LegacyHDMenu.Head, &NewMenuEntry->Link);
1372       HDNum++;
1373       break;
1374 
1375     case BBS_TYPE_CDROM:
1376       InsertTailList (&LegacyCDMenu.Head, &NewMenuEntry->Link);
1377       CDNum++;
1378       break;
1379 
1380     case BBS_TYPE_EMBEDDED_NETWORK:
1381       InsertTailList (&LegacyNETMenu.Head, &NewMenuEntry->Link);
1382       NETNum++;
1383       break;
1384 
1385     case BBS_TYPE_BEV:
1386       InsertTailList (&LegacyBEVMenu.Head, &NewMenuEntry->Link);
1387       BEVNum++;
1388       break;
1389     }
1390   }
1391 
1392   EfiBootManagerFreeLoadOptions (BootOption, BootOptionCount);
1393 
1394   LegacyFDMenu.MenuNumber   = FDNum;
1395   LegacyHDMenu.MenuNumber   = HDNum;
1396   LegacyCDMenu.MenuNumber   = CDNum;
1397   LegacyNETMenu.MenuNumber  = NETNum;
1398   LegacyBEVMenu.MenuNumber  = BEVNum;
1399 }
1400 
1401 
1402 /**
1403 
1404   Install Boot Manager Menu driver.
1405 
1406   @param ImageHandle     The image handle.
1407   @param SystemTable     The system table.
1408 
1409   @retval  EFI_SUCEESS  Install Boot manager menu success.
1410   @retval  Other        Return error status.
1411 
1412 **/
1413 EFI_STATUS
1414 EFIAPI
LegacyBootMaintUiLibConstructor(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)1415 LegacyBootMaintUiLibConstructor (
1416   IN EFI_HANDLE                            ImageHandle,
1417   IN EFI_SYSTEM_TABLE                      *SystemTable
1418   )
1419 {
1420   EFI_STATUS                        Status;
1421   EFI_LEGACY_BIOS_PROTOCOL          *LegacyBios;
1422   LEGACY_BOOT_OPTION_CALLBACK_DATA  *LegacyBootOptionData;
1423 
1424   Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
1425   if (!EFI_ERROR (Status)) {
1426     //
1427     // Create LegacyBootOptionData structures for Driver Callback
1428     //
1429     LegacyBootOptionData = AllocateZeroPool (sizeof (LEGACY_BOOT_OPTION_CALLBACK_DATA));
1430     ASSERT (LegacyBootOptionData != NULL);
1431 
1432     LegacyBootOptionData->MaintainMapData = AllocateZeroPool (sizeof (LEGACY_BOOT_MAINTAIN_DATA));
1433     ASSERT (LegacyBootOptionData->MaintainMapData != NULL);
1434 
1435     LegacyBootOptionData->ConfigAccess.ExtractConfig = LegacyBootOptionExtractConfig;
1436     LegacyBootOptionData->ConfigAccess.RouteConfig   = LegacyBootOptionRouteConfig;
1437     LegacyBootOptionData->ConfigAccess.Callback      = LegacyBootOptionCallback;
1438 
1439     //
1440     // Install Device Path Protocol and Config Access protocol to driver handle
1441     //
1442     Status = gBS->InstallMultipleProtocolInterfaces (
1443                     &LegacyBootOptionData->DriverHandle,
1444                     &gEfiDevicePathProtocolGuid,
1445                     &mLegacyBootOptionHiiVendorDevicePath,
1446                     &gEfiHiiConfigAccessProtocolGuid,
1447                     &LegacyBootOptionData->ConfigAccess,
1448                     NULL
1449                     );
1450     ASSERT_EFI_ERROR (Status);
1451 
1452     //
1453     // Publish our HII data
1454     //
1455     LegacyBootOptionData->HiiHandle = HiiAddPackages (
1456                                       &mLegacyBootOptionGuid,
1457                                       LegacyBootOptionData->DriverHandle,
1458                                       LegacyBootMaintUiVfrBin,
1459                                       LegacyBootMaintUiLibStrings,
1460                                       NULL
1461                                       );
1462     ASSERT (LegacyBootOptionData->HiiHandle != NULL);
1463 
1464     mLegacyBootOptionPrivate = LegacyBootOptionData;
1465   }
1466 
1467   return EFI_SUCCESS;
1468 }
1469 
1470 /**
1471   Destructor of Customized Display Library Instance.
1472 
1473   @param  ImageHandle   The firmware allocated handle for the EFI image.
1474   @param  SystemTable   A pointer to the EFI System Table.
1475 
1476   @retval EFI_SUCCESS   The destructor completed successfully.
1477   @retval Other value   The destructor did not complete successfully.
1478 
1479 **/
1480 EFI_STATUS
1481 EFIAPI
LegacyBootMaintUiLibDestructor(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)1482 LegacyBootMaintUiLibDestructor (
1483   IN EFI_HANDLE        ImageHandle,
1484   IN EFI_SYSTEM_TABLE  *SystemTable
1485   )
1486 {
1487   EFI_STATUS    Status;
1488 
1489   if (mLegacyBootOptionPrivate->DriverHandle != NULL) {
1490     Status = gBS->UninstallMultipleProtocolInterfaces (
1491                     mLegacyBootOptionPrivate->DriverHandle,
1492                     &gEfiDevicePathProtocolGuid,
1493                     &mLegacyBootOptionHiiVendorDevicePath,
1494                     &gEfiHiiConfigAccessProtocolGuid,
1495                     &mLegacyBootOptionPrivate->ConfigAccess,
1496                     NULL
1497                     );
1498     ASSERT_EFI_ERROR (Status);
1499 
1500     HiiRemovePackages (mLegacyBootOptionPrivate->HiiHandle);
1501 
1502     FreePool (mLegacyBootOptionPrivate->MaintainMapData);
1503     FreePool (mLegacyBootOptionPrivate);
1504   }
1505 
1506   return EFI_SUCCESS;
1507 }
1508 
1509