OpenCoreKernel.c 22.4 KB
Newer Older
V
vit9696 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/** @file
  OpenCore driver.

Copyright (c) 2019, vit9696. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution.  The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php

THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.

**/

15
#include "ProcessorBind.h"
V
vit9696 已提交
16 17 18 19 20 21
#include <OpenCore.h>

#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/OcAppleKernelLib.h>
22
#include <Library/OcMiscLib.h>
V
vit9696 已提交
23
#include <Library/OcStringLib.h>
V
vit9696 已提交
24 25 26 27 28 29
#include <Library/OcVirtualFsLib.h>
#include <Library/PrintLib.h>
#include <Library/UefiBootServicesTableLib.h>

STATIC OC_STORAGE_CONTEXT  *mOcStorage;
STATIC OC_GLOBAL_CONFIG    *mOcConfiguration;
30
STATIC OC_CPU_INFO         *mOcCpuInfo;
V
vit9696 已提交
31

32
STATIC
33 34 35 36 37 38
UINT32
OcParseDarwinVersion (
  IN  CONST CHAR8         *String
  )
{
  UINT32  Version;
39
  UINT32  VersionPart;
40 41 42 43 44 45 46 47 48 49
  UINT32  Index;
  UINT32  Index2;

  if (*String == '\0' || *String < '0' || *String > '9') {
    return 0;
  }

  Version = 0;

  for (Index = 0; Index < 3; ++Index) {
50 51 52 53
    Version *= 100;

    VersionPart = 0;

54
    for (Index2 = 0; Index2 < 2; ++Index2) {
55 56 57 58 59 60 61
      //
      // Handle single digit parts, i.e. parse 1.2.3 as 010203.
      //
      if (*String != '.' && *String != '\0') {
        VersionPart *= 10;
      }

62
      if (*String >= '0' && *String <= '9') {
63
        VersionPart += *String++ - '0';
64 65 66 67 68
      } else if (*String != '.' && *String != '\0') {
        return 0;
      }
    }

69 70
    Version += VersionPart;

71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
    if (*String == '.') {
      ++String;
    }
  }

  return Version;
}

STATIC
BOOLEAN
OcMatchDarwinVersion (
  IN  UINT32  CurrentVersion,
  IN  UINT32  MinVersion,
  IN  UINT32  MaxVersion
  )
{
  //
  // Check against min <= curr <= max.
  // curr=0 -> curr=inf, max=0  -> max=inf
  //

  //
  // Replace max inf with max known version.
  //
  if (MaxVersion == 0) {
    MaxVersion = CurrentVersion;
  }

  //
  // Handle curr=inf <= max=inf(?) case.
  //
  if (CurrentVersion == 0) {
    return MaxVersion == 0;
  }

  //
  // Handle curr=num > max=num case.
  //
  if (CurrentVersion > MaxVersion) {
    return FALSE;
  }

  //
  // Handle min=num > curr=num case.
  //
  if (CurrentVersion < MinVersion) {
    return FALSE;
  }

  return TRUE;
}

STATIC
UINT32
125 126
OcKernelReadDarwinVersion (
  IN  CONST UINT8   *Kernel,
127
  IN  UINT32        KernelSize
128 129 130 131
  )
{
  INT32   Offset;
  UINT32  Index;
132
  CHAR8   DarwinVersion[32];
133
  UINT32  DarwinVersionInteger;
134 135 136 137 138 139 140 141 142 143 144 145 146


  Offset = FindPattern (
    (CONST UINT8 *) "Darwin Kernel Version ",
    NULL,
    L_STR_LEN ("Darwin Kernel Version "),
    Kernel,
    KernelSize,
    0
    );

  if (Offset < 0) {
    DEBUG ((DEBUG_WARN, "OC: Failed to determine kernel version\n"));
147
    return 0;
148 149
  }

150 151
  Offset += L_STR_LEN ("Darwin Kernel Version ");

152
  for (Index = 0; Index < ARRAY_SIZE (DarwinVersion) - 1; ++Index, ++Offset) {
153
    if ((UINT32) Offset >= KernelSize || Kernel[Offset] == ':') {
154 155 156 157 158
      break;
    }
    DarwinVersion[Index] = (CHAR8) Kernel[Offset];
  }
  DarwinVersion[Index] = '\0';
159
  DarwinVersionInteger = OcParseDarwinVersion (DarwinVersion);
160 161 162 163 164 165 166

  DEBUG ((
    DEBUG_INFO,
    "OC: Read kernel version %a (%u)\n",
    DarwinVersion,
    DarwinVersionInteger
    ));
167

168
  return DarwinVersionInteger;
169 170
}

V
vit9696 已提交
171
STATIC
172
EFI_STATUS
V
vit9696 已提交
173 174
OcKernelLoadKextsAndReserve (
  IN OC_STORAGE_CONTEXT  *Storage,
175 176 177
  IN OC_GLOBAL_CONFIG    *Config,
  OUT UINT32             *ReservedExeSize,
  OUT UINT32             *ReservedInfoSize
V
vit9696 已提交
178 179
  )
{
180
  EFI_STATUS           Status;
V
vit9696 已提交
181
  UINT32               Index;
182
  CHAR8                *BundlePath;
183
  CHAR8                *Comment;
V
vit9696 已提交
184 185
  CHAR8                *PlistPath;
  CHAR8                *ExecutablePath;
186
  CHAR16               FullPath[OC_STORAGE_SAFE_PATH_MAX];
V
vit9696 已提交
187
  OC_KERNEL_ADD_ENTRY  *Kext;
V
vit9696 已提交
188

189 190
  *ReservedInfoSize = PRELINK_INFO_RESERVE_SIZE;
  *ReservedExeSize  = 0;
V
vit9696 已提交
191 192

  for (Index = 0; Index < Config->Kernel.Add.Count; ++Index) {
V
vit9696 已提交
193 194
    Kext = Config->Kernel.Add.Values[Index];

V
vit9696 已提交
195
    if (!Kext->Enabled) {
V
vit9696 已提交
196 197 198
      continue;
    }

V
vit9696 已提交
199
    if (Kext->PlistDataSize == 0) {
200
      BundlePath     = OC_BLOB_GET (&Kext->BundlePath);
201
      Comment        = OC_BLOB_GET (&Kext->Comment);
V
vit9696 已提交
202
      PlistPath      = OC_BLOB_GET (&Kext->PlistPath);
203
      if (BundlePath[0] == '\0' || PlistPath[0] == '\0') {
V
vit9696 已提交
204
        DEBUG ((DEBUG_ERROR, "OC: Your config has improper for kext info\n"));
V
vit9696 已提交
205
        Kext->Enabled = FALSE;
V
vit9696 已提交
206 207 208
        continue;
      }

209
      Status = OcUnicodeSafeSPrint (
V
vit9696 已提交
210 211 212
        FullPath,
        sizeof (FullPath),
        OPEN_CORE_KEXT_PATH "%a\\%a",
213
        BundlePath,
V
vit9696 已提交
214 215
        PlistPath
        );
216 217 218 219 220 221 222 223 224 225 226
      if (EFI_ERROR (Status)) {
        DEBUG ((
          DEBUG_WARN,
          "OC: Failed to fit kext path %s%a\\%a",
          OPEN_CORE_KEXT_PATH,
          BundlePath,
          PlistPath
          ));
        Kext->Enabled = FALSE;
        continue;
      }
V
vit9696 已提交
227

V
vit9696 已提交
228 229 230
      UnicodeUefiSlashes (FullPath);

      Kext->PlistData = OcStorageReadFileUnicode (
V
vit9696 已提交
231 232
        Storage,
        FullPath,
V
vit9696 已提交
233
        &Kext->PlistDataSize
V
vit9696 已提交
234 235
        );

V
vit9696 已提交
236
      if (Kext->PlistData == NULL) {
237 238 239 240 241 242 243
        DEBUG ((
          DEBUG_ERROR,
          "OC: Plist %s is missing for kext %a (%a)\n",
          FullPath,
          BundlePath,
          Comment
          ));
V
vit9696 已提交
244
        Kext->Enabled = FALSE;
V
vit9696 已提交
245 246 247
        continue;
      }

V
vit9696 已提交
248
      ExecutablePath = OC_BLOB_GET (&Kext->ExecutablePath);
V
vit9696 已提交
249
      if (ExecutablePath[0] != '\0') {
250
        Status = OcUnicodeSafeSPrint (
V
vit9696 已提交
251 252 253
          FullPath,
          sizeof (FullPath),
          OPEN_CORE_KEXT_PATH "%a\\%a",
254
          BundlePath,
V
vit9696 已提交
255 256
          ExecutablePath
          );
257 258 259 260 261 262 263 264 265 266 267 268 269
        if (EFI_ERROR (Status)) {
          DEBUG ((
            DEBUG_WARN,
            "OC: Failed to fit kext path %s%a\\%a",
            OPEN_CORE_KEXT_PATH,
            BundlePath,
            ExecutablePath
            ));
          Kext->Enabled = FALSE;
          FreePool (Kext->PlistData);
          Kext->PlistData = NULL;
          continue;
        }
V
vit9696 已提交
270

V
vit9696 已提交
271 272 273
        UnicodeUefiSlashes (FullPath);

        Kext->ImageData = OcStorageReadFileUnicode (
V
vit9696 已提交
274 275
          Storage,
          FullPath,
V
vit9696 已提交
276
          &Kext->ImageDataSize
V
vit9696 已提交
277 278
          );

V
vit9696 已提交
279
        if (Kext->ImageData == NULL) {
280 281 282 283 284 285 286
          DEBUG ((
            DEBUG_ERROR,
            "OC: Image %s is missing for kext %a (%a)\n",
            FullPath,
            BundlePath,
            Comment
            ));
V
vit9696 已提交
287
          Kext->Enabled = FALSE;
288 289
          FreePool (Kext->PlistData);
          Kext->PlistData = NULL;
V
vit9696 已提交
290
          continue;
V
vit9696 已提交
291 292 293 294
        }
      }
    }

295 296 297
    Status = PrelinkedReserveKextSize (
      ReservedInfoSize,
      ReservedExeSize,
V
vit9696 已提交
298 299 300
      Kext->PlistDataSize,
      Kext->ImageData,
      Kext->ImageDataSize
V
vit9696 已提交
301
      );
302 303 304 305 306 307 308 309 310 311 312 313
    if (EFI_ERROR (Status)) {
      DEBUG ((
        DEBUG_ERROR,
        "OC: Failed to fit kext %a (%a)\n",
        BundlePath,
        Comment
        ));
      Kext->Enabled = FALSE;
      FreePool (Kext->PlistData);
      Kext->PlistData = NULL;
      continue;
    }
V
vit9696 已提交
314 315
  }

316 317 318 319
  if (*ReservedExeSize > PRELINKED_KEXTS_MAX_SIZE
   || *ReservedInfoSize + *ReservedExeSize < *ReservedExeSize) {
    return EFI_UNSUPPORTED;
  }
V
vit9696 已提交
320

321 322
  DEBUG ((
    DEBUG_INFO,
323 324
    "OC: Kext reservation size info %X exe %X\n",
    *ReservedInfoSize, *ReservedExeSize
325 326
    ));
  return EFI_SUCCESS;
V
vit9696 已提交
327 328
}

V
vit9696 已提交
329 330 331 332
STATIC
VOID
OcKernelApplyPatches (
  IN     OC_GLOBAL_CONFIG  *Config,
333
  IN     UINT32            DarwinVersion,
V
vit9696 已提交
334 335 336 337 338 339 340 341 342 343 344
  IN     PRELINKED_CONTEXT *Context,
  IN OUT UINT8             *Kernel,
  IN     UINT32            Size
  )
{
  EFI_STATUS             Status;
  PATCHER_CONTEXT        Patcher;
  UINT32                 Index;
  PATCHER_GENERIC_PATCH  Patch;
  OC_KERNEL_PATCH_ENTRY  *UserPatch;
  CONST CHAR8            *Target;
345 346 347
  CONST CHAR8            *Comment;
  UINT32                 MaxKernel;
  UINT32                 MinKernel;
V
vit9696 已提交
348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366
  BOOLEAN                IsKernelPatch;

  IsKernelPatch = Context == NULL;

  if (IsKernelPatch) {
    ASSERT (Kernel != NULL);

    Status = PatcherInitContextFromBuffer (
      &Patcher,
      Kernel,
      Size
      );

    if (EFI_ERROR (Status)) {
      DEBUG ((DEBUG_ERROR, "OC: Kernel patcher kernel init failure - %r\n", Status));
      return;
    }
  }

367
  for (Index = 0; Index < Config->Kernel.Patch.Count; ++Index) {
V
vit9696 已提交
368 369
    UserPatch = Config->Kernel.Patch.Values[Index];
    Target    = OC_BLOB_GET (&UserPatch->Identifier);
370
    Comment   = OC_BLOB_GET (&UserPatch->Comment);
V
vit9696 已提交
371

372
    if (!UserPatch->Enabled || (AsciiStrCmp (Target, "kernel") == 0) != IsKernelPatch) {
V
vit9696 已提交
373 374 375
      continue;
    }

376
    MaxKernel   = OcParseDarwinVersion (OC_BLOB_GET (&UserPatch->MaxKernel));
377
    MinKernel   = OcParseDarwinVersion (OC_BLOB_GET (&UserPatch->MinKernel));
378

379
    if (!OcMatchDarwinVersion (DarwinVersion, MinKernel, MaxKernel)) {
380 381
      DEBUG ((
        DEBUG_INFO,
382
        "OC: Kernel patcher skips %a (%a) patch at %u due to version %u <= %u <= %u\n",
383
        Target,
384
        Comment,
385
        Index,
386 387 388
        MinKernel,
        DarwinVersion,
        MaxKernel
389 390 391 392
        ));
      continue;
    }

V
vit9696 已提交
393 394 395 396 397 398 399 400
    if (!IsKernelPatch) {
      Status = PatcherInitContextFromPrelinked (
        &Patcher,
        Context,
        Target
        );

      if (EFI_ERROR (Status)) {
401
        DEBUG ((DEBUG_WARN, "OC: Kernel patcher %a (%a) init failure - %r\n", Target, Comment, Status));
402
        continue;
403
      } else {
404
        DEBUG ((DEBUG_INFO, "OC: Kernel patcher %a (%a) init succeed\n", Target, Comment));
V
vit9696 已提交
405 406 407 408 409 410 411 412 413 414 415
      }
    }

    //
    // Ignore patch if:
    // - There is nothing to replace.
    // - We have neither symbolic base, nor find data.
    // - Find and replace mismatch in size.
    // - Mask and ReplaceMask mismatch in size when are available.
    //
    if (UserPatch->Replace.Size == 0
416
      || (OC_BLOB_GET (&UserPatch->Base)[0] == '\0' && UserPatch->Find.Size != UserPatch->Replace.Size)
V
vit9696 已提交
417 418
      || (UserPatch->Mask.Size > 0 && UserPatch->Find.Size != UserPatch->Mask.Size)
      || (UserPatch->ReplaceMask.Size > 0 && UserPatch->Find.Size != UserPatch->ReplaceMask.Size)) {
419
      DEBUG ((DEBUG_ERROR, "OC: Kernel patch %u for %a (%a) is borked\n", Index, Target, Comment));
V
vit9696 已提交
420 421 422 423 424
      continue;
    }

    ZeroMem (&Patch, sizeof (Patch));

425 426 427 428
    if (OC_BLOB_GET (&UserPatch->Comment)[0] != '\0') {
      Patch.Comment  = OC_BLOB_GET (&UserPatch->Comment);
    }

429
    if (OC_BLOB_GET (&UserPatch->Base)[0] != '\0') {
V
vit9696 已提交
430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452
      Patch.Base  = OC_BLOB_GET (&UserPatch->Base);
    }

    if (UserPatch->Find.Size > 0) {
      Patch.Find  = OC_BLOB_GET (&UserPatch->Find);
    }

    Patch.Replace = OC_BLOB_GET (&UserPatch->Replace);

    if (UserPatch->Mask.Size > 0) {
      Patch.Mask  = OC_BLOB_GET (&UserPatch->Mask);
    }

    if (UserPatch->ReplaceMask.Size > 0) {
      Patch.ReplaceMask = OC_BLOB_GET (&UserPatch->ReplaceMask);
    }

    Patch.Size    = UserPatch->Replace.Size;
    Patch.Count   = UserPatch->Count;
    Patch.Skip    = UserPatch->Skip;
    Patch.Limit   = UserPatch->Limit;

    Status = PatcherApplyGenericPatch (&Patcher, &Patch);
V
vit9696 已提交
453
    DEBUG ((
454
      EFI_ERROR (Status) ? DEBUG_WARN : DEBUG_INFO,
455
      "OC: Kernel patcher result %u for %a (%a) - %r\n",
V
vit9696 已提交
456 457
      Index,
      Target,
458
      Comment,
V
vit9696 已提交
459 460
      Status
      ));
V
vit9696 已提交
461
  }
462 463 464

  if (!IsKernelPatch) {
    if (Config->Kernel.Quirks.AppleCpuPmCfgLock) {
465
      PatchAppleCpuPmCfgLock (Context);
466 467 468 469 470 471
    }

    if (Config->Kernel.Quirks.ExternalDiskIcons) {
      PatchForceInternalDiskIcons (Context);
    }

472 473
    if (Config->Kernel.Quirks.ThirdPartyDrives) {
      PatchThirdPartyDriveSupport (Context);
474 475 476 477 478
    }

    if (Config->Kernel.Quirks.XhciPortLimit) {
      PatchUsbXhciPortLimit (Context);
    }
479 480 481 482

    if (Config->Kernel.Quirks.DisableIoMapper) {
      PatchAppleIoMapperSupport (Context);
    }
483

484 485 486 487
    if (Config->Kernel.Quirks.DisableRtcChecksum) {
      PatchAppleRtcChecksum (Context);
    }

488 489 490 491
    if (Config->Kernel.Quirks.IncreasePciBarSize) {
      PatchIncreasePciBarSize (Context);     
    }

492 493 494
    if (Config->Kernel.Quirks.CustomSmbiosGuid) {
      PatchCustomSmbiosGuid (Context);
    }
495 496 497 498

    if (Config->Kernel.Quirks.DummyPowerManagement) {
      PatchDummyPowerManagement (Context);
    }
499 500 501 502
  } else {
    if (Config->Kernel.Quirks.AppleXcpmCfgLock) {
      PatchAppleXcpmCfgLock (&Patcher);
    }
503

504 505 506 507
    if (Config->Kernel.Quirks.AppleXcpmExtraMsrs) {
      PatchAppleXcpmExtraMsrs (&Patcher);
    }

508 509 510 511
    if (Config->Kernel.Quirks.AppleXcpmForceBoost) {
      PatchAppleXcpmForceBoost (&Patcher);
    }

512
    if (Config->Kernel.Quirks.PanicNoKextDump) {
513
      PatchPanicKextDump (&Patcher);
514 515
    }

516 517 518 519 520 521 522 523 524 525 526
    if (Config->Kernel.Emulate.Cpuid1Data[0] != 0
      || Config->Kernel.Emulate.Cpuid1Data[1] != 0
      || Config->Kernel.Emulate.Cpuid1Data[2] != 0
      || Config->Kernel.Emulate.Cpuid1Data[3] != 0) {
      PatchKernelCpuId (
        &Patcher,
        mOcCpuInfo,
        Config->Kernel.Emulate.Cpuid1Data,
        Config->Kernel.Emulate.Cpuid1Mask
        );
    }
V
vit9696 已提交
527 528 529 530

    if (Config->Kernel.Quirks.LapicKernelPanic) {
      PatchLapicKernelPanic (&Patcher);
    }
531 532 533 534

    if (Config->Kernel.Quirks.PowerTimeoutKernelPanic) {
      PatchPowerStateTimeout (&Patcher);
    }
535 536 537 538 539 540 541
  }
}

STATIC
VOID
OcKernelBlockKexts (
  IN     OC_GLOBAL_CONFIG  *Config,
542
  IN     UINT32            DarwinVersion,
543 544 545 546 547 548 549 550
  IN     PRELINKED_CONTEXT *Context
  )
{
  EFI_STATUS             Status;
  PATCHER_CONTEXT        Patcher;
  UINT32                 Index;
  OC_KERNEL_BLOCK_ENTRY  *Kext;
  CONST CHAR8            *Target;
551 552 553
  CONST CHAR8            *Comment;
  UINT32                 MaxKernel;
  UINT32                 MinKernel;
554 555

  for (Index = 0; Index < Config->Kernel.Block.Count; ++Index) {
556 557 558
    Kext    = Config->Kernel.Block.Values[Index];
    Target  = OC_BLOB_GET (&Kext->Identifier);
    Comment = OC_BLOB_GET (&Kext->Comment);
559

V
vit9696 已提交
560
    if (!Kext->Enabled) {
561 562 563
      continue;
    }

564
    MaxKernel = OcParseDarwinVersion (OC_BLOB_GET (&Kext->MaxKernel));
565
    MinKernel = OcParseDarwinVersion (OC_BLOB_GET (&Kext->MinKernel));
566

567
    if (!OcMatchDarwinVersion (DarwinVersion, MinKernel, MaxKernel)) {
568 569
      DEBUG ((
        DEBUG_INFO,
570
        "OC: Prelink blocker skips %a (%a) block at %u due to version %u <= %u <= %u\n",
571
        Target,
572
        Comment,
573
        Index,
574 575 576
        MinKernel,
        DarwinVersion,
        MaxKernel
577 578 579 580 581 582 583 584 585 586 587
        ));
      continue;
    }

    Status = PatcherInitContextFromPrelinked (
      &Patcher,
      Context,
      Target
      );

    if (EFI_ERROR (Status)) {
588
      DEBUG ((DEBUG_WARN, "OC: Prelink blocker %a (%a) init failure - %r\n", Target, Comment, Status));
589 590 591 592
      continue;
    }

    Status = PatcherBlockKext (&Patcher);
593 594 595

    DEBUG ((
      EFI_ERROR (Status) ? DEBUG_WARN : DEBUG_INFO,
596
      "OC: Prelink blocker %a (%a) - %r\n",
597
      Target,
598
      Comment,
599 600
      Status
      ));
601
  }
V
vit9696 已提交
602 603
}

V
vit9696 已提交
604 605 606 607
STATIC
EFI_STATUS
OcKernelProcessPrelinked (
  IN     OC_GLOBAL_CONFIG  *Config,
608
  IN     UINT32            DarwinVersion,
V
vit9696 已提交
609 610
  IN OUT UINT8             *Kernel,
  IN     UINT32            *KernelSize,
611 612 613
  IN     UINT32            AllocatedSize,
  IN     UINT32            LinkedExpansion,
  IN     UINT32            ReservedExeSize
V
vit9696 已提交
614 615
  )
{
616 617
  EFI_STATUS           Status;
  PRELINKED_CONTEXT    Context;
618
  CHAR8                *BundlePath;
619
  CHAR8                *ExecutablePath;
620
  CHAR8                *Comment;
621
  UINT32               Index;
622
  CHAR8                FullPath[OC_STORAGE_SAFE_PATH_MAX];
623
  OC_KERNEL_ADD_ENTRY  *Kext;
624 625
  UINT32               MaxKernel;
  UINT32               MinKernel;
V
vit9696 已提交
626 627 628 629

  Status = PrelinkedContextInit (&Context, Kernel, *KernelSize, AllocatedSize);

  if (!EFI_ERROR (Status)) {
630 631 632
    OcKernelApplyPatches (Config, DarwinVersion, &Context, NULL, 0);

    OcKernelBlockKexts (Config, DarwinVersion, &Context);
V
vit9696 已提交
633

634 635 636 637 638
    Status = PrelinkedInjectPrepare (
      &Context,
      LinkedExpansion,
      ReservedExeSize
      );
V
vit9696 已提交
639 640
    if (!EFI_ERROR (Status)) {
      for (Index = 0; Index < Config->Kernel.Add.Count; ++Index) {
641 642
        Kext = Config->Kernel.Add.Values[Index];

V
vit9696 已提交
643
        if (!Kext->Enabled || Kext->PlistDataSize == 0) {
644 645 646
          continue;
        }

647
        BundlePath  = OC_BLOB_GET (&Kext->BundlePath);
648 649
        Comment     = OC_BLOB_GET (&Kext->Comment);
        MaxKernel   = OcParseDarwinVersion (OC_BLOB_GET (&Kext->MaxKernel));
650
        MinKernel   = OcParseDarwinVersion (OC_BLOB_GET (&Kext->MinKernel));
651

652
        if (!OcMatchDarwinVersion (DarwinVersion, MinKernel, MaxKernel)) {
653 654
          DEBUG ((
            DEBUG_INFO,
655
            "OC: Prelink injection skips %a (%a) kext at %u due to version %u <= %u <= %u\n",
656
            BundlePath,
657
            Comment,
658
            Index,
659 660 661
            MinKernel,
            DarwinVersion,
            MaxKernel
662
            ));
V
vit9696 已提交
663 664 665
          continue;
        }

666 667 668 669 670 671
        Status = OcAsciiSafeSPrint (FullPath, sizeof (FullPath), "/Library/Extensions/%a", BundlePath);
        if (EFI_ERROR (Status)) {
          DEBUG ((DEBUG_WARN, "OC: Failed to fit kext path /Library/Extensions/%a", BundlePath));
          continue;
        }

672 673
        if (Kext->ImageData != NULL) {
          ExecutablePath = OC_BLOB_GET (&Kext->ExecutablePath);
V
vit9696 已提交
674 675 676 677 678 679 680
        } else {
          ExecutablePath = NULL;
        }

        Status = PrelinkedInjectKext (
          &Context,
          FullPath,
681 682
          Kext->PlistData,
          Kext->PlistDataSize,
V
vit9696 已提交
683
          ExecutablePath,
684 685
          Kext->ImageData,
          Kext->ImageDataSize
V
vit9696 已提交
686 687
          );

688 689
        DEBUG ((
          EFI_ERROR (Status) ? DEBUG_WARN : DEBUG_INFO,
690
          "OC: Prelink injection %a (%a) - %r\n",
691
          BundlePath,
692
          Comment,
693 694
          Status
          ));
V
vit9696 已提交
695 696
      }

697 698 699 700 701 702 703 704
      DEBUG ((
        DEBUG_INFO,
        "OC: Prelink size %u kext offset %u reserved %u\n",
        Context.PrelinkedSize,
        Context.KextsFileOffset,
        ReservedExeSize
        ));

705 706
      ASSERT (Context.PrelinkedSize - Context.KextsFileOffset <= ReservedExeSize);

V
vit9696 已提交
707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734
      Status = PrelinkedInjectComplete (&Context);
      if (EFI_ERROR (Status)) {
        DEBUG ((DEBUG_WARN, "OC: Prelink insertion error - %r\n", Status));
      }
    } else {
      DEBUG ((DEBUG_WARN, "OC: Prelink inject prepare error - %r\n", Status));
    }

    *KernelSize = Context.PrelinkedSize;

    PrelinkedContextFree (&Context);
  }

  return Status;
}

STATIC
EFI_STATUS
EFIAPI
OcKernelFileOpen (
  IN  EFI_FILE_PROTOCOL       *This,
  OUT EFI_FILE_PROTOCOL       **NewHandle,
  IN  CHAR16                  *FileName,
  IN  UINT64                  OpenMode,
  IN  UINT64                  Attributes
  )
{
  EFI_STATUS         Status;
735
  BOOLEAN            Result;
V
vit9696 已提交
736 737 738 739 740 741 742
  UINT8              *Kernel;
  UINT32             KernelSize;
  UINT32             AllocatedSize;
  CHAR16             *FileNameCopy;
  EFI_FILE_PROTOCOL  *VirtualFileHandle;
  EFI_STATUS         PrelinkedStatus;
  EFI_TIME           ModificationTime;
743
  UINT32             DarwinVersion;
744 745 746 747
  UINT32             ReservedInfoSize;
  UINT32             ReservedExeSize;
  UINT32             LinkedExpansion;
  UINT32             ReservedFullSize;
V
vit9696 已提交
748

V
vit9696 已提交
749
  Status = SafeFileOpen (This, NewHandle, FileName, OpenMode, Attributes);
V
vit9696 已提交
750

751 752
  DEBUG ((
    DEBUG_VERBOSE,
753
    "OC: Opening file %s with %u mode gave - %r\n",
754 755 756 757 758
    FileName,
    (UINT32) OpenMode,
    Status
    ));

V
vit9696 已提交
759 760 761 762 763 764 765 766 767 768
  if (EFI_ERROR (Status)) {
    return Status;
  }

  //
  // boot.efi uses /S/L/K/kernel as is to determine valid filesystem.
  // Just skip it to speedup the boot process.
  // On 10.9 mach_kernel is loaded for manual linking aferwards, so we cannot skip it.
  //
  if (OpenMode == EFI_FILE_MODE_READ
769
    && OcStriStr (FileName, L"kernel") != NULL
V
vit9696 已提交
770 771
    && StrCmp (FileName, L"System\\Library\\Kernels\\kernel") != 0) {

772 773 774
    OcKernelLoadKextsAndReserve (
      mOcStorage,
      mOcConfiguration,
775 776
      &ReservedExeSize,
      &ReservedInfoSize
777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793
      );

    LinkedExpansion = KcGetSegmentFixupChainsSize (ReservedExeSize);
    if (LinkedExpansion == 0) {
      return EFI_UNSUPPORTED;
    }

    Result = OcOverflowTriAddU32 (
      ReservedInfoSize,
      ReservedExeSize,
      LinkedExpansion,
      &ReservedFullSize
      );
    if (Result) {
      return EFI_UNSUPPORTED;
    }

794
    DEBUG ((DEBUG_INFO, "OC: Trying XNU hook on %s\n", FileName));
V
vit9696 已提交
795 796 797 798 799
    Status = ReadAppleKernel (
      *NewHandle,
      &Kernel,
      &KernelSize,
      &AllocatedSize,
800
      ReservedFullSize
V
vit9696 已提交
801
      );
802
    DEBUG ((DEBUG_INFO, "OC: Result of XNU hook on %s is %r\n", FileName, Status));
V
vit9696 已提交
803 804

    if (!EFI_ERROR (Status)) {
805
      DarwinVersion = OcKernelReadDarwinVersion (Kernel, KernelSize);
806
      OcKernelApplyPatches (mOcConfiguration, DarwinVersion, NULL, Kernel, KernelSize);
V
vit9696 已提交
807 808 809

      PrelinkedStatus = OcKernelProcessPrelinked (
        mOcConfiguration,
810
        DarwinVersion,
V
vit9696 已提交
811 812
        Kernel,
        &KernelSize,
813 814 815
        AllocatedSize,
        LinkedExpansion,
        ReservedExeSize
V
vit9696 已提交
816 817
        );

818
      DEBUG ((DEBUG_INFO, "OC: Prelinked status - %r\n", PrelinkedStatus));
V
vit9696 已提交
819 820 821 822 823 824 825 826 827 828 829 830 831

      Status = GetFileModifcationTime (*NewHandle, &ModificationTime);
      if (EFI_ERROR (Status)) {
        ZeroMem (&ModificationTime, sizeof (ModificationTime));
      }

      (*NewHandle)->Close(*NewHandle);

      //
      // This was our file, yet firmware is dying.
      //
      FileNameCopy = AllocateCopyPool (StrSize (FileName), FileName);
      if (FileNameCopy == NULL) {
832
        DEBUG ((DEBUG_WARN, "OC: Failed to allocate kernel name (%a) copy\n", FileName));
V
vit9696 已提交
833 834 835 836 837 838
        FreePool (Kernel);
        return EFI_OUT_OF_RESOURCES;
      }

      Status = CreateVirtualFile (FileNameCopy, Kernel, KernelSize, &ModificationTime, &VirtualFileHandle);
      if (EFI_ERROR (Status)) {
839
        DEBUG ((DEBUG_WARN, "OC: Failed to virtualise kernel file (%a)\n", FileName));
V
vit9696 已提交
840 841 842 843 844 845 846 847 848 849 850 851 852
        FreePool (Kernel);
        FreePool (FileNameCopy);
        return EFI_OUT_OF_RESOURCES;
      }

      //
      // Return our handle.
      //
      *NewHandle = VirtualFileHandle;
      return EFI_SUCCESS;
    }
  }

853
  //
854
  // This is not Apple kernel, just return the original file.
855 856 857
  // We recurse the filtering to additionally catch com.apple.boot.[RPS] directories.
  //
  return CreateRealFile (*NewHandle, OcKernelFileOpen, TRUE, NewHandle);
V
vit9696 已提交
858 859 860 861 862
}

VOID
OcLoadKernelSupport (
  IN OC_STORAGE_CONTEXT  *Storage,
863 864
  IN OC_GLOBAL_CONFIG    *Config,
  IN OC_CPU_INFO         *CpuInfo
V
vit9696 已提交
865 866 867 868 869 870 871 872 873
  )
{
  EFI_STATUS  Status;

  Status = EnableVirtualFs (gBS, OcKernelFileOpen);

  if (!EFI_ERROR (Status)) {
    mOcStorage       = Storage;
    mOcConfiguration = Config;
874
    mOcCpuInfo       = CpuInfo;
V
vit9696 已提交
875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895
  } else {
    DEBUG ((DEBUG_ERROR, "OC: Failed to enable vfs - %r\n", Status));
  }
}

VOID
OcUnloadKernelSupport (
  VOID
  )
{
  EFI_STATUS  Status;

  if (mOcStorage != NULL) {
    Status = DisableVirtualFs (gBS);
    if (EFI_ERROR (Status)) {
      DEBUG ((DEBUG_ERROR, "OC: Failed to disable vfs - %r\n", Status));
    }
    mOcStorage       = NULL;
    mOcConfiguration = NULL;
  }
}