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