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