提交 f6bf1f2d 编写于 作者: M Mike Beaton

EnableGop: Provide standalone GOP driver for EFI-era Macs

上级 b07843fe
......@@ -6,6 +6,8 @@ OpenCore Changelog
- Added Linux support to legacy boot BootInstall script
- Updated builtin firmware versions for SMBIOS and the rest
- Fixed incomplete console mode initialisation when started in graphics mode
- Provided additional UEFI forge mode, for use in firmware drivers
- Implemented firmware driver enabling pre-OpenCore graphics on non-natively supported GPUs on EFI-era Macs
#### v0.8.8
- Updated underlying EDK II package to edk2-stable202211
......
......@@ -3723,10 +3723,15 @@ the default boot entry choice will remain changed until the next manual reconfig
\emph{Note 3}: On Macs with problematic GOP, it may be difficult to re-bless OpenCore if its bless status
is lost. The \texttt{BootKicker} utility can be used to work around this problem, if set up as a Tool
in OpenCore (e.g. on a CDROM) with \texttt{FullNvramAccess} enabled. It will launch the Apple picker,
which allows selection of an item to boot next (with \texttt{Enter}), or next and subsequently, i.e.
as the blessed entry (with \texttt{CTRL+Enter}), as normal. After the selection is made, the system
will reboot and the chosen entry will be booted.
in OpenCore with \texttt{FullNvramAccess} enabled. It will launch the Apple picker,
which allows selection of an item to boot next (with \texttt{Enter}), or next and from then on until
the next change (with \texttt{CTRL+Enter}). Note that after the selection is made, the system
\emph{will reboot} before the chosen entry is booted. While this behaviour might seem surprising,
it can be used both to switch which OpenCore installation is blessed, with \texttt{CTRL+Enter},
e.g. from a recovery OpenCore installation on CD (selected with the \texttt{C} key on boot) back
to the main installion of OpenCore on the hard drive, if this is lost after an NVRAM reset. It can
also be used, even when the native picker cannot be shown normally (unsupported GPU), to do a one-shot
boot without OpenCore, e.g. to another OS or tool, or to an earlier version of macOS.
\item
\texttt{PickerVariant}\\
......@@ -6355,6 +6360,11 @@ even cause permanent firmware damage. Some of the known drivers are listed below
any available writeable filesystem upon pressing \texttt{F10}.
This is a modified version of \href{https://github.com/LongSoft/CrScreenshotDxe}{\texttt{CrScreenshotDxe}}
driver by \href{https://github.com/NikolajSchlej}{Nikolaj Schlej}. \\
\href{https://github.com/acidanthera/OpenCorePkg}{\texttt{EnableGop\{Direct\}}}\textbf{*}
& Early beta release firmware-embeddable driver providing pre-OpenCore non-native GPU support
on MacPro5,1. Installation instructions can be found in the
\href{https://github.com/acidanthera/OpenCorePkg/blob/master/Staging/EnableGop/README.md}{\texttt{Utilities/EnableGop}}
directory of the OpenCore release zip file - proceed with caution. \\
\href{https://github.com/acidanthera/OcBinaryData}{\texttt{ExFatDxe}}
& Proprietary ExFAT file system driver for Bootcamp support commonly found in Apple
firmware. For Sandy Bridge and earlier CPUs, the \texttt{ExFatDxeLegacy} driver should be
......
......@@ -6,7 +6,8 @@
#ifndef OC_BOOT_MANAGEMENT_LIB_H
#define OC_BOOT_MANAGEMENT_LIB_H
#include <Uefi.h>
#include <PiDxe.h>
#include <Guid/AppleVariable.h>
#include <IndustryStandard/AppleBootArgs.h>
#include <IndustryStandard/AppleHid.h>
#include <Library/OcAppleBootPolicyLib.h>
......@@ -19,6 +20,8 @@
#include <Protocol/LoadedImage.h>
#include <Protocol/AppleBeepGen.h>
#include <Protocol/OcAudio.h>
#include <Protocol/GraphicsOutput.h>
#include <Protocol/AppleUserInterface.h>
#if defined (OC_TARGET_DEBUG) || defined (OC_TARGET_NOOPT)
// #define BUILTIN_DEMONSTRATE_TYPING
......@@ -2075,6 +2078,17 @@ OcAddEntriesFromBootEntryProtocol (
IN BOOLEAN CreateForHotKey
);
/**
Force Apple Firmware UI to always reconnect to current console GOP.
@retval EFI_SUCCESS Firmware UI ConnectGop method was successfully reset.
@retval other Compatible firmware UI protocol for reset could not be found.
**/
EFI_STATUS
OcUnlockAppleFirmwareUI (
VOID
);
/**
Launch Apple boot picker firmware application.
......
......@@ -73,11 +73,17 @@ OcPciInfoDump (
/**
Upgrade UEFI version to 2.x.
@param[in] Forge If TRUE forge, else just report status.
@param[in] Trash If TRUE trash gBS->CreateEventEx directly, else reallocate gBS.
Reallocate strategy will only affect current image and any images
it loads. Trash strategy should affect all images.
@retval EFI_SUCCESS on success.
**/
EFI_STATUS
OcForgeUefiSupport (
VOID
IN BOOLEAN Forge,
IN BOOLEAN Trash
);
/**
......
......@@ -459,16 +459,30 @@ OcRunBootPicker (
}
}
STATIC
EFI_STATUS
SetPickerEntryReason (
IN APPLE_PICKER_ENTRY_REASON PickerEntryReason
)
{
return gRT->SetVariable (
APPLE_PICKER_ENTRY_REASON_VARIABLE_NAME,
&gAppleVendorVariableGuid,
EFI_VARIABLE_BOOTSERVICE_ACCESS,
sizeof (PickerEntryReason),
&PickerEntryReason
);
}
EFI_STATUS
OcRunFirmwareApplication (
IN EFI_GUID *ApplicationGuid,
IN BOOLEAN SetReason
)
{
EFI_STATUS Status;
EFI_HANDLE NewHandle;
EFI_DEVICE_PATH_PROTOCOL *Dp;
APPLE_PICKER_ENTRY_REASON PickerEntryReason;
EFI_STATUS Status;
EFI_HANDLE NewHandle;
EFI_DEVICE_PATH_PROTOCOL *Dp;
DEBUG ((DEBUG_INFO, "OCB: run fw app attempting to find %g...\n", ApplicationGuid));
......@@ -493,14 +507,7 @@ OcRunFirmwareApplication (
if (!EFI_ERROR (Status)) {
if (SetReason) {
PickerEntryReason = ApplePickerEntryReasonUnknown;
Status = gRT->SetVariable (
APPLE_PICKER_ENTRY_REASON_VARIABLE_NAME,
&gAppleVendorVariableGuid,
EFI_VARIABLE_BOOTSERVICE_ACCESS,
sizeof (PickerEntryReason),
&PickerEntryReason
);
Status = SetPickerEntryReason (ApplePickerEntryReasonUnknown);
}
DEBUG ((
......@@ -524,14 +531,86 @@ OcRunFirmwareApplication (
return Status;
}
//
// Patching prolog of this function works on more similar era firmware
// than assuming that mGopAlreadyConnected is located immediately after
// protocol interface (which applies on MacPro5,1 v144.0.0.0.0 but not others).
//
// MacPro5,1 + some iMacs:
//
// sub rsp, 28h
// cmp cs:mGopAlreadyConnected, 0 ///< Ignore offset of this var
// jz short loc_10004431
// xor eax, eax
// jmp short loc_1000446F ///< Change this to no jump
//
STATIC CONST UINT8 ConnectGopPrologue[] = {
0x48, 0x83, 0xEC, 0x28, 0x80, 0x3D, 0x00, 0x00,
0x00, 0x00, 0x00, 0x74, 0x04, 0x33, 0xC0, 0xEB,
0x3E
};
STATIC CONST UINT8 ConnectGopPrologueMask[] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF
};
STATIC CONST UINT8 ConnectGopReplace[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00
};
STATIC CONST UINT8 ConnectGopReplaceMask[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF
};
//
// iMac11,1:
//
// push rbx
// sub rsp, 30h
// cmp cs:byte_100065C8, 0
// jz short loc_10004077
// xor ebx, ebx
// jmp short loc_100040D1
//
STATIC CONST UINT8 AltConnectGopPrologue[] = {
0x48, 0x53, 0x48, 0x83, 0xEC, 0x30,
0x80, 0x3D, 0x00, 0x00, 0x00, 0x00,0x00,
0x74, 0x04, 0x33, 0xDB, 0xEB, 0x5A
};
STATIC CONST UINT8 AltConnectGopPrologueMask[] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
STATIC CONST UINT8 AltConnectGopReplace[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
STATIC CONST UINT8 AltConnectGopReplaceMask[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF
};
EFI_STATUS
OcLaunchAppleBootPicker (
OcUnlockAppleFirmwareUI (
VOID
)
{
EFI_STATUS Status;
APPLE_FIRMWARE_USER_INTERFACE_PROTOCOL *FirmwareUI;
UINT8 *aGopAlreadyConnected;
UINT32 ReplaceCount;
Status = gBS->LocateProtocol (
&gAppleFirmwareUserInterfaceProtocolGuid,
......@@ -540,11 +619,11 @@ OcLaunchAppleBootPicker (
);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_INFO, "OC: Cannot locate FirmwareUI protocol - %r\n", Status));
DEBUG ((DEBUG_INFO, "OCB: Cannot locate FirmwareUI protocol - %r\n", Status));
} else if (FirmwareUI->Revision != APPLE_FIRMWARE_USER_INTERFACE_PROTOCOL_REVISION) {
DEBUG ((
DEBUG_INFO,
"OC: Launch Apple picker incompatible FirmwareUI protocol revision %u != %u\n",
"OCB: Unlock FirmwareUI incompatible protocol revision %u != %u\n",
FirmwareUI->Revision,
APPLE_FIRMWARE_USER_INTERFACE_PROTOCOL_REVISION
));
......@@ -552,19 +631,63 @@ OcLaunchAppleBootPicker (
}
if (!EFI_ERROR (Status)) {
//
// Location of relevant byte variable within loaded driver.
//
aGopAlreadyConnected = (VOID *)((UINT8 *)FirmwareUI + sizeof (APPLE_FIRMWARE_USER_INTERFACE_PROTOCOL));
ReplaceCount = ApplyPatch (
ConnectGopPrologue,
ConnectGopPrologueMask,
sizeof (ConnectGopPrologue),
ConnectGopReplace,
ConnectGopReplaceMask,
(VOID *)FirmwareUI->ConnectGop,
sizeof (ConnectGopPrologue),
1,
0
);
if (ReplaceCount == 0) {
ReplaceCount = ApplyPatch (
AltConnectGopPrologue,
AltConnectGopPrologueMask,
sizeof (AltConnectGopPrologue),
AltConnectGopReplace,
AltConnectGopReplaceMask,
(VOID *)FirmwareUI->ConnectGop,
sizeof (AltConnectGopPrologue),
1,
0
);
}
if (*aGopAlreadyConnected != 1) {
DEBUG ((DEBUG_WARN, "OC: Cannot force reconnect Apple GOP %u\n", *aGopAlreadyConnected));
} else {
*aGopAlreadyConnected = 0;
DEBUG ((DEBUG_INFO, "OC: Force reconnect Apple GOP\n"));
Status = EFI_SUCCESS;
if (ReplaceCount == 0) {
Status = EFI_NOT_FOUND;
DEBUG ((
DEBUG_INFO,
"OCB: 0x%016LX 0x%016LX 0x%016LX\n",
*((UINT64 *)((UINT8 *)FirmwareUI->ConnectGop)),
*((UINT64 *)(((UINT8 *)FirmwareUI->ConnectGop) + 8)),
*((UINT64 *)(((UINT8 *)FirmwareUI->ConnectGop) + 16))
));
}
DEBUG ((
EFI_ERROR (Status) ? DEBUG_WARN : DEBUG_INFO,
"OCB: FirmwareUI ConnectGop patch - %r\n",
Status
));
}
return Status;
}
EFI_STATUS
OcLaunchAppleBootPicker (
VOID
)
{
EFI_STATUS Status;
OcUnlockAppleFirmwareUI ();
Status = OcRunFirmwareApplication (&gAppleBootPickerFileGuid, TRUE);
return Status;
......
/** @file
Copyright (c) 2020, joevt. All rights reserved.
Copyright (C) 2021, vit9696. All rights reserved.
Copyright (C) 2021-2023, vit9696, mikebeaton. All rights reserved.
All rights reserved.
......@@ -13,13 +13,14 @@
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include <Uefi.h>
#include <PiDxe.h>
#include <Guid/EventGroup.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/DxeServicesTableLib.h>
#include <Library/IoLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/OcDeviceMiscLib.h>
......@@ -67,23 +68,46 @@ OcCreateEventEx (
return EFI_SUCCESS;
}
//
// The Trash strategy relies on old Apple firmware allocating gBS and gDS consecutively.
// This layout is directly inherited from standard edk EFI code.
// The strategy trashes the DXE_SERVICES_SIGNATURE value in gDS->Hdr.Signature, which
// happily is only used when the memory is being loaded (when we check for references
// to DXE_SERVICES_SIGNATURE throughout the edk code).
// For the Trash strategy to work, we are required to trash exactly that QWORD of memory,
// but in the targeted firmware we can confirm that it is harmless to do so before proceeding.
//
EFI_STATUS
OcForgeUefiSupport (
VOID
IN BOOLEAN Forge,
IN BOOLEAN Trash
)
{
EFI_BOOT_SERVICES *NewBS;
DEBUG ((
DEBUG_INFO,
"OCDM: Found 0x%X UEFI version (%u bytes, rebuilding to %u)\n",
"OCDM: Found 0x%X/0x%X UEFI version (%u bytes, %u %a to %u) gST %p gBS %p gBS->CreateEventEx %p &gBS %p\n",
gST->Hdr.Revision,
gBS->Hdr.Revision,
gBS->Hdr.HeaderSize,
(UINT32)sizeof (EFI_BOOT_SERVICES)
Forge,
Trash ? "trashing" : "rebuilding",
(UINT32)sizeof (EFI_BOOT_SERVICES),
gST,
gBS,
gBS->CreateEventEx,
&gBS
));
if (!Forge) {
return EFI_SUCCESS;
}
//
// Already too new.
// This check will replace any earlier forge to 2.0 <= UEFI < 2.3.
// This is desirable in some cases and harmless in others.
//
if (gST->Hdr.Revision >= EFI_2_30_SYSTEM_TABLE_REVISION) {
return EFI_ALREADY_STARTED;
......@@ -93,14 +117,30 @@ OcForgeUefiSupport (
return EFI_INVALID_PARAMETER;
}
NewBS = AllocateZeroPool (sizeof (EFI_BOOT_SERVICES));
if (NewBS == NULL) {
DEBUG ((DEBUG_INFO, "OCDM: Failed to allocate BS copy\n"));
return EFI_OUT_OF_RESOURCES;
if (Trash) {
if ((VOID *)&gBS->CreateEventEx != (VOID *)gDS) {
DEBUG ((
DEBUG_WARN,
"OCDM: Aborting trash strategy, gDS does not follow gBS\n"
));
return EFI_UNSUPPORTED;
}
DEBUG ((
DEBUG_INFO,
"OCDM: Trashing gDS->Hdr.Signature with gBS->CreateEventEx\n"
));
NewBS = gBS;
} else {
NewBS = AllocateZeroPool (sizeof (EFI_BOOT_SERVICES));
if (NewBS == NULL) {
DEBUG ((DEBUG_INFO, "OCDM: Failed to allocate BS copy\n"));
return EFI_OUT_OF_RESOURCES;
}
CopyMem (NewBS, gBS, gBS->Hdr.HeaderSize);
}
CopyMem (NewBS, gBS, gBS->Hdr.HeaderSize);
NewBS->CreateEventEx = OcCreateEventEx;
NewBS->Hdr.HeaderSize = sizeof (EFI_BOOT_SERVICES);
NewBS->Hdr.Revision = EFI_2_30_SYSTEM_TABLE_REVISION;
......@@ -113,5 +153,10 @@ OcForgeUefiSupport (
gST->Hdr.CRC32 = 0;
gST->Hdr.CRC32 = CalculateCrc32 (gST, gST->Hdr.HeaderSize);
if (Trash) {
gDS->Hdr.CRC32 = 0;
gDS->Hdr.CRC32 = CalculateCrc32 (gDS, gDS->Hdr.HeaderSize);
}
return EFI_SUCCESS;
}
......@@ -62,6 +62,7 @@
PrintLib
UefiLib
UefiBootServicesTableLib
DxeServicesTableLib
[Sources]
ActivateHpetSupport.c
......
......@@ -939,9 +939,7 @@ OcLoadUefiSupport (
OcInstallPermissiveSecurityPolicy ();
}
if (Config->Uefi.Quirks.ForgeUefiSupport) {
OcForgeUefiSupport ();
}
OcForgeUefiSupport (Config->Uefi.Quirks.ForgeUefiSupport, FALSE);
if (Config->Uefi.Quirks.ReloadOptionRoms) {
OcReloadOptionRoms ();
......
......@@ -744,6 +744,12 @@
## @Prompt Use Pin Capabilities to identify audio outputs.
gOpenCorePkgTokenSpaceGuid.PcdAudioControllerUsePinCapsForOutputs|TRUE|BOOLEAN|0x00000008
## Indicates whether to build EnableGop driver with DirectGopRendering.<BR><BR>
## TRUE - DirectGopRendering will be used.<BR>
## FALSE - DirectGopRendering will not be used.<BR>
## @Prompt Use DirectGopRendering.
gOpenCorePkgTokenSpaceGuid.PcdEnableGopDirect|FALSE|BOOLEAN|0x00000009
[PcdsFixedAtBuild]
## Defines the Console Control initialization mode set on entry.<BR><BR>
## 0 - EfiConsoleControlScreenText<BR>
......
......@@ -22,6 +22,7 @@
BUILD_TARGETS = RELEASE|DEBUG|NOOPT
SKUID_IDENTIFIER = DEFAULT
DSC_SPECIFICATION = 0x00010006
FLASH_DEFINITION = OpenCorePkg/OpenCorePkg.fdf
#
# Network definition
......@@ -319,6 +320,14 @@
OpenCorePkg/Platform/ResetNvramEntry/ResetNvramEntry.inf
OpenCorePkg/Platform/ToggleSipEntry/ToggleSipEntry.inf
OpenCorePkg/Staging/AudioDxe/AudioDxe.inf
OpenCorePkg/Staging/EnableGop/EnableGop.inf {
<LibraryClasses>
DebugLib|OpenCorePkg/Library/OcDebugLibNull/OcDebugLibNull.inf
}
OpenCorePkg/Staging/EnableGop/EnableGopDirect.inf {
<LibraryClasses>
DebugLib|OpenCorePkg/Library/OcDebugLibNull/OcDebugLibNull.inf
}
OpenCorePkg/Staging/OpenHfsPlus/OpenHfsPlus.inf
OpenCorePkg/Tests/AcpiTest/AcpiTest.inf
OpenCorePkg/Tests/AcpiTest/AcpiTestApp.inf
......
## @file
# Compile standalone firmware filesystem files.
#
# Copyright (C) 2022-2023, Mike Beaton. All rights reserved.<BR>
# SPDX-License-Identifier: BSD-3-Clause
##
#
# For now disable non-64-bit build; Mac Pro cannot use it, and EDK-II
# build system does not separate 64 bit and 32 bit .ffs files, which
# we want to distribute.
#
# If we needed all archs in future we could distribute the complete
# .fv files, from which the .ffs can be re-extracted.
#
!if ($(ARCH) == X64)
!if ($(ARCH) == X64)
[FV.FfsFilesX64]
!else
[FV.FfsFilesIA32]
!endif
BlockSize = 0x10000
NumBlocks = 8
FvAlignment = 16 #FV alignment and FV attributes setting.
ERASE_POLARITY = 1
MEMORY_MAPPED = TRUE
STICKY_WRITE = TRUE
LOCK_CAP = TRUE
LOCK_STATUS = TRUE
WRITE_DISABLED_CAP = TRUE
WRITE_ENABLED_CAP = TRUE
WRITE_STATUS = TRUE
WRITE_LOCK_CAP = TRUE
WRITE_LOCK_STATUS = TRUE
READ_DISABLED_CAP = TRUE
READ_ENABLED_CAP = TRUE
READ_STATUS = TRUE
READ_LOCK_CAP = TRUE
READ_LOCK_STATUS = TRUE
#
# DXE Drivers (other .inf files for conversion to .ffs may be added here)
#
INF OpenCorePkg/Staging/EnableGop/EnableGop.inf
!if ($(ARCH) == X64)
[FV.EnableGopDirectX64]
!else
[FV.EnableGopDirectIA32]
!endif
BlockSize = 0x10000
NumBlocks = 8
FvAlignment = 16 #FV alignment and FV attributes setting.
ERASE_POLARITY = 1
MEMORY_MAPPED = TRUE
STICKY_WRITE = TRUE
LOCK_CAP = TRUE
LOCK_STATUS = TRUE
WRITE_DISABLED_CAP = TRUE
WRITE_ENABLED_CAP = TRUE
WRITE_STATUS = TRUE
WRITE_LOCK_CAP = TRUE
WRITE_LOCK_STATUS = TRUE
READ_DISABLED_CAP = TRUE
READ_ENABLED_CAP = TRUE
READ_STATUS = TRUE
READ_LOCK_CAP = TRUE
READ_LOCK_STATUS = TRUE
#
# DXE Drivers
#
#
# EnableGopDirect intentionally has the same GUID as EnableGop, so it must go in a separate FV.
# (We don't care about the FV, rather the intermediate FFS files which are generated during build.)
#
INF OpenCorePkg/Staging/EnableGop/EnableGopDirect.inf
!endif
#
# Ideally we would match the compressed layout of DXE drivers in Mac Pro 144.0.0.0.0 firmware,
# as per the commented out lines, but Mac Pro will not load this with standard compression.
# With lines commented out we make a different, non-compressed layout which the Mac Pro will load.
#
# TODO: Is there a way to make a Tiano-compressed COMPRESS section, as in Mac Pro firmware, using
# EDK-II build tools? If we manually reconstuct one with UEFITool 0.25.1, Mac Pro will load it.
#
# Note: `GUIDED A31280AD-481E-41B6-95E8-127F4C984779` will make a Tiano compressed GUIDED
# section, but this is different and 144.0.0.0.0 will not load it.
#
[Rule.Common.DXE_DRIVER]
FILE DRIVER = $(NAMED_GUID) Checksum {
# COMPRESS {
# GUIDED {
DXE_DEPEX DXE_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex
PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi
UI STRING="$(MODULE_NAME)" Optional
# }
# }
}
/** @file
Provide GOP on unsupported graphics cards on EFI-era MacPro and iMac.
Copyright (c) 2022-2023, Mike Beaton. All rights reserved.<BR>
SPDX-License-Identifier: BSD-3-Clause
**/
#include <Uefi.h>
#include <Library/DxeServicesTableLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Library/OcBootManagementLib.h>
#include <Library/OcConsoleLib.h>
#include <Library/OcDeviceMiscLib.h>
STATIC EFI_GET_MEMORY_SPACE_MAP mOriginalGetMemorySpaceMap;
//
// Equivalent to a very cut down OcLoadUefiOutputSupport.
//
STATIC
EFI_STATUS
LoadUefiOutputSupport (
VOID
)
{
EFI_STATUS Status;
Status = OcProvideConsoleGop (FALSE);
if (EFI_ERROR (Status)) {
return Status;
}
OcSetConsoleResolution (
0,
0,
0,
FALSE
);
if (FeaturePcdGet (PcdEnableGopDirect)) {
OcUseDirectGop (-1);
}
OcSetupConsole (
OcConsoleRendererBuiltinGraphics,
FALSE,
FALSE,
FALSE,
FALSE
);
return EFI_SUCCESS;
}
STATIC
EFI_STATUS
ProvideGop (
VOID
)
{
OcUnlockAppleFirmwareUI ();
return LoadUefiOutputSupport ();
}
//
// This memory map access happens twice during PlatformBdsPolicyBehavior, once
// in the equivalent of efi InitializeMemoryTest at the start of the function,
// and once during PlatformBdsDiagnostics, slightly later. The second call(s)
// (there is more than one code path, depending on the boot type) are after
// the default console has been connected, and therefore ideal for us.
//
EFI_STATUS
EFIAPI
WrappedGetMemorySpaceMap (
OUT UINTN *NumberOfDescriptors,
OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR **MemorySpaceMap
)
{
STATIC UINTN mGetMemorySpaceMapAccessCount = 0;
mGetMemorySpaceMapAccessCount++;
if (mGetMemorySpaceMapAccessCount == 2) {
ProvideGop ();
}
return mOriginalGetMemorySpaceMap (
NumberOfDescriptors,
MemorySpaceMap
);
}
STATIC
VOID
WrapGetMemorySpaceMap (
VOID
)
{
mOriginalGetMemorySpaceMap = gDS->GetMemorySpaceMap;
gDS->GetMemorySpaceMap = WrappedGetMemorySpaceMap;
gDS->Hdr.CRC32 = 0;
gBS->CalculateCrc32 (gDS, gDS->Hdr.HeaderSize, &gDS->Hdr.CRC32);
}
//
// If we execute the entire console setup at Driver#### time then we have to forge UEFI, reload option ROMs
// and connect them, all at that point.
// This works on some systems but causes crashes others, or causes an empty picker with question mark folder.
// Current strategy is:
// - Forge UEFI early; relatively easy: just do it immediately, as below, and insert this driver either
// a) anywhere in main firmware volume, or b) in VBIOS anywhere before GOP driver which needs it
// - Execute rest of payload after option roms have been loaded, _and_ after firmware has already connected
// them (see WrapGetMemorySpaceMap strategy above).
// With this strategy we do not need to reload or reconnect any option ROMs, which is much more stable.
//
EFI_STATUS
EFIAPI
UefiMain (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
OcForgeUefiSupport (TRUE, TRUE);
WrapGetMemorySpaceMap ();
return EFI_SUCCESS;
}
## @file
#
# Provide GOP on unsupported graphics cards on EFI-era MacPro and iMac.
#
# Copyright (c) 2022-2023, Mike Beaton. All rights reserved.
# SPDX-License-Identifier: BSD-3-Clause
#
##
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = EnableGop
FILE_GUID = 3FBA58B1-F8C0-41BC-ACD8-253043A3A17F
MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.0
ENTRY_POINT = UefiMain
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64
#
[Sources]
EnableGop.c
[Packages]
MdePkg/MdePkg.dec
OpenCorePkg/OpenCorePkg.dec
UefiCpuPkg/UefiCpuPkg.dec
[LibraryClasses]
BaseLib
DxeServicesTableLib
OcBootManagementLib
OcConsoleLib
OcDeviceMiscLib
UefiBootServicesTableLib
UefiDriverEntryPoint
UefiRuntimeServicesTableLib
[FeaturePcd]
gOpenCorePkgTokenSpaceGuid.PcdEnableGopDirect|FALSE
[Depex]
TRUE
## @file
#
# Provide GOP on unsupported graphics cards on EFI-era MacPro and iMac using DirectGopRendering.
#
# Copyright (c) 2023, Mike Beaton. All rights reserved.
# SPDX-License-Identifier: BSD-3-Clause
#
##
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = EnableGopDirect
FILE_GUID = 3FBA58B1-F8C0-41BC-ACD8-253043A3A17F
MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.0
ENTRY_POINT = UefiMain
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64
#
[Sources]
EnableGop.c
[Packages]
MdePkg/MdePkg.dec
OpenCorePkg/OpenCorePkg.dec
UefiCpuPkg/UefiCpuPkg.dec
[LibraryClasses]
BaseLib
DxeServicesTableLib
OcBootManagementLib
OcConsoleLib
OcDeviceMiscLib
UefiBootServicesTableLib
UefiDriverEntryPoint
UefiRuntimeServicesTableLib
[FeaturePcd]
gOpenCorePkgTokenSpaceGuid.PcdEnableGopDirect|TRUE
[Depex]
TRUE
#!/bin/bash
#
# Copyright © 2023 Mike Beaton. All rights reserved.
# SPDX-License-Identifier: BSD-3-Clause
#
# Insert EFI into Nvidia VBIOS.
#
# TODO: Check that original GOP is present, and locate it in the original file automatically.
#
usage() {
echo "Usage: ./${SELFNAME} {rom-file} {efi-file} {GOP offset} {out-file}"
echo "E.g.:"
echo " ./${SELFNAME} nv.rom GOP.efi 0xFC00 mod.rom"
echo " ./${SELFNAME} nv.rom GOP.efi 64512 mod.rom"
echo ""
}
SELFNAME="$(/usr/bin/basename "${0}")"
if [ "$#" -ne 4 ] ; then
usage
exit 0
fi
commands=(
"EfiRom"
"UEFIRomExtract"
)
FOUND=1
for command in "${commands[@]}"; do
if ! command -v "$command" 1>/dev/null ; then
echo "${command} not available!"
FOUND=0
fi
done
if [ "$FOUND" -eq 0 ] ; then
exit 1
fi
ROM_FILE="$1"
EFI_FILE="$2"
GOP_OFFSET="$3"
OUT_FILE="$4"
# https://unix.stackexchange.com/a/84980/340732
tmpdir=$(mktemp -d 2>/dev/null || mktemp -d -t 'vbios') || exit 1
echo "Splitting original ROM..."
dd bs=1 if="$ROM_FILE" of="$tmpdir/original_first_part.rom" count=$(($GOP_OFFSET)) status=none || exit 1
dd bs=1 if="$ROM_FILE" of="$tmpdir/original_last_part.rom" skip=$(($GOP_OFFSET)) status=none || exit 1
echo "Compressing ${EFI_FILE} using EfiRom..."
EfiRom -o "$tmpdir/insert.rom" -ec "$EFI_FILE" -f 0xAAAA -i 0xBBBB -l 0x30000 || exit 1
echo "Adding Nvidia header..."
dd bs=1 if="$tmpdir/insert.rom" of="$tmpdir/insert_first_part" count=$((0x38)) status=none || exit 1
dd bs=1 if="$tmpdir/insert.rom" of="$tmpdir/insert_last_part" skip=$((0x38)) status=none || exit 1
INSERT_SIZE=$(stat -f%z "$tmpdir/insert.rom") || exit 1
# add NPDE from original GOP
dd bs=1 if="$tmpdir/original_last_part.rom" of="$tmpdir/insert_first_part" skip=$((0x38)) seek=$((0x38)) count=$((0x18)) status=none || exit 1
cat "$tmpdir/insert_first_part" "$tmpdir/insert_last_part" > "$tmpdir/insert_oversize.rom" || exit 1
# `truncate` not present by default on macOS
dd bs=1 if="$tmpdir/insert_oversize.rom" of="$tmpdir/insert_fixed.rom" count="$INSERT_SIZE" status=none || exit 1
# patch size in NPDE
dd bs=1 if="$tmpdir/insert.rom" of="$tmpdir/insert_fixed.rom" skip=$((0x2)) seek=$((0x48)) count=1 conv=notrunc status=none || exit 1
# patch with vendor and device id from original GOP
dd bs=1 if="$tmpdir/original_last_part.rom" of="$tmpdir/insert_fixed.rom" skip=$((0x20)) seek=$((0x20)) count=4 conv=notrunc status=none || exit 1
# patch size in PCIR
dd bs=1 if="$tmpdir/original_last_part.rom" of="$tmpdir/insert_fixed.rom" skip=$((0x16)) seek=$((0x16)) count=1 conv=notrunc status=none || exit 1
# patch end marker in NPDE in fixed ROM (leave PCIR correct and EFI extractable from fixed ROM)
echo -n -e '\x00' | dd bs=1 of="$tmpdir/insert_fixed.rom" seek=$((0x4A)) conv=notrunc status=none || exit 1
echo "Writing ${OUT_FILE}..."
cat "$tmpdir/original_first_part.rom" "$tmpdir/insert_fixed.rom" "$tmpdir/original_last_part.rom" > "$OUT_FILE" || exit 1
# patch end marker in PCIR in out file
echo -n -e '\x00' | dd bs=1 of="$OUT_FILE" seek=$(($GOP_OFFSET + 0x31)) conv=notrunc status=none || exit 1
echo "Verifying ${OUT_FILE}..."
dd bs=1 if="$OUT_FILE" of="$tmpdir/out_efi_part.rom" skip=$(($GOP_OFFSET)) status=none || exit 1
UEFIRomExtract "$tmpdir/out_efi_part.rom" "$tmpdir/extracted.efi" 1>/dev/null || exit 1
ERROR=0
diff "$tmpdir/extracted.efi" "$EFI_FILE" 1>/dev/null || ERROR=1
if [ "$ERROR" -ne 0 ] ; then
echo " - Failure comparing extracted EFI to original!"
fi
OLD_EFI_COUNT=$(EfiRom -d "$tmpdir/original_last_part.rom" | grep "0x0EF1" | wc -l) || exit 1
OLD_EFI_COUNT=$(($OLD_EFI_COUNT)) || exit 1
NEW_EFI_COUNT=$(EfiRom -d "$tmpdir/out_efi_part.rom" | grep "0x0EF1" | wc -l) || exit 1
NEW_EFI_COUNT=$(($NEW_EFI_COUNT)) || exit 1
if [ "$NEW_EFI_COUNT" -ne $(($OLD_EFI_COUNT + 1)) ] ; then
echo " - Found ${NEW_EFI_COUNT} EFI parts, expected $(($OLD_EFI_COUNT + 1))!"
fi
if [ "$ERROR" -eq 0 ] ; then
echo "SUCCESS."
else
echo "*** WARNING - FAIL ***"
fi
rm -rf "$tmpdir" || exit 1
echo "Done."
# Provides standalone GOP driver for EFI era Mac Pro and iMac
## Status
**Current status: Early beta release.**
This driver has been tested and is working on several iMac models
with several different GPUs, and on several MacPro4,1/5,1 machines with several different GPUs. However, in the worst
case (and still quite possible) scenario, an incompatible or incorrectly installed driver
in firmware may brick your hardware.
*In all cases take a backup of the main firmware or VBIOS firmware which you are modifying, and confirm that
you can successfully restore from this, before starting.*
## Recovery from bricked hardware
- If attempting firmware insertion on a MacPro4,1/5,1, for recovery from a bricked device you will either
need a Matt card (which may breach intellectual property laws in some jurisdictions) or the ability to
desolder and reprogram your own NVRAM chip.
- If testing via firmware insertion on an iMac, you will need the ability to disassemble your iMac and
reprogram its NVRAM chip using a SOIC clip attached to a CH341A controller running on another computer.
- If testing via VBIOS insertion (iMac or Mac Pro), you will need the ability to disassemble your system,
likely remove the heat sink from the graphics card, and then reprogram its NVRAM chip using a SOIC
clip attached to a CH341A controller running on another computer.
- If testing via VBIOS insertion, in some cases it may also be possible
to use physical electrical connection to your GPU NVRAM chip in order to boot with no graphics, then connect
to your machine with `ssh` (which must have been enabled beforehand) and reprogram the GPU NVRAM. Advice on
this is not provided here, but may be found for instance on the iMac GPU related forum threads listed below.
*If you are not familiar with the above procedures, you are strongly recommended to wait for further testing by
users who are. No further help can be provided here, and you proceed entirely at your own risk.*
## Summary
Targetting EFI-era (~2009-2012) MacPro4,1/5,1 and iMac firmware, this driver gathers and injects the parts of
OpenCore needed for pre-boot graphics support with non-natively supported GPUs.
The requirements for using this driver are:
- EFI-era (~2009-2012) MacPro4,1/5,1 or iMac with most recent firmware.
- A GPU which does not produce native pre-boot graphics (such as native picker when pressing ALT key during boot)
before OpenCore starts (otherwise, you do not need it).
- A GPU which produces graphics when using OpenCore (this must include successfully showing the native Apple boot
picker when started via the latest version of OpenCore tool `BootKicker.efi`) (otherwise, the driver will not work).
- *Note*: If your OpenCore installation includes a required GOP driver for your graphics card (this is added
automatically on some systems by recent versions of OpenCore Legacy Patcher, as a way to enable OpenCore menu
in cards such as ex-mining GPUs), then you would also need to burn that driver to the VBIOS of your graphics
card in order to obtain pre-OpenCore graphics; instructions for this are outside the scope of this tutorial,
although the procedures required for modifying VBIOS are similar to what is covered here.
When installed, the driver should enable:
- Native boot picker via ALT key
- Firmware password UI
- Target disk mode UI
- macOS boot progress screen
- etc.
Compiled versions of the driver files and these instructions may be found in the `Utilities/EnableGop`
directory of the OpenCore release package.
For GPUs needing `DirectGopRendering` in OpenCore configuration, use `EnableGopDirect.efi`, otherwise use `EnableGop.efi`
as it renders faster on most other systems.
The driver may be installed to VBIOS or to main firmware. It is expected that most Mac Pro users will use firmware insertion
and most iMac users will chose VBIOS insertion, however both techniques work on both systems (but it is harder to modify the
iMac firmware).
## Usage
## Install to firmware
For reading and writing to firmware on the Mac Pro, @Macschrauber's [Rom Dump](https://www.youtube.com/watch?v=q4NW00oyUKE) works
well. Alternatively the kexts and executables which this uses can be sourced individually (or extracted from the Rom Dump app) and
run from the command line.
The firmware on the iMac cannot be updated without an initial hardware flash (SOIC clip plus CH341A controller), therefore
the recommended approach on iMac systems is [VBIOS injection](#install-to-vbios). However, the below instructions for firmware
injection do work, if you are willing to do a hardware flash of the resulting firmware file, or if you have already
[unprotected your iMac firmware](https://forums.macrumors.com/threads/imac-2011-see-more-uefi-firmware-mod.2257435/page-3?post=31087001#post-31087001) -
which reduces security, and is only recommended for those actively developing firmware modifications.
The `.ffs` file provided in this directory can be manually added to the extracted firmware file using [`UEFITool`](https://github.com/LongSoft/UEFITool),
or automatically added using @dosdude1's [`DXEInject`](https://dosdude1.com/apps/). Once more, if you are not familiar with these procedures,
you are recommended to proceed with extreme caution.
### Using DXEInject
To install the driver via `DXEInject`, the command is:
- `DXEInject {original}.rom {modified}.rom EnableGop.ffs`
The file `{modifed}.rom` is ready for burning, although the result can be checked using UEFITool, if required.
> *Note*: If only reading a file with UEFITool, the latest version is recommended, as it provides the most information.
For writing, the older version 0.25.1 must be used, as described below.
### Using UEFITool
The `.ffs` file may be inserted anywhere within the same firmware volume which contains `DuetBds`
(file GUID `A6F691AC-31C8-4444-854C-E2C1A6950F92`). However, for simplicity, these instructions
will insert it in the same place that `DXEInject` does:
- Use UEFITool 0.25.1 (it must be that old version, not the newer NE or new engine versions, which
cannot yet edit)
- Perform a header-only GUID search for `BAE7599F-3C6B-43B7-BDF0-9CE07AA91AA6`
- Double-click on the search result
- Right-click on the DXE driver with that GUID which should then appear
- Choose "Insert after..." and select `EnableGop.ffs`
- Save the modified firmware
The end result, after saving and re-loading, should look like this:
<img src="UEFITool_Inserted_Screenshot.png">
## Install to VBIOS
Instructions and a script for inserting the driver into NVidia VBIOS are provided.
Similar techniques are appropriate for AMD GPUs.
For further information on VBIOS modification, see:
- https://forums.macrumors.com/threads/2011-imac-graphics-card-upgrade.1596614/
- https://forums.macrumors.com/threads/imac-2011-maxwell-and-pascal-gpu-upgrade.2300989/
- https://github.com/Ausdauersportler/IMAC-EFI-BOOT-SCREEN/wiki
- https://winraid.level1techs.com/t/amd-and-nvidia-gop-update-no-requests-diy/30917
### Nvidia
To use the provided `NvInsertEfi.sh` script:
- Locate an appropriate version of the `nvflash` tool (avilable for Linux and Windows), which can be used to read
from and write to your Nvidia GPU VBIOS.
- Use `nvflash` to read a copy of your VBIOS.
- Using a hex editor, search in the VBIOS for the byte sequence `F1 0E 00 00` with the byte sequence `55 AA` coming
close before it; the start address of the `55 AA` is the value needed for the insertion offset in the next step.
- Run `./NvInsertEfi.Sh {original}.rom EnableGop.ffs {offset} {modified}/.rom`.
- Only if you modified a rom file obtained via `flashrom` rather than `nvflash`, you should manually truncate
the modified file's size to the original file's size at this point. (`nvflash` files only contain the used section
of the VBIOS, and therefore must not be truncated.)
- The new file `{modified}.rom` may be burnt to the VBIOS firmware.
Please note all the cautions already given above about the difficulty of recovering, unless you are familiar with
the procedures necessary, if this process fails.
### AMD
Similar procedures as for Nvidia apply.
- Further assistance and information may be available in the forums and pages listed above.
## No longer supported: Install as Driver#### entry
Early test versions of this driver included code to allow it to work when installed as a `Driver####` entry
(`Driver####` entries do work when installed via `bcfg` and using MacPro4,1/5,1 firmware; they do not work on
that firmware if using `efibootmgr`, and they are not supported by iMac firmware). This code has been removed
in order to minimise the driver size for VBIOS insertion.
Staging drivers considered experimental and not production ready.
## OpenHfsPlus
This driver implements HFS+ support with bless extensions.
## AudioDxe
Improved audio driver (currently only Intel HD audio).
HDMI or other digital outputs don't work.
## EnableGop
Standalone firmware-embeddable driver for non-native GPU support on EFI-era Mac Pro and iMac.
## OpenHfsPlus
This driver implements HFS+ support with bless extensions.
......@@ -249,6 +249,32 @@ package() {
fi
done
# Copy Mac Pro GOP firmware driver.
mkdir -p "${dstdir}/Utilities/EnableGop" || exit 1
ENABLE_GOP_GUID="3FBA58B1-F8C0-41BC-ACD8-253043A3A17F"
ffsNames=(
"EnableGop"
"EnableGopDirect"
)
for ffsName in "${ffsNames[@]}"; do
cp "FV/Ffs/${ENABLE_GOP_GUID}${ffsName}/${ENABLE_GOP_GUID}.ffs" "${dstdir}/Utilities/EnableGop/${ffsName}.ffs" || exit 1
done
gopDrivers=(
"EnableGop.efi"
"EnableGopDirect.efi"
)
for file in "${gopDrivers[@]}"; do
cp "X64/${file}" "${dstdir}/Utilities/EnableGop"/ || exit 1
done
helpFiles=(
"README.md"
"UEFITool_Inserted_Screenshot.png"
"NvInsertEfi.sh"
)
for file in "${helpFiles[@]}"; do
cp "${selfdir}/Staging/EnableGop/${file}" "${dstdir}/Utilities/EnableGop"/ || exit 1
done
utils=(
"ACPIe"
"acdtinfo"
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册