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