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