Home | History | Annotate | Download | only in BootMaint
      1 /** @file
      2   This function deal with the legacy boot option, it create, delete
      3   and manage the legacy boot option, all legacy boot option is getting from
      4   the legacy BBS table.
      5 
      6 Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
      7 This program and the accompanying materials
      8 are licensed and made available under the terms and conditions of the BSD License
      9 which accompanies this distribution.  The full text of the license may be found at
     10 http://opensource.org/licenses/bsd-license.php
     11 
     12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     14 
     15 **/
     16 
     17 #include "BBSsupport.h"
     18 
     19 #pragma pack(1)
     20 typedef struct {
     21   BBS_TABLE BbsEntry;
     22   UINT16    BbsIndex;
     23 } LEGACY_BOOT_OPTION_BBS_DATA;
     24 #pragma pack()
     25 
     26 /**
     27   Re-order the Boot Option according to the DevOrder.
     28 
     29   The routine re-orders the Boot Option in BootOption array according to
     30   the order specified by DevOrder.
     31 
     32   @param DevOrder           Pointer to buffer containing the BBS Index,
     33                             high 8-bit value 0xFF indicating a disabled boot option
     34   @param DevOrderCount      Count of the BBS Index
     35   @param EnBootOption       Callee allocated buffer containing the enabled Boot Option Numbers
     36   @param EnBootOptionCount  Count of the enabled Boot Option Numbers
     37   @param DisBootOption      Callee allocated buffer containing the disabled Boot Option Numbers
     38   @param DisBootOptionCount Count of the disabled Boot Option Numbers
     39 **/
     40 VOID
     41 OrderLegacyBootOption4SameType (
     42   UINT16                   *DevOrder,
     43   UINTN                    DevOrderCount,
     44   UINT16                   **EnBootOption,
     45   UINTN                    *EnBootOptionCount,
     46   UINT16                   **DisBootOption,
     47   UINTN                    *DisBootOptionCount
     48   )
     49 {
     50   EFI_STATUS               Status;
     51   UINT16                   *NewBootOption;
     52   UINT16                   *BootOrder;
     53   UINTN                    BootOrderSize;
     54   UINTN                    Index;
     55   UINTN                    StartPosition;
     56 
     57   BDS_COMMON_OPTION        *BootOption;
     58 
     59   CHAR16                   OptionName[sizeof ("Boot####")];
     60   UINT16                   *BbsIndexArray;
     61   UINT16                   *DeviceTypeArray;
     62   LIST_ENTRY               List;
     63 
     64   BootOrder = BdsLibGetVariableAndSize (
     65                 L"BootOrder",
     66                 &gEfiGlobalVariableGuid,
     67                 &BootOrderSize
     68                 );
     69   ASSERT (BootOrder != NULL);
     70 
     71   BbsIndexArray       = AllocatePool (BootOrderSize);
     72   DeviceTypeArray     = AllocatePool (BootOrderSize);
     73   *EnBootOption       = AllocatePool (BootOrderSize);
     74   *DisBootOption      = AllocatePool (BootOrderSize);
     75   *DisBootOptionCount = 0;
     76   *EnBootOptionCount  = 0;
     77   Index               = 0;
     78 
     79   ASSERT (BbsIndexArray != NULL);
     80   ASSERT (DeviceTypeArray != NULL);
     81   ASSERT (*EnBootOption != NULL);
     82   ASSERT (*DisBootOption != NULL);
     83 
     84   for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {
     85 
     86     UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", BootOrder[Index]);
     87     InitializeListHead (&List);
     88     BootOption = BdsLibVariableToOption (&List, OptionName);
     89     ASSERT (BootOption != NULL);
     90 
     91     if ((DevicePathType (BootOption->DevicePath) == BBS_DEVICE_PATH) &&
     92         (DevicePathSubType (BootOption->DevicePath) == BBS_BBS_DP)) {
     93       //
     94       // Legacy Boot Option
     95       //
     96       ASSERT (BootOption->LoadOptionsSize == sizeof (LEGACY_BOOT_OPTION_BBS_DATA));
     97 
     98       DeviceTypeArray[Index] = ((BBS_BBS_DEVICE_PATH *) BootOption->DevicePath)->DeviceType;
     99       BbsIndexArray  [Index] = ((LEGACY_BOOT_OPTION_BBS_DATA *) BootOption->LoadOptions)->BbsIndex;
    100     } else {
    101       DeviceTypeArray[Index] = BBS_TYPE_UNKNOWN;
    102       BbsIndexArray  [Index] = 0xFFFF;
    103     }
    104     FreePool (BootOption->DevicePath);
    105     FreePool (BootOption->Description);
    106     FreePool (BootOption->LoadOptions);
    107     FreePool (BootOption);
    108   }
    109 
    110   //
    111   // Record the corresponding Boot Option Numbers according to the DevOrder
    112   // Record the EnBootOption and DisBootOption according to the DevOrder
    113   //
    114   StartPosition = BootOrderSize / sizeof (UINT16);
    115   NewBootOption = AllocatePool (DevOrderCount * sizeof (UINT16));
    116   ASSERT (NewBootOption != NULL);
    117   while (DevOrderCount-- != 0) {
    118     for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {
    119       if (BbsIndexArray[Index] == (DevOrder[DevOrderCount] & 0xFF)) {
    120         StartPosition = MIN (StartPosition, Index);
    121         NewBootOption[DevOrderCount] = BootOrder[Index];
    122 
    123         if ((DevOrder[DevOrderCount] & 0xFF00) == 0xFF00) {
    124           (*DisBootOption)[*DisBootOptionCount] = BootOrder[Index];
    125           (*DisBootOptionCount)++;
    126         } else {
    127           (*EnBootOption)[*EnBootOptionCount] = BootOrder[Index];
    128           (*EnBootOptionCount)++;
    129         }
    130         break;
    131       }
    132     }
    133   }
    134 
    135   //
    136   // Overwrite the old BootOption
    137   //
    138   CopyMem (&BootOrder[StartPosition], NewBootOption, (*DisBootOptionCount + *EnBootOptionCount) * sizeof (UINT16));
    139   Status = gRT->SetVariable (
    140                   L"BootOrder",
    141                   &gEfiGlobalVariableGuid,
    142                   EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
    143                   BootOrderSize,
    144                   BootOrder
    145                   );
    146   //
    147   // Changing content without increasing its size with current variable implementation shouldn't fail.
    148   //
    149   ASSERT_EFI_ERROR (Status);
    150 
    151   FreePool (NewBootOption);
    152   FreePool (DeviceTypeArray);
    153   FreePool (BbsIndexArray);
    154   FreePool (BootOrder);
    155 }
    156 
    157 /**
    158   Group the legacy boot options in the BootOption.
    159 
    160   The routine assumes the boot options in the beginning that covers all the device
    161   types are ordered properly and re-position the following boot options just after
    162   the corresponding boot options with the same device type.
    163   For example:
    164   1. Input  = [Harddisk1 CdRom2 Efi1 Harddisk0 CdRom0 CdRom1 Harddisk2 Efi0]
    165      Assuming [Harddisk1 CdRom2 Efi1] is ordered properly
    166      Output = [Harddisk1 Harddisk0 Harddisk2 CdRom2 CdRom0 CdRom1 Efi1 Efi0]
    167 
    168   2. Input  = [Efi1 Efi0 CdRom1 Harddisk0 Harddisk1 Harddisk2 CdRom0 CdRom2]
    169      Assuming [Efi1 Efi0 CdRom1 Harddisk0] is ordered properly
    170      Output = [Efi1 Efi0 CdRom1 CdRom0 CdRom2 Harddisk0 Harddisk1 Harddisk2]
    171 
    172 **/
    173 VOID
    174 GroupMultipleLegacyBootOption4SameType (
    175   VOID
    176   )
    177 {
    178   EFI_STATUS                   Status;
    179   UINTN                        Index;
    180   UINTN                        DeviceIndex;
    181   UINTN                        DeviceTypeIndex[7];
    182   UINTN                        *NextIndex;
    183   UINT16                       OptionNumber;
    184   UINT16                       *BootOrder;
    185   UINTN                        BootOrderSize;
    186   CHAR16                       OptionName[sizeof ("Boot####")];
    187   BDS_COMMON_OPTION            *BootOption;
    188   LIST_ENTRY                   List;
    189 
    190   SetMem (DeviceTypeIndex, sizeof (DeviceTypeIndex), 0xff);
    191 
    192   BootOrder = BdsLibGetVariableAndSize (
    193                 L"BootOrder",
    194                 &gEfiGlobalVariableGuid,
    195                 &BootOrderSize
    196                 );
    197 
    198   for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {
    199     UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", BootOrder[Index]);
    200     InitializeListHead (&List);
    201     BootOption = BdsLibVariableToOption (&List, OptionName);
    202     ASSERT (BootOption != NULL);
    203 
    204     if ((DevicePathType (BootOption->DevicePath) == BBS_DEVICE_PATH) &&
    205         (DevicePathSubType (BootOption->DevicePath) == BBS_BBS_DP)) {
    206       //
    207       // Legacy Boot Option
    208       //
    209       ASSERT ((((BBS_BBS_DEVICE_PATH *) BootOption->DevicePath)->DeviceType & 0xF) < ARRAY_SIZE (DeviceTypeIndex));
    210       NextIndex = &DeviceTypeIndex[((BBS_BBS_DEVICE_PATH *) BootOption->DevicePath)->DeviceType & 0xF];
    211 
    212       if (*NextIndex == (UINTN) -1) {
    213         //
    214         // *NextIndex is the Index in BootOrder to put the next Option Number for the same type
    215         //
    216         *NextIndex = Index + 1;
    217       } else {
    218         //
    219         // insert the current boot option before *NextIndex, causing [*Next .. Index] shift right one position
    220         //
    221         OptionNumber = BootOrder[Index];
    222         CopyMem (&BootOrder[*NextIndex + 1], &BootOrder[*NextIndex], (Index - *NextIndex) * sizeof (UINT16));
    223         BootOrder[*NextIndex] = OptionNumber;
    224 
    225         //
    226         // Update the DeviceTypeIndex array to reflect the right shift operation
    227         //
    228         for (DeviceIndex = 0; DeviceIndex < ARRAY_SIZE (DeviceTypeIndex); DeviceIndex++) {
    229           if (DeviceTypeIndex[DeviceIndex] != (UINTN) -1 && DeviceTypeIndex[DeviceIndex] >= *NextIndex) {
    230             DeviceTypeIndex[DeviceIndex]++;
    231           }
    232         }
    233       }
    234     }
    235     FreePool (BootOption->DevicePath);
    236     FreePool (BootOption->Description);
    237     FreePool (BootOption->LoadOptions);
    238     FreePool (BootOption);
    239   }
    240 
    241   Status = gRT->SetVariable (
    242                   L"BootOrder",
    243                   &gEfiGlobalVariableGuid,
    244                   EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
    245                   BootOrderSize,
    246                   BootOrder
    247                   );
    248   //
    249   // Changing content without increasing its size with current variable implementation shouldn't fail.
    250   //
    251   ASSERT_EFI_ERROR (Status);
    252   FreePool (BootOrder);
    253 }
    254 
    255