Home | History | Annotate | Download | only in Bds
      1 /** @file
      2 *
      3 *  Copyright (c) 2011-2015, ARM Limited. All rights reserved.
      4 *
      5 *  This program and the accompanying materials
      6 *  are licensed and made available under the terms and conditions of the BSD License
      7 *  which accompanies this distribution.  The full text of the license may be found at
      8 *  http://opensource.org/licenses/bsd-license.php
      9 *
     10 *  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 *  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 *
     13 **/
     14 
     15 #include "BdsInternal.h"
     16 
     17 EFI_STATUS
     18 BootOptionStart (
     19   IN BDS_LOAD_OPTION *BootOption
     20   )
     21 {
     22   EFI_STATUS Status;
     23   UINT16     LoadOptionIndexSize;
     24 
     25   // Connect all the drivers if the EFI Application is not a EFI OS Loader
     26   if ((BootOption->Attributes & LOAD_OPTION_CATEGORY) == LOAD_OPTION_CATEGORY_APP) {
     27     BdsConnectAllDrivers ();
     28   }
     29 
     30   // Set BootCurrent variable
     31   LoadOptionIndexSize = sizeof (UINT16);
     32   gRT->SetVariable (L"BootCurrent", &gEfiGlobalVariableGuid,
     33             EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
     34             LoadOptionIndexSize, &(BootOption->LoadOptionIndex));
     35 
     36   Status = BdsStartEfiApplication (gImageHandle, BootOption->FilePathList, BootOption->OptionalDataSize, BootOption->OptionalData);
     37 
     38   // Clear BootCurrent variable
     39   LoadOptionIndexSize = sizeof (UINT16);
     40   gRT->SetVariable (L"BootCurrent", &gEfiGlobalVariableGuid,
     41             EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
     42             0, NULL);
     43 
     44   return Status;
     45 }
     46 
     47 EFI_STATUS
     48 BootOptionList (
     49   IN OUT LIST_ENTRY *BootOptionList
     50   )
     51 {
     52   EFI_STATUS                    Status;
     53   UINTN                         Index;
     54   UINT16*                       BootOrder;
     55   UINTN                         BootOrderSize;
     56   BDS_LOAD_OPTION*              BdsLoadOption;
     57   BDS_LOAD_OPTION_ENTRY*        BdsLoadOptionEntry;
     58 
     59   InitializeListHead (BootOptionList);
     60 
     61   // Get the Boot Option Order from the environment variable
     62   Status = GetGlobalEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);
     63   if (EFI_ERROR(Status)) {
     64     return Status;
     65   }
     66 
     67   for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {
     68     Status = BootOptionFromLoadOptionIndex (BootOrder[Index], &BdsLoadOption);
     69     if (!EFI_ERROR(Status)) {
     70       BdsLoadOptionEntry = (BDS_LOAD_OPTION_ENTRY*)AllocatePool(sizeof(BDS_LOAD_OPTION_ENTRY));
     71       BdsLoadOptionEntry->BdsLoadOption = BdsLoadOption;
     72       InsertTailList (BootOptionList,&BdsLoadOptionEntry->Link);
     73     }
     74   }
     75 
     76   FreePool (BootOrder);
     77 
     78   return EFI_SUCCESS;
     79 }
     80 
     81 STATIC
     82 EFI_STATUS
     83 BootOptionSetFields (
     84   IN BDS_LOAD_OPTION*           BootOption,
     85   IN UINT32                     Attributes,
     86   IN CHAR16*                    BootDescription,
     87   IN EFI_DEVICE_PATH_PROTOCOL*  DevicePath,
     88   IN UINT8*                     OptionalData,
     89   IN UINTN                      OptionalDataSize
     90   )
     91 {
     92   EFI_LOAD_OPTION               *EfiLoadOption;
     93   UINTN                         EfiLoadOptionSize;
     94   UINTN                         BootDescriptionSize;
     95   UINT16                        FilePathListLength;
     96   UINT8*                        EfiLoadOptionPtr;
     97 
     98   // If we are overwriting an existent Boot Option then we have to free previously allocated memory
     99   if (BootOption->LoadOption) {
    100     FreePool (BootOption->LoadOption);
    101   }
    102 
    103   BootDescriptionSize = StrSize (BootDescription);
    104 
    105   // Compute the size of the FilePath list
    106   FilePathListLength = GetUnalignedDevicePathSize (DevicePath);
    107 
    108   // Allocate the memory for the EFI Load Option
    109   EfiLoadOptionSize = sizeof(UINT32) + sizeof(UINT16) + BootDescriptionSize + FilePathListLength + OptionalDataSize;
    110   EfiLoadOption = (EFI_LOAD_OPTION *)AllocatePool(EfiLoadOptionSize);
    111   EfiLoadOptionPtr = (UINT8 *)EfiLoadOption;
    112 
    113   //
    114   // Populate the EFI Load Option and BDS Boot Option structures
    115   //
    116 
    117   // Attributes fields
    118   BootOption->Attributes = Attributes;
    119   *(UINT32*)EfiLoadOptionPtr = Attributes;
    120   EfiLoadOptionPtr += sizeof(UINT32);
    121 
    122   // FilePath List fields
    123   BootOption->FilePathListLength = FilePathListLength;
    124   *(UINT16*)EfiLoadOptionPtr = FilePathListLength;
    125   EfiLoadOptionPtr += sizeof(UINT16);
    126 
    127   // Boot description fields
    128   BootOption->Description = (CHAR16*)EfiLoadOptionPtr;
    129   CopyMem (EfiLoadOptionPtr, BootDescription, BootDescriptionSize);
    130   EfiLoadOptionPtr += BootDescriptionSize;
    131 
    132   // File path fields
    133   BootOption->FilePathList = (EFI_DEVICE_PATH_PROTOCOL*)EfiLoadOptionPtr;
    134   CopyMem (EfiLoadOptionPtr, DevicePath, FilePathListLength);
    135   EfiLoadOptionPtr += FilePathListLength;
    136 
    137   // Optional Data fields, Do unaligned writes
    138   BootOption->OptionalData = EfiLoadOptionPtr;
    139 
    140   if (OptionalData != NULL) {
    141     CopyMem (BootOption->OptionalData, OptionalData, OptionalDataSize);
    142   }
    143 
    144   BootOption->OptionalDataSize = OptionalDataSize;
    145 
    146   // If this function is called at the creation of the Boot Device entry (not at the update) the
    147   // BootOption->LoadOptionSize must be zero then we get a new BootIndex for this entry
    148   if (BootOption->LoadOptionSize == 0) {
    149     BootOption->LoadOptionIndex = BootOptionAllocateBootIndex ();
    150   }
    151 
    152   // Fill the EFI Load option fields
    153   BootOption->LoadOption = EfiLoadOption;
    154   BootOption->LoadOptionSize = EfiLoadOptionSize;
    155 
    156   return EFI_SUCCESS;
    157 }
    158 
    159 EFI_STATUS
    160 BootOptionCreate (
    161   IN  UINT32                    Attributes,
    162   IN  CHAR16*                   BootDescription,
    163   IN  EFI_DEVICE_PATH_PROTOCOL* DevicePath,
    164   IN  UINT8*                    OptionalData,
    165   IN  UINTN                     OptionalDataSize,
    166   OUT BDS_LOAD_OPTION**         BdsLoadOption
    167   )
    168 {
    169   EFI_STATUS                    Status;
    170   BDS_LOAD_OPTION_ENTRY*        BootOptionEntry;
    171   BDS_LOAD_OPTION*              BootOption;
    172   CHAR16                        BootVariableName[9];
    173   UINT16*                       BootOrder;
    174   UINTN                         BootOrderSize;
    175 
    176   //
    177   // Allocate and fill the memory for the BDS Load Option structure
    178   //
    179   BootOptionEntry = (BDS_LOAD_OPTION_ENTRY*)AllocatePool (sizeof (BDS_LOAD_OPTION_ENTRY));
    180   InitializeListHead (&BootOptionEntry->Link);
    181   BootOptionEntry->BdsLoadOption = (BDS_LOAD_OPTION*)AllocateZeroPool (sizeof(BDS_LOAD_OPTION));
    182 
    183   BootOption = BootOptionEntry->BdsLoadOption;
    184   BootOptionSetFields (BootOption, Attributes, BootDescription, DevicePath, OptionalData, OptionalDataSize);
    185 
    186   //
    187   // Set the related environment variables
    188   //
    189 
    190   // Create Boot#### environment variable
    191   UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", BootOption->LoadOptionIndex);
    192   Status = gRT->SetVariable (
    193       BootVariableName,
    194       &gEfiGlobalVariableGuid,
    195       EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
    196       BootOption->LoadOptionSize,
    197       BootOption->LoadOption
    198       );
    199 
    200   // Add the new Boot Index to the list
    201   Status = GetGlobalEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);
    202   if (!EFI_ERROR(Status)) {
    203     BootOrder = ReallocatePool (BootOrderSize, BootOrderSize + sizeof(UINT16), BootOrder);
    204     // Add the new index at the end
    205     BootOrder[BootOrderSize / sizeof(UINT16)] = BootOption->LoadOptionIndex;
    206     BootOrderSize += sizeof(UINT16);
    207   } else {
    208     // BootOrder does not exist. Create it
    209     BootOrderSize = sizeof(UINT16);
    210     BootOrder = &(BootOption->LoadOptionIndex);
    211   }
    212 
    213   // Update (or Create) the BootOrder environment variable
    214   Status = gRT->SetVariable (
    215       L"BootOrder",
    216       &gEfiGlobalVariableGuid,
    217       EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
    218       BootOrderSize,
    219       BootOrder
    220       );
    221 
    222   // We only free it if the UEFI Variable 'BootOrder' was already existing
    223   if (BootOrderSize > sizeof(UINT16)) {
    224     FreePool (BootOrder);
    225   }
    226 
    227   *BdsLoadOption = BootOption;
    228   return Status;
    229 }
    230 
    231 EFI_STATUS
    232 BootOptionUpdate (
    233   IN  BDS_LOAD_OPTION*          BdsLoadOption,
    234   IN  UINT32                    Attributes,
    235   IN  CHAR16*                   BootDescription,
    236   IN  EFI_DEVICE_PATH_PROTOCOL* DevicePath,
    237   IN UINT8*                     OptionalData,
    238   IN UINTN                      OptionalDataSize
    239   )
    240 {
    241   EFI_STATUS      Status;
    242   CHAR16          BootVariableName[9];
    243 
    244   // Update the BDS Load Option structure
    245   BootOptionSetFields (BdsLoadOption, Attributes, BootDescription, DevicePath, OptionalData, OptionalDataSize);
    246 
    247   // Update the related environment variables
    248   UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", BdsLoadOption->LoadOptionIndex);
    249 
    250   Status = gRT->SetVariable (
    251       BootVariableName,
    252       &gEfiGlobalVariableGuid,
    253       EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
    254       BdsLoadOption->LoadOptionSize,
    255       BdsLoadOption->LoadOption
    256       );
    257 
    258   return Status;
    259 }
    260 
    261 EFI_STATUS
    262 BootOptionDelete (
    263   IN  BDS_LOAD_OPTION *BootOption
    264   )
    265 {
    266   UINTN         Index;
    267   UINTN         BootOrderSize;
    268   UINT16*       BootOrder;
    269   UINTN         BootOrderCount;
    270   CHAR16        BootVariableName[9];
    271   EFI_STATUS    Status;
    272 
    273   // Remove the entry from the BootOrder environment variable
    274   Status = GetGlobalEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);
    275   if (!EFI_ERROR(Status)) {
    276     BootOrderCount = BootOrderSize / sizeof(UINT16);
    277 
    278     // Find the index of the removed entry
    279     for (Index = 0; Index < BootOrderCount; Index++) {
    280       if (BootOrder[Index] == BootOption->LoadOptionIndex) {
    281         // If it the last entry we do not need to rearrange the BootOrder list
    282         if (Index + 1 != BootOrderCount) {
    283           CopyMem (
    284             &BootOrder[Index],
    285             &BootOrder[Index + 1],
    286             (BootOrderCount - (Index + 1)) * sizeof(UINT16)
    287             );
    288         }
    289         break;
    290       }
    291     }
    292 
    293     // Update the BootOrder environment variable
    294     Status = gRT->SetVariable (
    295         L"BootOrder",
    296         &gEfiGlobalVariableGuid,
    297         EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
    298         BootOrderSize - sizeof(UINT16),
    299         BootOrder
    300         );
    301   }
    302 
    303   // Delete Boot#### environment variable
    304   UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", BootOption->LoadOptionIndex);
    305   Status = gRT->SetVariable (
    306       BootVariableName,
    307       &gEfiGlobalVariableGuid,
    308       EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
    309       0,
    310       NULL
    311       );
    312 
    313   FreePool (BootOrder);
    314 
    315   return Status;
    316 }
    317