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