OpenCore  1.0.4
OpenCore Bootloader
Loading...
Searching...
No Matches
VariableManagement.c
Go to the documentation of this file.
1
15#include <Uefi.h>
16
18#include <Guid/AppleVariable.h>
19#include <Guid/GlobalVariable.h>
21#include <Guid/OcVariable.h>
22
23#include <Library/DebugLib.h>
24#include <Library/BaseMemoryLib.h>
25#include <Library/MemoryAllocationLib.h>
28#include <Library/OcMiscLib.h>
29#include <Library/OcStringLib.h>
31#include <Library/PrintLib.h>
32#include <Library/UefiBootServicesTableLib.h>
33#include <Library/UefiRuntimeServicesTableLib.h>
34#include <Library/UefiLib.h>
35
36STATIC
37EFI_GUID
39 0x1F8E0C02, 0x58A9, 0x4E34, { 0xAE, 0x22, 0x2B, 0x63, 0x74, 0x5F, 0xA1, 0x01 }
40};
41
42STATIC
43EFI_GUID
45 0x9480E8A1, 0x1793, 0x46C9, { 0x91, 0xD8, 0x11, 0x08, 0xDB, 0xA4, 0x73, 0x1C }
46};
47
48STATIC
49EFI_GUID
51 0x89D4F995, 0x67E3, 0x4895, { 0x8F, 0x18, 0x45, 0x4B, 0x65, 0x1D, 0x92, 0x15 }
52};
53
54EFI_LOAD_OPTION *
56 OUT UINTN *OptionSize,
57 IN UINT16 BootOption,
58 IN CONST EFI_GUID *BootGuid
59 )
60{
61 EFI_STATUS Status;
62 CHAR16 BootVarName[L_STR_LEN (L"Boot####") + 1];
63 UINTN LoadOptionSize;
64 EFI_LOAD_OPTION *LoadOption;
65
66 if (CompareGuid (BootGuid, &gOcVendorVariableGuid)) {
67 UnicodeSPrint (
68 BootVarName,
69 sizeof (BootVarName),
71 BootOption
72 );
73 } else {
74 UnicodeSPrint (BootVarName, sizeof (BootVarName), L"Boot%04x", BootOption);
75 }
76
77 Status = GetVariable2 (
78 BootVarName,
79 BootGuid,
80 (VOID **)&LoadOption,
81 &LoadOptionSize
82 );
83 if (EFI_ERROR (Status)) {
84 return NULL;
85 }
86
87 if (LoadOptionSize < sizeof (*LoadOption)) {
88 FreePool (LoadOption);
89 return NULL;
90 }
91
92 *OptionSize = LoadOptionSize;
93 return LoadOption;
94}
95
96STATIC
97BOOLEAN
99 IN CHAR16 *Name,
100 IN EFI_GUID *Guid,
101 IN BOOLEAN PreserveBoot
102 )
103{
104 //
105 // Apple GUIDs
106 //
117 {
118 return TRUE;
119 //
120 // Global variable boot options
121 //
122 } else if (CompareGuid (Guid, &gEfiGlobalVariableGuid)) {
123 //
124 // Only erase boot and driver entries for BDS
125 // I.e. BootOrder, Boot####, DriverOrder, Driver####
126 // Preserve Boot#### entries except BootNext when PreserveBoot is TRUE.
127 //
128 if ( (StrCmp (Name, L"BootNext") == 0)
129 || ( !PreserveBoot
130 && (StrnCmp (Name, L"Boot", L_STR_LEN (L"Boot")) == 0)
131 && (StrCmp (Name, L"BootOptionSupport") != 0))
132 || (StrnCmp (Name, L"Driver", L_STR_LEN (L"Driver")) == 0))
133 {
134 return TRUE;
135 }
136
137 //
138 // Lilu & OpenCore extensions if present
139 //
140 } else if (CompareGuid (Guid, &gOcVendorVariableGuid)) {
141 //
142 // Do not remove OpenCore critical variables.
143 //
144 if ( (StrCmp (Name, OC_BOOT_REDIRECT_VARIABLE_NAME) != 0)
145 && (StrCmp (Name, OC_SCAN_POLICY_VARIABLE_NAME) != 0))
146 {
147 return TRUE;
148 }
149 } else if ( CompareGuid (Guid, &gOcReadOnlyVariableGuid)
151 {
152 return TRUE;
153 //
154 // Ozmozis extensions if present
155 //
156 } else if ( CompareGuid (Guid, &mOzmosisProprietary1Guid)
158 {
159 return TRUE;
160 //
161 // Boot Chime preferences if present
162 //
163 } else if (CompareGuid (Guid, &mBootChimeVendorVariableGuid)) {
164 return TRUE;
165 //
166 // Microsoft certificates if present
167 //
168 } else if (CompareGuid (Guid, &gMicrosoftVariableGuid)) {
169 //
170 // Do not remove current OEM policy.
171 //
172 if (StrCmp (Name, L"CurrentPolicy") != 0) {
173 return TRUE;
174 }
175 }
176
177 return FALSE;
178}
179
180VOID
182 IN OC_PROCESS_VARIABLE ProcessVariable,
183 IN VOID *Context
184 )
185{
186 EFI_GUID CurrentGuid;
187 EFI_STATUS Status;
188 CHAR16 *Buffer;
189 CHAR16 *TmpBuffer;
190 UINTN BufferSize;
191 UINTN RequestedSize;
192 BOOLEAN Restart;
193 BOOLEAN CriticalFailure;
194 OC_PROCESS_VARIABLE_RESULT ProcessResult;
195
196 //
197 // Request 1024 byte buffer.
198 //
199 Buffer = NULL;
200 BufferSize = 0;
201 RequestedSize = 1024;
202
203 //
204 // Force starting from 0th GUID.
205 //
206 Restart = TRUE;
207
208 //
209 // Assume we have not failed yet.
210 // TODO: The reasoning behind the logic of CriticalFailure seems not entirely
211 // clear here, if anyone can add a note reminding? (Should be safe, but why 2
212 // failures, not 2 per variable? Or n? Also, was it ever meant to restart the
213 // scan entirely? These possible behaviours could be configured as params to
214 // OcScanVariables.)
215 //
216 CriticalFailure = FALSE;
217
218 do {
219 //
220 // Allocate new buffer if needed.
221 //
222 if (RequestedSize > BufferSize) {
223 TmpBuffer = AllocateZeroPool (RequestedSize);
224 if (TmpBuffer != NULL) {
225 if (Buffer != NULL) {
226 CopyMem (TmpBuffer, Buffer, BufferSize);
227 FreePool (Buffer);
228 }
229
230 Buffer = TmpBuffer;
231 BufferSize = RequestedSize;
232 } else {
233 DEBUG ((
234 DEBUG_INFO,
235 "OCVAR: Failed to allocate variable name buffer of %u bytes\n",
236 (UINT32)RequestedSize
237 ));
238 break;
239 }
240 }
241
242 //
243 // To start the search variable name should be L"".
244 //
245 if (Restart) {
246 ZeroMem (&CurrentGuid, sizeof (CurrentGuid));
247 ZeroMem (Buffer, BufferSize);
248 Restart = FALSE;
249 }
250
251 //
252 // Always pass maximum variable name size to reduce reallocations.
253 //
254 RequestedSize = BufferSize;
255 Status = gRT->GetNextVariableName (&RequestedSize, Buffer, &CurrentGuid);
256
257 if (!EFI_ERROR (Status)) {
258 ProcessResult = ProcessVariable (&CurrentGuid, Buffer, Context);
259 if (ProcessResult == OcProcessVariableAbort) {
260 break;
261 }
262
263 if (ProcessResult == OcProcessVariableRestart) {
264 Restart = TRUE;
265 continue;
266 }
267
268 ASSERT (ProcessResult == OcProcessVariableContinue);
269 } else if ((Status != EFI_BUFFER_TOO_SMALL) && (Status != EFI_NOT_FOUND)) {
270 if (!CriticalFailure) {
271 DEBUG ((DEBUG_INFO, "OCVAR: Unexpected error (%r), trying to rescan\n", Status));
272 CriticalFailure = TRUE;
273 } else {
274 DEBUG ((DEBUG_INFO, "OCVAR: Unexpected error (%r), aborting\n", Status));
275 break;
276 }
277 }
278 } while (Status != EFI_NOT_FOUND);
279
280 if (Buffer != NULL) {
281 FreePool (Buffer);
282 }
283}
284
285STATIC
287EFIAPI
289 IN EFI_GUID *Guid,
290 IN CHAR16 *Name,
291 IN VOID *Context
292 )
293{
294 EFI_STATUS Status;
295 BOOLEAN Restart;
296 BOOLEAN *PreserveBoot;
297
298 ASSERT (Guid != NULL);
299 ASSERT (Name != NULL);
300 ASSERT (Context != NULL);
301
302 PreserveBoot = Context;
303 Restart = FALSE;
304
305 if (IsDeletableVariable (Name, Guid, *PreserveBoot)) {
306 Status = gRT->SetVariable (Name, Guid, 0, 0, NULL);
307 if (!EFI_ERROR (Status)) {
308 DEBUG ((
309 DEBUG_INFO,
310 "Deleting %g:%s... OK\n",
311 Guid,
312 Name
313 ));
314 //
315 // Calls to SetVariable() between calls to GetNextVariableName()
316 // may produce unpredictable results, so we restart.
317 //
318 Restart = TRUE;
319 } else if ((Status == EFI_NOT_FOUND) || (Status == EFI_SECURITY_VIOLATION)) {
320 DEBUG ((
321 DEBUG_INFO,
322 "Deleting %g:%s... SKIP - %r\n",
323 Guid,
324 Name,
325 Status
326 ));
327 } else {
328 DEBUG ((
329 DEBUG_INFO,
330 "Deleting %g:%s... FAIL - %r\n",
331 Guid,
332 Name,
333 Status
334 ));
335 }
336 } else {
337 // Print (L"Skipping %g:%s\n", Guid, Name);
338 }
339
341}
342
343STATIC
344VOID
346 IN BOOLEAN PreserveBoot
347 )
348{
349 OcScanVariables (DeleteVariable, &PreserveBoot);
350}
351
352STATIC
353VOID *
355 OUT UINTN *OptionSize,
356 OUT UINT16 *Option
357 )
358{
359 EFI_STATUS Status;
360 UINTN BootOrderSize;
361 UINT16 *BootOrder;
362 VOID *OptionData;
363
364 BootOrderSize = 0;
365 Status = gRT->GetVariable (
366 EFI_BOOT_ORDER_VARIABLE_NAME,
368 NULL,
369 &BootOrderSize,
370 NULL
371 );
372
373 DEBUG ((
374 DEBUG_INFO,
375 "OCVAR: Have existing order of size %u - %r\n",
376 (UINT32)BootOrderSize,
377 Status
378 ));
379
380 if ((Status != EFI_BUFFER_TOO_SMALL) || (BootOrderSize == 0) || (BootOrderSize % sizeof (UINT16) != 0)) {
381 return NULL;
382 }
383
384 BootOrder = AllocatePool (BootOrderSize);
385 if (BootOrder == NULL) {
386 DEBUG ((DEBUG_INFO, "OCVAR: Failed to allocate boot order\n"));
387 return NULL;
388 }
389
390 Status = gRT->GetVariable (
391 EFI_BOOT_ORDER_VARIABLE_NAME,
393 NULL,
394 &BootOrderSize,
395 BootOrder
396 );
397 if (EFI_ERROR (Status) || (BootOrderSize == 0) || (BootOrderSize % sizeof (UINT16) != 0)) {
398 DEBUG ((DEBUG_INFO, "OCVAR: Failed to obtain boot order %u - %r\n", (UINT32)BootOrderSize, Status));
399 FreePool (BootOrder);
400 return NULL;
401 }
402
403 //
404 // OpenCore moved Bootstrap to BootOrder[0] on initialisation.
405 //
406 OptionData = OcGetBootOptionData (
407 OptionSize,
408 BootOrder[0],
410 );
411 *Option = BootOrder[0];
412
413 FreePool (BootOrder);
414
415 return OptionData;
416}
417
420 VOID
421 )
422{
423 EFI_STATUS Status;
425 OC_FWRT_CONFIG Config;
426
427 Status = gBS->LocateProtocol (
429 NULL,
430 (VOID **)&FwRuntime
431 );
432
433 if (!EFI_ERROR (Status) && (FwRuntime->Revision == OC_FIRMWARE_RUNTIME_REVISION)) {
434 ZeroMem (&Config, sizeof (Config));
435 FwRuntime->SetOverride (&Config);
436 DEBUG ((DEBUG_INFO, "OCVAR: Found FW NVRAM, full access %d\n", Config.BootVariableRedirect));
437 } else {
438 FwRuntime = NULL;
439 DEBUG ((DEBUG_INFO, "OCVAR: Missing compatible FW NVRAM, going on...\n"));
440 }
441
442 return FwRuntime;
443}
444
445VOID
447 IN OC_FIRMWARE_RUNTIME_PROTOCOL *FwRuntime
448 )
449{
450 if (FwRuntime != NULL) {
451 DEBUG ((DEBUG_INFO, "OCVAR: Restoring FW NVRAM...\n"));
452 FwRuntime->SetOverride (NULL);
453 }
454}
455
456VOID
458 IN BOOLEAN PreserveBoot
459 )
460{
461 EFI_STATUS Status;
463 UINTN BootProtectSize;
464 UINT32 BootProtect;
465 VOID *BootOption;
466 UINTN BootOptionSize;
467 UINT16 BootOptionIndex;
468
469 DEBUG ((DEBUG_INFO, "OCVAR: NVRAM cleanup %d...\n", PreserveBoot));
470
471 //
472 // Obtain boot protection marker.
473 //
474 if (PreserveBoot) {
475 //
476 // We do not need or want to re-create entry and overwrite boot order, in this case.
477 //
478 BootProtect = 0;
479 } else {
480 BootProtectSize = sizeof (BootProtect);
481 Status = gRT->GetVariable (
484 NULL,
485 &BootProtectSize,
486 &BootProtect
487 );
488 if (EFI_ERROR (Status) || (BootProtectSize != sizeof (BootProtect))) {
489 BootProtect = 0;
490 }
491 }
492
493 FwRuntime = OcDisableNvramProtection ();
494
495 if ((BootProtect & OC_BOOT_PROTECT_VARIABLE_BOOTSTRAP) != 0) {
496 BootOption = GetBootstrapBootData (&BootOptionSize, &BootOptionIndex);
497 if (BootOption != NULL) {
498 DEBUG ((
499 DEBUG_INFO,
500 "OCVAR: Found %g:Boot%04x for preservation of %u bytes\n",
502 BootOptionIndex,
503 (UINT32)BootOptionSize
504 ));
505 } else {
506 BootProtect = 0;
507 }
508 }
509
510 DeleteVariables (PreserveBoot);
511
512 if ((BootProtect & OC_BOOT_PROTECT_VARIABLE_BOOTSTRAP) != 0) {
513 BootOptionIndex = 1;
514 Status = gRT->SetVariable (
515 L"Boot0001",
517 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
518 BootOptionSize,
519 BootOption
520 );
521 if (!EFI_ERROR (Status)) {
522 Status = gRT->SetVariable (
523 EFI_BOOT_ORDER_VARIABLE_NAME,
525 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
526 sizeof (BootOptionIndex),
527 &BootOptionIndex
528 );
529 }
530
531 DEBUG ((DEBUG_INFO, "OCVAR: Set bootstrap option to Boot%04x - %r\n", BootOptionIndex, Status));
532 FreePool (BootOption);
533 }
534
535 OcRestoreNvramProtection (FwRuntime);
536}
537
538EFI_STATUS
540 IN BOOLEAN PreserveBoot
541 )
542{
543 OcDeleteVariables (PreserveBoot);
545 return EFI_DEVICE_ERROR;
546}
EFI_GUID gAppleTamperResistantBootVariableGuid
EFI_GUID gAppleWirelessNetworkVariableGuid
EFI_GUID gAppleTamperResistantBootSecureVariableGuid
EFI_GUID gAppleBootVariableGuid
EFI_GUID gAppleVendorVariableGuid
EFI_GUID gApplePersonalizationVariableGuid
EFI_GUID gAppleNetbootVariableGuid
EFI_GUID gAppleSecureBootVariableGuid
EFI_GUID gAppleCoreStorageVariableGuid
EFI_GUID gAppleTamperResistantBootEfiUserVariableGuid
EFI_GUID gMicrosoftVariableGuid
EFI_BOOT_SERVICES * gBS
VOID DirectResetCold(VOID)
Definition DirectReset.c:16
#define OC_FIRMWARE_RUNTIME_REVISION
EFI_GUID gOcFirmwareRuntimeProtocolGuid
#define L_STR_LEN(String)
Definition OcStringLib.h:26
OC_TYPING_BUFFER_ENTRY Buffer[OC_TYPING_BUFFER_SIZE]
Definition OcTypingLib.h:42
EFI_GUID gOcWriteOnlyVariableGuid
#define OC_BOOT_REDIRECT_VARIABLE_NAME
Definition OcVariable.h:33
EFI_GUID gOcReadOnlyVariableGuid
#define OC_BOOT_PROTECT_VARIABLE_BOOTSTRAP
Definition OcVariable.h:49
EFI_GUID gOcVendorVariableGuid
#define OC_VENDOR_BOOT_VARIABLE_PREFIX
Definition OcVariable.h:85
#define OC_BOOT_PROTECT_VARIABLE_NAME
Definition OcVariable.h:44
#define OC_SCAN_POLICY_VARIABLE_NAME
Definition OcVariable.h:39
enum _OC_PROCESS_VARIABLE_RESULT OC_PROCESS_VARIABLE_RESULT
OC_PROCESS_VARIABLE_RESULT(EFIAPI * OC_PROCESS_VARIABLE)(IN EFI_GUID *Guid, IN CHAR16 *Name, IN VOID *Context OPTIONAL)
@ OcProcessVariableContinue
@ OcProcessVariableRestart
@ OcProcessVariableAbort
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
BOOLEAN EFIAPI CompareGuid(IN CONST GUID *Guid1, IN CONST GUID *Guid2)
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
EFI_RUNTIME_SERVICES * gRT
EFI_GUID gEfiGlobalVariableGuid
STATIC VOID DeleteVariables(IN BOOLEAN PreserveBoot)
VOID OcScanVariables(IN OC_PROCESS_VARIABLE ProcessVariable, IN VOID *Context)
STATIC OC_PROCESS_VARIABLE_RESULT EFIAPI DeleteVariable(IN EFI_GUID *Guid, IN CHAR16 *Name, IN VOID *Context)
STATIC BOOLEAN IsDeletableVariable(IN CHAR16 *Name, IN EFI_GUID *Guid, IN BOOLEAN PreserveBoot)
STATIC EFI_GUID mBootChimeVendorVariableGuid
OC_FIRMWARE_RUNTIME_PROTOCOL * OcDisableNvramProtection(VOID)
VOID OcRestoreNvramProtection(IN OC_FIRMWARE_RUNTIME_PROTOCOL *FwRuntime)
STATIC VOID * GetBootstrapBootData(OUT UINTN *OptionSize, OUT UINT16 *Option)
STATIC EFI_GUID mOzmosisProprietary1Guid
VOID OcDeleteVariables(IN BOOLEAN PreserveBoot)
STATIC EFI_GUID mOzmosisProprietary2Guid
EFI_STATUS OcResetNvram(IN BOOLEAN PreserveBoot)
EFI_LOAD_OPTION * OcGetBootOptionData(OUT UINTN *OptionSize, IN UINT16 BootOption, IN CONST EFI_GUID *BootGuid)
#define ASSERT(x)
Definition coder.h:55
OC_FWRT_SET_OVERRIDE_CONFIG SetOverride