OcConsoleLib: Additional info in GOP dump; additional guards on GopBurstMode

This commit is contained in:
Mike Beaton 2023-04-03 19:55:48 +01:00
parent fe15c15d17
commit 5d8e3f5836
6 changed files with 378 additions and 122 deletions

View File

@ -3,6 +3,8 @@ OpenCore Changelog
#### v0.9.2
- Added `DisableIoMapperMapping` quirk, thx @CaseySJ
- Fixed disabling single user mode when Apple Secure Boot is enabled
- Improved guard checks for `GopBurstMode` on systems where it's not needed
- Improved compatibilty of `GopBurstMode` with some very non-standard GOP implementations
#### v0.9.1
- Fixed long comment printing for ACPI patches, thx @corpnewt

View File

@ -8252,8 +8252,18 @@ for additional options.
for GOP memory, even though the CPU supports it. Setting this can give a considerable
speed-up for GOP operations, especially on systems which require \texttt{DirectGopRendering}.
\emph{Note}: This takes effect whether or not \texttt{DirectGopRendering} is set, and may
give some speed-up to GOP operations even when \texttt{DirectGopRendering} is \texttt{false}.
\emph{Note 1}: This quirk takes effect whether or not \texttt{DirectGopRendering} is set, and
in some cases may give a noticeable speed-up to GOP operations even when \texttt{DirectGopRendering}
is \texttt{false}.
\emph{Note 2}: On most systems from circa 2013 onwards, write-combining
caching is already applied by the firmware to GOP memory, in which case \texttt{GopBurstMode}
is unnecessary. On such systems enabling the quirk should normally be harmless, producing an
\texttt{OCC:} debug log entry indicating that burst mode is already started.
\emph{Note 3}: Some caution should be taken when enabling this quirk, as it has been observed
to cause hangs on a few systems. Since additional guards have been added to try to prevent this,
please log a bugtracker issue if such a system is found.
\item
\texttt{GopPassThrough}\\

View File

@ -15,9 +15,10 @@
#ifndef OC_CONSOLE_LIB_H
#define OC_CONSOLE_LIB_H
#include <Protocol/ConsoleControl.h>
#include <Protocol/AppleFramebufferInfo.h>
#include <Protocol/AppleEg2Info.h>
#include <Protocol/ConsoleControl.h>
#include <Protocol/GraphicsOutput.h>
#include <Library/OcFileLib.h>
@ -113,6 +114,47 @@ OcSetGopBurstMode (
VOID
);
/**
Return the bytes per pixel for the current GOP mode.
GOP mode information does not include anything directly containing the bytes
per pixel, but there is a defined algorithm for working out this size, even for
non-standard pixel masks, and also a defined situation (PixelBltOnly pixel
format) where there is no such size.
@param[in] Mode GOP mode.
@param[in] BytesPerPixel Bytes per pixel for the mode in use.
@retval EFI_SUCCESS Success.
@retval EFI_UNSUPPORTED There is no frame buffer.
@retval EFI_INVALID_PARAMETER Mode info parameters are outside valid ranges.
**/
EFI_STATUS
OcGopModeBytesPerPixel (
IN EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *Mode,
OUT UINTN *BytesPerPixel
);
/**
Return the frame buffer size in use for the current GOP mode, even where
Gop->Mode->FrameBufferSize misreports this.
Occasional GOP implementations report a frame buffer size far larger (e.g. ~100x)
than required for the actual mode in use.
@param[in] Mode GOP mode.
@param[in] FrameBufferSize Frame buffer size in use.
@retval EFI_SUCCESS Success.
@retval EFI_UNSUPPORTED There is no frame buffer.
@retval EFI_INVALID_PARAMETER Size parameters are outside valid ranges.
**/
EFI_STATUS
OcGopModeSafeFrameBufferSize (
IN EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *Mode,
OUT UINTN *FrameBufferSize
);
/**
Set screen resolution on console handle.

View File

@ -1,5 +1,5 @@
/** @file
Dump GOP info - currently dumps memory caching info from MTRR and PAT.
Dump GOP info for current/default mode, including memory caching info from MTRR and PAT.
Copyright (C) 2023, Mike Beaton. All rights reserved.<BR>
SPDX-License-Identifier: BSD-3-Clause
@ -34,6 +34,8 @@ OcGopInfoDump (
EFI_VIRTUAL_ADDRESS VirtualAddress;
EFI_PHYSICAL_ADDRESS PhysicalAddress;
EFI_PHYSICAL_ADDRESS EndAddress;
UINTN FrameBufferSize;
UINTN BytesPerPixel;
UINT64 Bits;
UINT8 Level;
BOOLEAN HasMtrr;
@ -65,115 +67,183 @@ OcGopInfoDump (
return EFI_OUT_OF_RESOURCES;
}
HasMtrr = IsMtrrSupported ();
HasPat = OcIsPatSupported ();
Status = EFI_SUCCESS;
OcAsciiPrintBuffer (
&FileBuffer,
&FileBufferSize,
"MTRR %asupported PAT %asupported\n",
HasMtrr ? "" : "not ",
HasPat ? "" : "not "
);
if (HasMtrr) {
if (HasPat) {
PatMsr = AsmReadMsr64 (MSR_IA32_CR_PAT);
HasDefaultPat = (PatMsr == PAT_DEFAULTS);
OcAsciiPrintBuffer (
&FileBuffer,
&FileBufferSize,
"PAT 0x%016LX (%a)\n",
PatMsr,
HasDefaultPat ? "default" : "not default!"
);
}
PageTable = OcGetCurrentPageTable (NULL);
VirtualAddress = Gop->Mode->FrameBufferBase;
EndAddress = VirtualAddress + Gop->Mode->FrameBufferSize;
Status = EFI_SUCCESS;
do {
MtrrCacheType = MtrrGetMemoryAttribute (VirtualAddress);
if (HasPat) {
Status = OcGetSetPageTableInfoForAddress (
PageTable,
VirtualAddress,
&PhysicalAddress,
&Level,
&Bits,
&PatIndex,
FALSE
);
if (EFI_ERROR (Status)) {
break;
}
OcAsciiPrintBuffer (
&FileBuffer,
&FileBufferSize,
"0x%LX->0x%LX MTRR %u=%a PTE%u bits 0x%016LX PAT %u->%u=%a\n",
VirtualAddress,
PhysicalAddress,
MtrrCacheType,
OcGetMtrrTypeString (MtrrCacheType),
Level,
Bits,
PatIndex.Index,
GET_PAT_N (PatMsr, PatIndex.Index),
OcGetPatTypeString (GET_PAT_N (PatMsr, PatIndex.Index))
);
if (VirtualAddress != PhysicalAddress) {
Status = EFI_UNSUPPORTED;
break;
}
} else {
Level = 2;
OcAsciiPrintBuffer (
&FileBuffer,
&FileBufferSize,
"0x%LX MTRR %u=%a\n",
VirtualAddress,
MtrrCacheType,
OcGetMtrrTypeString (MtrrCacheType)
);
}
switch (Level) {
case 1:
VirtualAddress += SIZE_1GB;
break;
case 2:
VirtualAddress += SIZE_2MB;
break;
case 4:
VirtualAddress += SIZE_4KB;
break;
default:
Status = EFI_UNSUPPORTED;
break;
}
} while (!EFI_ERROR (Status) && VirtualAddress < EndAddress);
}
if (EFI_ERROR (Status)) {
if ((Gop->Mode == NULL) || (Gop->Mode->Info == NULL)) {
OcAsciiPrintBuffer (
&FileBuffer,
&FileBufferSize,
"Failure reading page table! - %r\n",
"INVALID GOP %p %p!\n",
Gop->Mode,
(Gop->Mode != NULL) ? Gop->Mode->Info : NULL
);
Status = EFI_UNSUPPORTED;
}
if (!EFI_ERROR (Status)) {
OcAsciiPrintBuffer (
&FileBuffer,
&FileBufferSize,
"GOP INFO %u(%u)x%u fmt %u\n",
Gop->Mode->Info->HorizontalResolution,
Gop->Mode->Info->PixelsPerScanLine,
Gop->Mode->Info->VerticalResolution,
Gop->Mode->Info->PixelFormat
);
if (Gop->Mode->Info->PixelFormat == PixelBitMask) {
OcAsciiPrintBuffer (
&FileBuffer,
&FileBufferSize,
"GOP pix mask 0x%X:0x%X:0x%X:0x%X\n",
Gop->Mode->Info->PixelInformation.RedMask,
Gop->Mode->Info->PixelInformation.GreenMask,
Gop->Mode->Info->PixelInformation.BlueMask,
Gop->Mode->Info->PixelInformation.ReservedMask
);
}
OcAsciiPrintBuffer (
&FileBuffer,
&FileBufferSize,
"GOP FB 0x%LX[0x%X]\n",
Gop->Mode->FrameBufferBase,
Gop->Mode->FrameBufferSize
);
Status = OcGopModeBytesPerPixel (Gop->Mode, &BytesPerPixel);
OcAsciiPrintBuffer (
&FileBuffer,
&FileBufferSize,
"GOP BPP %u - %r\n",
BytesPerPixel,
Status
);
if (!EFI_ERROR (Status)) {
Status = OcGopModeSafeFrameBufferSize (Gop->Mode, &FrameBufferSize);
OcAsciiPrintBuffer (
&FileBuffer,
&FileBufferSize,
"GOP FBS 0x%X%a - %r\n",
FrameBufferSize,
(Gop->Mode->FrameBufferSize != FrameBufferSize) ? " (FBS mismatch! Using this.)" : "",
Status
);
}
}
if (!EFI_ERROR (Status)) {
HasMtrr = IsMtrrSupported ();
HasPat = OcIsPatSupported ();
OcAsciiPrintBuffer (
&FileBuffer,
&FileBufferSize,
"MTRR %asupported PAT %asupported\n",
HasMtrr ? "" : "not ",
HasPat ? "" : "not "
);
if (HasMtrr) {
if (HasPat) {
PatMsr = AsmReadMsr64 (MSR_IA32_CR_PAT);
HasDefaultPat = (PatMsr == PAT_DEFAULTS);
OcAsciiPrintBuffer (
&FileBuffer,
&FileBufferSize,
"PAT 0x%016LX (%a)\n",
PatMsr,
HasDefaultPat ? "default" : "not default!"
);
}
PageTable = OcGetCurrentPageTable (NULL);
VirtualAddress = Gop->Mode->FrameBufferBase;
EndAddress = VirtualAddress + FrameBufferSize;
Status = EFI_SUCCESS;
do {
MtrrCacheType = MtrrGetMemoryAttribute (VirtualAddress);
if (HasPat) {
Status = OcGetSetPageTableInfoForAddress (
PageTable,
VirtualAddress,
&PhysicalAddress,
&Level,
&Bits,
&PatIndex,
FALSE
);
if (EFI_ERROR (Status)) {
break;
}
OcAsciiPrintBuffer (
&FileBuffer,
&FileBufferSize,
"0x%LX~0x%LX MTRR %u=%a PTE%u bits 0x%016LX PAT@%u->%u=%a\n",
VirtualAddress,
PhysicalAddress,
MtrrCacheType,
OcGetMtrrTypeString (MtrrCacheType),
Level,
Bits,
PatIndex.Index,
GET_PAT_N (PatMsr, PatIndex.Index),
OcGetPatTypeString (GET_PAT_N (PatMsr, PatIndex.Index))
);
if (VirtualAddress != PhysicalAddress) {
Status = EFI_UNSUPPORTED;
break;
}
} else {
Level = 2;
OcAsciiPrintBuffer (
&FileBuffer,
&FileBufferSize,
"0x%LX MTRR %u=%a\n",
VirtualAddress,
MtrrCacheType,
OcGetMtrrTypeString (MtrrCacheType)
);
}
switch (Level) {
case 1:
VirtualAddress += SIZE_1GB;
break;
case 2:
VirtualAddress += SIZE_2MB;
break;
case 4:
VirtualAddress += SIZE_4KB;
break;
default:
Status = EFI_UNSUPPORTED;
break;
}
} while (!EFI_ERROR (Status) && VirtualAddress < EndAddress);
}
if (EFI_ERROR (Status)) {
OcAsciiPrintBuffer (
&FileBuffer,
&FileBufferSize,
"Failure reading page table! - %r\n",
Status
);
}
}
//

View File

@ -1,6 +1,5 @@
/** @file
Use PAT to enable write-combining caching (burst mode) on GOP memory,
when it is suppported but firmware has not set it up.
GOP buffer and pixel size utility methods, and GOP burst mode caching code.
Copyright (C) 2023, Mike Beaton. All rights reserved.<BR>
SPDX-License-Identifier: BSD-3-Clause
@ -18,6 +17,7 @@
#include <Library/DebugLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/MtrrLib.h>
#include <Library/OcGuardLib.h>
#include <Library/OcMemoryLib.h>
#include <Library/OcStringLib.h>
#include <Library/PrintLib.h>
@ -25,6 +25,104 @@
#define PAT_INDEX_TO_CHANGE 7
EFI_STATUS
OcGopModeBytesPerPixel (
IN EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *Mode,
OUT UINTN *BytesPerPixel
)
{
UINT32 MergedMasks;
if ( (Mode == NULL)
|| (Mode->Info == NULL))
{
ASSERT (
(Mode != NULL)
&& (Mode->Info != NULL)
);
return EFI_UNSUPPORTED;
}
//
// This can occur without PixelBltOnly, including in rotated DirectGopRendering -
// see comment about PixelFormat in ConsoleGop.c RotateMode method.
//
if (Mode->FrameBufferBase == 0ULL) {
return EFI_UNSUPPORTED;
}
switch (Mode->Info->PixelFormat) {
case PixelRedGreenBlueReserved8BitPerColor:
case PixelBlueGreenRedReserved8BitPerColor:
*BytesPerPixel = sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
return EFI_SUCCESS;
case PixelBitMask:
break;
case PixelBltOnly:
return EFI_UNSUPPORTED;
default:
return EFI_INVALID_PARAMETER;
}
MergedMasks = Mode->Info->PixelInformation.RedMask
|| Mode->Info->PixelInformation.GreenMask
|| Mode->Info->PixelInformation.BlueMask
|| Mode->Info->PixelInformation.ReservedMask;
if (MergedMasks == 0) {
return EFI_INVALID_PARAMETER;
}
*BytesPerPixel = (UINT32)((HighBitSet32 (MergedMasks) + 7) / 8);
return EFI_SUCCESS;
}
EFI_STATUS
OcGopModeSafeFrameBufferSize (
IN EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *Mode,
OUT UINTN *FrameBufferSize
)
{
EFI_STATUS Status;
UINTN BytesPerPixel;
if ( (Mode == NULL)
|| (Mode->Info == NULL))
{
ASSERT (
(Mode != NULL)
&& (Mode->Info != NULL)
);
return EFI_UNSUPPORTED;
}
Status = OcGopModeBytesPerPixel (Mode, &BytesPerPixel);
if (EFI_ERROR (Status)) {
return Status;
}
if (OcOverflowTriMulUN (
Mode->Info->PixelsPerScanLine,
Mode->Info->VerticalResolution,
BytesPerPixel,
FrameBufferSize
))
{
return EFI_INVALID_PARAMETER;
}
return EFI_SUCCESS;
}
//
// Use PAT to enable write-combining caching (burst mode) on GOP memory,
// when it is suppported but firmware has not set it up.
//
STATIC
EFI_STATUS
WriteCombineGop (
@ -37,6 +135,7 @@ WriteCombineGop (
PAGE_MAP_AND_DIRECTORY_POINTER *PageTable;
EFI_VIRTUAL_ADDRESS VirtualAddress;
EFI_PHYSICAL_ADDRESS PhysicalAddress;
UINTN FrameBufferSize;
UINT64 Bits;
UINT8 Level;
BOOLEAN HasMtrr;
@ -51,6 +150,23 @@ WriteCombineGop (
return EFI_SUCCESS;
}
if ( (Gop == NULL)
|| (Gop->Mode == NULL)
|| (Gop->Mode->Info == NULL))
{
ASSERT (
(Gop != NULL)
&& (Gop->Mode != NULL)
&& (Gop->Mode->Info != NULL)
);
return EFI_UNSUPPORTED;
}
Status = OcGopModeSafeFrameBufferSize (Gop->Mode, &FrameBufferSize);
if (EFI_ERROR (Status)) {
return Status;
}
HasMtrr = IsMtrrSupported ();
HasPat = OcIsPatSupported ();
@ -81,8 +197,6 @@ WriteCombineGop (
MtrrCacheType = MtrrGetMemoryAttribute (Gop->Mode->FrameBufferBase);
DEBUG_CODE_BEGIN ();
VirtualAddress = Gop->Mode->FrameBufferBase;
Status = OcGetSetPageTableInfoForAddress (
@ -97,9 +211,8 @@ WriteCombineGop (
DEBUG ((
DEBUG_INFO,
"OCC: 0x%LX->0x%LX MTRR %u=%a PTE%u bits 0x%016LX PAT %u->%u=%a - %r\n",
"OCC: 0x%LX MTRR %u=%a PTE%u bits 0x%016LX PAT@%u->%u=%a - %r\n",
VirtualAddress,
PhysicalAddress,
MtrrCacheType,
OcGetMtrrTypeString (MtrrCacheType),
Level,
@ -110,20 +223,27 @@ WriteCombineGop (
Status
));
ASSERT_EFI_ERROR (Status);
if (EFI_ERROR (Status)) {
ASSERT (!AlreadySet);
return Status;
}
ASSERT (VirtualAddress == PhysicalAddress);
if (AlreadySet) {
break;
}
DEBUG_CODE_END ();
//
// If MTRR is already set to WC, no need to set it via PAT.
// (Ignore implausible scenario where WC is set via MTRR but overridden via PAT.)
// Attempting to set again if set in PAT works on some systems (including if set
// before by us) but fails with a hang on some others, so avoid it even though we
// might otherwise prefer to make sure to set the whole memory for the current mode.
// Definitely no need to set again if set in MTRR.
//
if (MtrrCacheType == CacheWriteCombining) {
if ( (MtrrCacheType == CacheWriteCombining)
|| (GET_PAT_N (PatMsr, PatIndex.Index) == PatWriteCombining)
)
{
return EFI_ALREADY_STARTED;
}
@ -161,7 +281,15 @@ WriteCombineGop (
}
}
Status = OcSetPatIndexForAddressRange (PageTable, Gop->Mode->FrameBufferBase, Gop->Mode->FrameBufferSize, &PatIndex);
//
// TODO: Use full GOP memory range not just range in use for current mode?
//
Status = OcSetPatIndexForAddressRange (
PageTable,
Gop->Mode->FrameBufferBase,
FrameBufferSize,
&PatIndex
);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "OCC: Failed to set PAT index for range - %r\n", Status));
@ -197,7 +325,11 @@ OcSetGopBurstMode (
Status = WriteCombineGop (Gop, TRUE);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_WARN, "OCC: Failed to set burst mode - %r\n", Status));
DEBUG ((
(Status == EFI_ALREADY_STARTED) ? DEBUG_INFO : DEBUG_WARN,
"OCC: Failed to set burst mode - %r\n",
Status
));
}
return Status;

View File

@ -47,7 +47,7 @@
Eg2Info.c
FramebufferInfo.c
GopInfoDump.c
GopBurstMode.c
GopUtils.c
GopPassThrough.c
OcConsoleLib.c
OcConsoleLibInternal.h