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