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