mirror of
https://github.com/acidanthera/OpenCorePkg.git
synced 2025-12-08 19:25:01 +00:00
1032 lines
32 KiB
C
1032 lines
32 KiB
C
/** @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.
|
|
|
|
**/
|
|
|
|
#include <Library/OcMainLib.h>
|
|
|
|
#include <Guid/AppleVariable.h>
|
|
#include <Guid/OcVariable.h>
|
|
#include <Guid/GlobalVariable.h>
|
|
|
|
#include <Library/BaseLib.h>
|
|
#include <Library/DevicePathLib.h>
|
|
#include <Library/MemoryAllocationLib.h>
|
|
#include <Library/OcAfterBootCompatLib.h>
|
|
#include <Library/OcAppleBootPolicyLib.h>
|
|
#include <Library/OcAppleEventLib.h>
|
|
#include <Library/OcAppleImageConversionLib.h>
|
|
#include <Library/OcAudioLib.h>
|
|
#include <Library/OcBootManagementLib.h>
|
|
#include <Library/OcInputLib.h>
|
|
#include <Library/OcApfsLib.h>
|
|
#include <Library/OcAppleImg4Lib.h>
|
|
#include <Library/OcAppleKeyMapLib.h>
|
|
#include <Library/OcAppleSecureBootLib.h>
|
|
#include <Library/OcAppleUserInterfaceThemeLib.h>
|
|
#include <Library/OcConsoleLib.h>
|
|
#include <Library/OcCpuLib.h>
|
|
#include <Library/OcDataHubLib.h>
|
|
#include <Library/OcLogAggregatorLib.h>
|
|
#include <Library/OcDebugLogLib.h>
|
|
#include <Library/OcDeviceMiscLib.h>
|
|
#include <Library/OcDevicePropertyLib.h>
|
|
#include <Library/OcDriverConnectionLib.h>
|
|
#include <Library/OcFirmwareVolumeLib.h>
|
|
#include <Library/OcHashServicesLib.h>
|
|
#include <Library/OcMiscLib.h>
|
|
#include <Library/OcMemoryLib.h>
|
|
#include <Library/OcRtcLib.h>
|
|
#include <Library/OcSmcLib.h>
|
|
#include <Library/OcOSInfoLib.h>
|
|
#include <Library/OcUnicodeCollationEngGenericLib.h>
|
|
#include <Library/OcVariableLib.h>
|
|
#include <Library/PrintLib.h>
|
|
#include <Library/UefiBootServicesTableLib.h>
|
|
#include <Library/UefiLib.h>
|
|
#include <Library/UefiRuntimeServicesTableLib.h>
|
|
|
|
#include <Protocol/DevicePath.h>
|
|
#include <Protocol/GraphicsOutput.h>
|
|
#include <Protocol/Security.h>
|
|
#include <Protocol/Security2.h>
|
|
#include <Protocol/SimplePointer.h>
|
|
|
|
#define OC_EXIT_BOOT_SERVICES_HANDLER_MAX 5
|
|
|
|
STATIC EFI_EVENT_NOTIFY mOcExitBootServicesHandlers[OC_EXIT_BOOT_SERVICES_HANDLER_MAX+1];
|
|
STATIC VOID *mOcExitBootServicesContexts[OC_EXIT_BOOT_SERVICES_HANDLER_MAX];
|
|
STATIC UINTN mOcExitBootServicesIndex;
|
|
|
|
VOID
|
|
OcScheduleExitBootServices (
|
|
IN EFI_EVENT_NOTIFY Handler,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
if (mOcExitBootServicesIndex + 1 == OC_EXIT_BOOT_SERVICES_HANDLER_MAX) {
|
|
ASSERT (FALSE);
|
|
return;
|
|
}
|
|
|
|
mOcExitBootServicesHandlers[mOcExitBootServicesIndex] = Handler;
|
|
mOcExitBootServicesContexts[mOcExitBootServicesIndex] = Context;
|
|
++mOcExitBootServicesIndex;
|
|
}
|
|
|
|
VOID
|
|
OcLoadDrivers (
|
|
IN OC_STORAGE_CONTEXT *Storage,
|
|
IN OC_GLOBAL_CONFIG *Config,
|
|
OUT EFI_HANDLE **DriversToConnect OPTIONAL,
|
|
IN BOOLEAN LoadEarly
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
VOID *Driver;
|
|
UINT32 DriverSize;
|
|
UINT32 Index;
|
|
CHAR16 DriverPath[OC_STORAGE_SAFE_PATH_MAX];
|
|
EFI_HANDLE ImageHandle;
|
|
EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
|
|
EFI_HANDLE *DriversToConnectIterator;
|
|
VOID *DriverBinding;
|
|
BOOLEAN SkipDriver;
|
|
OC_UEFI_DRIVER_ENTRY *DriverEntry;
|
|
CONST CHAR8 *DriverComment;
|
|
CHAR8 *DriverFileName;
|
|
CONST CHAR8 *DriverArguments;
|
|
CONST CHAR8 *UnescapedArguments;
|
|
|
|
ASSERT (!LoadEarly || DriversToConnect == NULL);
|
|
|
|
DriversToConnectIterator = NULL;
|
|
if (DriversToConnect != NULL) {
|
|
*DriversToConnect = NULL;
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "OC: Got %u drivers\n", Config->Uefi.Drivers.Count));
|
|
|
|
for (Index = 0; Index < Config->Uefi.Drivers.Count; ++Index) {
|
|
DriverEntry = Config->Uefi.Drivers.Values[Index];
|
|
DriverComment = OC_BLOB_GET (&DriverEntry->Comment);
|
|
DriverFileName = OC_BLOB_GET (&DriverEntry->Path);
|
|
DriverArguments = OC_BLOB_GET (&DriverEntry->Arguments);
|
|
|
|
SkipDriver = ( !DriverEntry->Enabled
|
|
|| (DriverFileName == NULL)
|
|
|| (DriverFileName[0] == '\0')
|
|
|| (LoadEarly != DriverEntry->LoadEarly)
|
|
);
|
|
|
|
//
|
|
// Avoid showing skipped lines at early load since this can be several
|
|
// lines and is basically duplicate info; this also avoids too much
|
|
// traffic in early log, which can be problematic on some machines.
|
|
//
|
|
if (!LoadEarly || !SkipDriver) {
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"OC: Driver %a at %u (%a) is %a\n",
|
|
DriverFileName,
|
|
Index,
|
|
DriverComment,
|
|
SkipDriver ? "skipped!" : "being loaded..."
|
|
));
|
|
}
|
|
|
|
//
|
|
// Skip disabled drivers.
|
|
//
|
|
if (SkipDriver) {
|
|
continue;
|
|
}
|
|
|
|
Status = OcUnicodeSafeSPrint (
|
|
DriverPath,
|
|
sizeof (DriverPath),
|
|
OPEN_CORE_UEFI_DRIVER_PATH "%a",
|
|
DriverFileName
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((
|
|
DEBUG_ERROR,
|
|
"OC: Driver %s%a does not fit path!\n",
|
|
OPEN_CORE_UEFI_DRIVER_PATH,
|
|
DriverFileName
|
|
));
|
|
continue;
|
|
}
|
|
|
|
Driver = OcStorageReadFileUnicode (Storage, DriverPath, &DriverSize);
|
|
if (Driver == NULL) {
|
|
DEBUG ((
|
|
DEBUG_ERROR,
|
|
"OC: Driver %a at %u cannot be found!\n",
|
|
DriverFileName,
|
|
Index
|
|
));
|
|
//
|
|
// TODO: This should cause security violation if configured!
|
|
//
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// TODO: Use AppleLoadedImage!!
|
|
//
|
|
ImageHandle = NULL;
|
|
Status = gBS->LoadImage (
|
|
FALSE,
|
|
gImageHandle,
|
|
NULL,
|
|
Driver,
|
|
DriverSize,
|
|
&ImageHandle
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((
|
|
DEBUG_ERROR,
|
|
"OC: Driver %a at %u cannot be loaded - %r!\n",
|
|
DriverFileName,
|
|
Index,
|
|
Status
|
|
));
|
|
FreePool (Driver);
|
|
continue;
|
|
}
|
|
|
|
if ((DriverArguments != NULL) && (DriverArguments[0] != '\0')) {
|
|
Status = gBS->HandleProtocol (
|
|
ImageHandle,
|
|
&gEfiLoadedImageProtocolGuid,
|
|
(VOID **)&LoadedImage
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((
|
|
DEBUG_ERROR,
|
|
"OC: Failed to locate loaded image for driver %a at %u - %r!\n",
|
|
DriverFileName,
|
|
Index,
|
|
Status
|
|
));
|
|
gBS->UnloadImage (ImageHandle);
|
|
FreePool (Driver);
|
|
continue;
|
|
}
|
|
|
|
UnescapedArguments = XmlUnescapeString (DriverArguments);
|
|
if (UnescapedArguments == NULL) {
|
|
DEBUG ((
|
|
DEBUG_ERROR,
|
|
"OC: Cannot unescape arguments for driver %a at %u\n",
|
|
DriverFileName,
|
|
Index
|
|
));
|
|
gBS->UnloadImage (ImageHandle);
|
|
FreePool (Driver);
|
|
continue;
|
|
}
|
|
|
|
if (!OcAppendArgumentsToLoadedImage (LoadedImage, &UnescapedArguments, 1, TRUE)) {
|
|
DEBUG ((
|
|
DEBUG_ERROR,
|
|
"OC: Unable to apply arguments to driver %a at %u - %r!\n",
|
|
DriverFileName,
|
|
Index,
|
|
Status
|
|
));
|
|
gBS->UnloadImage (ImageHandle);
|
|
FreePool (Driver);
|
|
FreePool ((CHAR8 *)UnescapedArguments);
|
|
continue;
|
|
}
|
|
|
|
FreePool ((CHAR8 *)UnescapedArguments);
|
|
}
|
|
|
|
Status = gBS->StartImage (
|
|
ImageHandle,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((
|
|
DEBUG_ERROR,
|
|
"OC: Driver %a at %u cannot be started - %r!\n",
|
|
DriverFileName,
|
|
Index,
|
|
Status
|
|
));
|
|
gBS->UnloadImage (ImageHandle);
|
|
}
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"OC: Driver %a at %u is successfully loaded!\n",
|
|
DriverFileName,
|
|
Index
|
|
));
|
|
|
|
if (DriversToConnect != NULL) {
|
|
Status = gBS->HandleProtocol (
|
|
ImageHandle,
|
|
&gEfiDriverBindingProtocolGuid,
|
|
(VOID **)&DriverBinding
|
|
);
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
if (*DriversToConnect == NULL) {
|
|
//
|
|
// Allocate enough entries for the drivers to connect.
|
|
//
|
|
*DriversToConnect = AllocatePool (
|
|
(Config->Uefi.Drivers.Count + 1 - Index) * sizeof (**DriversToConnect)
|
|
);
|
|
|
|
if (*DriversToConnect != NULL) {
|
|
DriversToConnectIterator = *DriversToConnect;
|
|
} else {
|
|
DEBUG ((DEBUG_ERROR, "OC: Failed to allocate memory for drivers to connect\n"));
|
|
FreePool (Driver);
|
|
return;
|
|
}
|
|
}
|
|
|
|
*DriversToConnectIterator = ImageHandle;
|
|
++DriversToConnectIterator;
|
|
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"OC: Driver %a at %u needs connection.\n",
|
|
DriverFileName,
|
|
Index
|
|
));
|
|
}
|
|
}
|
|
}
|
|
|
|
FreePool (Driver);
|
|
}
|
|
|
|
//
|
|
// Driver connection list should be null-terminated.
|
|
//
|
|
if (DriversToConnectIterator != NULL) {
|
|
*DriversToConnectIterator = NULL;
|
|
}
|
|
}
|
|
|
|
STATIC
|
|
VOID
|
|
EFIAPI
|
|
OcExitBootServicesHandler (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
OC_GLOBAL_CONFIG *Config;
|
|
|
|
Config = (OC_GLOBAL_CONFIG *)Context;
|
|
|
|
//
|
|
// Printing from ExitBootServices is dangerous, as it may cause
|
|
// memory reallocation, which can make ExitBootServices fail.
|
|
// Only do that on error, which is not expected.
|
|
//
|
|
|
|
if (Config->Uefi.Quirks.ReleaseUsbOwnership) {
|
|
Status = ReleaseUsbOwnership ();
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_INFO, "OC: ReleaseUsbOwnership - %r\n", Status));
|
|
}
|
|
}
|
|
|
|
//
|
|
// FIXME: This is a very ugly hack for (at least) ASUS Z87-Pro.
|
|
// This board results in still waiting for root devices due to firmware
|
|
// performing some timer(?) actions in parallel to ExitBootServices.
|
|
// Some day we should figure out what exactly happens there.
|
|
// It is not the first time I face this, check AptioInputFix timer code:
|
|
// https://github.com/acidanthera/AptioFixPkg/blob/e54c185/Platform/AptioInputFix/Timer/AIT.c#L72-L73
|
|
// Roughly 5 seconds is good enough.
|
|
//
|
|
if (Config->Uefi.Quirks.ExitBootServicesDelay > 0) {
|
|
gBS->Stall (Config->Uefi.Quirks.ExitBootServicesDelay);
|
|
}
|
|
}
|
|
|
|
STATIC
|
|
VOID
|
|
OcReinstallProtocols (
|
|
IN OC_GLOBAL_CONFIG *Config
|
|
)
|
|
{
|
|
CONST CHAR8 *AppleEventMode;
|
|
BOOLEAN InstallAppleEvent;
|
|
BOOLEAN OverrideAppleEvent;
|
|
|
|
if (OcAudioInstallProtocols (
|
|
Config->Uefi.ProtocolOverrides.AppleAudio,
|
|
Config->Uefi.Audio.DisconnectHda
|
|
) == NULL)
|
|
{
|
|
DEBUG ((DEBUG_INFO, "OC: Disabling audio in favour of firmware implementation\n"));
|
|
}
|
|
|
|
if (OcAppleBootPolicyInstallProtocol (Config->Uefi.ProtocolOverrides.AppleBootPolicy) == NULL) {
|
|
DEBUG ((DEBUG_INFO, "OC: Failed to install boot policy protocol\n"));
|
|
}
|
|
|
|
if (OcDataHubInstallProtocol (Config->Uefi.ProtocolOverrides.DataHub) == NULL) {
|
|
DEBUG ((DEBUG_INFO, "OC: Failed to install data hub protocol\n"));
|
|
}
|
|
|
|
if (OcDevicePathPropertyInstallProtocol (Config->Uefi.ProtocolOverrides.DeviceProperties) == NULL) {
|
|
DEBUG ((DEBUG_INFO, "OC: Failed to install device properties protocol\n"));
|
|
}
|
|
|
|
if (OcAppleImageConversionInstallProtocol (Config->Uefi.ProtocolOverrides.AppleImageConversion) == NULL) {
|
|
DEBUG ((DEBUG_INFO, "OC: Failed to install image conversion protocol\n"));
|
|
}
|
|
|
|
if (OcAppleDebugLogInstallProtocol (Config->Uefi.ProtocolOverrides.AppleDebugLog) == NULL) {
|
|
DEBUG ((DEBUG_INFO, "OC: Failed to install debug log protocol\n"));
|
|
}
|
|
|
|
if (OcSmcIoInstallProtocol (Config->Uefi.ProtocolOverrides.AppleSmcIo, Config->Misc.Security.AuthRestart) == NULL) {
|
|
DEBUG ((DEBUG_INFO, "OC: Failed to install smc i/o protocol\n"));
|
|
}
|
|
|
|
if (OcAppleUserInterfaceThemeInstallProtocol (Config->Uefi.ProtocolOverrides.AppleUserInterfaceTheme) == NULL) {
|
|
DEBUG ((DEBUG_INFO, "OC: Failed to install user interface theme protocol\n"));
|
|
}
|
|
|
|
if (OcUnicodeCollationEngInstallProtocol (Config->Uefi.ProtocolOverrides.UnicodeCollation) == NULL) {
|
|
DEBUG ((DEBUG_INFO, "OC: Failed to install unicode collation protocol\n"));
|
|
}
|
|
|
|
if (OcHashServicesInstallProtocol (Config->Uefi.ProtocolOverrides.HashServices) == NULL) {
|
|
DEBUG ((DEBUG_INFO, "OC: Failed to install hash services protocol\n"));
|
|
}
|
|
|
|
if (OcAppleKeyMapInstallProtocols (Config->Uefi.ProtocolOverrides.AppleKeyMap) == NULL) {
|
|
DEBUG ((DEBUG_INFO, "OC: Failed to install key map protocols\n"));
|
|
}
|
|
|
|
InstallAppleEvent = TRUE;
|
|
OverrideAppleEvent = FALSE;
|
|
|
|
AppleEventMode = OC_BLOB_GET (&Config->Uefi.AppleInput.AppleEvent);
|
|
|
|
if (AsciiStrCmp (AppleEventMode, "Auto") == 0) {
|
|
} else if (AsciiStrCmp (AppleEventMode, "OEM") == 0) {
|
|
InstallAppleEvent = FALSE;
|
|
} else if (AsciiStrCmp (AppleEventMode, "Builtin") == 0) {
|
|
OverrideAppleEvent = TRUE;
|
|
} else {
|
|
DEBUG ((DEBUG_INFO, "OC: Invalid AppleInput AppleEvent setting %a, using Auto\n", AppleEventMode));
|
|
}
|
|
|
|
if ( (OcAppleEventInstallProtocol (
|
|
InstallAppleEvent,
|
|
OverrideAppleEvent,
|
|
Config->Uefi.AppleInput.CustomDelays,
|
|
Config->Uefi.AppleInput.KeyInitialDelay,
|
|
Config->Uefi.AppleInput.KeySubsequentDelay,
|
|
Config->Uefi.AppleInput.GraphicsInputMirroring,
|
|
Config->Uefi.AppleInput.PointerPollMin,
|
|
Config->Uefi.AppleInput.PointerPollMax,
|
|
Config->Uefi.AppleInput.PointerPollMask,
|
|
Config->Uefi.AppleInput.PointerSpeedDiv,
|
|
Config->Uefi.AppleInput.PointerSpeedMul
|
|
) == NULL)
|
|
&& InstallAppleEvent)
|
|
{
|
|
DEBUG ((DEBUG_INFO, "OC: Failed to install apple event protocol\n"));
|
|
}
|
|
|
|
if (OcFirmwareVolumeInstallProtocol (Config->Uefi.ProtocolOverrides.FirmwareVolume) == NULL) {
|
|
DEBUG ((DEBUG_INFO, "OC: Failed to install firmware volume protocol\n"));
|
|
}
|
|
|
|
if (OcOSInfoInstallProtocol (Config->Uefi.ProtocolOverrides.OSInfo) == NULL) {
|
|
DEBUG ((DEBUG_INFO, "OC: Failed to install os info protocol\n"));
|
|
}
|
|
|
|
if (OcAppleRtcRamInstallProtocol (Config->Uefi.ProtocolOverrides.AppleRtcRam) == NULL) {
|
|
DEBUG ((DEBUG_INFO, "OC: Failed to install rtc ram protocol\n"));
|
|
}
|
|
|
|
if (OcAppleFbInfoInstallProtocol (Config->Uefi.ProtocolOverrides.AppleFramebufferInfo) == NULL) {
|
|
DEBUG ((DEBUG_INFO, "OC: Failed to install fb info protocol\n"));
|
|
}
|
|
|
|
if (OcAppleEg2InfoInstallProtocol (Config->Uefi.ProtocolOverrides.AppleEg2Info) == NULL) {
|
|
DEBUG ((DEBUG_INFO, "OC: Failed to install eg2 info protocol\n"));
|
|
}
|
|
}
|
|
|
|
STATIC
|
|
VOID
|
|
OcLoadAppleSecureBoot (
|
|
IN OC_GLOBAL_CONFIG *Config,
|
|
IN OC_CPU_INFO *CpuInfo
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
APPLE_SECURE_BOOT_PROTOCOL *SecureBoot;
|
|
CONST CHAR8 *SecureBootModel;
|
|
CONST CHAR8 *RealSecureBootModel;
|
|
CONST CHAR8 *DmgLoading;
|
|
UINT8 SecureBootPolicy;
|
|
|
|
SecureBootModel = OC_BLOB_GET (&Config->Misc.Security.SecureBootModel);
|
|
if ((AsciiStrCmp (SecureBootModel, OC_SB_MODEL_DEFAULT) == 0) || (SecureBootModel[0] == '\0')) {
|
|
SecureBootModel = OcGetDefaultSecureBootModel (Config, CpuInfo);
|
|
}
|
|
|
|
RealSecureBootModel = OcAppleImg4GetHardwareModel (SecureBootModel);
|
|
|
|
if (AsciiStrCmp (SecureBootModel, OC_SB_MODEL_DISABLED) == 0) {
|
|
SecureBootPolicy = AppleImg4SbModeDisabled;
|
|
} else if ( (Config->Misc.Security.ApECID != 0)
|
|
&& ( (RealSecureBootModel == NULL)
|
|
|| (AsciiStrCmp (RealSecureBootModel, OC_SB_MODEL_LEGACY) != 0)))
|
|
{
|
|
//
|
|
// Note, for x86legacy it is always medium policy.
|
|
//
|
|
SecureBootPolicy = AppleImg4SbModeFull;
|
|
} else {
|
|
SecureBootPolicy = AppleImg4SbModeMedium;
|
|
}
|
|
|
|
//
|
|
// We blindly trust DMG contents after signature verification
|
|
// essentially skipping secure boot in this case.
|
|
// Do not allow enabling one but not the other.
|
|
//
|
|
if (SecureBootPolicy != AppleImg4SbModeDisabled) {
|
|
DmgLoading = OC_BLOB_GET (&Config->Misc.Security.DmgLoading);
|
|
//
|
|
// Check against all valid values in case more are added.
|
|
//
|
|
if ( (AsciiStrCmp (DmgLoading, "Signed") != 0)
|
|
&& (AsciiStrCmp (DmgLoading, "Disabled") != 0)
|
|
&& (DmgLoading[0] != '\0'))
|
|
{
|
|
DEBUG ((DEBUG_ERROR, "OC: Cannot use Secure Boot with Any DmgLoading!\n"));
|
|
CpuDeadLoop ();
|
|
return;
|
|
}
|
|
}
|
|
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"OC: Loading Apple Secure Boot with %a (level %u)\n",
|
|
SecureBootModel,
|
|
SecureBootPolicy
|
|
));
|
|
|
|
if (SecureBootPolicy != AppleImg4SbModeDisabled) {
|
|
if (RealSecureBootModel == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "OC: Failed to find SB model %a\n", SecureBootModel));
|
|
return;
|
|
}
|
|
|
|
//
|
|
// This is what Apple does at least.
|
|
// I believe no ECID is invalid for macOS 12.
|
|
//
|
|
if ( (AsciiStrCmp (RealSecureBootModel, OC_SB_MODEL_LEGACY) == 0)
|
|
&& (Config->Misc.Security.ApECID == 0))
|
|
{
|
|
DEBUG ((DEBUG_INFO, "OC: Discovered x86legacy with zero ECID, using system-id\n"));
|
|
OcGetLegacySecureBootECID (Config, &Config->Misc.Security.ApECID);
|
|
}
|
|
|
|
Status = OcAppleImg4BootstrapValues (RealSecureBootModel, Config->Misc.Security.ApECID);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "OC: Failed to bootstrap IMG4 NVRAM values - %r\n", Status));
|
|
return;
|
|
}
|
|
|
|
Status = OcAppleSecureBootBootstrapValues (RealSecureBootModel, Config->Misc.Security.ApECID);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "OC: Failed to bootstrap SB NVRAM values - %r\n", Status));
|
|
return;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Provide protocols even in disabled state.
|
|
//
|
|
if (OcAppleImg4VerificationInstallProtocol (Config->Uefi.ProtocolOverrides.AppleImg4Verification) == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "OC: Failed to install im4m protocol\n"));
|
|
return;
|
|
}
|
|
|
|
//
|
|
// TODO: Do we need to make Windows policy configurable?
|
|
//
|
|
SecureBoot = OcAppleSecureBootInstallProtocol (
|
|
Config->Uefi.ProtocolOverrides.AppleSecureBoot,
|
|
SecureBootPolicy,
|
|
0,
|
|
FALSE
|
|
);
|
|
if (SecureBoot == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "OC: Failed to install secure boot protocol\n"));
|
|
}
|
|
}
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
OcSecurityFileAuthentication (
|
|
IN CONST EFI_SECURITY_ARCH_PROTOCOL *This,
|
|
IN UINT32 AuthenticationStatus,
|
|
IN CONST EFI_DEVICE_PATH_PROTOCOL *File
|
|
)
|
|
{
|
|
DEBUG ((DEBUG_VERBOSE, "OC: Security V1 %u\n", AuthenticationStatus));
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
OcSecurity2FileAuthentication (
|
|
IN CONST EFI_SECURITY2_ARCH_PROTOCOL *This,
|
|
IN CONST EFI_DEVICE_PATH_PROTOCOL *File OPTIONAL,
|
|
IN VOID *FileBuffer,
|
|
IN UINTN FileSize,
|
|
IN BOOLEAN BootPolicy
|
|
)
|
|
{
|
|
DEBUG ((DEBUG_VERBOSE, "OC: Security V2 %u\n", BootPolicy));
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
STATIC
|
|
VOID
|
|
OcInstallPermissiveSecurityPolicy (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_SECURITY_ARCH_PROTOCOL *Security;
|
|
EFI_SECURITY2_ARCH_PROTOCOL *Security2;
|
|
|
|
DEBUG ((DEBUG_INFO, "OC: Installing DISABLING secure boot policy overrides\n"));
|
|
|
|
Status = gBS->LocateProtocol (
|
|
&gEfiSecurityArchProtocolGuid,
|
|
NULL,
|
|
(VOID **)&Security
|
|
);
|
|
|
|
DEBUG ((DEBUG_INFO, "OC: Security arch protocol - %r\n", Status));
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
Security->FileAuthenticationState = OcSecurityFileAuthentication;
|
|
}
|
|
|
|
Status = gBS->LocateProtocol (
|
|
&gEfiSecurity2ArchProtocolGuid,
|
|
NULL,
|
|
(VOID **)&Security2
|
|
);
|
|
|
|
DEBUG ((DEBUG_INFO, "OC: Security2 arch protocol - %r\n", Status));
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
Security2->FileAuthentication = OcSecurity2FileAuthentication;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
OcLoadBooterUefiSupport (
|
|
IN OC_GLOBAL_CONFIG *Config,
|
|
IN OC_CPU_INFO *CpuInfo,
|
|
IN UINT8 *Signature
|
|
)
|
|
{
|
|
OC_ABC_SETTINGS AbcSettings;
|
|
UINT32 Index;
|
|
UINT32 NextIndex;
|
|
OC_BOOTER_PATCH_ENTRY *UserPatch;
|
|
OC_BOOTER_PATCH *Patch;
|
|
|
|
ZeroMem (&AbcSettings, sizeof (AbcSettings));
|
|
|
|
AbcSettings.AvoidRuntimeDefrag = Config->Booter.Quirks.AvoidRuntimeDefrag;
|
|
AbcSettings.DevirtualiseMmio = Config->Booter.Quirks.DevirtualiseMmio;
|
|
AbcSettings.DisableSingleUser = Config->Booter.Quirks.DisableSingleUser;
|
|
AbcSettings.DisableVariableWrite = Config->Booter.Quirks.DisableVariableWrite;
|
|
AbcSettings.ProtectSecureBoot = Config->Booter.Quirks.ProtectSecureBoot;
|
|
AbcSettings.DiscardHibernateMap = Config->Booter.Quirks.DiscardHibernateMap;
|
|
AbcSettings.AllowRelocationBlock = Config->Booter.Quirks.AllowRelocationBlock;
|
|
AbcSettings.EnableSafeModeSlide = Config->Booter.Quirks.EnableSafeModeSlide;
|
|
AbcSettings.EnableWriteUnprotector = Config->Booter.Quirks.EnableWriteUnprotector;
|
|
AbcSettings.ForceExitBootServices = Config->Booter.Quirks.ForceExitBootServices;
|
|
AbcSettings.ForceBooterSignature = Config->Booter.Quirks.ForceBooterSignature;
|
|
CopyMem (AbcSettings.BooterSignature, Signature, sizeof (AbcSettings.BooterSignature));
|
|
AbcSettings.ProtectMemoryRegions = Config->Booter.Quirks.ProtectMemoryRegions;
|
|
AbcSettings.ProvideCustomSlide = Config->Booter.Quirks.ProvideCustomSlide;
|
|
AbcSettings.ProvideMaxSlide = Config->Booter.Quirks.ProvideMaxSlide;
|
|
AbcSettings.ProtectUefiServices = Config->Booter.Quirks.ProtectUefiServices;
|
|
AbcSettings.RebuildAppleMemoryMap = Config->Booter.Quirks.RebuildAppleMemoryMap;
|
|
AbcSettings.ResizeAppleGpuBars = Config->Booter.Quirks.ResizeAppleGpuBars;
|
|
AbcSettings.SetupVirtualMap = Config->Booter.Quirks.SetupVirtualMap;
|
|
AbcSettings.SignalAppleOS = Config->Booter.Quirks.SignalAppleOS;
|
|
AbcSettings.SyncRuntimePermissions = Config->Booter.Quirks.SyncRuntimePermissions;
|
|
|
|
//
|
|
// Handle MmioWhitelist patches.
|
|
//
|
|
if (AbcSettings.DevirtualiseMmio && (Config->Booter.MmioWhitelist.Count > 0)) {
|
|
AbcSettings.MmioWhitelist = AllocatePool (
|
|
Config->Booter.MmioWhitelist.Count * sizeof (AbcSettings.MmioWhitelist[0])
|
|
);
|
|
|
|
if (AbcSettings.MmioWhitelist != NULL) {
|
|
NextIndex = 0;
|
|
for (Index = 0; Index < Config->Booter.MmioWhitelist.Count; ++Index) {
|
|
if (Config->Booter.MmioWhitelist.Values[Index]->Enabled) {
|
|
AbcSettings.MmioWhitelist[NextIndex] = Config->Booter.MmioWhitelist.Values[Index]->Address;
|
|
++NextIndex;
|
|
}
|
|
}
|
|
|
|
AbcSettings.MmioWhitelistSize = NextIndex;
|
|
} else {
|
|
DEBUG ((
|
|
DEBUG_ERROR,
|
|
"OC: Failed to allocate %u slots for mmio addresses\n",
|
|
(UINT32)Config->Booter.MmioWhitelist.Count
|
|
));
|
|
}
|
|
}
|
|
|
|
//
|
|
// Handle customised booter patches.
|
|
//
|
|
if (Config->Booter.Patch.Count > 0) {
|
|
AbcSettings.BooterPatches = AllocateZeroPool (
|
|
Config->Booter.Patch.Count * sizeof (AbcSettings.BooterPatches[0])
|
|
);
|
|
|
|
if (AbcSettings.BooterPatches != NULL) {
|
|
NextIndex = 0;
|
|
for (Index = 0; Index < Config->Booter.Patch.Count; ++Index) {
|
|
Patch = &AbcSettings.BooterPatches[NextIndex];
|
|
UserPatch = Config->Booter.Patch.Values[Index];
|
|
|
|
if (!UserPatch->Enabled) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Ignore patch if:
|
|
// - There is nothing to replace.
|
|
// - Find and replace mismatch in size.
|
|
// - Mask and ReplaceMask mismatch in size when are available.
|
|
//
|
|
if ( (UserPatch->Replace.Size == 0)
|
|
|| (UserPatch->Find.Size != UserPatch->Replace.Size)
|
|
|| ((UserPatch->Mask.Size > 0) && (UserPatch->Find.Size != UserPatch->Mask.Size))
|
|
|| ((UserPatch->ReplaceMask.Size > 0) && (UserPatch->Find.Size != UserPatch->ReplaceMask.Size)))
|
|
{
|
|
DEBUG ((DEBUG_ERROR, "OC: Booter patch %u is borked\n", Index));
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Also, ignore patch on mismatched architecture.
|
|
//
|
|
Patch->Arch = OC_BLOB_GET (&UserPatch->Arch);
|
|
if ((Patch->Arch[0] != '\0') && (AsciiStrCmp (Patch->Arch, "Any") != 0)) {
|
|
#if defined (MDE_CPU_X64)
|
|
if (AsciiStrCmp (Patch->Arch, "x86_64") != 0) {
|
|
continue;
|
|
}
|
|
|
|
#elif defined (MDE_CPU_IA32)
|
|
if (AsciiStrCmp (Patch->Arch, "i386") != 0) {
|
|
continue;
|
|
}
|
|
|
|
#else
|
|
#error "Unsupported architecture"
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// Here we simply receive Identifier from user,
|
|
// and it will be parsed by the internal patch function.
|
|
//
|
|
Patch->Identifier = OC_BLOB_GET (&UserPatch->Identifier);
|
|
|
|
Patch->Find = OC_BLOB_GET (&UserPatch->Find);
|
|
Patch->Replace = OC_BLOB_GET (&UserPatch->Replace);
|
|
|
|
Patch->Comment = OC_BLOB_GET (&UserPatch->Comment);
|
|
|
|
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;
|
|
|
|
++NextIndex;
|
|
}
|
|
|
|
AbcSettings.BooterPatchesSize = NextIndex;
|
|
} else {
|
|
DEBUG ((
|
|
DEBUG_ERROR,
|
|
"OC: Failed to allocate %u slots for user booter patches\n",
|
|
(UINT32)Config->Booter.Patch.Count
|
|
));
|
|
}
|
|
}
|
|
|
|
AbcSettings.ExitBootServicesHandlers = mOcExitBootServicesHandlers;
|
|
AbcSettings.ExitBootServicesHandlerContexts = mOcExitBootServicesContexts;
|
|
|
|
OcAbcInitialize (&AbcSettings, CpuInfo);
|
|
}
|
|
|
|
VOID
|
|
OcReserveMemory (
|
|
IN OC_GLOBAL_CONFIG *Config
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN Index;
|
|
EFI_PHYSICAL_ADDRESS ReservedAddress;
|
|
EFI_MEMORY_TYPE RsvdMemoryType;
|
|
CHAR8 *RsvdMemoryTypeStr;
|
|
|
|
for (Index = 0; Index < Config->Uefi.ReservedMemory.Count; ++Index) {
|
|
if (!Config->Uefi.ReservedMemory.Values[Index]->Enabled) {
|
|
continue;
|
|
}
|
|
|
|
if ( ((Config->Uefi.ReservedMemory.Values[Index]->Address & (BASE_4KB - 1)) != 0)
|
|
|| ((Config->Uefi.ReservedMemory.Values[Index]->Size & (BASE_4KB - 1)) != 0))
|
|
{
|
|
Status = EFI_INVALID_PARAMETER;
|
|
} else {
|
|
RsvdMemoryTypeStr = OC_BLOB_GET (&Config->Uefi.ReservedMemory.Values[Index]->Type);
|
|
|
|
Status = OcDescToMemoryType (RsvdMemoryTypeStr, &RsvdMemoryType);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_INFO, "OC: Invalid ReservedMemory Type: %a\n", RsvdMemoryTypeStr));
|
|
RsvdMemoryType = EfiReservedMemoryType;
|
|
}
|
|
|
|
ReservedAddress = Config->Uefi.ReservedMemory.Values[Index]->Address;
|
|
Status = gBS->AllocatePages (
|
|
AllocateAddress,
|
|
RsvdMemoryType,
|
|
(UINTN)EFI_SIZE_TO_PAGES (Config->Uefi.ReservedMemory.Values[Index]->Size),
|
|
&ReservedAddress
|
|
);
|
|
}
|
|
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"OC: Reserving region %Lx of %Lx size - %r\n",
|
|
Config->Uefi.ReservedMemory.Values[Index]->Address,
|
|
Config->Uefi.ReservedMemory.Values[Index]->Size,
|
|
Status
|
|
));
|
|
}
|
|
}
|
|
|
|
VOID
|
|
OcLoadUefiSupport (
|
|
IN OC_STORAGE_CONTEXT *Storage,
|
|
IN OC_GLOBAL_CONFIG *Config,
|
|
IN OC_CPU_INFO *CpuInfo,
|
|
IN UINT8 *Signature
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_HANDLE *DriversToConnect;
|
|
EFI_HANDLE *HandleBuffer;
|
|
UINTN HandleCount;
|
|
EFI_EVENT Event;
|
|
BOOLEAN AccelEnabled;
|
|
|
|
OcReinstallProtocols (Config);
|
|
|
|
OcImageLoaderInit (Config->Booter.Quirks.ProtectUefiServices);
|
|
|
|
OcLoadAppleSecureBoot (Config, CpuInfo);
|
|
|
|
OcLoadUefiInputSupport (Config);
|
|
|
|
//
|
|
// Setup Apple bootloader specific UEFI features.
|
|
//
|
|
OcLoadBooterUefiSupport (Config, CpuInfo, Signature);
|
|
|
|
if (Config->Uefi.Quirks.ActivateHpetSupport) {
|
|
ActivateHpetSupport ();
|
|
}
|
|
|
|
if (Config->Uefi.Quirks.IgnoreInvalidFlexRatio) {
|
|
OcCpuCorrectFlexRatio (CpuInfo);
|
|
}
|
|
|
|
if (Config->Uefi.Quirks.EnableVmx) {
|
|
Status = OcCpuEnableVmx ();
|
|
DEBUG ((EFI_ERROR (Status) ? DEBUG_WARN : DEBUG_INFO, "OC: Enable VMX - %r\n", Status));
|
|
}
|
|
|
|
if (Config->Uefi.Quirks.TscSyncTimeout > 0) {
|
|
OcCpuCorrectTscSync (CpuInfo, Config->Uefi.Quirks.TscSyncTimeout);
|
|
}
|
|
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"OC: RequestBootVarRouting %d\n",
|
|
Config->Uefi.Quirks.RequestBootVarRouting
|
|
));
|
|
|
|
//
|
|
// Inform platform support whether we want Boot#### routing or not.
|
|
//
|
|
OcSetSystemVariable (
|
|
OC_BOOT_REDIRECT_VARIABLE_NAME,
|
|
OPEN_CORE_INT_NVRAM_ATTR,
|
|
sizeof (Config->Uefi.Quirks.RequestBootVarRouting),
|
|
&Config->Uefi.Quirks.RequestBootVarRouting,
|
|
NULL
|
|
);
|
|
|
|
if (Config->Uefi.Quirks.UnblockFsConnect) {
|
|
OcUnblockUnmountedPartitions ();
|
|
}
|
|
|
|
if (Config->Uefi.Quirks.DisableSecurityPolicy) {
|
|
OcInstallPermissiveSecurityPolicy ();
|
|
}
|
|
|
|
if (Config->Uefi.Quirks.ForgeUefiSupport) {
|
|
OcForgeUefiSupport ();
|
|
}
|
|
|
|
if (Config->Uefi.Quirks.ReloadOptionRoms) {
|
|
OcReloadOptionRoms ();
|
|
}
|
|
|
|
if (Config->Uefi.Quirks.EnableVectorAcceleration) {
|
|
AccelEnabled = TryEnableAccel ();
|
|
DEBUG ((DEBUG_INFO, "OC: AVX enabled - %u\n", AccelEnabled));
|
|
}
|
|
|
|
if ( (Config->Uefi.Quirks.ResizeGpuBars >= 0)
|
|
&& (Config->Uefi.Quirks.ResizeGpuBars < PciBarTotal))
|
|
{
|
|
DEBUG ((DEBUG_INFO, "OC: Increasing GPU BARs to %d\n", Config->Uefi.Quirks.ResizeGpuBars));
|
|
ResizeGpuBars (Config->Uefi.Quirks.ResizeGpuBars, TRUE);
|
|
}
|
|
|
|
OcMiscUefiQuirksLoaded (Config);
|
|
|
|
//
|
|
// Reserve requested memory regions
|
|
//
|
|
OcReserveMemory (Config);
|
|
|
|
if (Config->Uefi.ConnectDrivers) {
|
|
OcLoadDrivers (Storage, Config, &DriversToConnect, FALSE);
|
|
DEBUG ((DEBUG_INFO, "OC: Connecting drivers...\n"));
|
|
if (DriversToConnect != NULL) {
|
|
OcRegisterDriversToHighestPriority (DriversToConnect);
|
|
//
|
|
// DriversToConnect is not freed as it is owned by OcRegisterDriversToHighestPriority.
|
|
//
|
|
}
|
|
|
|
if (Config->Uefi.Output.ReconnectGraphicsOnConnect) {
|
|
DEBUG ((DEBUG_INFO, "OC: Disconnecting graphics drivers...\n"));
|
|
OcDisconnectGraphicsDrivers ();
|
|
DEBUG ((DEBUG_INFO, "OC: Disconnecting graphics drivers done...\n"));
|
|
}
|
|
|
|
OcConnectDrivers ();
|
|
DEBUG ((DEBUG_INFO, "OC: Connecting drivers done...\n"));
|
|
} else {
|
|
OcLoadDrivers (Storage, Config, NULL, FALSE);
|
|
}
|
|
|
|
DEBUG_CODE_BEGIN ();
|
|
HandleCount = 0;
|
|
HandleBuffer = NULL;
|
|
Status = gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiSimplePointerProtocolGuid,
|
|
NULL,
|
|
&HandleCount,
|
|
&HandleBuffer
|
|
);
|
|
DEBUG ((DEBUG_INFO, "OC: Found %u pointer devices - %r\n", HandleCount, Status));
|
|
if (!EFI_ERROR (Status)) {
|
|
FreePool (HandleBuffer);
|
|
}
|
|
|
|
DEBUG_CODE_END ();
|
|
|
|
if (Config->Uefi.Apfs.EnableJumpstart) {
|
|
OcApfsConfigure (
|
|
Config->Uefi.Apfs.MinVersion,
|
|
Config->Uefi.Apfs.MinDate,
|
|
Config->Misc.Security.ScanPolicy,
|
|
Config->Uefi.Apfs.GlobalConnect,
|
|
Config->Uefi.Quirks.UnblockFsConnect,
|
|
Config->Uefi.Apfs.HideVerbose
|
|
);
|
|
|
|
OcApfsConnectDevices (
|
|
Config->Uefi.Apfs.JumpstartHotPlug
|
|
);
|
|
}
|
|
|
|
OcLoadUefiOutputSupport (Config);
|
|
|
|
OcLoadUefiAudioSupport (Storage, Config);
|
|
|
|
gBS->CreateEvent (
|
|
EVT_SIGNAL_EXIT_BOOT_SERVICES,
|
|
TPL_CALLBACK,
|
|
OcExitBootServicesHandler,
|
|
Config,
|
|
&Event
|
|
);
|
|
}
|