]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPlatformPkg/Bds/BootOption.c
ArmPlatformPkg/Bds: Remove any use of the "Fdt" UEFI variable
[mirror_edk2.git] / ArmPlatformPkg / Bds / BootOption.c
CommitLineData
ea46ebbe 1/** @file\r
2*\r
c3b6d975 3* Copyright (c) 2011-2014, ARM Limited. All rights reserved.\r
ea46ebbe 4*\r
5* This program and the accompanying materials\r
6* are licensed and made available under the terms and conditions of the BSD License\r
7* which accompanies this distribution. The full text of the license may be found at\r
8* http://opensource.org/licenses/bsd-license.php\r
9*\r
10* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12*\r
13**/\r
14\r
c0b2e477 15#include <Guid/ArmGlobalVariableHob.h>\r
ea46ebbe 16#include "BdsInternal.h"\r
17\r
ea46ebbe 18EFI_STATUS\r
19BootOptionStart (\r
20 IN BDS_LOAD_OPTION *BootOption\r
21 )\r
22{\r
c60ea9a8 23 EFI_STATUS Status;\r
c60ea9a8 24 UINT32 LoaderType;\r
2ccfb71e 25 ARM_BDS_LOADER_OPTIONAL_DATA* OptionalData;\r
26 ARM_BDS_LINUX_ARGUMENTS* LinuxArguments;\r
2ccfb71e 27 UINTN CmdLineSize;\r
28 UINTN InitrdSize;\r
29 EFI_DEVICE_PATH* Initrd;\r
91213ad3 30 UINT16 LoadOptionIndexSize;\r
2ccfb71e 31\r
a6e97d28 32 if (IS_ARM_BDS_BOOTENTRY (BootOption)) {\r
2ccfb71e 33 Status = EFI_UNSUPPORTED;\r
34 OptionalData = BootOption->OptionalData;\r
35 LoaderType = ReadUnaligned32 ((CONST UINT32*)&OptionalData->Header.LoaderType);\r
36\r
37 if (LoaderType == BDS_LOADER_EFI_APPLICATION) {\r
5c670b21 38 if ((BootOption->Attributes & LOAD_OPTION_CATEGORY) == LOAD_OPTION_CATEGORY_APP) {\r
4c8bb1eb
OM
39 // Need to connect every drivers to ensure no dependencies are missing for the application\r
40 BdsConnectAllDrivers ();\r
41 }\r
2ccfb71e 42\r
c3b6d975 43 Status = BdsStartEfiApplication (gImageHandle, BootOption->FilePathList, 0, NULL);\r
2ccfb71e 44 } else if (LoaderType == BDS_LOADER_KERNEL_LINUX_ATAG) {\r
45 LinuxArguments = &(OptionalData->Arguments.LinuxArguments);\r
46 CmdLineSize = ReadUnaligned16 ((CONST UINT16*)&LinuxArguments->CmdLineSize);\r
47 InitrdSize = ReadUnaligned16 ((CONST UINT16*)&LinuxArguments->InitrdSize);\r
48\r
49 if (InitrdSize > 0) {\r
50 Initrd = GetAlignedDevicePath ((EFI_DEVICE_PATH*)((UINTN)(LinuxArguments + 1) + CmdLineSize));\r
51 } else {\r
52 Initrd = NULL;\r
53 }\r
ea46ebbe 54\r
76d17c31 55 Status = BdsBootLinuxAtag (BootOption->FilePathList,\r
2ccfb71e 56 Initrd, // Initrd\r
76d17c31 57 (CHAR8*)(LinuxArguments + 1)); // CmdLine\r
2ccfb71e 58 } else if (LoaderType == BDS_LOADER_KERNEL_LINUX_FDT) {\r
59 LinuxArguments = &(OptionalData->Arguments.LinuxArguments);\r
60 CmdLineSize = ReadUnaligned16 ((CONST UINT16*)&LinuxArguments->CmdLineSize);\r
61 InitrdSize = ReadUnaligned16 ((CONST UINT16*)&LinuxArguments->InitrdSize);\r
62\r
63 if (InitrdSize > 0) {\r
64 Initrd = GetAlignedDevicePath ((EFI_DEVICE_PATH*)((UINTN)(LinuxArguments + 1) + CmdLineSize));\r
65 } else {\r
66 Initrd = NULL;\r
67 }\r
6332ffb0
RC
68 Status = BdsBootLinuxFdt (\r
69 BootOption->FilePathList,\r
70 Initrd,\r
71 (CHAR8*)(LinuxArguments + 1)\r
72 );\r
a6e97d28 73 }\r
74 } else {\r
4c8bb1eb 75 // Connect all the drivers if the EFI Application is not a EFI OS Loader\r
5c670b21 76 if ((BootOption->Attributes & LOAD_OPTION_CATEGORY) == LOAD_OPTION_CATEGORY_APP) {\r
4c8bb1eb
OM
77 BdsConnectAllDrivers ();\r
78 }\r
79\r
91213ad3 80 // Set BootCurrent variable\r
81 LoadOptionIndexSize = sizeof(UINT16);\r
82 gRT->SetVariable (L"BootCurrent", &gEfiGlobalVariableGuid,\r
83 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
84 LoadOptionIndexSize, &(BootOption->LoadOptionIndex));\r
85\r
c3b6d975 86 Status = BdsStartEfiApplication (gImageHandle, BootOption->FilePathList, BootOption->OptionalDataSize, BootOption->OptionalData);\r
91213ad3 87\r
88 // Clear BootCurrent variable\r
89 LoadOptionIndexSize = sizeof(UINT16);\r
90 gRT->SetVariable (L"BootCurrent", &gEfiGlobalVariableGuid,\r
91 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
92 0, NULL);\r
a6e97d28 93 }\r
ea46ebbe 94\r
95 return Status;\r
96}\r
97\r
ea46ebbe 98EFI_STATUS\r
99BootOptionList (\r
100 IN OUT LIST_ENTRY *BootOptionList\r
101 )\r
102{\r
a6e97d28 103 EFI_STATUS Status;\r
104 UINTN Index;\r
105 UINT16* BootOrder;\r
106 UINTN BootOrderSize;\r
107 BDS_LOAD_OPTION* BdsLoadOption;\r
108 BDS_LOAD_OPTION_ENTRY* BdsLoadOptionEntry;\r
ea46ebbe 109\r
110 InitializeListHead (BootOptionList);\r
111\r
112 // Get the Boot Option Order from the environment variable\r
c0b2e477 113 Status = GetGlobalEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);\r
ea46ebbe 114 if (EFI_ERROR(Status)) {\r
115 return Status;\r
116 }\r
117\r
118 for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {\r
4aa24170 119 Status = BootOptionFromLoadOptionIndex (BootOrder[Index], &BdsLoadOption);\r
ea46ebbe 120 if (!EFI_ERROR(Status)) {\r
a6e97d28 121 BdsLoadOptionEntry = (BDS_LOAD_OPTION_ENTRY*)AllocatePool(sizeof(BDS_LOAD_OPTION_ENTRY));\r
122 BdsLoadOptionEntry->BdsLoadOption = BdsLoadOption;\r
123 InsertTailList (BootOptionList,&BdsLoadOptionEntry->Link);\r
ea46ebbe 124 }\r
125 }\r
126\r
b148591a 127 FreePool (BootOrder);\r
128\r
ea46ebbe 129 return EFI_SUCCESS;\r
130}\r
131\r
ea46ebbe 132STATIC\r
133EFI_STATUS\r
134BootOptionSetFields (\r
c60ea9a8 135 IN BDS_LOAD_OPTION* BootOption,\r
136 IN UINT32 Attributes,\r
137 IN CHAR16* BootDescription,\r
138 IN EFI_DEVICE_PATH_PROTOCOL* DevicePath,\r
2ccfb71e 139 IN ARM_BDS_LOADER_TYPE BootType,\r
90a44ec4
OM
140 IN UINT8* OptionalData,\r
141 IN UINTN OptionalDataSize\r
ea46ebbe 142 )\r
143{\r
2ccfb71e 144 EFI_LOAD_OPTION EfiLoadOption;\r
145 UINTN EfiLoadOptionSize;\r
146 UINTN BootDescriptionSize;\r
2ccfb71e 147 UINT16 FilePathListLength;\r
148 UINT8* EfiLoadOptionPtr;\r
149 UINT8* InitrdPathListPtr;\r
2ccfb71e 150 ARM_BDS_LINUX_ARGUMENTS* DestLinuxArguments;\r
151 ARM_BDS_LINUX_ARGUMENTS* SrcLinuxArguments;\r
90a44ec4 152 ARM_BDS_LOADER_ARGUMENTS* BootArguments;\r
ea46ebbe 153\r
154 // If we are overwriting an existent Boot Option then we have to free previously allocated memory\r
155 if (BootOption->LoadOption) {\r
90a44ec4 156 FreePool (BootOption->LoadOption);\r
ea46ebbe 157 }\r
158\r
2ccfb71e 159 BootDescriptionSize = StrSize (BootDescription);\r
90a44ec4
OM
160\r
161 // Fixup the size in case of entry specific to ArmPlatformPkg/Bds\r
2ccfb71e 162 if ((BootType == BDS_LOADER_KERNEL_LINUX_ATAG) || (BootType == BDS_LOADER_KERNEL_LINUX_FDT)) {\r
90a44ec4 163 OptionalDataSize += sizeof(ARM_BDS_LOADER_OPTIONAL_DATA_HEADER);\r
2ccfb71e 164 }\r
ea46ebbe 165\r
166 // Compute the size of the FilePath list\r
2ccfb71e 167 FilePathListLength = GetUnalignedDevicePathSize (DevicePath);\r
656416bc 168\r
ea46ebbe 169 // Allocate the memory for the EFI Load Option\r
90a44ec4 170 EfiLoadOptionSize = sizeof(UINT32) + sizeof(UINT16) + BootDescriptionSize + FilePathListLength + OptionalDataSize;\r
ea46ebbe 171 EfiLoadOption = (EFI_LOAD_OPTION)AllocatePool(EfiLoadOptionSize);\r
172 EfiLoadOptionPtr = EfiLoadOption;\r
173\r
174 //\r
175 // Populate the EFI Load Option and BDS Boot Option structures\r
176 //\r
177\r
178 // Attributes fields\r
179 BootOption->Attributes = Attributes;\r
180 *(UINT32*)EfiLoadOptionPtr = Attributes;\r
181 EfiLoadOptionPtr += sizeof(UINT32);\r
182\r
183 // FilePath List fields\r
184 BootOption->FilePathListLength = FilePathListLength;\r
185 *(UINT16*)EfiLoadOptionPtr = FilePathListLength;\r
186 EfiLoadOptionPtr += sizeof(UINT16);\r
187\r
188 // Boot description fields\r
189 BootOption->Description = (CHAR16*)EfiLoadOptionPtr;\r
190 CopyMem (EfiLoadOptionPtr, BootDescription, BootDescriptionSize);\r
191 EfiLoadOptionPtr += BootDescriptionSize;\r
192\r
193 // File path fields\r
194 BootOption->FilePathList = (EFI_DEVICE_PATH_PROTOCOL*)EfiLoadOptionPtr;\r
2ccfb71e 195 CopyMem (EfiLoadOptionPtr, DevicePath, FilePathListLength);\r
196 EfiLoadOptionPtr += FilePathListLength;\r
ea46ebbe 197\r
198 // Optional Data fields, Do unaligned writes\r
2ccfb71e 199 BootOption->OptionalData = EfiLoadOptionPtr;\r
ea46ebbe 200\r
2ccfb71e 201 if ((BootType == BDS_LOADER_KERNEL_LINUX_ATAG) || (BootType == BDS_LOADER_KERNEL_LINUX_FDT)) {\r
90a44ec4
OM
202 // Write the header\r
203 WriteUnaligned32 ((UINT32 *)EfiLoadOptionPtr, ARM_BDS_OPTIONAL_DATA_SIGNATURE);\r
204 WriteUnaligned32 ((UINT32 *)(EfiLoadOptionPtr + 4), BootType);\r
205\r
b4c22265
OM
206 // OptionalData should have been initialized by the caller of this function\r
207 ASSERT (OptionalData != NULL);\r
90a44ec4 208 BootArguments = (ARM_BDS_LOADER_ARGUMENTS*)OptionalData;\r
2ccfb71e 209 SrcLinuxArguments = &(BootArguments->LinuxArguments);\r
210 DestLinuxArguments = &((ARM_BDS_LOADER_OPTIONAL_DATA*)EfiLoadOptionPtr)->Arguments.LinuxArguments;\r
656416bc 211\r
2ccfb71e 212 WriteUnaligned16 ((UINT16 *)&(DestLinuxArguments->CmdLineSize), SrcLinuxArguments->CmdLineSize);\r
213 WriteUnaligned16 ((UINT16 *)&(DestLinuxArguments->InitrdSize), SrcLinuxArguments->InitrdSize);\r
656416bc 214\r
2ccfb71e 215 if (SrcLinuxArguments->CmdLineSize > 0) {\r
216 CopyMem ((VOID*)(DestLinuxArguments + 1), (VOID*)(SrcLinuxArguments + 1), SrcLinuxArguments->CmdLineSize);\r
2ccfb71e 217 }\r
656416bc 218\r
2ccfb71e 219 if (SrcLinuxArguments->InitrdSize > 0) {\r
220 InitrdPathListPtr = (UINT8*)((UINTN)(DestLinuxArguments + 1) + SrcLinuxArguments->CmdLineSize);\r
221 CopyMem (InitrdPathListPtr, (VOID*)((UINTN)(SrcLinuxArguments + 1) + SrcLinuxArguments->CmdLineSize), SrcLinuxArguments->InitrdSize);\r
656416bc 222 }\r
90a44ec4 223 } else {\r
b4c22265
OM
224 if (OptionalData != NULL) {\r
225 CopyMem (BootOption->OptionalData, OptionalData, OptionalDataSize);\r
226 }\r
656416bc 227 }\r
2ccfb71e 228 BootOption->OptionalDataSize = OptionalDataSize;\r
229\r
6bab33c7 230 // If this function is called at the creation of the Boot Device entry (not at the update) the\r
231 // BootOption->LoadOptionSize must be zero then we get a new BootIndex for this entry\r
232 if (BootOption->LoadOptionSize == 0) {\r
2ccfb71e 233 BootOption->LoadOptionIndex = BootOptionAllocateBootIndex ();\r
6bab33c7 234 }\r
235\r
ea46ebbe 236 // Fill the EFI Load option fields\r
ea46ebbe 237 BootOption->LoadOption = EfiLoadOption;\r
238 BootOption->LoadOptionSize = EfiLoadOptionSize;\r
239\r
240 return EFI_SUCCESS;\r
241}\r
242\r
243EFI_STATUS\r
244BootOptionCreate (\r
c60ea9a8 245 IN UINT32 Attributes,\r
246 IN CHAR16* BootDescription,\r
ea46ebbe 247 IN EFI_DEVICE_PATH_PROTOCOL* DevicePath,\r
2ccfb71e 248 IN ARM_BDS_LOADER_TYPE BootType,\r
90a44ec4
OM
249 IN UINT8* OptionalData,\r
250 IN UINTN OptionalDataSize,\r
a6e97d28 251 OUT BDS_LOAD_OPTION** BdsLoadOption\r
ea46ebbe 252 )\r
253{\r
a6e97d28 254 EFI_STATUS Status;\r
255 BDS_LOAD_OPTION_ENTRY* BootOptionEntry;\r
256 BDS_LOAD_OPTION* BootOption;\r
257 CHAR16 BootVariableName[9];\r
258 UINT16* BootOrder;\r
259 UINTN BootOrderSize;\r
ea46ebbe 260\r
261 //\r
262 // Allocate and fill the memory for the BDS Load Option structure\r
263 //\r
a6e97d28 264 BootOptionEntry = (BDS_LOAD_OPTION_ENTRY*)AllocatePool (sizeof (BDS_LOAD_OPTION_ENTRY));\r
265 InitializeListHead (&BootOptionEntry->Link);\r
266 BootOptionEntry->BdsLoadOption = (BDS_LOAD_OPTION*)AllocateZeroPool (sizeof(BDS_LOAD_OPTION));\r
ea46ebbe 267\r
a6e97d28 268 BootOption = BootOptionEntry->BdsLoadOption;\r
90a44ec4 269 BootOptionSetFields (BootOption, Attributes, BootDescription, DevicePath, BootType, OptionalData, OptionalDataSize);\r
ea46ebbe 270\r
271 //\r
272 // Set the related environment variables\r
273 //\r
274\r
275 // Create Boot#### environment variable\r
276 UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", BootOption->LoadOptionIndex);\r
277 Status = gRT->SetVariable (\r
278 BootVariableName,\r
279 &gEfiGlobalVariableGuid,\r
280 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
281 BootOption->LoadOptionSize,\r
282 BootOption->LoadOption\r
283 );\r
284\r
285 // Add the new Boot Index to the list\r
c0b2e477 286 Status = GetGlobalEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);\r
ea46ebbe 287 if (!EFI_ERROR(Status)) {\r
288 BootOrder = ReallocatePool (BootOrderSize, BootOrderSize + sizeof(UINT16), BootOrder);\r
289 // Add the new index at the end\r
290 BootOrder[BootOrderSize / sizeof(UINT16)] = BootOption->LoadOptionIndex;\r
291 BootOrderSize += sizeof(UINT16);\r
292 } else {\r
293 // BootOrder does not exist. Create it\r
294 BootOrderSize = sizeof(UINT16);\r
295 BootOrder = &(BootOption->LoadOptionIndex);\r
296 }\r
297\r
298 // Update (or Create) the BootOrder environment variable\r
299 Status = gRT->SetVariable (\r
300 L"BootOrder",\r
301 &gEfiGlobalVariableGuid,\r
302 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
303 BootOrderSize,\r
304 BootOrder\r
305 );\r
306\r
b148591a 307 // We only free it if the UEFI Variable 'BootOrder' was already existing\r
308 if (BootOrderSize > sizeof(UINT16)) {\r
309 FreePool (BootOrder);\r
310 }\r
311\r
ea46ebbe 312 *BdsLoadOption = BootOption;\r
313 return Status;\r
314}\r
315\r
316EFI_STATUS\r
317BootOptionUpdate (\r
2ccfb71e 318 IN BDS_LOAD_OPTION* BdsLoadOption,\r
319 IN UINT32 Attributes,\r
320 IN CHAR16* BootDescription,\r
ea46ebbe 321 IN EFI_DEVICE_PATH_PROTOCOL* DevicePath,\r
2ccfb71e 322 IN ARM_BDS_LOADER_TYPE BootType,\r
90a44ec4
OM
323 IN UINT8* OptionalData,\r
324 IN UINTN OptionalDataSize\r
ea46ebbe 325 )\r
326{\r
327 EFI_STATUS Status;\r
ea46ebbe 328 CHAR16 BootVariableName[9];\r
329\r
330 // Update the BDS Load Option structure\r
90a44ec4 331 BootOptionSetFields (BdsLoadOption, Attributes, BootDescription, DevicePath, BootType, OptionalData, OptionalDataSize);\r
ea46ebbe 332\r
333 // Update the related environment variables\r
6bab33c7 334 UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", BdsLoadOption->LoadOptionIndex);\r
335\r
ea46ebbe 336 Status = gRT->SetVariable (\r
337 BootVariableName,\r
338 &gEfiGlobalVariableGuid,\r
339 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
6bab33c7 340 BdsLoadOption->LoadOptionSize,\r
341 BdsLoadOption->LoadOption\r
ea46ebbe 342 );\r
343\r
344 return Status;\r
345}\r
346\r
347EFI_STATUS\r
348BootOptionDelete (\r
349 IN BDS_LOAD_OPTION *BootOption\r
350 )\r
351{\r
a6e97d28 352 UINTN Index;\r
353 UINTN BootOrderSize;\r
354 UINT16* BootOrder;\r
355 UINTN BootOrderCount;\r
c41bffd3 356 CHAR16 BootVariableName[9];\r
a6e97d28 357 EFI_STATUS Status;\r
ea46ebbe 358\r
359 // Remove the entry from the BootOrder environment variable\r
c0b2e477 360 Status = GetGlobalEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);\r
ea46ebbe 361 if (!EFI_ERROR(Status)) {\r
362 BootOrderCount = BootOrderSize / sizeof(UINT16);\r
363\r
364 // Find the index of the removed entry\r
365 for (Index = 0; Index < BootOrderCount; Index++) {\r
366 if (BootOrder[Index] == BootOption->LoadOptionIndex) {\r
367 // If it the last entry we do not need to rearrange the BootOrder list\r
368 if (Index + 1 != BootOrderCount) {\r
9127a094 369 CopyMem (\r
370 &BootOrder[Index],\r
371 &BootOrder[Index + 1],\r
372 (BootOrderCount - (Index + 1)) * sizeof(UINT16)\r
373 );\r
ea46ebbe 374 }\r
375 break;\r
376 }\r
377 }\r
378\r
379 // Update the BootOrder environment variable\r
380 Status = gRT->SetVariable (\r
381 L"BootOrder",\r
382 &gEfiGlobalVariableGuid,\r
383 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
384 BootOrderSize - sizeof(UINT16),\r
385 BootOrder\r
386 );\r
387 }\r
388\r
c41bffd3
HL
389 // Delete Boot#### environment variable\r
390 UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", BootOption->LoadOptionIndex);\r
391 Status = gRT->SetVariable (\r
392 BootVariableName,\r
393 &gEfiGlobalVariableGuid,\r
394 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
395 0,\r
396 NULL\r
397 );\r
398\r
b148591a 399 FreePool (BootOrder);\r
400\r
c41bffd3 401 return Status;\r
ea46ebbe 402}\r