OpenCore  1.0.4
OpenCore Bootloader
Loading...
Searching...
No Matches
OpenCoreKernel.c
Go to the documentation of this file.
1
15#include <Base.h>
16
17#include <Library/OcMainLib.h>
18
19#include <Library/BaseLib.h>
20#include <Library/DebugLib.h>
21#include <Library/MemoryAllocationLib.h>
24#include <Library/OcMiscLib.h>
26#include <Library/OcStringLib.h>
28#include <Library/PrintLib.h>
29#include <Library/UefiBootServicesTableLib.h>
30#include <Library/UefiRuntimeServicesTableLib.h>
31
33STATIC OC_GLOBAL_CONFIG *mOcConfiguration;
36
37STATIC UINT32 mOcDarwinVersion;
38STATIC BOOLEAN mUse32BitKernel;
39
42
43STATIC EFI_FILE_PROTOCOL *mCustomKernelDirectory;
45
46STATIC
47VOID
49 IN OUT EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,
50 IN UINT32 Capabilities
51 )
52{
53 CONST CHAR8 *KernelArch;
54 CHAR8 *AppleArchValue;
55 CONST CHAR8 *NewArguments[2];
56 UINT32 ArgumentCount;
57 UINT32 RequestedArch;
58 BOOLEAN HasAppleArch;
59 UINT32 KernelVersion;
60 BOOLEAN IsSnowLeo;
61 BOOLEAN IsLion;
62
63 DEBUG ((DEBUG_VERBOSE, "OC: Supported boot capabilities %u\n", Capabilities));
64
65 //
66 // Reset to the default value.
67 // Capabilities will always have K64 stripped when compiled for IA32.
68 //
69 mUse32BitKernel = (Capabilities & OC_KERN_CAPABILITY_K64_U64) == 0;
70
71 //
72 // Skip if not Apple image.
73 //
74 if ( (LoadedImage->FilePath == NULL)
75 || ((OcGetBootDevicePathType (LoadedImage->FilePath, NULL, NULL) & OC_BOOT_APPLE_ANY) == 0))
76 {
77 return;
78 }
79
80 //
81 // arch boot argument overrides any compatibility checks.
82 //
83 HasAppleArch = OcCheckArgumentFromEnv (
84 LoadedImage,
85 gRT->GetVariable,
86 "arch=",
87 L_STR_LEN ("arch="),
88 &AppleArchValue
89 );
90
91 if (HasAppleArch) {
92 mUse32BitKernel = AsciiStrCmp (AppleArchValue, "i386") == 0;
93 DEBUG ((DEBUG_INFO, "OC: Arch %a overrides capabilities %u\n", AppleArchValue, Capabilities));
94 FreePool (AppleArchValue);
95 return;
96 }
97
98 //
99 // Determine the current operating system.
100 //
101 IsSnowLeo = FALSE;
102 IsLion = FALSE;
103
104 if ((Capabilities & OC_KERN_CAPABILITY_ALL) == OC_KERN_CAPABILITY_ALL) {
106 IsSnowLeo = TRUE;
107 } else if ((Capabilities & OC_KERN_CAPABILITY_ALL) == OC_KERN_CAPABILITY_K32_K64_U64) {
109 IsLion = TRUE;
110 } else if ((Capabilities & OC_KERN_CAPABILITY_ALL) == OC_KERN_CAPABILITY_K32_U32_U64) {
112 } else {
114 }
115
116 //
117 // Determine requested arch.
118 //
119 // There are issues with booting with -legacy on 10.4 and 10.5, and EFI64.
120 // We can only use this on 10.6, or on 10.4/10.5 if on EFI32.
121 //
122 // i386-user32 is not supported on 10.7, fallback to i386.
123 //
124 KernelArch = OC_BLOB_GET (&mOcConfiguration->Kernel.Scheme.KernelArch);
125 if (AsciiStrCmp (KernelArch, "x86_64") == 0) {
126 RequestedArch = OC_KERN_CAPABILITY_K64_U64;
127 } else if (AsciiStrCmp (KernelArch, "i386") == 0) {
128 RequestedArch = OC_KERN_CAPABILITY_K32_U64;
129 } else if ( AsciiStrCmp (KernelArch, "i386-user32") == 0
130 #if defined (MDE_CPU_X64)
131 && (IsSnowLeo || IsLion)
132 #endif
133 )
134 {
135 if (!IsLion) {
136 RequestedArch = OC_KERN_CAPABILITY_K32_U32;
137 } else {
138 DEBUG ((DEBUG_INFO, "OC: Requested arch i386-user32 is not supported on 10.7, falling back to i386\n"));
139 RequestedArch = OC_KERN_CAPABILITY_K32_U64;
140 }
141 } else {
142 RequestedArch = 0;
143 }
144
145 //
146 // In automatic mode, if we do not support SSSE3 and can downgrade to U32, do it.
147 // See also note above regarding 10.4 and 10.5.
148 //
149 if ( RequestedArch == 0
150 #if defined (MDE_CPU_X64)
151 && IsSnowLeo
152 #endif
155 && (Capabilities & OC_KERN_CAPABILITY_K32_U32) != 0)
156 {
157 //
158 // Should be guaranteed that we support 32-bit kernel with a 64-bit userspace.
159 //
160 ASSERT ((Capabilities & OC_KERN_CAPABILITY_K32_U64) != 0);
161
162 DEBUG ((DEBUG_INFO, "OC: Missing SSSE3 disables U64 capabilities %u\n", Capabilities));
163 Capabilities = OC_KERN_CAPABILITY_K32_U32;
164 }
165
166 //
167 // If we support K64 mode, check whether the board supports it.
168 //
169 if ( ((Capabilities & OC_KERN_CAPABILITY_K64_U64) != 0)
171 {
172 DEBUG ((DEBUG_INFO, "OC: K64 forbidden due to current platform on version %u\n", KernelVersion));
173 Capabilities &= ~(OC_KERN_CAPABILITY_K64_U64);
174 }
175
176 //
177 // If we are not choosing the architecture automatically, try to use the requested one.
178 // Otherwise try best available.
179 //
180 if ((RequestedArch != 0) && ((Capabilities & RequestedArch) != 0)) {
181 Capabilities = RequestedArch;
182 } else if ((Capabilities & OC_KERN_CAPABILITY_K64_U64) != 0) {
183 Capabilities = OC_KERN_CAPABILITY_K64_U64;
184 } else if ((Capabilities & OC_KERN_CAPABILITY_K32_U64) != 0) {
185 Capabilities = OC_KERN_CAPABILITY_K32_U64;
186 } else if ((Capabilities & OC_KERN_CAPABILITY_K32_U32) != 0) {
187 Capabilities = OC_KERN_CAPABILITY_K32_U32;
188 } else {
189 ASSERT (FALSE);
190 }
191
192 //
193 // Pass arch argument when we are:
194 // - SnowLeo64 and try to boot x86_64.
195 // - SnowLeo64 or Lion64 and try to boot i386.
196 //
197 ArgumentCount = 0;
198 if ((Capabilities == OC_KERN_CAPABILITY_K64_U64) && IsSnowLeo) {
199 NewArguments[ArgumentCount++] = "arch=x86_64";
200 } else if ((Capabilities != OC_KERN_CAPABILITY_K64_U64) && (IsSnowLeo || IsLion)) {
201 NewArguments[ArgumentCount++] = "arch=i386";
202 }
203
204 //
205 // Pass legacy argument when we are booting i386.
206 //
207 if ( (Capabilities == OC_KERN_CAPABILITY_K32_U32)
208 && !OcCheckArgumentFromEnv (LoadedImage, gRT->GetVariable, "-legacy", L_STR_LEN ("-legacy"), NULL))
209 {
210 NewArguments[ArgumentCount++] = "-legacy";
211 }
212
213 //
214 // Update argument list.
215 //
216 if (ArgumentCount > 0) {
218 LoadedImage,
219 &NewArguments[0],
220 ArgumentCount,
221 FALSE
222 );
223 }
224
225 //
226 // If we do not support K64 for this target, force 32.
227 //
228 if ((Capabilities & OC_KERN_CAPABILITY_K64_U64) == 0) {
229 mUse32BitKernel = TRUE;
230 }
231}
232
233STATIC
234VOID
236 IN OC_KERNEL_ADD_ENTRY *Kext,
237 IN UINT32 Index,
238 IN BOOLEAN IsForced,
239 IN EFI_FILE_PROTOCOL *RootFile,
240 IN OC_STORAGE_CONTEXT *Storage,
241 IN OC_GLOBAL_CONFIG *Config,
242 IN KERNEL_CACHE_TYPE CacheType,
243 IN BOOLEAN Is32Bit,
244 IN OUT UINT32 *ReservedExeSize,
245 IN OUT UINT32 *ReservedInfoSize,
246 IN OUT UINT32 *NumReservedKexts
247 )
248{
249 EFI_STATUS Status;
250 CHAR8 *Identifier;
251 CHAR8 *BundlePath;
252 CHAR8 *Comment;
253 CONST CHAR8 *Arch;
254 CHAR8 *PlistPath;
255 CHAR8 *ExecutablePath;
256 CHAR16 FullPath[OC_STORAGE_SAFE_PATH_MAX];
257
258 if (!Kext->Enabled) {
259 return;
260 }
261
262 //
263 // Free existing data if present, but only for forced kexts.
264 // Injected kexts will never change.
265 //
266 if (IsForced && (Kext->PlistData != NULL)) {
267 FreePool (Kext->PlistData);
268 Kext->PlistDataSize = 0;
269 Kext->PlistData = NULL;
270
271 if (Kext->ImageData != NULL) {
272 FreePool (Kext->ImageData);
273 Kext->ImageDataSize = 0;
274 Kext->ImageData = NULL;
275 }
276 }
277
278 Identifier = OC_BLOB_GET (&Kext->Identifier);
279 BundlePath = OC_BLOB_GET (&Kext->BundlePath);
280 Comment = OC_BLOB_GET (&Kext->Comment);
281 Arch = OC_BLOB_GET (&Kext->Arch);
282 PlistPath = OC_BLOB_GET (&Kext->PlistPath);
283 if ((BundlePath[0] == '\0') || (PlistPath[0] == '\0') || (IsForced && (Identifier[0] == '\0'))) {
284 DEBUG ((
285 DEBUG_ERROR,
286 "OC: %s kext %u (%a) has invalid info\n",
287 IsForced ? L"Forced" : L"Injected",
288 Index,
289 Comment
290 ));
291 Kext->Enabled = FALSE;
292 return;
293 }
294
295 if (AsciiStrCmp (Arch, Is32Bit ? "x86_64" : "i386") == 0) {
296 DEBUG ((
297 DEBUG_INFO,
298 "OC: %s kext %a (%a) at %u skipped due to arch %a != %a\n",
299 IsForced ? L"Forced" : L"Injected",
300 BundlePath,
301 Comment,
302 Index,
303 Arch,
304 Is32Bit ? "i386" : "x86_64"
305 ));
306 return;
307 }
308
309 //
310 // Required for possible cacheless force injection later on.
311 //
312 AsciiUefiSlashes (BundlePath);
313
314 //
315 // Get plist path and data.
316 //
317 Status = OcUnicodeSafeSPrint (
318 FullPath,
319 sizeof (FullPath),
320 IsForced ? L"%a\\%a" : OPEN_CORE_KEXT_PATH "%a\\%a",
321 BundlePath,
322 PlistPath
323 );
324 if (EFI_ERROR (Status)) {
325 DEBUG ((
326 DEBUG_WARN,
327 "OC: Failed to fit %s kext path %s%a\\%a",
328 IsForced ? L"forced" : L"injected",
329 IsForced ? L"" : OPEN_CORE_KEXT_PATH,
330 BundlePath,
331 PlistPath
332 ));
333 Kext->Enabled = IsForced;
334 return;
335 }
336
337 UnicodeUefiSlashes (FullPath);
338
339 if (IsForced) {
340 Kext->PlistData = OcReadFileFromDirectory (
341 RootFile,
342 FullPath,
343 &Kext->PlistDataSize,
344 0
345 );
346 } else {
347 Kext->PlistData = OcStorageReadFileUnicode (
348 Storage,
349 FullPath,
350 &Kext->PlistDataSize
351 );
352 }
353
354 if (Kext->PlistData == NULL) {
355 DEBUG ((
356 IsForced ? DEBUG_INFO : DEBUG_ERROR,
357 "OC: Plist %s is missing for %s kext %a (%a)\n",
358 FullPath,
359 IsForced ? L"forced" : L"injected",
360 BundlePath,
361 Comment
362 ));
363 Kext->Enabled = IsForced;
364 return;
365 }
366
367 //
368 // Get executable path and data, if present.
369 //
370 ExecutablePath = OC_BLOB_GET (&Kext->ExecutablePath);
371 if (ExecutablePath[0] != '\0') {
372 Status = OcUnicodeSafeSPrint (
373 FullPath,
374 sizeof (FullPath),
375 IsForced ? L"%a\\%a" : OPEN_CORE_KEXT_PATH "%a\\%a",
376 BundlePath,
377 ExecutablePath
378 );
379 if (EFI_ERROR (Status)) {
380 DEBUG ((
381 DEBUG_WARN,
382 "OC: Failed to fit %s kext path %s%a\\%a",
383 IsForced ? L"forced" : L"injected",
384 IsForced ? L"" : OPEN_CORE_KEXT_PATH,
385 BundlePath,
386 ExecutablePath
387 ));
388 Kext->Enabled = IsForced;
389 FreePool (Kext->PlistData);
390 Kext->PlistData = NULL;
391 return;
392 }
393
394 UnicodeUefiSlashes (FullPath);
395
396 if (IsForced) {
397 Kext->ImageData = OcReadFileFromDirectory (
398 RootFile,
399 FullPath,
400 &Kext->ImageDataSize,
401 0
402 );
403 } else {
404 Kext->ImageData = OcStorageReadFileUnicode (
405 Storage,
406 FullPath,
407 &Kext->ImageDataSize
408 );
409 }
410
411 if (Kext->ImageData == NULL) {
412 DEBUG ((
413 IsForced ? DEBUG_INFO : DEBUG_ERROR,
414 "OC: Image %s is missing for %s kext %a (%a)\n",
415 FullPath,
416 IsForced ? L"forced" : L"injected",
417 BundlePath,
418 Comment
419 ));
420 Kext->Enabled = IsForced;
421 FreePool (Kext->PlistData);
422 Kext->PlistData = NULL;
423 return;
424 }
425 }
426
427 if ((CacheType == CacheTypeCacheless) || (CacheType == CacheTypeMkext)) {
428 Status = MkextReserveKextSize (
429 ReservedInfoSize,
430 ReservedExeSize,
431 Kext->PlistDataSize,
432 Kext->ImageData,
433 Kext->ImageDataSize,
434 Is32Bit
435 );
436 } else if (CacheType == CacheTypePrelinked) {
437 Status = PrelinkedReserveKextSize (
438 ReservedInfoSize,
439 ReservedExeSize,
440 Kext->PlistDataSize,
441 Kext->ImageData,
442 Kext->ImageDataSize,
443 Is32Bit
444 );
445 }
446
447 if (EFI_ERROR (Status)) {
448 DEBUG ((
449 DEBUG_INFO,
450 "OC: Failed to fit %s kext %a (%a) - %r\n",
451 Is32Bit ? L"32-bit" : L"64-bit",
452 BundlePath,
453 Comment,
454 Status
455 ));
456 if (Kext->ImageData != NULL) {
457 FreePool (Kext->ImageData);
458 Kext->ImageData = NULL;
459 }
460
461 FreePool (Kext->PlistData);
462 Kext->PlistData = NULL;
463 return;
464 }
465
466 (*NumReservedKexts)++;
467}
468
469STATIC
470EFI_STATUS
472 IN EFI_FILE_PROTOCOL *RootFile,
473 IN OC_STORAGE_CONTEXT *Storage,
474 IN OC_GLOBAL_CONFIG *Config,
475 IN KERNEL_CACHE_TYPE CacheType,
476 IN BOOLEAN Is32Bit,
477 OUT UINT32 *ReservedExeSize,
478 OUT UINT32 *ReservedInfoSize,
479 OUT UINT32 *NumReservedKexts
480 )
481{
482 UINT32 Index;
483 OC_KERNEL_ADD_ENTRY *Kext;
484
485 *ReservedInfoSize = PRELINK_INFO_RESERVE_SIZE;
486 *ReservedExeSize = 0;
487 *NumReservedKexts = 0;
488
489 //
490 // Process system kexts to be force injected.
491 //
492 for (Index = 0; Index < Config->Kernel.Force.Count; Index++) {
493 Kext = Config->Kernel.Force.Values[Index];
494
496 Kext,
497 Index,
498 TRUE,
499 RootFile,
500 Storage,
501 Config,
502 CacheType,
503 Is32Bit,
504 ReservedExeSize,
505 ReservedInfoSize,
506 NumReservedKexts
507 );
508 }
509
510 //
511 // Process kexts to be injected.
512 //
513 for (Index = 0; Index < Config->Kernel.Add.Count; Index++) {
514 Kext = Config->Kernel.Add.Values[Index];
515
517 Kext,
518 Index,
519 FALSE,
520 RootFile,
521 Storage,
522 Config,
523 CacheType,
524 Is32Bit,
525 ReservedExeSize,
526 ReservedInfoSize,
527 NumReservedKexts
528 );
529 }
530
531 if (CacheType == CacheTypePrelinked) {
532 if ( (*ReservedExeSize > PRELINKED_KEXTS_MAX_SIZE)
533 || (*ReservedInfoSize + *ReservedExeSize < *ReservedExeSize))
534 {
535 return EFI_UNSUPPORTED;
536 }
537 }
538
539 DEBUG ((
540 DEBUG_INFO,
541 "OC: Kext reservation size info %X exe %X\n",
542 *ReservedInfoSize,
543 *ReservedExeSize
544 ));
545 return EFI_SUCCESS;
546}
547
548STATIC
549VOID
551 IN OC_KERNEL_ADD_ENTRY *Kext,
552 IN UINT32 Index,
553 IN BOOLEAN IsForced,
554 IN KERNEL_CACHE_TYPE CacheType,
555 IN VOID *Context,
556 IN UINT32 DarwinVersion,
557 IN BOOLEAN Is32Bit
558 )
559{
560 EFI_STATUS Status;
561 CONST CHAR8 *Identifier;
562 CONST CHAR8 *BundlePath;
563 CONST CHAR8 *ExecutablePath;
564 CONST CHAR8 *Comment;
565 CHAR8 FullPath[OC_STORAGE_SAFE_PATH_MAX];
566 UINT32 MaxKernel;
567 UINT32 MinKernel;
568 CHAR8 BundleVersion[MAX_INFO_BUNDLE_VERSION_KEY_SIZE];
569
570 if (!Kext->Enabled || (Kext->PlistData == NULL)) {
571 return;
572 }
573
574 Identifier = OC_BLOB_GET (&Kext->Identifier);
575 BundlePath = OC_BLOB_GET (&Kext->BundlePath);
576 Comment = OC_BLOB_GET (&Kext->Comment);
577 MaxKernel = OcParseDarwinVersion (OC_BLOB_GET (&Kext->MaxKernel));
578 MinKernel = OcParseDarwinVersion (OC_BLOB_GET (&Kext->MinKernel));
579
580 //
581 // Assume no bundle version from the beginning.
582 // 'v' will be printed in the message, and hence is omitted here.
583 //
584 AsciiStrCpyS (BundleVersion, MAX_INFO_BUNDLE_VERSION_KEY_SIZE, "ersion unavailable");
585
586 if (!OcMatchDarwinVersion (DarwinVersion, MinKernel, MaxKernel)) {
587 DEBUG ((
588 DEBUG_INFO,
589 "OC: %a%a injection skips %a (%a) kext at %u due to version %u <= %u <= %u\n",
590 PRINT_KERNEL_CACHE_TYPE (CacheType),
591 IsForced ? " force" : "",
592 BundlePath,
593 Comment,
594 Index,
595 MinKernel,
596 DarwinVersion,
597 MaxKernel
598 ));
599 return;
600 }
601
602 if (Kext->ImageData != NULL) {
603 ExecutablePath = OC_BLOB_GET (&Kext->ExecutablePath);
604 } else {
605 ExecutablePath = NULL;
606 }
607
608 if (!IsForced) {
609 Status = OcAsciiSafeSPrint (FullPath, sizeof (FullPath), "/Library/Extensions/%a", BundlePath);
610 if (EFI_ERROR (Status)) {
611 DEBUG ((DEBUG_WARN, "OC: Failed to fit kext path /Library/Extensions/%a", BundlePath));
612 return;
613 }
614 }
615
616 if (CacheType == CacheTypeCacheless) {
617 if ( IsForced
618 && (AsciiStrnCmp (BundlePath, "System\\Library\\Extensions", L_STR_LEN ("System\\Library\\Extensions")) == 0))
619 {
620 Status = CachelessContextForceKext (Context, Identifier);
621 } else {
622 Status = CachelessContextAddKext (
623 Context,
624 Kext->PlistData,
625 Kext->PlistDataSize,
626 Kext->ImageData,
627 Kext->ImageDataSize,
628 BundleVersion
629 );
630 }
631 } else if (CacheType == CacheTypeMkext) {
632 Status = MkextInjectKext (
633 Context,
634 IsForced ? Identifier : NULL,
635 IsForced ? BundlePath : FullPath,
636 Kext->PlistData,
637 Kext->PlistDataSize,
638 Kext->ImageData,
639 Kext->ImageDataSize,
640 BundleVersion
641 );
642 } else if (CacheType == CacheTypePrelinked) {
643 Status = PrelinkedInjectKext (
644 Context,
645 IsForced ? Identifier : NULL,
646 IsForced ? BundlePath : FullPath,
647 Kext->PlistData,
648 Kext->PlistDataSize,
649 ExecutablePath,
650 Kext->ImageData,
651 Kext->ImageDataSize,
652 BundleVersion
653 );
654 } else {
655 Status = EFI_UNSUPPORTED;
656 }
657
658 DEBUG ((
659 !IsForced && EFI_ERROR (Status) ? DEBUG_WARN : DEBUG_INFO,
660 "OC: %a%a injection %a (%a) - %r\n",
661 PRINT_KERNEL_CACHE_TYPE (CacheType),
662 IsForced ? " force" : "",
663 BundlePath,
664 Comment,
665 Status
666 ));
667
668 //
669 // Report kext bundle version for DEBUG build.
670 //
671 DEBUG_CODE_BEGIN ();
672 DEBUG ((
673 !IsForced && EFI_ERROR (Status) ? DEBUG_WARN : DEBUG_INFO,
674 "OC: %a%a injection %a v%a\n",
675 PRINT_KERNEL_CACHE_TYPE (CacheType),
676 IsForced ? " force" : "",
677 BundlePath,
678 BundleVersion
679 ));
680
681 DEBUG_CODE_END ();
682}
683
684VOID
686 IN OC_GLOBAL_CONFIG *Config,
687 IN KERNEL_CACHE_TYPE CacheType,
688 IN VOID *Context,
689 IN UINT32 DarwinVersion,
690 IN BOOLEAN Is32Bit,
691 IN UINT32 LinkedExpansion,
692 IN UINT32 ReservedExeSize
693 )
694{
695 EFI_STATUS Status;
696 UINT32 Index;
697
698 if (CacheType == CacheTypePrelinked) {
699 Status = PrelinkedInjectPrepare (
700 Context,
701 LinkedExpansion,
702 ReservedExeSize
703 );
704 if (EFI_ERROR (Status)) {
705 DEBUG ((DEBUG_WARN, "OC: Prelink inject prepare error - %r\n", Status));
706 return;
707 }
708 }
709
710 //
711 // Process system kexts to be force injected.
712 //
713 for (Index = 0; Index < Config->Kernel.Force.Count; Index++) {
715 Config->Kernel.Force.Values[Index],
716 Index,
717 TRUE,
718 CacheType,
719 Context,
720 DarwinVersion,
721 Is32Bit
722 );
723 }
724
725 //
726 // Process kexts to be injected.
727 //
728 for (Index = 0; Index < Config->Kernel.Add.Count; Index++) {
730 Config->Kernel.Add.Values[Index],
731 Index,
732 FALSE,
733 CacheType,
734 Context,
735 DarwinVersion,
736 Is32Bit
737 );
738 }
739
740 if ((CacheType == CacheTypeCacheless) || (CacheType == CacheTypeMkext)) {
741 Status = EFI_SUCCESS;
742 } else if (CacheType == CacheTypePrelinked) {
743 DEBUG ((
744 DEBUG_INFO,
745 "OC: Prelink size %u kext offset %u reserved %u\n",
746 ((PRELINKED_CONTEXT *)Context)->PrelinkedSize,
747 ((PRELINKED_CONTEXT *)Context)->KextsFileOffset,
748 ReservedExeSize
749 ));
750
751 ASSERT (
752 ((PRELINKED_CONTEXT *)Context)->PrelinkedSize -
753 ((PRELINKED_CONTEXT *)Context)->KextsFileOffset <= ReservedExeSize
754 );
755
756 Status = PrelinkedInjectComplete (Context);
757 } else {
758 Status = EFI_UNSUPPORTED;
759 }
760
761 if (EFI_ERROR (Status)) {
762 DEBUG ((DEBUG_WARN, "OC: %a insertion error - %r\n", PRINT_KERNEL_CACHE_TYPE (CacheType), Status));
763 }
764}
765
766EFI_STATUS
768 IN OC_GLOBAL_CONFIG *Config,
769 IN UINT32 DarwinVersion,
770 IN BOOLEAN Is32Bit,
771 IN OUT UINT8 *Kernel,
772 IN UINT32 *KernelSize,
773 IN UINT32 AllocatedSize,
774 IN UINT32 LinkedExpansion,
775 IN UINT32 ReservedExeSize
776 )
777{
778 EFI_STATUS Status;
779 PRELINKED_CONTEXT Context;
780
781 Status = PrelinkedContextInit (&Context, Kernel, *KernelSize, AllocatedSize, Is32Bit);
782
783 if (!EFI_ERROR (Status)) {
784 OcKernelBlockKexts (Config, DarwinVersion, Is32Bit, CacheTypePrelinked, &Context);
785
786 OcKernelInjectKexts (Config, CacheTypePrelinked, &Context, DarwinVersion, Is32Bit, LinkedExpansion, ReservedExeSize);
787
788 OcKernelApplyPatches (Config, mOcCpuInfo, DarwinVersion, Is32Bit, CacheTypePrelinked, &Context, NULL, 0);
789
790 *KernelSize = Context.PrelinkedSize;
791
792 PrelinkedContextFree (&Context);
793 }
794
795 return Status;
796}
797
798STATIC
799EFI_STATUS
801 IN OC_GLOBAL_CONFIG *Config,
802 IN UINT32 DarwinVersion,
803 IN BOOLEAN Is32Bit,
804 IN OUT UINT8 *Mkext,
805 IN OUT UINT32 *MkextSize,
806 IN UINT32 AllocatedSize
807 )
808{
809 EFI_STATUS Status;
810 MKEXT_CONTEXT Context;
811
812 Status = MkextContextInit (&Context, Mkext, *MkextSize, AllocatedSize);
813 if (EFI_ERROR (Status)) {
814 return Status;
815 }
816
817 OcKernelBlockKexts (Config, DarwinVersion, Is32Bit, CacheTypeMkext, &Context);
818
819 OcKernelInjectKexts (Config, CacheTypeMkext, &Context, DarwinVersion, Is32Bit, 0, 0);
820
821 OcKernelApplyPatches (Config, mOcCpuInfo, DarwinVersion, Is32Bit, CacheTypeMkext, &Context, NULL, 0);
822
823 MkextInjectPatchComplete (&Context);
824
825 *MkextSize = Context.MkextSize;
826
827 MkextContextFree (&Context);
828 return Status;
829}
830
831STATIC
832EFI_STATUS
834 IN OC_GLOBAL_CONFIG *Config,
835 IN CACHELESS_CONTEXT *Context,
836 IN UINT32 DarwinVersion,
837 IN BOOLEAN Is32Bit,
838 IN CHAR16 *FileName,
839 IN EFI_FILE_PROTOCOL *ExtensionsDir,
840 OUT EFI_FILE_PROTOCOL **File
841 )
842{
843 EFI_STATUS Status;
844
845 Status = CachelessContextInit (
846 Context,
847 FileName,
848 ExtensionsDir,
849 DarwinVersion,
850 Is32Bit
851 );
852 if (EFI_ERROR (Status)) {
853 return Status;
854 }
855
856 OcKernelBlockKexts (Config, DarwinVersion, Is32Bit, CacheTypeCacheless, Context);
857
858 OcKernelInjectKexts (Config, CacheTypeCacheless, Context, DarwinVersion, Is32Bit, 0, 0);
859
860 OcKernelApplyPatches (Config, mOcCpuInfo, DarwinVersion, Is32Bit, CacheTypeCacheless, Context, NULL, 0);
861
862 return CachelessContextOverlayExtensionsDir (Context, File);
863}
864
865STATIC
866EFI_STATUS
868 IN EFI_FILE_PROTOCOL *RootFile,
869 IN EFI_FILE_PROTOCOL *KernelFile,
870 IN CHAR16 *FileName,
871 IN BOOLEAN Is32Bit,
872 IN OUT UINT32 *DarwinVersion,
873 OUT UINT8 **Kernel,
874 OUT UINT32 *KernelSize,
875 OUT UINT32 *AllocatedSize,
876 OUT UINT32 *ReservedExeSize,
877 OUT UINT32 *LinkedExpansion,
878 OUT UINT8 *Digest OPTIONAL
879 )
880{
881 EFI_STATUS Status;
882 BOOLEAN Result;
883 UINT32 DarwinVersionNew;
884 BOOLEAN IsKernel32Bit;
885
886 UINT32 ReservedInfoSize;
887 UINT32 NumReservedKexts;
888 UINT32 ReservedFullSize;
889
891 RootFile,
895 Is32Bit,
896 ReservedExeSize,
897 &ReservedInfoSize,
898 &NumReservedKexts
899 );
900
901 *LinkedExpansion = KcGetSegmentFixupChainsSize (*ReservedExeSize);
902 if (*LinkedExpansion == 0) {
903 return EFI_UNSUPPORTED;
904 }
905
906 Result = BaseOverflowTriAddU32 (
907 ReservedInfoSize,
908 *ReservedExeSize,
909 *LinkedExpansion,
910 &ReservedFullSize
911 );
912 if (Result) {
913 return EFI_UNSUPPORTED;
914 }
915
916 //
917 // Read last requested architecture for kernel.
918 //
919 DEBUG ((DEBUG_INFO, "OC: Trying %a XNU hook on %s\n", Is32Bit ? "32-bit" : "64-bit", FileName));
920 Status = ReadAppleKernel (
921 KernelFile,
922 Is32Bit,
923 &IsKernel32Bit,
924 Kernel,
925 KernelSize,
926 AllocatedSize,
927 ReservedFullSize,
928 Digest
929 );
930 DEBUG ((
931 DEBUG_INFO,
932 "OC: Result of %a XNU hook on %s (%02X%02X%02X%02X) is %r\n",
933 IsKernel32Bit ? "32-bit" : "64-bit",
934 FileName,
935 Digest != NULL ? Digest[0] : 0,
936 Digest != NULL ? Digest[1] : 0,
937 Digest != NULL ? Digest[2] : 0,
938 Digest != NULL ? Digest[3] : 0,
939 Status
940 ));
941
942 if (!EFI_ERROR (Status)) {
943 //
944 // 10.6 and below may keep older prelinkedkernels around, do not load those.
945 //
946 DarwinVersionNew = OcKernelReadDarwinVersion (*Kernel, *KernelSize);
947 if (DarwinVersionNew < *DarwinVersion) {
948 FreePool (*Kernel);
949 *Kernel = NULL;
950
951 return EFI_INVALID_PARAMETER;
952 }
953
954 //
955 // If we failed to obtain the requested bitness for the platform, abort.
956 //
957 if (Is32Bit != IsKernel32Bit) {
958 DEBUG ((DEBUG_WARN, "OC: %a kernel architecture is not available, aborting.\n", Is32Bit ? "32-bit" : "64-bit"));
959 FreePool (*Kernel);
960 *Kernel = NULL;
961 return EFI_NOT_FOUND;
962 }
963
964 *DarwinVersion = DarwinVersionNew;
965 }
966
967 return Status;
968}
969
970STATIC
971EFI_STATUS
973 IN EFI_FILE_PROTOCOL *RootFile,
974 IN CHAR16 *FileName,
975 IN UINT64 OpenMode,
976 IN UINT64 Attributes,
977 IN BOOLEAN Is32Bit,
978 IN OUT UINT32 *DarwinVersion,
979 OUT EFI_FILE_PROTOCOL **KernelFile,
980 OUT UINT8 **Kernel,
981 OUT UINT32 *KernelSize,
982 OUT UINT32 *AllocatedSize,
983 OUT UINT32 *ReservedExeSize,
984 OUT UINT32 *LinkedExpansion,
985 OUT UINT8 *Digest OPTIONAL
986 )
987{
988 EFI_STATUS Status;
989 EFI_FILE_PROTOCOL *FileDirectory;
990 CHAR16 *FileNameDir;
991 UINTN FileNameDirLength;
992
993 EFI_FILE_INFO *FileInfo;
994 EFI_FILE_INFO *FileInfoNext;
995 CHAR16 *FileNameCacheNew;
996 UINTN FileNameCacheNewLength;
997 UINTN FileNameCacheNewSize;
998
1000
1001 FileInfo = NULL;
1002 FileNameCacheNew = NULL;
1003
1004 //
1005 // Open parent directory.
1006 //
1007 FileNameDirLength = OcStriStr (FileName, L"\\kernelcache") - FileName;
1008 FileNameDir = AllocateZeroPool (StrnSizeS (FileName, FileNameDirLength));
1009 if (FileNameDir == NULL) {
1010 return EFI_OUT_OF_RESOURCES;
1011 }
1012
1013 CopyMem (FileNameDir, FileName, StrnSizeS (FileName, FileNameDirLength) - sizeof (*FileName));
1014
1015 Status = OcSafeFileOpen (RootFile, &FileDirectory, FileNameDir, EFI_FILE_MODE_READ, 0);
1016 if (EFI_ERROR (Status)) {
1017 FreePool (FileNameDir);
1018 return Status;
1019 }
1020
1021 //
1022 // Search for kernelcache files, trying each one.
1023 //
1024 OcDirectorySeachContextInit (&Context);
1025 do {
1027 &Context,
1028 FileDirectory,
1029 L"kernelcache",
1030 &FileInfoNext
1031 );
1032
1033 if (EFI_ERROR (Status)) {
1034 break;
1035 }
1036
1037 if (FileInfo != NULL) {
1038 FreePool (FileInfo);
1039 }
1040
1041 if (FileNameCacheNew != NULL) {
1042 FreePool (FileNameCacheNew);
1043 }
1044
1045 FileInfo = FileInfoNext;
1046
1047 FileNameCacheNewLength = FileNameDirLength + L_STR_LEN ("\\") + StrLen (FileInfo->FileName);
1048 FileNameCacheNewSize = (FileNameCacheNewLength + 1) * sizeof (*FileNameCacheNew);
1049 FileNameCacheNew = AllocateZeroPool (FileNameCacheNewSize);
1050 if (FileNameCacheNew == NULL) {
1051 Status = EFI_OUT_OF_RESOURCES;
1052 break;
1053 }
1054
1055 Status = OcUnicodeSafeSPrint (FileNameCacheNew, FileNameCacheNewSize, L"%s\\%s", FileNameDir, FileInfo->FileName);
1056 if (EFI_ERROR (Status)) {
1057 break;
1058 }
1059
1060 Status = OcSafeFileOpen (RootFile, KernelFile, FileNameCacheNew, OpenMode, Attributes);
1061 if (EFI_ERROR (Status)) {
1062 continue;
1063 }
1064
1065 Status = OcKernelReadAppleKernel (
1066 RootFile,
1067 *KernelFile,
1068 FileNameCacheNew,
1069 Is32Bit,
1070 DarwinVersion,
1071 Kernel,
1072 KernelSize,
1073 AllocatedSize,
1074 ReservedExeSize,
1075 LinkedExpansion,
1076 Digest
1077 );
1078 } while (EFI_ERROR (Status));
1079
1080 if (FileInfo != NULL) {
1081 FreePool (FileInfo);
1082 }
1083
1084 if (FileNameCacheNew != NULL) {
1085 FreePool (FileNameCacheNew);
1086 }
1087
1088 FreePool (FileNameDir);
1089
1090 return Status;
1091}
1092
1093STATIC
1094EFI_STATUS
1095EFIAPI
1097 IN EFI_FILE_PROTOCOL *This,
1098 OUT EFI_FILE_PROTOCOL **NewHandle,
1099 IN CHAR16 *FileName,
1100 IN UINT64 OpenMode,
1101 IN UINT64 Attributes
1102 )
1103{
1104 EFI_STATUS Status;
1105 BOOLEAN Result;
1106 CONST CHAR8 *ForceCacheType;
1107 CONST CHAR8 *SecureBootModel;
1108 KERNEL_CACHE_TYPE MaxCacheTypeAllowed;
1109 BOOLEAN UseSecureBoot;
1110
1111 UINT8 *Kernel;
1112 UINT32 KernelSize;
1113 UINT32 AllocatedSize;
1114 EFI_FILE_PROTOCOL *VirtualFileHandle;
1115 EFI_STATUS PrelinkedStatus;
1116 EFI_TIME ModificationTime;
1117 UINT32 ReservedInfoSize;
1118 UINT32 ReservedExeSize;
1119 UINT32 NumReservedKexts;
1120 UINT32 LinkedExpansion;
1121 UINT32 ReservedFullSize;
1122 CHAR16 *NewFileName;
1123 EFI_FILE_PROTOCOL *EspNewHandle;
1124
1126 DEBUG ((DEBUG_INFO, "OC: Skipping OpenFile hooking on ESP Kernels directory\n"));
1127 return OcSafeFileOpen (This, NewHandle, FileName, OpenMode, Attributes);
1128 }
1129
1130 //
1131 // Prevent access to cache files depending on maximum cache type allowed.
1132 //
1133 ForceCacheType = OC_BLOB_GET (&mOcConfiguration->Kernel.Scheme.KernelCache);
1134 if (AsciiStrCmp (ForceCacheType, "Cacheless") == 0) {
1135 MaxCacheTypeAllowed = CacheTypeCacheless;
1136 } else if (AsciiStrCmp (ForceCacheType, "Mkext") == 0) {
1137 MaxCacheTypeAllowed = CacheTypeMkext;
1138 } else if (AsciiStrCmp (ForceCacheType, "Prelinked") == 0) {
1139 MaxCacheTypeAllowed = CacheTypePrelinked;
1140 } else {
1141 MaxCacheTypeAllowed = CacheTypeNone;
1142 }
1143
1144 //
1145 // We only want to calculate kernel hashes if secure boot is enabled.
1146 //
1147 SecureBootModel = OC_BLOB_GET (&mOcConfiguration->Misc.Security.SecureBootModel);
1148 UseSecureBoot = AsciiStrCmp (SecureBootModel, OC_SB_MODEL_DISABLED) != 0;
1149
1150 //
1151 // Hook injected OcXXXXXXXX.kext reads from /S/L/E.
1152 //
1154 && (OpenMode == EFI_FILE_MODE_READ)
1155 && (StrnCmp (FileName, L"System\\Library\\Extensions\\Oc", L_STR_LEN (L"System\\Library\\Extensions\\Oc")) == 0))
1156 {
1157 Status = CachelessContextPerformInject (&mOcCachelessContext, FileName, NewHandle);
1158 DEBUG ((
1159 DEBUG_INFO,
1160 "OC: Hooking SLE injected file %s with %u mode gave - %r\n",
1161 FileName,
1162 (UINT32)OpenMode,
1163 Status
1164 ));
1165
1166 return Status;
1167 }
1168
1169 Status = OcSafeFileOpen (This, NewHandle, FileName, OpenMode, Attributes);
1170
1171 DEBUG ((
1172 DEBUG_VERBOSE,
1173 "OC: Opening file %s with %u mode gave - %r\n",
1174 FileName,
1175 (UINT32)OpenMode,
1176 Status
1177 ));
1178
1179 //
1180 // Hook kernelcache read attempts for fuzzy kernelcache matching.
1181 // Only hook if the desired kernelcache file does not exist.
1182 //
1183 Kernel = NULL;
1184 if ( mOcConfiguration->Kernel.Scheme.FuzzyMatch
1185 && (Status == EFI_NOT_FOUND)
1186 && (OpenMode == EFI_FILE_MODE_READ)
1187 && (StrStr (FileName, L"\\kernelcache") != NULL))
1188 {
1189 //
1190 // Change the target to the custom one if requested CustomKernel.
1191 //
1192 if (mCustomKernelDirectory != NULL) {
1193 DEBUG ((DEBUG_INFO, "OC: Redirecting %s to the custom one on ESP\n", FileName));
1194 NewFileName = OcStrrChr (FileName, L'\\');
1195 if (NewFileName == NULL) {
1196 NewFileName = FileName;
1197 }
1198
1199 DEBUG ((DEBUG_INFO, "OC: Filename after redirection: %s\n", NewFileName));
1200
1202 FileName = NewFileName;
1203 }
1204
1205 DEBUG ((DEBUG_INFO, "OC: Trying kernelcache fuzzy matching on %s\n", FileName));
1206
1207 Status = OcKernelFuzzyMatch (
1208 This,
1209 FileName,
1210 OpenMode,
1211 Attributes,
1214 NewHandle,
1215 &Kernel,
1216 &KernelSize,
1217 &AllocatedSize,
1218 &ReservedExeSize,
1219 &LinkedExpansion,
1220 UseSecureBoot ? mKernelDigest : NULL
1221 );
1222 }
1223
1224 if (EFI_ERROR (Status)) {
1225 return Status;
1226 }
1227
1228 //
1229 // boot.efi uses /S/L/K/kernel as is to determine valid filesystem.
1230 // Just skip it to speedup the boot process.
1231 // On 10.9 mach_kernel is loaded for manual linking aferwards, so we cannot skip it.
1232 // We also want to skip files named "kernel" that are part of kext bundles, and im4m.
1233 //
1234 if ( (OpenMode == EFI_FILE_MODE_READ)
1235 && (OcStriStr (FileName, L"kernel") != NULL)
1236 && (StrCmp (FileName, L"System\\Library\\Kernels\\kernel") != 0)
1237 && (OcStriStr (FileName, L".kext\\") == NULL)
1238 && (OcStriStr (FileName, L".im4m") == NULL))
1239 {
1240 //
1241 // Change the target to the custom one if requested CustomKernel.
1242 //
1243 if (mCustomKernelDirectory != NULL) {
1244 DEBUG ((DEBUG_INFO, "OC: Redirecting %s to the custom one on ESP\n", FileName));
1245 NewFileName = OcStrrChr (FileName, L'\\');
1246 if (NewFileName == NULL) {
1247 NewFileName = FileName;
1248 }
1249
1250 DEBUG ((DEBUG_INFO, "OC: Filename after redirection: %s\n", NewFileName));
1251
1253 Status = OcSafeFileOpen (mCustomKernelDirectory, &EspNewHandle, NewFileName, OpenMode, Attributes);
1255 if (!EFI_ERROR (Status)) {
1256 (*NewHandle)->Close (*NewHandle);
1257
1259 *NewHandle = EspNewHandle;
1260 FileName = NewFileName;
1261 }
1262 }
1263
1264 //
1265 // Kernel loading for fuzzy kernelcache is performed earlier.
1266 //
1267 if (Kernel == NULL) {
1268 Status = OcKernelReadAppleKernel (
1269 This,
1270 *NewHandle,
1271 FileName,
1274 &Kernel,
1275 &KernelSize,
1276 &AllocatedSize,
1277 &ReservedExeSize,
1278 &LinkedExpansion,
1279 UseSecureBoot ? mKernelDigest : NULL
1280 );
1281
1282 if (Status == EFI_NOT_FOUND) {
1283 (*NewHandle)->Close (*NewHandle);
1284 *NewHandle = NULL;
1285
1286 return Status;
1287 }
1288 }
1289
1290 if (!EFI_ERROR (Status)) {
1291 //
1292 // Disable prelinked if forcing mkext or cacheless, but only on appropriate versions.
1293 // We also disable prelinked on 10.5 or older due to prelinked on those versions being unsupported.
1294 //
1295 if ( ((OcStriStr (FileName, L"kernelcache") != NULL) || (OcStriStr (FileName, L"prelinkedkernel") != NULL))
1296 && ( ((MaxCacheTypeAllowed == CacheTypeNone) && (mOcDarwinVersion <= KERNEL_VERSION_LEOPARD_MAX))
1297 || ((MaxCacheTypeAllowed == CacheTypeMkext) && (mOcDarwinVersion <= KERNEL_VERSION_SNOW_LEOPARD_MAX))
1298 || ((MaxCacheTypeAllowed == CacheTypeCacheless) && (mOcDarwinVersion <= KERNEL_VERSION_MAVERICKS_MAX))))
1299 {
1300 DEBUG ((DEBUG_INFO, "OC: Blocking prelinked due to ForceKernelCache=%a: %s\n", ForceCacheType, FileName));
1301
1302 FreePool (Kernel);
1303 (*NewHandle)->Close (*NewHandle);
1304 *NewHandle = NULL;
1305
1306 return EFI_NOT_FOUND;
1307 }
1308
1309 //
1310 // Apply patches to kernel itself, and then process prelinked.
1311 //
1314 mOcCpuInfo,
1318 NULL,
1319 Kernel,
1320 KernelSize
1321 );
1322
1323 PrelinkedStatus = OcKernelProcessPrelinked (
1327 Kernel,
1328 &KernelSize,
1329 AllocatedSize,
1330 LinkedExpansion,
1331 ReservedExeSize
1332 );
1333
1334 DEBUG ((DEBUG_INFO, "OC: Prelinked status - %r\n", PrelinkedStatus));
1335
1336 Status = OcGetFileModificationTime (*NewHandle, &ModificationTime);
1337 if (EFI_ERROR (Status)) {
1338 ZeroMem (&ModificationTime, sizeof (ModificationTime));
1339 }
1340
1341 (*NewHandle)->Close (*NewHandle);
1342
1343 //
1344 // Virtualise newly created kernel.
1345 //
1346 Status = CreateVirtualFileFileNameCopy (FileName, Kernel, KernelSize, &ModificationTime, &VirtualFileHandle);
1347 if (EFI_ERROR (Status)) {
1348 DEBUG ((DEBUG_WARN, "OC: Failed to virtualise kernel file (%s) - %r\n", FileName, Status));
1349 FreePool (Kernel);
1350 return EFI_OUT_OF_RESOURCES;
1351 }
1352
1353 if (UseSecureBoot) {
1354 OcAppleImg4RegisterOverride (mKernelDigest, Kernel, KernelSize);
1355 }
1356
1357 //
1358 // Return our handle.
1359 //
1360 *NewHandle = VirtualFileHandle;
1361 return EFI_SUCCESS;
1362 }
1363 }
1364
1365 if ( (OpenMode == EFI_FILE_MODE_READ)
1366 && (OcStriStr (FileName, L"Extensions.mkext") != NULL))
1367 {
1368 //
1369 // Disable mkext booting if forcing cacheless.
1370 //
1371 if (MaxCacheTypeAllowed == CacheTypeCacheless) {
1372 DEBUG ((DEBUG_INFO, "OC: Blocking mkext due to ForceKernelCache=%a: %s\n", ForceCacheType, FileName));
1373 (*NewHandle)->Close (*NewHandle);
1374 *NewHandle = NULL;
1375
1376 return EFI_NOT_FOUND;
1377 }
1378
1380 This,
1381 mOcStorage,
1385 &ReservedExeSize,
1386 &ReservedInfoSize,
1387 &NumReservedKexts
1388 );
1389
1390 Result = BaseOverflowAddU32 (
1391 ReservedInfoSize,
1392 ReservedExeSize,
1393 &ReservedFullSize
1394 );
1395 if (Result) {
1396 return EFI_UNSUPPORTED;
1397 }
1398
1399 DEBUG ((DEBUG_INFO, "OC: Trying %a mkext hook on %s\n", mUse32BitKernel ? "32-bit" : "64-bit", FileName));
1400 Status = ReadAppleMkext (
1401 *NewHandle,
1403 &Kernel,
1404 &KernelSize,
1405 &AllocatedSize,
1406 ReservedFullSize,
1407 NumReservedKexts
1408 );
1409 DEBUG ((DEBUG_INFO, "OC: Result of mkext hook on %s is %r\n", FileName, Status));
1410
1411 if (!EFI_ERROR (Status)) {
1412 //
1413 // Process mkext.
1414 //
1415 Status = OcKernelProcessMkext (
1419 Kernel,
1420 &KernelSize,
1421 AllocatedSize
1422 );
1423 DEBUG ((DEBUG_INFO, "OC: Mkext status - %r\n", Status));
1424 if (!EFI_ERROR (Status)) {
1425 Status = OcGetFileModificationTime (*NewHandle, &ModificationTime);
1426 if (EFI_ERROR (Status)) {
1427 ZeroMem (&ModificationTime, sizeof (ModificationTime));
1428 }
1429
1430 (*NewHandle)->Close (*NewHandle);
1431
1432 //
1433 // Virtualise newly created mkext.
1434 //
1435 Status = CreateVirtualFileFileNameCopy (FileName, Kernel, KernelSize, &ModificationTime, &VirtualFileHandle);
1436 if (EFI_ERROR (Status)) {
1437 DEBUG ((DEBUG_WARN, "OC: Failed to virtualise mkext file (%s) - %r\n", FileName, Status));
1438 FreePool (Kernel);
1439 return EFI_OUT_OF_RESOURCES;
1440 }
1441
1442 *NewHandle = VirtualFileHandle;
1443 return EFI_SUCCESS;
1444 } else {
1445 FreePool (Kernel);
1446 }
1447 }
1448 }
1449
1450 //
1451 // Hook /S/L/E for cacheless boots.
1452 //
1453 if ( (OpenMode == EFI_FILE_MODE_READ)
1454 && (StrCmp (FileName, L"System\\Library\\Extensions") == 0))
1455 {
1456 //
1457 // Free existing context if we are re-opening Extensions directory.
1458 //
1461 }
1462
1463 mOcCachelessInProgress = FALSE;
1464
1466 This,
1467 mOcStorage,
1471 &ReservedExeSize,
1472 &ReservedInfoSize,
1473 &NumReservedKexts
1474 );
1475
1476 //
1477 // Initialize Extensions directory overlay for cacheless injection.
1478 //
1479 Status = OcKernelInitCacheless (
1484 FileName,
1485 *NewHandle,
1486 &VirtualFileHandle
1487 );
1488
1489 DEBUG ((DEBUG_INFO, "OC: Result of SLE hook on %s is %r\n", FileName, Status));
1490
1491 if (!EFI_ERROR (Status)) {
1493 *NewHandle = VirtualFileHandle;
1494 return EFI_SUCCESS;
1495 }
1496 }
1497
1498 //
1499 // Hook /S/L/E contents for processing during cacheless boots.
1500 //
1502 && (OpenMode == EFI_FILE_MODE_READ)
1503 && (StrnCmp (FileName, L"System\\Library\\Extensions\\", L_STR_LEN (L"System\\Library\\Extensions\\")) == 0))
1504 {
1507 FileName,
1508 *NewHandle,
1509 &VirtualFileHandle
1510 );
1511
1512 if (EFI_ERROR (Status)) {
1513 DEBUG ((DEBUG_INFO, "OC: Error SLE hooking %s - %r\n", FileName, Status));
1514 }
1515
1516 if (!EFI_ERROR (Status) && (VirtualFileHandle != NULL)) {
1517 *NewHandle = VirtualFileHandle;
1518 return EFI_SUCCESS;
1519 }
1520 }
1521
1522 //
1523 // This is not Apple kernel, just return the original file.
1524 // We recurse the filtering to additionally catch com.apple.boot.[RPS] directories.
1525 //
1526 return CreateRealFile (*NewHandle, OcKernelFileOpen, TRUE, NewHandle);
1527}
1528
1529VOID
1531 IN OC_STORAGE_CONTEXT *Storage,
1532 IN OC_GLOBAL_CONFIG *Config,
1533 IN OC_CPU_INFO *CpuInfo
1534 )
1535{
1536 EFI_STATUS Status;
1537 EFI_FILE_PROTOCOL *Root;
1538
1540
1541 if (!EFI_ERROR (Status)) {
1542 mOcStorage = Storage;
1543 mOcConfiguration = Config;
1544 mOcCpuInfo = CpuInfo;
1545 mOcDarwinVersion = 0;
1546 mOcCachelessInProgress = FALSE;
1548 //
1549 // Open customised Kernels if needed.
1550 //
1552 if (mOcConfiguration->Kernel.Scheme.CustomKernel) {
1553 Status = OcFindWritableOcFileSystem (&Root);
1554 if (!EFI_ERROR (Status)) {
1555 //
1556 // Open Kernels directory.
1557 //
1558 Status = Root->Open (
1559 Root,
1561 L"Kernels",
1562 EFI_FILE_MODE_READ,
1563 EFI_FILE_DIRECTORY
1564 );
1565 if (EFI_ERROR (Status)) {
1566 DEBUG ((DEBUG_INFO, "OC: Unable to open Kernels folder for custom kernel - %r, falling back to normal one\n", Status));
1568 }
1569 } else {
1570 DEBUG ((DEBUG_INFO, "OC: Unable to find root writable filesystem for custom kernel - %r, falling back to normal one\n", Status));
1571 }
1572 }
1573
1575 } else {
1576 DEBUG ((DEBUG_ERROR, "OC: Failed to enable vfs - %r\n", Status));
1577 }
1578}
1579
1580VOID
1582 VOID
1583 )
1584{
1585 EFI_STATUS Status;
1586
1587 if (mOcStorage != NULL) {
1589 Status = DisableVirtualFs (gBS);
1590 if (EFI_ERROR (Status)) {
1591 DEBUG ((DEBUG_ERROR, "OC: Failed to disable vfs - %r\n", Status));
1592 }
1593
1594 mOcStorage = NULL;
1595 mOcConfiguration = NULL;
1596 }
1597}
#define CPUID_EXTFEATURE_EM64T
Extended Mem 64 Technology.
Definition CpuId.h:101
#define CPUID_FEATURE_SSSE3
Supplemental SSE3 Instructions.
Definition CpuId.h:67
STATIC UINT32 KernelVersion
Definition KextInject.c:28
VOID OcAppleImg4RegisterOverride(IN CONST UINT8 *OriginalDigest, IN CONST UINT8 *Image, IN UINT32 ImageSize)
#define OC_SB_MODEL_DISABLED
VOID CachelessContextFree(IN OUT CACHELESS_CONTEXT *Context)
#define KERNEL_VERSION_SNOW_LEOPARD_MIN
EFI_STATUS CachelessContextHookBuiltin(IN OUT CACHELESS_CONTEXT *Context, IN CONST CHAR16 *FileName, IN EFI_FILE_PROTOCOL *File, OUT EFI_FILE_PROTOCOL **VirtualFile)
EFI_STATUS ReadAppleKernel(IN EFI_FILE_PROTOCOL *File, IN BOOLEAN Prefer32Bit, OUT BOOLEAN *Is32Bit, OUT UINT8 **Kernel, OUT UINT32 *KernelSize, OUT UINT32 *AllocatedSize, IN UINT32 ReservedSize, OUT UINT8 *Digest OPTIONAL)
enum KERNEL_CACHE_TYPE_ KERNEL_CACHE_TYPE
#define KERNEL_VERSION_LEOPARD_MIN
VOID PrelinkedContextFree(IN OUT PRELINKED_CONTEXT *Context)
EFI_STATUS CachelessContextPerformInject(IN OUT CACHELESS_CONTEXT *Context, IN CONST CHAR16 *FileName, OUT EFI_FILE_PROTOCOL **VirtualFile)
#define PRELINKED_KEXTS_MAX_SIZE
#define KERNEL_VERSION_MOUNTAIN_LION_MIN
EFI_STATUS PrelinkedContextInit(IN OUT PRELINKED_CONTEXT *Context, IN OUT UINT8 *Prelinked, IN UINT32 PrelinkedSize, IN UINT32 PrelinkedAllocSize, IN BOOLEAN Is32Bit)
EFI_STATUS PrelinkedInjectPrepare(IN OUT PRELINKED_CONTEXT *Context, IN UINT32 LinkedExpansion, IN UINT32 ReservedExeSize)
EFI_STATUS MkextInjectPatchComplete(IN OUT MKEXT_CONTEXT *Context)
#define PRINT_KERNEL_CACHE_TYPE(a)
EFI_STATUS MkextReserveKextSize(IN OUT UINT32 *ReservedInfoSize, IN OUT UINT32 *ReservedExeSize, IN UINT32 InfoPlistSize, IN UINT8 *Executable OPTIONAL, IN UINT32 ExecutableSize OPTIONAL, IN BOOLEAN Is32Bit)
EFI_STATUS CachelessContextInit(IN OUT CACHELESS_CONTEXT *Context, IN CONST CHAR16 *FileName, IN EFI_FILE_PROTOCOL *ExtensionsDir, IN UINT32 KernelVersion, IN BOOLEAN Is32Bit)
#define KERNEL_VERSION_MAVERICKS_MAX
#define PRELINK_INFO_RESERVE_SIZE
#define MAX_INFO_BUNDLE_VERSION_KEY_SIZE
EFI_STATUS ReadAppleMkext(IN EFI_FILE_PROTOCOL *File, IN BOOLEAN Prefer32Bit, OUT UINT8 **Mkext, OUT UINT32 *MkextSize, OUT UINT32 *AllocatedSize, IN UINT32 ReservedSize, IN UINT32 NumReservedKexts)
EFI_STATUS CachelessContextAddKext(IN OUT CACHELESS_CONTEXT *Context, IN CONST CHAR8 *InfoPlist, IN UINT32 InfoPlistSize, IN UINT8 *Executable OPTIONAL, IN UINT32 ExecutableSize OPTIONAL, OUT CHAR8 BundleVersion[MAX_INFO_BUNDLE_VERSION_KEY_SIZE] OPTIONAL)
#define KERNEL_VERSION_SNOW_LEOPARD_MAX
EFI_STATUS CachelessContextForceKext(IN OUT CACHELESS_CONTEXT *Context, IN CONST CHAR8 *Identifier)
BOOLEAN OcMatchDarwinVersion(IN UINT32 CurrentVersion OPTIONAL, IN UINT32 MinVersion OPTIONAL, IN UINT32 MaxVersion OPTIONAL)
VOID MkextContextFree(IN OUT MKEXT_CONTEXT *Context)
EFI_STATUS PrelinkedReserveKextSize(IN OUT UINT32 *ReservedInfoSize, IN OUT UINT32 *ReservedExeSize, IN UINT32 InfoPlistSize, IN UINT8 *Executable OPTIONAL, IN UINT32 ExecutableSize OPTIONAL, IN BOOLEAN Is32Bit)
EFI_STATUS PrelinkedInjectKext(IN OUT PRELINKED_CONTEXT *Context, IN CONST CHAR8 *Identifier OPTIONAL, IN CONST CHAR8 *BundlePath, IN CONST CHAR8 *InfoPlist, IN UINT32 InfoPlistSize, IN CONST CHAR8 *ExecutablePath OPTIONAL, IN OUT CONST UINT8 *Executable OPTIONAL, IN UINT32 ExecutableSize OPTIONAL, OUT CHAR8 BundleVersion[MAX_INFO_BUNDLE_VERSION_KEY_SIZE] OPTIONAL)
EFI_STATUS CachelessContextOverlayExtensionsDir(IN OUT CACHELESS_CONTEXT *Context, OUT EFI_FILE_PROTOCOL **File)
EFI_STATUS MkextContextInit(IN OUT MKEXT_CONTEXT *Context, IN OUT UINT8 *Mkext, IN UINT32 MkextSize, IN UINT32 MkextAllocSize)
EFI_STATUS MkextInjectKext(IN OUT MKEXT_CONTEXT *Context, IN CONST CHAR8 *Identifier OPTIONAL, IN CONST CHAR8 *BundlePath, IN CONST CHAR8 *InfoPlist, IN UINT32 InfoPlistSize, IN UINT8 *Executable OPTIONAL, IN UINT32 ExecutableSize OPTIONAL, OUT CHAR8 BundleVersion[MAX_INFO_BUNDLE_VERSION_KEY_SIZE] OPTIONAL)
@ CacheTypeMkext
@ CacheTypeNone
@ CacheTypePrelinked
@ CacheTypeCacheless
UINT32 OcKernelReadDarwinVersion(IN CONST UINT8 *Kernel, IN UINT32 KernelSize)
UINT32 OcParseDarwinVersion(IN CONST CHAR8 *String)
#define KERNEL_VERSION_LEOPARD_MAX
#define KERNEL_VERSION_LION_MIN
EFI_STATUS PrelinkedInjectComplete(IN OUT PRELINKED_CONTEXT *Context)
UINT32 KcGetSegmentFixupChainsSize(IN UINT32 SegmentSize)
#define OC_KERN_CAPABILITY_K64_U64
Supports K64 and U64 (10.6+)
#define OC_KERN_CAPABILITY_ALL
#define OC_BOOT_APPLE_ANY
VOID OcImageLoaderRegisterConfigure(IN OC_IMAGE_LOADER_CONFIGURE Configure OPTIONAL)
#define OC_KERN_CAPABILITY_K32_U64
Supports K32 and U64 (10.4~10.7)
OC_BOOT_ENTRY_TYPE OcGetBootDevicePathType(IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, OUT BOOLEAN *IsFolder OPTIONAL, OUT BOOLEAN *IsGeneric OPTIONAL)
#define OC_KERN_CAPABILITY_K32_K64_U64
#define OC_KERN_CAPABILITY_K32_U32
Supports K32 and U32 (10.4~10.6)
BOOLEAN OcAppendArgumentsToLoadedImage(IN OUT EFI_LOADED_IMAGE_PROTOCOL *LoadedImage, IN CONST CHAR8 **Arguments, IN UINT32 ArgumentCount, IN BOOLEAN Replace)
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)
#define OC_KERN_CAPABILITY_K32_U32_U64
EFI_BOOT_SERVICES * gBS
#define SHA384_DIGEST_SIZE
Definition OcCryptoLib.h:46
VOID * OcReadFileFromDirectory(IN CONST EFI_FILE_PROTOCOL *RootDirectory, IN CONST CHAR16 *FilePath, OUT UINT32 *FileSize OPTIONAL, IN UINT32 MaxFileSize OPTIONAL)
Definition ReadFile.c:155
EFI_STATUS OcGetFileModificationTime(IN EFI_FILE_PROTOCOL *File, OUT EFI_TIME *Time)
VOID OcDirectorySeachContextInit(IN OUT DIRECTORY_SEARCH_CONTEXT *Context)
EFI_STATUS OcGetNewestFileFromDirectory(IN OUT DIRECTORY_SEARCH_CONTEXT *Context, IN EFI_FILE_PROTOCOL *Directory, IN CHAR16 *FileNameStartsWith OPTIONAL, OUT EFI_FILE_INFO **FileInfo)
EFI_STATUS OcFindWritableOcFileSystem(OUT EFI_FILE_PROTOCOL **FileSystem)
EFI_STATUS OcSafeFileOpen(IN CONST EFI_FILE_PROTOCOL *Directory, OUT EFI_FILE_PROTOCOL **NewHandle, IN CONST CHAR16 *FileName, IN CONST UINT64 OpenMode, IN CONST UINT64 Attributes)
Definition OpenFile.c:29
VOID OcKernelApplyPatches(IN OC_GLOBAL_CONFIG *Config, IN OC_CPU_INFO *CpuInfo, IN UINT32 DarwinVersion, IN BOOLEAN Is32Bit, IN KERNEL_CACHE_TYPE CacheType, IN VOID *Context, IN OUT UINT8 *Kernel, IN UINT32 Size)
BOOLEAN OcPlatformIs64BitSupported(IN UINT32 KernelVersion)
VOID OcKernelBlockKexts(IN OC_GLOBAL_CONFIG *Config, IN UINT32 DarwinVersion, IN BOOLEAN Is32Bit, IN KERNEL_CACHE_TYPE CacheType, IN VOID *Context)
#define OPEN_CORE_KEXT_PATH
Definition OcMainLib.h:60
VOID * OcStorageReadFileUnicode(IN OC_STORAGE_CONTEXT *Context, IN CONST CHAR16 *FilePath, OUT UINT32 *FileSize OPTIONAL)
#define OC_STORAGE_SAFE_PATH_MAX
VOID AsciiUefiSlashes(IN OUT CHAR8 *String)
Definition OcAsciiLib.c:86
CHAR16 *EFIAPI OcStrrChr(IN CONST CHAR16 *String, IN CHAR16 Char)
#define L_STR_LEN(String)
Definition OcStringLib.h:26
VOID UnicodeUefiSlashes(IN OUT CHAR16 *String)
EFI_STATUS EFIAPI OcAsciiSafeSPrint(OUT CHAR8 *StartOfBuffer, IN UINTN BufferSize, IN CONST CHAR8 *FormatString,...)
Definition OcAsciiLib.c:190
CHAR16 *EFIAPI OcStriStr(IN CONST CHAR16 *String, IN CONST CHAR16 *SearchString)
EFI_STATUS EFIAPI OcUnicodeSafeSPrint(OUT CHAR16 *StartOfBuffer, IN UINTN BufferSize, IN CONST CHAR16 *FormatString,...)
#define OC_BLOB_GET(Blob)
EFI_STATUS DisableVirtualFs(IN OUT EFI_BOOT_SERVICES *BootServices)
Definition VirtualFs.c:125
EFI_STATUS EnableVirtualFs(IN OUT EFI_BOOT_SERVICES *BootServices, IN EFI_FILE_OPEN OpenCallback)
Definition VirtualFs.c:99
EFI_STATUS CreateVirtualFileFileNameCopy(IN CONST CHAR16 *FileName, IN VOID *FileBuffer, IN UINT64 FileSize, IN CONST EFI_TIME *ModificationTime OPTIONAL, OUT EFI_FILE_PROTOCOL **File)
EFI_STATUS CreateRealFile(IN EFI_FILE_PROTOCOL *OriginalFile OPTIONAL, IN EFI_FILE_OPEN OpenCallback OPTIONAL, IN BOOLEAN CloseOnFailure, OUT EFI_FILE_PROTOCOL **File)
STATIC EFI_FILE_PROTOCOL * mCustomKernelDirectory
STATIC OC_CPU_INFO * mOcCpuInfo
STATIC EFI_STATUS OcKernelProcessMkext(IN OC_GLOBAL_CONFIG *Config, IN UINT32 DarwinVersion, IN BOOLEAN Is32Bit, IN OUT UINT8 *Mkext, IN OUT UINT32 *MkextSize, IN UINT32 AllocatedSize)
STATIC OC_GLOBAL_CONFIG * mOcConfiguration
VOID OcUnloadKernelSupport(VOID)
STATIC EFI_STATUS OcKernelReadAppleKernel(IN EFI_FILE_PROTOCOL *RootFile, IN EFI_FILE_PROTOCOL *KernelFile, IN CHAR16 *FileName, IN BOOLEAN Is32Bit, IN OUT UINT32 *DarwinVersion, OUT UINT8 **Kernel, OUT UINT32 *KernelSize, OUT UINT32 *AllocatedSize, OUT UINT32 *ReservedExeSize, OUT UINT32 *LinkedExpansion, OUT UINT8 *Digest OPTIONAL)
STATIC BOOLEAN mOcCachelessInProgress
STATIC UINT8 mKernelDigest[SHA384_DIGEST_SIZE]
STATIC OC_STORAGE_CONTEXT * mOcStorage
VOID OcKernelInjectKexts(IN OC_GLOBAL_CONFIG *Config, IN KERNEL_CACHE_TYPE CacheType, IN VOID *Context, IN UINT32 DarwinVersion, IN BOOLEAN Is32Bit, IN UINT32 LinkedExpansion, IN UINT32 ReservedExeSize)
STATIC VOID OcKernelConfigureCapabilities(IN OUT EFI_LOADED_IMAGE_PROTOCOL *LoadedImage, IN UINT32 Capabilities)
STATIC EFI_STATUS OcKernelInitCacheless(IN OC_GLOBAL_CONFIG *Config, IN CACHELESS_CONTEXT *Context, IN UINT32 DarwinVersion, IN BOOLEAN Is32Bit, IN CHAR16 *FileName, IN EFI_FILE_PROTOCOL *ExtensionsDir, OUT EFI_FILE_PROTOCOL **File)
STATIC CACHELESS_CONTEXT mOcCachelessContext
EFI_STATUS OcKernelProcessPrelinked(IN OC_GLOBAL_CONFIG *Config, IN UINT32 DarwinVersion, IN BOOLEAN Is32Bit, IN OUT UINT8 *Kernel, IN UINT32 *KernelSize, IN UINT32 AllocatedSize, IN UINT32 LinkedExpansion, IN UINT32 ReservedExeSize)
VOID OcLoadKernelSupport(IN OC_STORAGE_CONTEXT *Storage, IN OC_GLOBAL_CONFIG *Config, IN OC_CPU_INFO *CpuInfo)
STATIC EFI_STATUS EFIAPI OcKernelFileOpen(IN EFI_FILE_PROTOCOL *This, OUT EFI_FILE_PROTOCOL **NewHandle, IN CHAR16 *FileName, IN UINT64 OpenMode, IN UINT64 Attributes)
STATIC EFI_STATUS OcKernelLoadKextsAndReserve(IN EFI_FILE_PROTOCOL *RootFile, IN OC_STORAGE_CONTEXT *Storage, IN OC_GLOBAL_CONFIG *Config, IN KERNEL_CACHE_TYPE CacheType, IN BOOLEAN Is32Bit, OUT UINT32 *ReservedExeSize, OUT UINT32 *ReservedInfoSize, OUT UINT32 *NumReservedKexts)
STATIC BOOLEAN mUse32BitKernel
STATIC BOOLEAN mCustomKernelDirectoryInProgress
STATIC EFI_STATUS OcKernelFuzzyMatch(IN EFI_FILE_PROTOCOL *RootFile, IN CHAR16 *FileName, IN UINT64 OpenMode, IN UINT64 Attributes, IN BOOLEAN Is32Bit, IN OUT UINT32 *DarwinVersion, OUT EFI_FILE_PROTOCOL **KernelFile, OUT UINT8 **Kernel, OUT UINT32 *KernelSize, OUT UINT32 *AllocatedSize, OUT UINT32 *ReservedExeSize, OUT UINT32 *LinkedExpansion, OUT UINT8 *Digest OPTIONAL)
STATIC UINT32 mOcDarwinVersion
STATIC VOID OcKernelInjectKext(IN OC_KERNEL_ADD_ENTRY *Kext, IN UINT32 Index, IN BOOLEAN IsForced, IN KERNEL_CACHE_TYPE CacheType, IN VOID *Context, IN UINT32 DarwinVersion, IN BOOLEAN Is32Bit)
STATIC VOID OcKernelLoadAndReserveKext(IN OC_KERNEL_ADD_ENTRY *Kext, IN UINT32 Index, IN BOOLEAN IsForced, IN EFI_FILE_PROTOCOL *RootFile, IN OC_STORAGE_CONTEXT *Storage, IN OC_GLOBAL_CONFIG *Config, IN KERNEL_CACHE_TYPE CacheType, IN BOOLEAN Is32Bit, IN OUT UINT32 *ReservedExeSize, IN OUT UINT32 *ReservedInfoSize, IN OUT UINT32 *NumReservedKexts)
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
EFI_RUNTIME_SERVICES * gRT
#define ASSERT(x)
Definition coder.h:55
UINT64 ExtFeatures
Definition OcCpuLib.h:89
UINT64 Features
Definition OcCpuLib.h:88