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