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