OpenCore  1.0.4
OpenCore Bootloader
1.0.4
All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
ServiceOverrides.c
Go to the documentation of this file.
1
16#include "BootCompatInternal.h"
17
18#include <Guid/AppleVariable.h>
19#include <Guid/OcVariable.h>
20
23
24#include <Library/BaseLib.h>
25#include <Library/BaseMemoryLib.h>
26#include <Library/MemoryAllocationLib.h>
27#include <Library/DevicePathLib.h>
33#include <Library/OcMemoryLib.h>
34#include <Library/OcMiscLib.h>
35#include <Library/OcOSInfoLib.h>
36#include <Library/OcStringLib.h>
37#include <Library/UefiBootServicesTableLib.h>
38#include <Library/UefiLib.h>
39#include <Library/UefiRuntimeServicesTableLib.h>
40
42#include <Protocol/VMwareMac.h>
43
49STATIC
50VOID
52 IN BOOT_COMPAT_CONTEXT *BootCompat,
53 IN UINT32 Type
54 )
55{
56 EFI_STATUS Status;
57 EFI_PHYSICAL_ADDRESS Address;
58 UINTN Pages;
59
60 if ((Type != EfiRuntimeServicesCode) && (Type != EfiRuntimeServicesData)) {
61 return;
62 }
63
64 if (BootCompat->Settings.SyncRuntimePermissions && (BootCompat->ServiceState.FwRuntime != NULL)) {
65 //
66 // Be very careful of recursion here, who knows what the firmware can call.
67 //
68 BootCompat->Settings.SyncRuntimePermissions = FALSE;
69
70 Status = BootCompat->ServiceState.FwRuntime->GetExecArea (&Address, &Pages);
71
72 if (!EFI_ERROR (Status)) {
73 OcRebuildAttributes (Address, BootCompat->ServicePtrs.GetMemoryMap);
74 }
75
76 //
77 // Permit syncing runtime permissions again.
78 //
79 BootCompat->Settings.SyncRuntimePermissions = TRUE;
80 }
81}
82
93STATIC
94EFI_STATUS
96 IN EFI_HANDLE ImageHandle,
97 IN UINTN MapKey,
98 IN EFI_EXIT_BOOT_SERVICES ExitBootServices OPTIONAL,
99 IN EFI_GET_MEMORY_MAP GetMemoryMap OPTIONAL
100 )
101{
102 EFI_STATUS Status;
103 EFI_MEMORY_DESCRIPTOR *MemoryMap;
104 UINTN MemoryMapSize;
105 UINTN DescriptorSize;
106 UINT32 DescriptorVersion;
107
108 if (ExitBootServices == NULL) {
109 ExitBootServices = gBS->ExitBootServices;
110 }
111
112 if (GetMemoryMap == NULL) {
113 GetMemoryMap = gBS->GetMemoryMap;
114 }
115
116 //
117 // Firstly try the easy way.
118 //
119 Status = ExitBootServices (ImageHandle, MapKey);
120
121 if (EFI_ERROR (Status)) {
122 //
123 // It is too late to free memory map here, but it does not matter, because boot.efi has an old one
124 // and will freely use the memory.
125 // It is technically forbidden to allocate pool memory here, but we should not hit this code
126 // in the first place, and for older firmware, where it was necessary (?), it worked just fine.
127 //
129 &MemoryMapSize,
130 &MemoryMap,
131 &MapKey,
132 &DescriptorSize,
133 &DescriptorVersion,
134 GetMemoryMap,
135 NULL
136 );
137 if (Status == EFI_SUCCESS) {
138 //
139 // We have the latest memory map and its key, try again!
140 //
141 Status = ExitBootServices (ImageHandle, MapKey);
142 if (EFI_ERROR (Status)) {
143 DEBUG ((DEBUG_WARN, "OCABC: ExitBootServices failed twice - %r\n", Status));
144 }
145 } else {
146 DEBUG ((DEBUG_WARN, "OCABC: Failed to get MapKey for ExitBootServices - %r\n", Status));
147 Status = EFI_INVALID_PARAMETER;
148 }
149
150 if (EFI_ERROR (Status)) {
151 DEBUG ((DEBUG_WARN, "OCABC: Waiting 10 secs...\n"));
152 gBS->Stall (SECONDS_TO_MICROSECONDS (10));
153 }
154 }
155
156 return Status;
157}
158
166STATIC
167VOID
169 IN UINTN MemoryMapSize,
170 IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
171 IN UINTN DescriptorSize
172 )
173{
174 UINTN NumEntries;
175 UINTN Index;
176 EFI_MEMORY_DESCRIPTOR *Desc;
177 UINTN PhysicalEnd;
178
179 //
180 // AMI CSM module allocates up to two regions for legacy video output.
181 // 1. For PMM and EBDA areas.
182 // On Ivy Bridge and below it ends at 0xA0000-0x1000-0x1 and has EfiBootServicesCode type.
183 // On Haswell and above it is allocated below 0xA0000 address with the same type.
184 // 2. For Intel RC S3 reserved area, fixed from 0x9F000 to 0x9FFFF.
185 // On Sandy Bridge and below it is not present in memory map.
186 // On Ivy Bridge and newer it is present as EfiRuntimeServicesData.
187 // Starting from at least SkyLake it is present as EfiReservedMemoryType.
188 //
189 // Prior to AptioMemoryFix EfiRuntimeServicesData could have been relocated by boot.efi,
190 // and the 2nd region could have been overwritten by the kernel. Now it is no longer the
191 // case, and only the 1st region may need special handling.
192 // For the 1st region there appear to be (unconfirmed) reports that it may still be accessed
193 // after waking from sleep. This does not seem to be valid according to AMI code, but we still
194 // protect it in case such systems really exist.
195 //
196 // Initially researched and fixed on GIGABYTE boards by Slice.
197 //
198
199 Desc = MemoryMap;
200 NumEntries = MemoryMapSize / DescriptorSize;
201
202 for (Index = 0; Index < NumEntries; ++Index) {
203 if ((Desc->NumberOfPages > 0) && (Desc->Type == EfiBootServicesData)) {
204 ASSERT (LAST_DESCRIPTOR_ADDR (Desc) < MAX_UINTN);
205 PhysicalEnd = (UINTN)LAST_DESCRIPTOR_ADDR (Desc) + 1;
206
207 if ((PhysicalEnd >= 0x9E000) && (PhysicalEnd < 0xA0000)) {
208 Desc->Type = EfiACPIMemoryNVS;
209 break;
210 }
211 }
212
213 Desc = NEXT_MEMORY_DESCRIPTOR (Desc, DescriptorSize);
214 }
215
216 //
217 // Some types of firmware may leave MMIO regions as reserved memory with runtime flag,
218 // which will not get mapped by macOS kernel. This will cause boot failures due
219 // to such firmware accessing these regions at runtime for NVRAM support.
220 // REF: https://github.com/acidanthera/bugtracker/issues/791#issuecomment-608959387
221 //
222
223 Desc = MemoryMap;
224
225 for (Index = 0; Index < NumEntries; ++Index) {
226 if ((Desc->Type == EfiReservedMemoryType) && ((Desc->Attribute & EFI_MEMORY_RUNTIME) != 0)) {
227 Desc->Type = EfiMemoryMappedIO;
228 }
229
230 Desc = NEXT_MEMORY_DESCRIPTOR (Desc, DescriptorSize);
231 }
232}
233
243STATIC
244VOID
246 IN VOID *Context,
247 IN UINTN MemoryMapSize,
248 IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
249 IN UINTN DescriptorSize
250 )
251{
252 UINTN NumEntries;
253 UINTN Index;
254 UINTN Index2;
255 EFI_MEMORY_DESCRIPTOR *Desc;
256 CONST EFI_PHYSICAL_ADDRESS *Whitelist;
257 UINTN WhitelistSize;
258 BOOLEAN Skipped;
259 UINT64 PagesSaved;
260
261 Whitelist = ((BOOT_COMPAT_CONTEXT *)Context)->Settings.MmioWhitelist;
262 WhitelistSize = ((BOOT_COMPAT_CONTEXT *)Context)->Settings.MmioWhitelistSize;
263
264 //
265 // Some types of firmware (typically Haswell and earlier) need certain MMIO areas to have
266 // virtual addresses due to their firmware implementations to access NVRAM.
267 // For example, on Intel Haswell with APTIO that would be:
268 // 0xFED1C000 (SB_RCBA) is a 0x4 page memory region, containing SPI_BASE at 0x3800 (SPI_BASE_ADDRESS).
269 // 0xFF000000 (PCI root) is a 0x1000 page memory region.
270 // One can make exceptions with Whitelist, as it is required on certain laptops.
271 //
272
273 Desc = MemoryMap;
274 NumEntries = MemoryMapSize / DescriptorSize;
275 PagesSaved = 0;
276
277 if (!((BOOT_COMPAT_CONTEXT *)Context)->ServiceState.ReportedMmio) {
278 DEBUG ((DEBUG_INFO, "OCABC: MMIO devirt start\n"));
279 }
280
281 for (Index = 0; Index < NumEntries; ++Index) {
282 if ( (Desc->NumberOfPages > 0)
283 && (Desc->Type == EfiMemoryMappedIO)
284 && ((Desc->Attribute & EFI_MEMORY_RUNTIME) != 0))
285 {
286 Skipped = FALSE;
287
288 for (Index2 = 0; Index2 < WhitelistSize; ++Index2) {
289 if (AREA_WITHIN_DESCRIPTOR (Desc, Whitelist[Index2], 1)) {
290 Skipped = TRUE;
291 break;
292 }
293 }
294
295 if (!((BOOT_COMPAT_CONTEXT *)Context)->ServiceState.ReportedMmio) {
296 DEBUG ((
297 DEBUG_INFO,
298 "OCABC: MMIO devirt 0x%Lx (0x%Lx pages, 0x%Lx) skip %d\n",
299 (UINT64)Desc->PhysicalStart,
300 (UINT64)Desc->NumberOfPages,
301 (UINT64)Desc->Attribute,
302 Skipped
303 ));
304 }
305
306 if (!Skipped) {
307 Desc->Attribute &= ~EFI_MEMORY_RUNTIME;
308 PagesSaved += Desc->NumberOfPages;
309 }
310 }
311
312 Desc = NEXT_MEMORY_DESCRIPTOR (Desc, DescriptorSize);
313 }
314
315 if (!((BOOT_COMPAT_CONTEXT *)Context)->ServiceState.ReportedMmio) {
316 DEBUG ((
317 DEBUG_INFO,
318 "OCABC: MMIO devirt end, saved %Lu KB\n",
319 EFI_PAGES_TO_SIZE (PagesSaved) / BASE_1KB
320 ));
321 ((BOOT_COMPAT_CONTEXT *)Context)->ServiceState.ReportedMmio = TRUE;
322 }
323}
324
332STATIC
333VOID
335 IN OUT UINT8 *ImageBase,
336 IN UINTN ImageSize,
337 IN OC_BOOTER_PATCH *Patch
338 )
339{
340 UINT32 ReplaceCount;
341
342 if (ImageSize < Patch->Size) {
343 DEBUG ((DEBUG_INFO, "OCABC: Image size is even smaller than patch size\n"));
344 return;
345 }
346
347 if ((Patch->Limit > 0) && (Patch->Limit < ImageSize)) {
348 ImageSize = Patch->Limit;
349 }
350
351 ReplaceCount = ApplyPatch (
352 Patch->Find,
353 Patch->Mask,
354 Patch->Size,
355 Patch->Replace,
356 Patch->ReplaceMask,
357 ImageBase,
358 (UINT32)ImageSize,
359 Patch->Count,
360 Patch->Skip
361 );
362
363 if ((ReplaceCount > 0) && (Patch->Count > 0) && (ReplaceCount != Patch->Count)) {
364 DEBUG ((
365 DEBUG_INFO,
366 "OCABC: Booter patch (%a) performed only %u replacements out of %u\n",
367 Patch->Comment,
368 ReplaceCount,
369 Patch->Count
370 ));
371 } else if (ReplaceCount == 0) {
372 DEBUG ((
373 DEBUG_INFO,
374 "OCABC: Failed to apply Booter patch (%a) - not found\n",
375 Patch->Comment
376 ));
377 } else {
378 DEBUG ((DEBUG_INFO, "OCABC: Booter patch (%a) replace count - %u\n", Patch->Comment, ReplaceCount));
379 }
380}
381
390STATIC
391VOID
393 IN EFI_HANDLE ImageHandle,
394 IN BOOLEAN IsApple,
395 IN OC_BOOTER_PATCH *Patches,
396 IN UINT32 PatchCount
397 )
398{
399 EFI_STATUS Status;
400 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
401 UINT32 Index;
402 BOOLEAN UsePatch;
403 CONST CHAR8 *UserIdentifier;
404 CHAR16 *UserIdentifierUnicode;
405
406 Status = gBS->HandleProtocol (
407 ImageHandle,
409 (VOID **)&LoadedImage
410 );
411 if (EFI_ERROR (Status)) {
412 DEBUG ((DEBUG_ERROR, "OCABC: Failed to handle LoadedImage protocol - %r\n", Status));
413 return;
414 }
415
416 for (Index = 0; Index < PatchCount; ++Index) {
417 UserIdentifier = Patches[Index].Identifier;
418
419 if ((UserIdentifier[0] == '\0') || (AsciiStrCmp (UserIdentifier, "Any") == 0)) {
420 UsePatch = TRUE;
421 } else if (AsciiStrCmp (UserIdentifier, "Apple") == 0) {
422 UsePatch = IsApple;
423 } else {
424 UserIdentifierUnicode = AsciiStrCopyToUnicode (UserIdentifier, 0);
425 if (UserIdentifierUnicode == NULL) {
426 DEBUG ((DEBUG_INFO, "OCABC: Booter patch (%a) for %a is out of memory\n", Patches[Index].Comment, UserIdentifier));
427 continue;
428 }
429
430 UsePatch = OcDevicePathHasFilePathSuffix (LoadedImage->FilePath, UserIdentifierUnicode, StrLen (UserIdentifierUnicode));
431 FreePool (UserIdentifierUnicode);
432 }
433
434 if (UsePatch) {
436 (UINT8 *)LoadedImage->ImageBase,
437 (UINTN)LoadedImage->ImageSize,
438 &Patches[Index]
439 );
440 }
441 }
442}
443
448STATIC
449EFI_STATUS
450EFIAPI
452 IN EFI_ALLOCATE_TYPE Type,
453 IN EFI_MEMORY_TYPE MemoryType,
454 IN UINTN NumberOfPages,
455 IN OUT EFI_PHYSICAL_ADDRESS *Memory
456 )
457{
458 EFI_STATUS Status;
459 BOOT_COMPAT_CONTEXT *BootCompat;
460 BOOLEAN IsPerfAlloc;
461 BOOLEAN IsCallGateAlloc;
462
463 //
464 // Filter out garbage right away.
465 //
466 if (Memory == NULL) {
467 return EFI_INVALID_PARAMETER;
468 }
469
470 BootCompat = GetBootCompatContext ();
471 IsPerfAlloc = FALSE;
472 IsCallGateAlloc = FALSE;
473
474 if (BootCompat->ServiceState.AwaitingPerfAlloc) {
475 if (BootCompat->ServiceState.AppleBootNestedCount > 0) {
476 if ( (Type == AllocateMaxAddress)
477 && (MemoryType == EfiACPIReclaimMemory)
478 && (*Memory == BASE_4GB - 1))
479 {
480 IsPerfAlloc = TRUE;
481 }
482 } else {
483 BootCompat->ServiceState.AwaitingPerfAlloc = FALSE;
484 }
485 }
486
487 if ( (BootCompat->ServiceState.AppleBootNestedCount > 0)
488 && (Type == AllocateMaxAddress)
489 && (MemoryType == EfiLoaderCode)
490 && (*Memory == BASE_4GB - 1)
491 && (NumberOfPages == 1))
492 {
493 IsCallGateAlloc = TRUE;
494 }
495
496 if ( BootCompat->Settings.AllowRelocationBlock
497 && (BootCompat->ServiceState.AppleBootNestedCount > 0)
498 && (Type == AllocateAddress)
499 && (MemoryType == EfiLoaderData))
500 {
502 BootCompat,
503 BootCompat->ServicePtrs.GetMemoryMap,
504 BootCompat->ServicePtrs.AllocatePages,
505 NumberOfPages,
506 Memory
507 );
508 } else {
509 Status = EFI_UNSUPPORTED;
510 }
511
512 if (EFI_ERROR (Status)) {
513 Status = BootCompat->ServicePtrs.AllocatePages (
514 Type,
515 MemoryType,
516 NumberOfPages,
517 Memory
518 );
519 }
520
521 DEBUG ((DEBUG_VERBOSE, "OCABC: AllocPages %u 0x%Lx (%u) - %r\n", Type, *Memory, NumberOfPages, Status));
522
523 if (!EFI_ERROR (Status)) {
524 FixRuntimeAttributes (BootCompat, MemoryType);
525
526 if (BootCompat->ServiceState.AppleBootNestedCount > 0) {
527 if (IsCallGateAlloc) {
528 //
529 // Called from boot.efi.
530 // Memory allocated for boot.efi to kernel trampoline.
531 //
532 BootCompat->ServiceState.OldKernelCallGate = *Memory;
533 } else if (IsPerfAlloc) {
534 //
535 // Called from boot.efi.
536 // New perf data, it can be reallocated multiple times.
537 //
538 OcAppleDebugLogPerfAllocated ((VOID *)(UINTN)*Memory, EFI_PAGES_TO_SIZE (NumberOfPages));
539 }
540 }
541 }
542
543 return Status;
544}
545
550STATIC
551EFI_STATUS
552EFIAPI
554 IN EFI_PHYSICAL_ADDRESS Memory,
555 IN UINTN Pages
556 )
557{
558 EFI_STATUS Status;
559 BOOT_COMPAT_CONTEXT *BootCompat;
560
561 BootCompat = GetBootCompatContext ();
562
563 Status = BootCompat->ServicePtrs.FreePages (
564 Memory,
565 Pages
566 );
567
568 if (!EFI_ERROR (Status)) {
569 FixRuntimeAttributes (BootCompat, EfiRuntimeServicesData);
570 }
571
572 return Status;
573}
574
580STATIC
581EFI_STATUS
582EFIAPI
584 IN OUT UINTN *MemoryMapSize,
585 IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
586 OUT UINTN *MapKey,
587 OUT UINTN *DescriptorSize,
588 OUT UINT32 *DescriptorVersion
589 )
590{
591 EFI_STATUS Status;
592 EFI_STATUS Status2;
593 BOOT_COMPAT_CONTEXT *BootCompat;
594 EFI_PHYSICAL_ADDRESS Address;
595 UINTN Pages;
596 UINTN OriginalSize;
597
598 BootCompat = GetBootCompatContext ();
599
600 OriginalSize = MemoryMapSize != 0 ? *MemoryMapSize : 0;
601 Status = BootCompat->ServicePtrs.GetMemoryMap (
602 MemoryMapSize,
603 MemoryMap,
604 MapKey,
605 DescriptorSize,
606 DescriptorVersion
607 );
608
609 //
610 // Reserve larger area for the memory map when we need to split it.
611 //
612 if ((BootCompat->ServiceState.AppleBootNestedCount > 0) && (Status == EFI_BUFFER_TOO_SMALL)) {
613 *MemoryMapSize += OcCountSplitDescriptors () * *DescriptorSize;
614 return EFI_BUFFER_TOO_SMALL;
615 }
616
617 if (EFI_ERROR (Status)) {
618 return Status;
619 }
620
621 if (BootCompat->Settings.SyncRuntimePermissions && (BootCompat->ServiceState.FwRuntime != NULL)) {
622 //
623 // Some types of firmware mark runtime drivers loaded after EndOfDxe as EfiRuntimeServicesData:
624 // REF: https://github.com/acidanthera/bugtracker/issues/791#issuecomment-607935508
625 //
626 Status2 = BootCompat->ServiceState.FwRuntime->GetExecArea (&Address, &Pages);
627
628 if (!EFI_ERROR (Status2)) {
630 *MemoryMapSize,
631 MemoryMap,
632 *DescriptorSize,
633 Address,
634 EfiRuntimeServicesCode,
635 0,
636 0
637 );
638 }
639 }
640
641 if (BootCompat->ServiceState.AppleBootNestedCount > 0) {
642 if (BootCompat->Settings.ProtectMemoryRegions) {
644 *MemoryMapSize,
645 MemoryMap,
646 *DescriptorSize
647 );
648 }
649
650 if (BootCompat->Settings.DevirtualiseMmio) {
652 BootCompat,
653 *MemoryMapSize,
654 MemoryMap,
655 *DescriptorSize
656 );
657 }
658
659 if (BootCompat->Settings.RebuildAppleMemoryMap) {
660 OcSortMemoryMap (*MemoryMapSize, MemoryMap, *DescriptorSize);
661
663 OriginalSize,
664 MemoryMapSize,
665 MemoryMap,
666 *DescriptorSize
667 );
668 if (EFI_ERROR (Status2) && (Status2 != EFI_UNSUPPORTED)) {
669 DEBUG ((DEBUG_INFO, "OCABC: Cannot rebuild memory map - %r\n", Status));
670 }
671
673 MemoryMapSize,
674 MemoryMap,
675 *DescriptorSize
676 );
677 } else if (BootCompat->Settings.AllowRelocationBlock) {
678 //
679 // A sorted memory map is required when using a relocation block.
680 //
681 OcSortMemoryMap (*MemoryMapSize, MemoryMap, *DescriptorSize);
682 }
683
684 //
685 // Remember some descriptor size, since we will not have it later
686 // during hibernate wake to be able to iterate memory map.
687 //
688 BootCompat->ServiceState.MemoryMapDescriptorSize = *DescriptorSize;
689 }
690
691 return Status;
692}
693
698STATIC
699EFI_STATUS
700EFIAPI
702 IN EFI_MEMORY_TYPE PoolType,
703 IN UINTN Size,
704 OUT VOID **Buffer
705 )
706{
707 EFI_STATUS Status;
708 BOOT_COMPAT_CONTEXT *BootCompat;
709
710 BootCompat = GetBootCompatContext ();
711
712 Status = BootCompat->ServicePtrs.AllocatePool (
713 PoolType,
714 Size,
715 Buffer
716 );
717
718 if (!EFI_ERROR (Status)) {
719 FixRuntimeAttributes (BootCompat, PoolType);
720 }
721
722 return Status;
723}
724
729STATIC
730EFI_STATUS
731EFIAPI
733 IN VOID *Buffer
734 )
735{
736 EFI_STATUS Status;
737 BOOT_COMPAT_CONTEXT *BootCompat;
738
739 BootCompat = GetBootCompatContext ();
740
741 Status = BootCompat->ServicePtrs.FreePool (
742 Buffer
743 );
744
745 if (!EFI_ERROR (Status)) {
746 FixRuntimeAttributes (BootCompat, EfiRuntimeServicesData);
747 }
748
749 return Status;
750}
751
752/*
753 Verify whether a device path refers to EfiBootRt of a loaded EfiBoot image.
754
755 @param[in] EfiBootRtDevicePath The device path to verify.
756 @param[in] SourceBuffer The image buffer of EfiBootRtDevicePath.
757 @param[in] SourceSize The size, in Bytes, of SourceBuffer.
758 @param[in] EfiBootLoadedImage The loaded EfiBoot image.
759
760 @returns Whether EfiBootRtDevicePath refers to an EfiBootRt instance.
761*/
762STATIC
763BOOLEAN
765 IN EFI_DEVICE_PATH_PROTOCOL *EfiBootRtDevicePath OPTIONAL,
766 IN VOID *SourceBuffer OPTIONAL,
767 IN UINTN SourceSize,
768 IN EFI_LOADED_IMAGE_PROTOCOL *EfiBootLoadedImage
769 )
770{
771 INTN CmpResult;
772 BOOLEAN Overflow;
773 EFI_DEVICE_PATH_PROTOCOL *EfiBootDevicePath;
774 EFI_DEVICE_PATH_PROTOCOL *DevicePathEnd;
775 UINTN EfiBootRtDevicePathRemSize;
776 UINTN ComponentSize;
777 EFI_DEVICE_PATH_PROTOCOL *CurrentRtNode;
778
779 ASSERT (EfiBootLoadedImage != NULL);
780
781 if ( (EfiBootRtDevicePath == NULL)
782 || (SourceBuffer == NULL)
783 || (EfiBootLoadedImage->FilePath == NULL))
784 {
785 DEBUG ((
786 DEBUG_INFO,
787 "OCABC: Cannot be EfiBootRt (DP %d, Buf %d, EfiBoot FP %d)\n",
788 (EfiBootRtDevicePath == NULL),
789 (SourceBuffer == NULL),
790 (EfiBootLoadedImage->FilePath == NULL)
791 ));
792 return FALSE;
793 }
794
795 //
796 // The EfiBootRt device path appends a MemMap device path node with its loaded
797 // image information to the EfiBoot device path. Verify the EfiBoot device
798 // path is its prefix.
799 //
800 EfiBootDevicePath = DevicePathFromHandle (EfiBootLoadedImage->DeviceHandle);
801 if (EfiBootDevicePath == NULL) {
802 DEBUG ((
803 DEBUG_INFO,
804 "OCABC: Failed to get EfiBoot DP from handle 0x%llx\n",
805 (UINT64)(UINTN)EfiBootLoadedImage->DeviceHandle
806 ));
807 return FALSE;
808 }
809
811 DEBUG_INFO,
812 "OCABC: Current EfiBoot",
813 EfiBootDevicePath
814 );
815
816 EfiBootRtDevicePathRemSize = GetDevicePathSize (EfiBootRtDevicePath);
817
818 DevicePathEnd = FindDevicePathEndNode (EfiBootDevicePath);
819 ComponentSize = (UINTN)DevicePathEnd - (UINTN)EfiBootDevicePath;
820
821 Overflow = BaseOverflowSubUN (
822 EfiBootRtDevicePathRemSize,
823 ComponentSize,
824 &EfiBootRtDevicePathRemSize
825 );
826 if (Overflow) {
827 DEBUG ((
828 DEBUG_INFO,
829 "OCABC: EfiBootRt DP (0x%llx) is shorter than EfiBoot DP (0x%llx)\n",
830 (UINT64)EfiBootRtDevicePathRemSize,
831 (UINT64)ComponentSize
832 ));
833 return FALSE;
834 }
835
836 //
837 // The EfiBoot device path is constructed from the device path of its device
838 // and its file path node. Check them one by one.
839 //
840 CmpResult = CompareMem (
841 EfiBootRtDevicePath,
842 EfiBootDevicePath,
843 ComponentSize
844 );
845 if (CmpResult != 0) {
846 DEBUG ((DEBUG_INFO, "OCABC: EfiBoot DP is not a prefix of EfiBootRt DP\n"));
847 return FALSE;
848 }
849
850 CurrentRtNode = (EFI_DEVICE_PATH_PROTOCOL *)((UINT8 *)EfiBootRtDevicePath + ComponentSize);
851
852 DevicePathEnd = FindDevicePathEndNode (EfiBootLoadedImage->FilePath);
853 ComponentSize = (UINTN)DevicePathEnd - (UINTN)EfiBootLoadedImage->FilePath;
854
855 if (ComponentSize >= EfiBootRtDevicePathRemSize) {
856 DEBUG ((
857 DEBUG_INFO,
858 "OCABC: EfiBootRt FP (0x%llx) is shorter than EfiBoot FP (0x%llx)\n",
859 (UINT64)EfiBootRtDevicePathRemSize,
860 (UINT64)ComponentSize
861 ));
862 return FALSE;
863 }
864
865 CmpResult = CompareMem (
866 CurrentRtNode,
867 EfiBootLoadedImage->FilePath,
868 ComponentSize
869 );
870 if (CmpResult != 0) {
871 DEBUG ((DEBUG_INFO, "OCABC: EfiBoot FP is not a prefix of EfiBootRt FP\n"));
872 return FALSE;
873 }
874
875 CurrentRtNode = (EFI_DEVICE_PATH_PROTOCOL *)((UINT8 *)CurrentRtNode + ComponentSize);
876 //
877 // Verify the appended node is of MemMap type and matches the loaded image
878 // information.
879 //
880 if ( (DevicePathType (CurrentRtNode) != HARDWARE_DEVICE_PATH)
881 || (DevicePathSubType (CurrentRtNode) != HW_MEMMAP_DP))
882 {
883 DEBUG ((
884 DEBUG_INFO,
885 "OCABC: EfiBootRt FP is not succeeded by a MemMap node\n"
886 ));
887 return FALSE;
888 }
889
890 MEMMAP_DEVICE_PATH *MemMapNode = (MEMMAP_DEVICE_PATH *)CurrentRtNode;
891
892 if ( (MemMapNode->StartingAddress != (EFI_PHYSICAL_ADDRESS)(UINTN)SourceBuffer)
893 || (MemMapNode->EndingAddress != (EFI_PHYSICAL_ADDRESS)((UINTN)SourceBuffer + SourceSize)))
894 {
895 DEBUG ((
896 DEBUG_INFO,
897 "OCABC: MemMap [0x%llx, 0x%llx) mismatches EfiBootRt [0x%llx, 0x%llx)\n",
898 MemMapNode->StartingAddress,
899 MemMapNode->EndingAddress,
900 (EFI_PHYSICAL_ADDRESS)(UINTN)SourceBuffer,
901 (EFI_PHYSICAL_ADDRESS)((UINTN)SourceBuffer + SourceSize)
902 ));
903 return FALSE;
904 }
905
906 return TRUE;
907}
908
909#ifdef MDE_CPU_X64
910
911/*
912 Retrieves the offset of the kernel call gate in EfiBootRt.
913
914 @param[in] KcgSize On output, the maximum size, in Bytes, available to
915 the kernel call gate.
916 @param[in] BootCompat The Apple Boot Compatibility context.
917 @param[in] DevicePath The device path of EfiBootRt.
918 @param[in] SourceBuffer The image buffer of EfiBootRt.
919 @param[in] SourceSize The size, in Bytes, of SourceBuffer.
920
921 @retval 0 The function did not complete successfully.
922 @retval other The offset of the kernel call gate in EfiBootRt.
923*/
924STATIC
925UINTN
926InternalEfiBootRtGetKcgOffset (
927 OUT UINTN *KcgSize,
928 IN BOOT_COMPAT_CONTEXT *BootCompat,
929 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
930 IN VOID *SourceBuffer,
931 IN UINTN SourceSize
932 )
933{
934 EFI_STATUS Status;
935 BOOLEAN Overflow;
936 EFI_HANDLE EfiBootRtCopyHandle;
937 APPLE_EFI_BOOT_RT_INFO EfiBootRtLoadOptions;
938 UINTN KcgOffset;
939 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
940 UINTN ImageBase;
941
942 //
943 // Load a copy of EfiBootRt to retrieve its information structure. EfiBootRt
944 // must be loaded with the OpenCore image loader as it is not signed. This is
945 // not a security issue as it is implicitly signed via EfiBoot.
946 //
947 Status = OcImageLoaderLoad (
948 FALSE,
950 DevicePath,
951 SourceBuffer,
952 SourceSize,
953 &EfiBootRtCopyHandle
954 );
955 if (EFI_ERROR (Status)) {
956 DEBUG ((DEBUG_INFO, "OCABC: KCG load - %r\n", Status));
957 return 0;
958 }
959
960 //
961 // EfiBootRt publishes its information via a caller-allocated buffer wired to
962 // its launch options. For this, it must be launched.
963 //
964 Status = gBS->HandleProtocol (
965 EfiBootRtCopyHandle,
967 (VOID **)&LoadedImage
968 );
969 if (EFI_ERROR (Status)) {
970 DEBUG ((DEBUG_INFO, "OCABC: Handle KCG LoadedImage - %r\n", Status));
971 gBS->UnloadImage (EfiBootRtCopyHandle);
972 return 0;
973 }
974
975 ImageBase = (UINTN)LoadedImage->ImageBase;
976
977 ZeroMem (&EfiBootRtLoadOptions, sizeof (EfiBootRtLoadOptions));
978 LoadedImage->LoadOptions = &EfiBootRtLoadOptions;
979 LoadedImage->LoadOptionsSize = sizeof (EfiBootRtLoadOptions);
980 //
981 // The calls to these services are correct despite calling OcImageLoaderLoad()
982 // directly, as they will be overridden versions that support OpenCore loaded
983 // images.
984 //
985 Status = BootCompat->ServicePtrs.StartImage (EfiBootRtCopyHandle, NULL, NULL);
986
987 gBS->UnloadImage (EfiBootRtCopyHandle);
988
989 if (EFI_ERROR (Status)) {
990 DEBUG ((DEBUG_INFO, "OCABC: KCG start - %r\n", Status));
991 return 0;
992 }
993
994 //
995 // Compute the remaining space to the end of the image.
996 //
997 Overflow = BaseOverflowSubUN (
998 (UINTN)EfiBootRtLoadOptions.KernelCallGate,
999 ImageBase,
1000 &KcgOffset
1001 );
1002 Overflow |= BaseOverflowSubUN (
1003 SourceSize,
1004 KcgOffset,
1005 KcgSize
1006 );
1007 if (Overflow) {
1008 DEBUG ((
1009 DEBUG_INFO,
1010 "OCABC: KCG OOB (0x%llx, [0x%llx, 0x%llx)\n",
1011 (UINT64)(UINTN)EfiBootRtLoadOptions.KernelCallGate,
1012 (UINT64)ImageBase,
1013 (UINT64)(ImageBase + SourceSize)
1014 ));
1015 return 0;
1016 }
1017
1018 return KcgOffset;
1019}
1020
1021#endif
1022
1027STATIC
1028EFI_STATUS
1029EFIAPI
1031 IN BOOLEAN BootPolicy,
1032 IN EFI_HANDLE ParentImageHandle,
1033 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
1034 IN VOID *SourceBuffer OPTIONAL,
1035 IN UINTN SourceSize,
1036 OUT EFI_HANDLE *ImageHandle
1037 )
1038{
1039 BOOLEAN IsEfiBootRt;
1040 BOOT_COMPAT_CONTEXT *BootCompat;
1041
1042 BootCompat = GetBootCompatContext ();
1043
1044 DebugPrintDevicePath (DEBUG_INFO, "OCABC: EfiBootRt candidate", DevicePath);
1045
1046 //
1047 // Verify whether it's EfiBootRt that's being loaded. If it is, patch its
1048 // kernel call gate. This is relevant as of macOS 13 Developer Beta 1, as
1049 // Apple moved the kernel call gate from a direct to an indirect EfiBoot embed
1050 // in form of a separate driver, EfiBootRt.
1051 //
1052 IsEfiBootRt = FALSE;
1053 if (!BootPolicy && (BootCompat->ServiceState.AppleBootNestedCount > 0)) {
1054 IsEfiBootRt = InternalIsEfiBootRt (
1055 DevicePath,
1056 SourceBuffer,
1057 SourceSize,
1059 );
1060 }
1061
1062 DEBUG ((
1063 DEBUG_INFO,
1064 "OCABC: IsEfiBootRt %d (BP %d, Apple %d)\n",
1065 IsEfiBootRt,
1066 !BootPolicy,
1067 BootCompat->ServiceState.AppleBootNestedCount > 0
1068 ));
1069
1070 //
1071 // Anything but EfiBootRt can be loaded transparently. EfiBootRt must be
1072 // loaded with the OpenCore image loader as it is not signed. This is not a
1073 // security issue as it is implicitly signed via EfiBoot.
1074 //
1075 if (!IsEfiBootRt) {
1076 return BootCompat->ServicePtrs.LoadImage (
1077 BootPolicy,
1078 ParentImageHandle,
1079 DevicePath,
1080 SourceBuffer,
1081 SourceSize,
1082 ImageHandle
1083 );
1084 }
1085
1086 #if defined (MDE_CPU_X64)
1087 EFI_STATUS LoadImageStatus;
1088 EFI_STATUS Status;
1089 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
1090 UINTN KcgOffset;
1091 UINTN KcgSize;
1092
1093 LoadImageStatus = OcImageLoaderLoad (
1094 BootPolicy,
1095 ParentImageHandle,
1096 DevicePath,
1097 SourceBuffer,
1098 SourceSize,
1099 ImageHandle
1100 );
1101 if (EFI_ERROR (LoadImageStatus)) {
1102 DEBUG ((DEBUG_INFO, "OCABC: EfiBootRt load - %r\n", LoadImageStatus));
1103 return LoadImageStatus;
1104 }
1105
1106 //
1107 // Retrieve the EfiBootRt kernel call gate location.
1108 //
1109 KcgOffset = InternalEfiBootRtGetKcgOffset (
1110 &KcgSize,
1111 BootCompat,
1112 DevicePath,
1113 SourceBuffer,
1114 SourceSize
1115 );
1116 if ((KcgOffset == 0) || (KcgSize < CALL_GATE_MIN_SIZE)) {
1117 DEBUG ((
1118 DEBUG_INFO,
1119 "OCABC: Invalid KCG [0x%llx, 0x%llx)\n",
1120 (UINT64)KcgOffset,
1121 (UINT64)KcgSize
1122 ));
1123 return LoadImageStatus;
1124 }
1125
1126 Status = gBS->HandleProtocol (
1127 *ImageHandle,
1129 (VOID **)&LoadedImage
1130 );
1131 if (EFI_ERROR (Status)) {
1132 DEBUG ((DEBUG_INFO, "OCABC: Handle EfiBootRt LoadedImage - %r\n", Status));
1133 return LoadImageStatus;
1134 }
1135
1136 //
1137 // Patch the EfiBootRt kernel call gate.
1138 //
1140 BootCompat,
1141 (UINTN)LoadedImage->ImageBase + KcgOffset,
1143 );
1144
1145 DEBUG ((
1146 DEBUG_INFO,
1147 "OCABC: Patched KCG at 0x%llx\n",
1148 (UINTN)LoadedImage->ImageBase + KcgOffset
1149 ));
1150
1151 return LoadImageStatus;
1152 #elif defined (MDE_CPU_IA32)
1153 //
1154 // Something is completely borked if we are here in 32-bit mode.
1155 //
1156 return EFI_INVALID_PARAMETER;
1157 #endif
1158}
1159
1164STATIC
1165EFI_STATUS
1166EFIAPI
1168 IN EFI_HANDLE ImageHandle,
1169 OUT UINTN *ExitDataSize,
1170 OUT CHAR16 **ExitData OPTIONAL
1171 )
1172{
1173 EFI_STATUS Status;
1174 EFI_LOADED_IMAGE_PROTOCOL *AppleLoadedImage;
1175 EFI_LOADED_IMAGE_PROTOCOL *LastAppleBootImageTmp;
1176 EFI_OS_INFO_PROTOCOL *OSInfo;
1177 BOOT_COMPAT_CONTEXT *BootCompat;
1178 OC_FWRT_CONFIG Config;
1179 UINTN DataSize;
1180
1181 BootCompat = GetBootCompatContext ();
1182 AppleLoadedImage = OcGetAppleBootLoadedImage (ImageHandle);
1183
1184 //
1185 // Recover firmware-replaced GetMemoryMap pointer.
1186 //
1187 if ( BootCompat->Settings.ProtectUefiServices
1188 && (BootCompat->ServicePtrs.GetMemoryMap != OcGetMemoryMap))
1189 {
1190 DEBUG ((DEBUG_INFO, "OCABC: Recovering trashed GetMemoryMap pointer\n"));
1191 gBS->GetMemoryMap = OcGetMemoryMap;
1192 gBS->Hdr.CRC32 = 0;
1193 gBS->CalculateCrc32 (gBS, gBS->Hdr.HeaderSize, &gBS->Hdr.CRC32);
1194 }
1195
1196 FixRuntimeAttributes (BootCompat, EfiRuntimeServicesData);
1197
1198 //
1199 // Clear monitoring vars
1200 //
1201 BootCompat->ServiceState.OldKernelCallGate = 0;
1202
1203 if (AppleLoadedImage != NULL) {
1204 //
1205 // Report about macOS being loaded.
1206 //
1207 ++BootCompat->ServiceState.AppleBootNestedCount;
1208 //
1209 // Remember the last started Apple booter to match its EfiBootRt instance.
1210 //
1211 LastAppleBootImageTmp = BootCompat->ServiceState.LastAppleBootImage;
1212 BootCompat->ServiceState.LastAppleBootImage = AppleLoadedImage;
1213
1214 //
1215 // VMware uses OSInfo->SetName call by EfiBoot to ensure that we are allowed
1216 // to run this version of macOS on VMware. The relevant EfiBoot image handle
1217 // is determined by the return address of OSInfo->SetName call, which will
1218 // be found in the list they make within their StartImage wrapper.
1219 //
1220 // The problem here happens with Apple Secure Boot, which makes their StartImage
1221 // wrapper to not be called and therefore OSInfo->SetName to fail to install anything.
1222 // Simply install a protocol here. Maybe make it a quirk if necessary.
1223 //
1224 Status = gBS->InstallMultipleProtocolInterfaces (
1225 &ImageHandle,
1227 NULL,
1228 NULL
1229 );
1230 DEBUG ((DEBUG_INFO, "OCABC: VMware Mac installed on %p - %r\n", ImageHandle, Status));
1231
1234 AppleLoadedImage,
1235 BootCompat->ServicePtrs.GetVariable,
1236 "slide=",
1237 L_STR_LEN ("slide="),
1238 NULL
1239 );
1240
1241 if (BootCompat->Settings.EnableSafeModeSlide) {
1242 ASSERT (AppleLoadedImage->ImageSize <= MAX_UINTN);
1244 (UINT8 *)AppleLoadedImage->ImageBase,
1245 (UINTN)AppleLoadedImage->ImageSize
1246 );
1247 }
1248
1250 BootCompat,
1251 AppleLoadedImage,
1252 BootCompat->ServicePtrs.GetMemoryMap
1253 );
1254
1255 if ( (BootCompat->Settings.ResizeAppleGpuBars >= 0)
1256 && (BootCompat->Settings.ResizeAppleGpuBars < PciBarTotal))
1257 {
1258 ResizeGpuBars (BootCompat->Settings.ResizeAppleGpuBars, FALSE, BootCompat->Settings.ResizeUsePciRbIo);
1259 }
1260 } else if (BootCompat->Settings.SignalAppleOS) {
1261 Status = gBS->LocateProtocol (
1263 NULL,
1264 (VOID *)&OSInfo
1265 );
1266
1267 if (!EFI_ERROR (Status)) {
1268 //
1269 // Older versions of the protocol have less fields.
1270 // For instance, VMware installs 0x1 version.
1271 //
1272 if (OSInfo->Revision >= EFI_OS_INFO_PROTOCOL_REVISION_VENDOR) {
1273 OSInfo->OSVendor (EFI_OS_INFO_APPLE_VENDOR_NAME);
1274 }
1275
1276 if (OSInfo->Revision >= EFI_OS_INFO_PROTOCOL_REVISION_NAME) {
1277 OSInfo->OSName ("Mac OS X 10.15");
1278 }
1279 }
1280 }
1281
1282 if (BootCompat->ServiceState.FwRuntime != NULL) {
1283 BootCompat->ServiceState.FwRuntime->GetCurrent (&Config);
1284
1285 //
1286 // Support for ReadOnly and WriteOnly variables is OpenCore & Lilu security basics.
1287 // For now always enable it.
1288 //
1289 Config.RestrictedVariables = TRUE;
1290
1291 //
1292 // Restrict secure boot variables and never let them slip unless once restricted.
1293 //
1294 Config.ProtectSecureBoot = BootCompat->Settings.ProtectSecureBoot;
1295
1296 //
1297 // Enable Boot#### variable redirection if OpenCore requested it.
1298 // Do NOT disable it once enabled for stability reasons.
1299 //
1300 DataSize = sizeof (Config.BootVariableRedirect);
1301 BootCompat->ServicePtrs.GetVariable (
1304 NULL,
1305 &DataSize,
1306 &Config.BootVariableRedirect
1307 );
1308
1309 //
1310 // Enable Apple-specific changes if requested.
1311 // Disable them when this is no longer Apple.
1312 //
1313 if (BootCompat->ServiceState.AppleBootNestedCount > 0) {
1314 Config.ClearTaskSwitchBit = BootCompat->Settings.ClearTaskSwitchBit;
1315 Config.WriteProtection = BootCompat->Settings.DisableVariableWrite;
1317 } else {
1318 Config.ClearTaskSwitchBit = FALSE;
1319 Config.WriteProtection = FALSE;
1320 Config.WriteUnprotector = FALSE;
1321 }
1322
1323 BootCompat->ServiceState.FwRuntime->SetMain (
1324 &Config
1325 );
1326 }
1327
1328 //
1329 // Apply customised booter patches.
1330 //
1332 ImageHandle,
1333 AppleLoadedImage != NULL,
1334 BootCompat->Settings.BooterPatches,
1335 BootCompat->Settings.BooterPatchesSize
1336 );
1337
1338 Status = BootCompat->ServicePtrs.StartImage (
1339 ImageHandle,
1340 ExitDataSize,
1341 ExitData
1342 );
1343
1344 if (AppleLoadedImage != NULL) {
1345 //
1346 // On exit, restore the previous last started Apple booter.
1347 //
1348 BootCompat->ServiceState.LastAppleBootImage = LastAppleBootImageTmp;
1349 //
1350 // We failed but other operating systems should be loadable.
1351 //
1352 --BootCompat->ServiceState.AppleBootNestedCount;
1353
1354 if (BootCompat->ServiceState.AppleBootNestedCount == 0) {
1355 AppleRelocationRelease (BootCompat);
1356 }
1357 }
1358
1359 return Status;
1360}
1361
1377STATIC
1378EFI_STATUS
1379EFIAPI
1381 IN EFI_HANDLE ImageHandle,
1382 IN UINTN MapKey
1383 )
1384{
1385 EFI_STATUS Status;
1386 BOOT_COMPAT_CONTEXT *BootCompat;
1387 UINTN Index;
1388
1389 BootCompat = GetBootCompatContext ();
1390
1391 //
1392 // Handle events in case we have any.
1393 //
1394 if (BootCompat->Settings.ExitBootServicesHandlers != NULL) {
1395 for (Index = 0; BootCompat->Settings.ExitBootServicesHandlers[Index] != NULL; ++Index) {
1396 BootCompat->Settings.ExitBootServicesHandlers[Index](
1397 NULL,
1398 BootCompat->Settings.ExitBootServicesHandlerContexts[Index]
1399 );
1400 //
1401 // Even if ExitBootServices fails, do not subsequently call the events we handled.
1402 //
1403 BootCompat->Settings.ExitBootServicesHandlers[Index] = NULL;
1404 }
1405 }
1406
1407 FixRuntimeAttributes (BootCompat, EfiRuntimeServicesData);
1408
1409 //
1410 // For non-macOS operating systems return directly.
1411 //
1412 if (BootCompat->ServiceState.AppleBootNestedCount == 0) {
1413 return BootCompat->ServicePtrs.ExitBootServices (
1414 ImageHandle,
1415 MapKey
1416 );
1417 }
1418
1419 //
1420 // Enable custom SetVirtualAddressMap.
1421 //
1422 if (BootCompat->ServiceState.FwRuntime != NULL) {
1423 BootCompat->ServiceState.FwRuntime->OnSetAddressMap (NULL, TRUE);
1424 }
1425
1426 if (BootCompat->Settings.ForceExitBootServices) {
1427 Status = ForceExitBootServices (
1428 ImageHandle,
1429 MapKey,
1430 BootCompat->ServicePtrs.ExitBootServices,
1431 BootCompat->ServicePtrs.GetMemoryMap
1432 );
1433 } else {
1434 Status = BootCompat->ServicePtrs.ExitBootServices (
1435 ImageHandle,
1436 MapKey
1437 );
1438 }
1439
1440 //
1441 // Abort on error.
1442 //
1443 if (EFI_ERROR (Status)) {
1444 return Status;
1445 }
1446
1447 #ifdef MDE_CPU_IA32
1448 AppleMapPrepareKernelJump32 (BootCompat);
1449 #elif defined (MDE_CPU_X64)
1451 BootCompat,
1452 (UINTN)BootCompat->ServiceState.OldKernelCallGate,
1454 );
1455 #endif
1456
1457 return Status;
1458}
1459
1464STATIC
1465EFI_STATUS
1466EFIAPI
1468 IN UINTN MemoryMapSize,
1469 IN UINTN DescriptorSize,
1470 IN UINT32 DescriptorVersion,
1471 IN EFI_MEMORY_DESCRIPTOR *MemoryMap
1472 )
1473{
1474 EFI_STATUS Status;
1475 BOOT_COMPAT_CONTEXT *BootCompat;
1476
1477 BootCompat = GetBootCompatContext ();
1478
1479 ASSERT (BootCompat->ServiceState.AppleBootNestedCount > 0);
1480
1481 Status = AppleMapPrepareMemState (
1482 BootCompat,
1483 MemoryMapSize,
1484 DescriptorSize,
1485 DescriptorVersion,
1486 MemoryMap
1487 );
1488
1489 return Status;
1490}
1491
1496STATIC
1497EFI_STATUS
1498EFIAPI
1500 IN CHAR16 *VariableName,
1501 IN EFI_GUID *VendorGuid,
1502 OUT UINT32 *Attributes OPTIONAL,
1503 IN OUT UINTN *DataSize,
1504 OUT VOID *Data
1505 )
1506{
1507 EFI_STATUS Status;
1508 BOOT_COMPAT_CONTEXT *BootCompat;
1509 BOOLEAN IsApple;
1510
1511 BootCompat = GetBootCompatContext ();
1512 IsApple = BootCompat->ServiceState.AppleBootNestedCount > 0;
1513
1514 if (IsApple && (BootCompat->Settings.ProvideCustomSlide || BootCompat->Settings.AllowRelocationBlock)) {
1515 Status = AppleSlideGetVariable (
1516 BootCompat,
1517 BootCompat->ServicePtrs.GetVariable,
1518 BootCompat->ServicePtrs.GetMemoryMap,
1519 BootCompat->Settings.DevirtualiseMmio ? DevirtualiseMmio : NULL,
1520 BootCompat,
1521 VariableName,
1522 VendorGuid,
1523 Attributes,
1524 DataSize,
1525 Data
1526 );
1527 } else {
1528 Status = BootCompat->ServicePtrs.GetVariable (
1529 VariableName,
1530 VendorGuid,
1531 Attributes,
1532 DataSize,
1533 Data
1534 );
1535 }
1536
1537 //
1538 // Catch performance record allocation.
1539 //
1540 if ( IsApple
1541 && (Status == EFI_BUFFER_TOO_SMALL)
1542 && CompareGuid (VendorGuid, &gAppleBootVariableGuid)
1543 && (StrCmp (VariableName, APPLE_EFI_BOOT_PERF_VARIABLE_NAME) == 0))
1544 {
1545 BootCompat->ServiceState.AwaitingPerfAlloc = TRUE;
1546 DEBUG ((DEBUG_INFO, "OCABC: Caught successful request for %s\n", VariableName));
1547 }
1548
1549 return Status;
1550}
1551
1559STATIC
1560VOID
1561EFIAPI
1563 IN EFI_EVENT Event,
1564 IN VOID *Context
1565 )
1566{
1567 EFI_STATUS Status;
1569 BOOT_COMPAT_CONTEXT *BootCompat;
1570
1571 BootCompat = (BOOT_COMPAT_CONTEXT *)Context;
1572
1573 if (BootCompat->ServicePtrs.GetVariable == NULL) {
1574 Status = gBS->LocateProtocol (
1576 NULL,
1577 (VOID **)&FwRuntime
1578 );
1579
1580 if (!EFI_ERROR (Status)) {
1581 if (FwRuntime->Revision == OC_FIRMWARE_RUNTIME_REVISION) {
1582 DEBUG ((DEBUG_INFO, "OCABC: Got rendezvous with OpenRuntime r%u\n", OC_FIRMWARE_RUNTIME_REVISION));
1583 DEBUG ((DEBUG_INFO, "OCABC: MAT support is %d\n", OcGetMemoryAttributes (NULL) != NULL));
1584 Status = FwRuntime->OnGetVariable (OcGetVariable, &BootCompat->ServicePtrs.GetVariable);
1585 if (!EFI_ERROR (Status)) {
1586 //
1587 // We override virtual address mapping function to perform
1588 // runtime area protection to prevent boot.efi
1589 // defragmentation and setup virtual memory for firmware
1590 // accessing it after exit boot services.
1591 //
1592 // We cannot override it to non-RT area since this is prohibited
1593 // by spec and at least Linux does not support it.
1594 //
1595 Status = FwRuntime->OnSetAddressMap (OcSetVirtualAddressMap, FALSE);
1596 if (EFI_ERROR (Status)) {
1597 DEBUG ((DEBUG_INFO, "OCABC: OnSetAddressMap failure - %r\n", Status));
1598 }
1599 } else {
1600 DEBUG ((DEBUG_INFO, "OCABC: OnGetVariable failure - %r\n", Status));
1601 }
1602 } else {
1603 DEBUG ((
1604 DEBUG_ERROR,
1605 "OCABC: Incompatible OpenRuntime r%u, require r%u\n",
1606 (UINT32)FwRuntime->Revision,
1608 ));
1609 CpuDeadLoop ();
1610 }
1611 } else {
1612 DEBUG ((DEBUG_INFO, "OCABC: Awaiting rendezvous with OpenRuntime r%u\n", OC_FIRMWARE_RUNTIME_REVISION));
1613 Status = EFI_UNSUPPORTED;
1614 }
1615
1616 //
1617 // Mark protocol as useable.
1618 //
1619 if (!EFI_ERROR (Status)) {
1620 BootCompat->ServiceState.FwRuntime = FwRuntime;
1621 }
1622 }
1623}
1624
1625VOID
1627 IN OUT BOOT_COMPAT_CONTEXT *BootCompat
1628 )
1629{
1630 EFI_STATUS Status;
1631 VOID *Registration;
1632 UEFI_SERVICES_POINTERS *ServicePtrs;
1633 EFI_TPL OriginalTpl;
1634
1635 ServicePtrs = &BootCompat->ServicePtrs;
1636
1637 OriginalTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
1638
1639 ServicePtrs->AllocatePages = gBS->AllocatePages;
1640 ServicePtrs->FreePages = gBS->FreePages;
1641 ServicePtrs->GetMemoryMap = gBS->GetMemoryMap;
1642 ServicePtrs->AllocatePool = gBS->AllocatePool;
1643 ServicePtrs->FreePool = gBS->FreePool;
1644 ServicePtrs->ExitBootServices = gBS->ExitBootServices;
1645 ServicePtrs->LoadImage = gBS->LoadImage;
1646 ServicePtrs->StartImage = gBS->StartImage;
1647
1648 gBS->AllocatePages = OcAllocatePages;
1649 gBS->FreePages = OcFreePages;
1650 gBS->GetMemoryMap = OcGetMemoryMap;
1651 gBS->AllocatePool = OcAllocatePool;
1652 gBS->FreePool = OcFreePool;
1653 gBS->ExitBootServices = OcExitBootServices;
1654 gBS->LoadImage = OcLoadImage;
1655 gBS->StartImage = OcStartImage;
1656
1657 gBS->Hdr.CRC32 = 0;
1658 gBS->Hdr.CRC32 = CalculateCrc32 (gBS, gBS->Hdr.HeaderSize);
1659
1660 gBS->RestoreTPL (OriginalTpl);
1661
1662 //
1663 // Update GetVariable handle with the help of external runtime services.
1664 //
1665 SetGetVariableHookHandler (NULL, BootCompat);
1666
1667 if (BootCompat->ServicePtrs.GetVariable != NULL) {
1668 return;
1669 }
1670
1671 Status = gBS->CreateEvent (
1672 EVT_NOTIFY_SIGNAL,
1673 TPL_CALLBACK,
1675 BootCompat,
1676 &BootCompat->ServiceState.GetVariableEvent
1677 );
1678
1679 if (!EFI_ERROR (Status)) {
1680 Status = gBS->RegisterProtocolNotify (
1682 BootCompat->ServiceState.GetVariableEvent,
1683 &Registration
1684 );
1685
1686 if (EFI_ERROR (Status)) {
1687 gBS->CloseEvent (BootCompat->ServiceState.GetVariableEvent);
1688 }
1689 }
1690}
#define APPLE_EFI_BOOT_PERF_VARIABLE_NAME
EFI_GUID gAppleBootVariableGuid
EFI_STATUS EFIAPI AppleMapPrepareKernelStateNew64(IN UINTN SystemTable, IN OUT APPLE_EFI_BOOT_RT_KCG_ARGS *KcgArguments, IN KERNEL_CALL_GATE CallGate)
EFI_STATUS AppleRelocationRelease(IN OUT BOOT_COMPAT_CONTEXT *BootCompat)
#define CALL_GATE_MIN_SIZE
BOOT_COMPAT_CONTEXT * GetBootCompatContext(VOID)
VOID AppleSlideUnlockForSafeMode(IN OUT UINT8 *ImageBase, IN UINTN ImageSize)
VOID AppleMapPrepareBooterState(IN OUT BOOT_COMPAT_CONTEXT *BootCompat, IN OUT EFI_LOADED_IMAGE *LoadedImage, IN EFI_GET_MEMORY_MAP GetMemoryMap OPTIONAL)
VOID AppleMapPrepareKernelJump32(IN OUT BOOT_COMPAT_CONTEXT *BootCompat)
UINTN EFIAPI AppleMapPrepareKernelStateOld64(IN UINTN Args, IN UINTN EntryPoint, IN KERNEL_CALL_GATE CallGate)
EFI_STATUS AppleMapPrepareMemState(IN OUT BOOT_COMPAT_CONTEXT *BootCompat, IN UINTN MemoryMapSize, IN UINTN DescriptorSize, IN UINT32 DescriptorVersion, IN EFI_MEMORY_DESCRIPTOR *MemoryMap)
EFI_STATUS AppleRelocationAllocatePages(IN OUT BOOT_COMPAT_CONTEXT *BootCompat, IN EFI_GET_MEMORY_MAP GetMemoryMap, IN EFI_ALLOCATE_PAGES AllocatePages, IN UINTN NumberOfPages, IN OUT EFI_PHYSICAL_ADDRESS *Memory)
VOID AppleMapPrepareKernelJump64(IN OUT BOOT_COMPAT_CONTEXT *BootCompat, IN EFI_PHYSICAL_ADDRESS CallGate, IN UINTN HookAddress)
EFI_STATUS AppleSlideGetVariable(IN OUT BOOT_COMPAT_CONTEXT *BootCompat, IN EFI_GET_VARIABLE GetVariable, IN EFI_GET_MEMORY_MAP GetMemoryMap OPTIONAL, IN OC_MEMORY_FILTER FilterMap OPTIONAL, IN VOID *FilterMapContext OPTIONAL, IN CHAR16 *VariableName, IN EFI_GUID *VendorGuid, OUT UINT32 *Attributes OPTIONAL, IN OUT UINTN *DataSize, OUT VOID *Data)
EFI_GUID gEfiOSInfoProtocolGuid
#define EFI_OS_INFO_PROTOCOL_REVISION_NAME
Definition OSInfo.h:17
#define EFI_OS_INFO_PROTOCOL_REVISION_VENDOR
Definition OSInfo.h:18
#define EFI_OS_INFO_APPLE_VENDOR_NAME
Definition OSInfo.h:27
DMG_SIZE_DEVICE_PATH Size
EFI_LOADED_IMAGE_PROTOCOL * OcGetAppleBootLoadedImage(IN EFI_HANDLE ImageHandle)
EFI_STATUS EFIAPI OcImageLoaderLoad(IN BOOLEAN BootPolicy, IN EFI_HANDLE ParentImageHandle, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, IN VOID *SourceBuffer OPTIONAL, IN UINTN SourceSize, OUT EFI_HANDLE *ImageHandle)
BOOLEAN OcIsAppleHibernateWake(VOID)
BOOLEAN OcCheckArgumentFromEnv(IN EFI_LOADED_IMAGE *LoadedImage OPTIONAL, IN EFI_GET_VARIABLE GetVariable OPTIONAL, IN CONST CHAR8 *Argument, IN CONST UINTN ArgumentLength, IN OUT CHAR8 **Value OPTIONAL)
EFI_HANDLE gImageHandle
EFI_BOOT_SERVICES * gBS
VOID DebugPrintDevicePath(IN UINTN ErrorLevel, IN CONST CHAR8 *Message, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL)
@ PciBarTotal
EFI_STATUS ResizeGpuBars(IN PCI_BAR_SIZE Size, IN BOOLEAN Increase, IN BOOLEAN UseRbIo)
EFI_DEVICE_PATH_PROTOCOL * FindDevicePathEndNode(IN EFI_DEVICE_PATH_PROTOCOL *DevicePath)
BOOLEAN OcDevicePathHasFilePathSuffix(IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, IN CONST CHAR16 *Suffix, IN UINTN SuffixLen)
#define OC_FIRMWARE_RUNTIME_REVISION
EFI_GUID gOcFirmwareRuntimeProtocolGuid
VOID OcAppleDebugLogPerfAllocated(IN OUT VOID *PerfBuffer, IN UINTN PerfBufferSize)
Definition OcAppleLog.c:303
#define AREA_WITHIN_DESCRIPTOR(Desc, Area, AreaSize)
Definition OcMemoryLib.h:39
EFI_MEMORY_ATTRIBUTES_TABLE * OcGetMemoryAttributes(OUT EFI_MEMORY_DESCRIPTOR **MemoryAttributesEntry OPTIONAL)
EFI_STATUS OcGetCurrentMemoryMapAlloc(OUT UINTN *MemoryMapSize, OUT EFI_MEMORY_DESCRIPTOR **MemoryMap, OUT UINTN *MapKey, OUT UINTN *DescriptorSize, OUT UINT32 *DescriptorVersion, IN EFI_GET_MEMORY_MAP GetMemoryMap OPTIONAL, IN OUT EFI_PHYSICAL_ADDRESS *TopMemory OPTIONAL)
Definition MemoryMap.c:201
#define LAST_DESCRIPTOR_ADDR(Desc)
Definition OcMemoryLib.h:32
EFI_STATUS OcShrinkMemoryMap(IN OUT UINTN *MemoryMapSize, IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap, IN UINTN DescriptorSize)
Definition MemoryMap.c:333
EFI_STATUS OcRebuildAttributes(IN EFI_PHYSICAL_ADDRESS Address, IN EFI_GET_MEMORY_MAP GetMemoryMap OPTIONAL)
VOID OcSortMemoryMap(IN UINTN MemoryMapSize, IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap, IN UINTN DescriptorSize)
Definition MemoryMap.c:302
EFI_STATUS OcUpdateDescriptors(IN UINTN MemoryMapSize, IN EFI_MEMORY_DESCRIPTOR *MemoryMap, IN UINTN DescriptorSize, IN EFI_PHYSICAL_ADDRESS Address, IN EFI_MEMORY_TYPE Type, IN UINT64 SetAttributes, IN UINT64 DropAttributes)
Definition MemoryMap.c:505
UINTN OcCountSplitDescriptors(VOID)
EFI_STATUS OcSplitMemoryMapByAttributes(IN UINTN MaxMemoryMapSize, IN OUT UINTN *MemoryMapSize, IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap, IN UINTN DescriptorSize)
#define SECONDS_TO_MICROSECONDS(x)
Definition OcMiscLib.h:30
UINT32 ApplyPatch(IN CONST UINT8 *Pattern, IN CONST UINT8 *PatternMask OPTIONAL, IN CONST UINT32 PatternSize, IN CONST UINT8 *Replace, IN CONST UINT8 *ReplaceMask OPTIONAL, IN UINT8 *Data, IN UINT32 DataSize, IN UINT32 Count, IN UINT32 Skip)
#define L_STR_LEN(String)
Definition OcStringLib.h:26
CHAR16 * AsciiStrCopyToUnicode(IN CONST CHAR8 *String, IN UINTN Length)
Definition OcAsciiLib.c:119
OC_TYPING_BUFFER_ENTRY Buffer[OC_TYPING_BUFFER_SIZE]
Definition OcTypingLib.h:42
#define OC_BOOT_REDIRECT_VARIABLE_NAME
Definition OcVariable.h:33
EFI_GUID gOcVendorVariableGuid
STATIC EFI_STATUS EFIAPI OcExitBootServices(IN EFI_HANDLE ImageHandle, IN UINTN MapKey)
STATIC VOID EFIAPI SetGetVariableHookHandler(IN EFI_EVENT Event, IN VOID *Context)
STATIC VOID ProtectMemoryRegions(IN UINTN MemoryMapSize, IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap, IN UINTN DescriptorSize)
STATIC VOID FixRuntimeAttributes(IN BOOT_COMPAT_CONTEXT *BootCompat, IN UINT32 Type)
STATIC VOID DevirtualiseMmio(IN VOID *Context, IN UINTN MemoryMapSize, IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap, IN UINTN DescriptorSize)
STATIC VOID ApplyBooterPatch(IN OUT UINT8 *ImageBase, IN UINTN ImageSize, IN OC_BOOTER_PATCH *Patch)
STATIC EFI_STATUS EFIAPI OcAllocatePool(IN EFI_MEMORY_TYPE PoolType, IN UINTN Size, OUT VOID **Buffer)
STATIC EFI_STATUS EFIAPI OcGetMemoryMap(IN OUT UINTN *MemoryMapSize, IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap, OUT UINTN *MapKey, OUT UINTN *DescriptorSize, OUT UINT32 *DescriptorVersion)
VOID InstallServiceOverrides(IN OUT BOOT_COMPAT_CONTEXT *BootCompat)
STATIC EFI_STATUS EFIAPI OcFreePages(IN EFI_PHYSICAL_ADDRESS Memory, IN UINTN Pages)
STATIC BOOLEAN InternalIsEfiBootRt(IN EFI_DEVICE_PATH_PROTOCOL *EfiBootRtDevicePath OPTIONAL, IN VOID *SourceBuffer OPTIONAL, IN UINTN SourceSize, IN EFI_LOADED_IMAGE_PROTOCOL *EfiBootLoadedImage)
STATIC EFI_STATUS EFIAPI OcStartImage(IN EFI_HANDLE ImageHandle, OUT UINTN *ExitDataSize, OUT CHAR16 **ExitData OPTIONAL)
STATIC EFI_STATUS EFIAPI OcLoadImage(IN BOOLEAN BootPolicy, IN EFI_HANDLE ParentImageHandle, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, IN VOID *SourceBuffer OPTIONAL, IN UINTN SourceSize, OUT EFI_HANDLE *ImageHandle)
STATIC EFI_STATUS EFIAPI OcFreePool(IN VOID *Buffer)
STATIC EFI_STATUS EFIAPI OcSetVirtualAddressMap(IN UINTN MemoryMapSize, IN UINTN DescriptorSize, IN UINT32 DescriptorVersion, IN EFI_MEMORY_DESCRIPTOR *MemoryMap)
STATIC EFI_STATUS EFIAPI OcGetVariable(IN CHAR16 *VariableName, IN EFI_GUID *VendorGuid, OUT UINT32 *Attributes OPTIONAL, IN OUT UINTN *DataSize, OUT VOID *Data)
STATIC EFI_STATUS EFIAPI OcAllocatePages(IN EFI_ALLOCATE_TYPE Type, IN EFI_MEMORY_TYPE MemoryType, IN UINTN NumberOfPages, IN OUT EFI_PHYSICAL_ADDRESS *Memory)
STATIC VOID ApplyBooterPatches(IN EFI_HANDLE ImageHandle, IN BOOLEAN IsApple, IN OC_BOOTER_PATCH *Patches, IN UINT32 PatchCount)
STATIC EFI_STATUS ForceExitBootServices(IN EFI_HANDLE ImageHandle, IN UINTN MapKey, IN EFI_EXIT_BOOT_SERVICES ExitBootServices OPTIONAL, IN EFI_GET_MEMORY_MAP GetMemoryMap OPTIONAL)
INTN EFIAPI CompareMem(IN CONST 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_GUID gEfiLoadedImageProtocolGuid
EFI_DEVICE_PATH_PROTOCOL *EFIAPI DevicePathFromHandle(IN EFI_HANDLE Handle)
Definition UserMisc.c:680
EFI_GUID gVMwareMacProtocolGuid
#define ASSERT(x)
Definition coder.h:55
APPLE_EFI_BOOT_RT_KCG KernelCallGate
SERVICES_OVERRIDE_STATE ServiceState
UEFI_SERVICES_POINTERS ServicePtrs
EFI_EVENT_NOTIFY * ExitBootServicesHandlers
VOID ** ExitBootServicesHandlerContexts
OC_BOOTER_PATCH * BooterPatches
OC_FWRT_GET_CURRENT_CONFIG GetCurrent
OC_FWRT_GET_EXEC_AREA GetExecArea
OC_FWRT_ON_SET_ADDRESS_MAP OnSetAddressMap
OC_FWRT_SET_MAIN_CONFIG SetMain
EFI_LOADED_IMAGE_PROTOCOL * LastAppleBootImage
OC_FIRMWARE_RUNTIME_PROTOCOL * FwRuntime
EFI_PHYSICAL_ADDRESS OldKernelCallGate
EFI_EXIT_BOOT_SERVICES ExitBootServices
EFI_ALLOCATE_POOL AllocatePool
EFI_ALLOCATE_PAGES AllocatePages
EFI_GET_MEMORY_MAP GetMemoryMap