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