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