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