]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPlatformPkg/Bds/BootOption.c
bdd02b4ecda0c312c070427cb0b5e9bb9e4c420b
[mirror_edk2.git] / ArmPlatformPkg / Bds / BootOption.c
1 /** @file
2 *
3 * Copyright (c) 2011-2015, 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 UINT16 LoadOptionIndexSize;
25
26 // Connect all the drivers if the EFI Application is not a EFI OS Loader
27 if ((BootOption->Attributes & LOAD_OPTION_CATEGORY) == LOAD_OPTION_CATEGORY_APP) {
28 BdsConnectAllDrivers ();
29 }
30
31 // Set BootCurrent variable
32 LoadOptionIndexSize = sizeof (UINT16);
33 gRT->SetVariable (L"BootCurrent", &gEfiGlobalVariableGuid,
34 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
35 LoadOptionIndexSize, &(BootOption->LoadOptionIndex));
36
37 Status = BdsStartEfiApplication (gImageHandle, BootOption->FilePathList, BootOption->OptionalDataSize, BootOption->OptionalData);
38
39 // Clear BootCurrent variable
40 LoadOptionIndexSize = sizeof (UINT16);
41 gRT->SetVariable (L"BootCurrent", &gEfiGlobalVariableGuid,
42 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
43 0, NULL);
44
45 return Status;
46 }
47
48 EFI_STATUS
49 BootOptionList (
50 IN OUT LIST_ENTRY *BootOptionList
51 )
52 {
53 EFI_STATUS Status;
54 UINTN Index;
55 UINT16* BootOrder;
56 UINTN BootOrderSize;
57 BDS_LOAD_OPTION* BdsLoadOption;
58 BDS_LOAD_OPTION_ENTRY* BdsLoadOptionEntry;
59
60 InitializeListHead (BootOptionList);
61
62 // Get the Boot Option Order from the environment variable
63 Status = GetGlobalEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);
64 if (EFI_ERROR(Status)) {
65 return Status;
66 }
67
68 for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {
69 Status = BootOptionFromLoadOptionIndex (BootOrder[Index], &BdsLoadOption);
70 if (!EFI_ERROR(Status)) {
71 BdsLoadOptionEntry = (BDS_LOAD_OPTION_ENTRY*)AllocatePool(sizeof(BDS_LOAD_OPTION_ENTRY));
72 BdsLoadOptionEntry->BdsLoadOption = BdsLoadOption;
73 InsertTailList (BootOptionList,&BdsLoadOptionEntry->Link);
74 }
75 }
76
77 FreePool (BootOrder);
78
79 return EFI_SUCCESS;
80 }
81
82 STATIC
83 EFI_STATUS
84 BootOptionSetFields (
85 IN BDS_LOAD_OPTION* BootOption,
86 IN UINT32 Attributes,
87 IN CHAR16* BootDescription,
88 IN EFI_DEVICE_PATH_PROTOCOL* DevicePath,
89 IN UINT8* OptionalData,
90 IN UINTN OptionalDataSize
91 )
92 {
93 EFI_LOAD_OPTION *EfiLoadOption;
94 UINTN EfiLoadOptionSize;
95 UINTN BootDescriptionSize;
96 UINT16 FilePathListLength;
97 UINT8* EfiLoadOptionPtr;
98
99 // If we are overwriting an existent Boot Option then we have to free previously allocated memory
100 if (BootOption->LoadOption) {
101 FreePool (BootOption->LoadOption);
102 }
103
104 BootDescriptionSize = StrSize (BootDescription);
105
106 // Compute the size of the FilePath list
107 FilePathListLength = GetUnalignedDevicePathSize (DevicePath);
108
109 // Allocate the memory for the EFI Load Option
110 EfiLoadOptionSize = sizeof(UINT32) + sizeof(UINT16) + BootDescriptionSize + FilePathListLength + OptionalDataSize;
111 EfiLoadOption = (EFI_LOAD_OPTION *)AllocatePool(EfiLoadOptionSize);
112 EfiLoadOptionPtr = (UINT8 *)EfiLoadOption;
113
114 //
115 // Populate the EFI Load Option and BDS Boot Option structures
116 //
117
118 // Attributes fields
119 BootOption->Attributes = Attributes;
120 *(UINT32*)EfiLoadOptionPtr = Attributes;
121 EfiLoadOptionPtr += sizeof(UINT32);
122
123 // FilePath List fields
124 BootOption->FilePathListLength = FilePathListLength;
125 *(UINT16*)EfiLoadOptionPtr = FilePathListLength;
126 EfiLoadOptionPtr += sizeof(UINT16);
127
128 // Boot description fields
129 BootOption->Description = (CHAR16*)EfiLoadOptionPtr;
130 CopyMem (EfiLoadOptionPtr, BootDescription, BootDescriptionSize);
131 EfiLoadOptionPtr += BootDescriptionSize;
132
133 // File path fields
134 BootOption->FilePathList = (EFI_DEVICE_PATH_PROTOCOL*)EfiLoadOptionPtr;
135 CopyMem (EfiLoadOptionPtr, DevicePath, FilePathListLength);
136 EfiLoadOptionPtr += FilePathListLength;
137
138 // Optional Data fields, Do unaligned writes
139 BootOption->OptionalData = EfiLoadOptionPtr;
140
141 if (OptionalData != NULL) {
142 CopyMem (BootOption->OptionalData, OptionalData, OptionalDataSize);
143 }
144
145 BootOption->OptionalDataSize = OptionalDataSize;
146
147 // If this function is called at the creation of the Boot Device entry (not at the update) the
148 // BootOption->LoadOptionSize must be zero then we get a new BootIndex for this entry
149 if (BootOption->LoadOptionSize == 0) {
150 BootOption->LoadOptionIndex = BootOptionAllocateBootIndex ();
151 }
152
153 // Fill the EFI Load option fields
154 BootOption->LoadOption = EfiLoadOption;
155 BootOption->LoadOptionSize = EfiLoadOptionSize;
156
157 return EFI_SUCCESS;
158 }
159
160 EFI_STATUS
161 BootOptionCreate (
162 IN UINT32 Attributes,
163 IN CHAR16* BootDescription,
164 IN EFI_DEVICE_PATH_PROTOCOL* DevicePath,
165 IN UINT8* OptionalData,
166 IN UINTN OptionalDataSize,
167 OUT BDS_LOAD_OPTION** BdsLoadOption
168 )
169 {
170 EFI_STATUS Status;
171 BDS_LOAD_OPTION_ENTRY* BootOptionEntry;
172 BDS_LOAD_OPTION* BootOption;
173 CHAR16 BootVariableName[9];
174 UINT16* BootOrder;
175 UINTN BootOrderSize;
176
177 //
178 // Allocate and fill the memory for the BDS Load Option structure
179 //
180 BootOptionEntry = (BDS_LOAD_OPTION_ENTRY*)AllocatePool (sizeof (BDS_LOAD_OPTION_ENTRY));
181 InitializeListHead (&BootOptionEntry->Link);
182 BootOptionEntry->BdsLoadOption = (BDS_LOAD_OPTION*)AllocateZeroPool (sizeof(BDS_LOAD_OPTION));
183
184 BootOption = BootOptionEntry->BdsLoadOption;
185 BootOptionSetFields (BootOption, Attributes, BootDescription, DevicePath, OptionalData, OptionalDataSize);
186
187 //
188 // Set the related environment variables
189 //
190
191 // Create Boot#### environment variable
192 UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", BootOption->LoadOptionIndex);
193 Status = gRT->SetVariable (
194 BootVariableName,
195 &gEfiGlobalVariableGuid,
196 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
197 BootOption->LoadOptionSize,
198 BootOption->LoadOption
199 );
200
201 // Add the new Boot Index to the list
202 Status = GetGlobalEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);
203 if (!EFI_ERROR(Status)) {
204 BootOrder = ReallocatePool (BootOrderSize, BootOrderSize + sizeof(UINT16), BootOrder);
205 // Add the new index at the end
206 BootOrder[BootOrderSize / sizeof(UINT16)] = BootOption->LoadOptionIndex;
207 BootOrderSize += sizeof(UINT16);
208 } else {
209 // BootOrder does not exist. Create it
210 BootOrderSize = sizeof(UINT16);
211 BootOrder = &(BootOption->LoadOptionIndex);
212 }
213
214 // Update (or Create) the BootOrder environment variable
215 Status = gRT->SetVariable (
216 L"BootOrder",
217 &gEfiGlobalVariableGuid,
218 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
219 BootOrderSize,
220 BootOrder
221 );
222
223 // We only free it if the UEFI Variable 'BootOrder' was already existing
224 if (BootOrderSize > sizeof(UINT16)) {
225 FreePool (BootOrder);
226 }
227
228 *BdsLoadOption = BootOption;
229 return Status;
230 }
231
232 EFI_STATUS
233 BootOptionUpdate (
234 IN BDS_LOAD_OPTION* BdsLoadOption,
235 IN UINT32 Attributes,
236 IN CHAR16* BootDescription,
237 IN EFI_DEVICE_PATH_PROTOCOL* DevicePath,
238 IN UINT8* OptionalData,
239 IN UINTN OptionalDataSize
240 )
241 {
242 EFI_STATUS Status;
243 CHAR16 BootVariableName[9];
244
245 // Update the BDS Load Option structure
246 BootOptionSetFields (BdsLoadOption, Attributes, BootDescription, DevicePath, OptionalData, OptionalDataSize);
247
248 // Update the related environment variables
249 UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", BdsLoadOption->LoadOptionIndex);
250
251 Status = gRT->SetVariable (
252 BootVariableName,
253 &gEfiGlobalVariableGuid,
254 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
255 BdsLoadOption->LoadOptionSize,
256 BdsLoadOption->LoadOption
257 );
258
259 return Status;
260 }
261
262 EFI_STATUS
263 BootOptionDelete (
264 IN BDS_LOAD_OPTION *BootOption
265 )
266 {
267 UINTN Index;
268 UINTN BootOrderSize;
269 UINT16* BootOrder;
270 UINTN BootOrderCount;
271 CHAR16 BootVariableName[9];
272 EFI_STATUS Status;
273
274 // Remove the entry from the BootOrder environment variable
275 Status = GetGlobalEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);
276 if (!EFI_ERROR(Status)) {
277 BootOrderCount = BootOrderSize / sizeof(UINT16);
278
279 // Find the index of the removed entry
280 for (Index = 0; Index < BootOrderCount; Index++) {
281 if (BootOrder[Index] == BootOption->LoadOptionIndex) {
282 // If it the last entry we do not need to rearrange the BootOrder list
283 if (Index + 1 != BootOrderCount) {
284 CopyMem (
285 &BootOrder[Index],
286 &BootOrder[Index + 1],
287 (BootOrderCount - (Index + 1)) * sizeof(UINT16)
288 );
289 }
290 break;
291 }
292 }
293
294 // Update the BootOrder environment variable
295 Status = gRT->SetVariable (
296 L"BootOrder",
297 &gEfiGlobalVariableGuid,
298 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
299 BootOrderSize - sizeof(UINT16),
300 BootOrder
301 );
302 }
303
304 // Delete Boot#### environment variable
305 UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", BootOption->LoadOptionIndex);
306 Status = gRT->SetVariable (
307 BootVariableName,
308 &gEfiGlobalVariableGuid,
309 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
310 0,
311 NULL
312 );
313
314 FreePool (BootOrder);
315
316 return Status;
317 }