IntelFrameworkModulePkg/Csm: Add code to bypass NULL pointer detection

Legacy has to access interrupt vector, BDA, etc. located in memory between
0-4095. To allow as much code as possible to be monitored by NULL pointer
detection, we add code to temporarily disable this feature right before
those memory access and enable it again afterwards.

Cc: Star Zeng <star.zeng@intel.com>
Cc: Eric Dong <eric.dong@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Michael Kinney <michael.d.kinney@intel.com>
Cc: Ayellet Wolman <ayellet.wolman@intel.com>
Suggested-by: Ayellet Wolman <ayellet.wolman@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Reviewed-by: Jiewen Yao <jiewen.yao@intel.com>
Reviewed-by: Star Zeng <star.zeng@intel.com>
This commit is contained in:
Jian J Wang 2017-10-09 22:01:49 +08:00 committed by Eric Dong
parent f8c1133bbb
commit d057d8c4e9
10 changed files with 338 additions and 10 deletions

View File

@ -1732,6 +1732,98 @@ CheckKeyboardConnect (
}
}
/**
Disable NULL pointer detection
*/
VOID
DisableNullDetection (
VOID
)
{
EFI_STATUS Status;
EFI_GCD_MEMORY_SPACE_DESCRIPTOR Desc;
if ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT0) == 0) {
return;
}
//
// Check current capabilities and attributes
//
Status = gDS->GetMemorySpaceDescriptor (0, &Desc);
ASSERT_EFI_ERROR (Status);
//
// Try to add EFI_MEMORY_RP support if necessary
//
if ((Desc.Capabilities & EFI_MEMORY_RP) == 0) {
Desc.Capabilities |= EFI_MEMORY_RP;
Status = gDS->SetMemorySpaceCapabilities (0, EFI_PAGES_TO_SIZE(1),
Desc.Capabilities);
ASSERT_EFI_ERROR (Status);
if (EFI_ERROR (Status)) {
return;
}
}
//
// Don't bother if EFI_MEMORY_RP is already cleared.
//
if ((Desc.Attributes & EFI_MEMORY_RP) != 0) {
Desc.Attributes &= ~EFI_MEMORY_RP;
Status = gDS->SetMemorySpaceAttributes (0, EFI_PAGES_TO_SIZE(1),
Desc.Attributes);
ASSERT_EFI_ERROR (Status);
} else {
DEBUG ((DEBUG_WARN, "!!! Page 0 is supposed to be disabled !!!\r\n"));
}
}
/**
Enable NULL pointer detection
*/
VOID
EnableNullDetection (
VOID
)
{
EFI_STATUS Status;
EFI_GCD_MEMORY_SPACE_DESCRIPTOR Desc;
if ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT0) == 0) {
return;
}
//
// Check current capabilities and attributes
//
Status = gDS->GetMemorySpaceDescriptor (0, &Desc);
ASSERT_EFI_ERROR (Status);
//
// Try to add EFI_MEMORY_RP support if necessary
//
if ((Desc.Capabilities & EFI_MEMORY_RP) == 0) {
Desc.Capabilities |= EFI_MEMORY_RP;
Status = gDS->SetMemorySpaceCapabilities (0, EFI_PAGES_TO_SIZE(1),
Desc.Capabilities);
ASSERT_EFI_ERROR (Status);
if (EFI_ERROR (Status)) {
return;
}
}
//
// Don't bother if EFI_MEMORY_RP is already set.
//
if ((Desc.Attributes & EFI_MEMORY_RP) == 0) {
Desc.Attributes |= EFI_MEMORY_RP;
Status = gDS->SetMemorySpaceAttributes (0, EFI_PAGES_TO_SIZE(1),
Desc.Attributes);
ASSERT_EFI_ERROR (Status);
}
}
/**
Timer event handler: read a series of key stroke from 8042
and put them into memory key buffer.
@ -1839,6 +1931,11 @@ BiosKeyboardTimerHandler (
// 0 Right Shift pressed
//
// Disable NULL pointer detection temporarily
//
DisableNullDetection ();
//
// Clear the CTRL and ALT BDA flag
//
@ -1916,6 +2013,10 @@ BiosKeyboardTimerHandler (
KbFlag1 &= ~0x0C;
*((UINT8 *) (UINTN) 0x417) = KbFlag1;
//
// Restore NULL pointer detection
//
EnableNullDetection ();
//
// Output EFI input key and shift/toggle state

View File

@ -18,6 +18,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include <FrameworkDxe.h>
#include <Pi/PiDxeCis.h>
#include <Guid/StatusCodeDataTypeId.h>
#include <Protocol/SimpleTextIn.h>
@ -33,6 +34,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include <Library/ReportStatusCodeLib.h>
#include <Library/UefiDriverEntryPoint.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/DxeServicesTableLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/BaseLib.h>
#include <Library/PcdLib.h>

View File

@ -60,6 +60,7 @@
DebugLib
BaseLib
PcdLib
DxeServicesTableLib
[Protocols]
gEfiIsaIoProtocolGuid ## TO_START
@ -73,6 +74,7 @@
[Pcd]
gEfiMdeModulePkgTokenSpaceGuid.PcdFastPS2Detection ## SOMETIMES_CONSUMES
gEfiMdeModulePkgTokenSpaceGuid.PcdNullPointerDetectionPropertyMask ## CONSUMES
[UserExtensions.TianoCore."ExtraFiles"]
KeyboardDxeExtra.uni

View File

@ -34,6 +34,8 @@ LegacyBiosInitBda (
BDA_STRUC *Bda;
UINT8 *Ebda;
DisableNullDetection ();
Bda = (BDA_STRUC *) ((UINTN) 0x400);
Ebda = (UINT8 *) ((UINTN) 0x9fc00);
@ -62,5 +64,7 @@ LegacyBiosInitBda (
*Ebda = 0x01;
EnableNullDetection ();
return EFI_SUCCESS;
}

View File

@ -40,6 +40,7 @@ VOID *mRuntimeSmbiosEntryPoint = NULL;
EFI_PHYSICAL_ADDRESS mReserveSmbiosEntryPoint = 0;
EFI_PHYSICAL_ADDRESS mStructureTableAddress = 0;
UINTN mStructureTablePages = 0;
BOOLEAN mEndOfDxe = FALSE;
/**
Do an AllocatePages () of type AllocateMaxAddress for EfiBootServicesCode
@ -765,6 +766,135 @@ InstallSmbiosEventCallback (
}
}
/**
Callback function to toggle EndOfDxe status. NULL pointer detection needs
this status to decide if it's necessary to change attributes of page 0.
@param Event Event whose notification function is being invoked.
@param Context The pointer to the notification function's context,
which is implementation-dependent.
**/
VOID
EFIAPI
ToggleEndOfDxeStatus (
IN EFI_EVENT Event,
IN VOID *Context
)
{
mEndOfDxe = TRUE;
return;
}
//
// Legacy BIOS needs to access memory between 0-4095, which will cause page
// fault exception if NULL pointer detection mechanism is enabled. Following
// functions can be used to disable/enable NULL pointer detection before/after
// accessing those memory.
//
/**
Enable NULL pointer detection
*/
VOID
EnableNullDetection (
VOID
)
{
EFI_STATUS Status;
EFI_GCD_MEMORY_SPACE_DESCRIPTOR Desc;
if (((PcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT0) == 0)
||
((mEndOfDxe == TRUE) &&
((PcdGet8 (PcdNullPointerDetectionPropertyMask) & (BIT7|BIT0))
== (BIT7|BIT0)))
) {
return;
}
//
// Check current capabilities and attributes
//
Status = gDS->GetMemorySpaceDescriptor (0, &Desc);
ASSERT_EFI_ERROR (Status);
//
// Try to add EFI_MEMORY_RP support if necessary
//
if ((Desc.Capabilities & EFI_MEMORY_RP) == 0) {
Desc.Capabilities |= EFI_MEMORY_RP;
Status = gDS->SetMemorySpaceCapabilities (0, EFI_PAGES_TO_SIZE(1),
Desc.Capabilities);
ASSERT_EFI_ERROR (Status);
if (EFI_ERROR (Status)) {
return;
}
}
//
// Don't bother if EFI_MEMORY_RP is already set.
//
if ((Desc.Attributes & EFI_MEMORY_RP) == 0) {
Desc.Attributes |= EFI_MEMORY_RP;
Status = gDS->SetMemorySpaceAttributes (0, EFI_PAGES_TO_SIZE(1),
Desc.Attributes);
ASSERT_EFI_ERROR (Status);
}
}
/**
Disable NULL pointer detection
*/
VOID
DisableNullDetection (
VOID
)
{
EFI_STATUS Status;
EFI_GCD_MEMORY_SPACE_DESCRIPTOR Desc;
if (((PcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT0) == 0)
||
((mEndOfDxe == TRUE) &&
((PcdGet8 (PcdNullPointerDetectionPropertyMask) & (BIT7|BIT0))
== (BIT7|BIT0)))
) {
return;
}
//
// Check current capabilities and attributes
//
Status = gDS->GetMemorySpaceDescriptor (0, &Desc);
ASSERT_EFI_ERROR (Status);
//
// Try to add EFI_MEMORY_RP support if necessary
//
if ((Desc.Capabilities & EFI_MEMORY_RP) == 0) {
Desc.Capabilities |= EFI_MEMORY_RP;
Status = gDS->SetMemorySpaceCapabilities (0, EFI_PAGES_TO_SIZE(1),
Desc.Capabilities);
ASSERT_EFI_ERROR (Status);
if (EFI_ERROR (Status)) {
return;
}
}
//
// Don't bother if EFI_MEMORY_RP is already cleared.
//
if ((Desc.Attributes & EFI_MEMORY_RP) != 0) {
Desc.Attributes &= ~EFI_MEMORY_RP;
Status = gDS->SetMemorySpaceAttributes (0, EFI_PAGES_TO_SIZE(1),
Desc.Attributes);
ASSERT_EFI_ERROR (Status);
} else {
DEBUG ((DEBUG_WARN, "!!! Page 0 is supposed to be disabled !!!\r\n"));
}
}
/**
Install Driver to produce Legacy BIOS protocol.
@ -802,6 +932,7 @@ LegacyBiosInstall (
UINT64 Length;
UINT8 *SecureBoot;
EFI_EVENT InstallSmbiosEvent;
EFI_EVENT EndOfDxeEvent;
//
// Load this driver's image to memory
@ -964,8 +1095,10 @@ LegacyBiosInstall (
// Initialize region from 0x0000 to 4k. This initializes interrupt vector
// range.
//
DisableNullDetection ();
gBS->SetMem ((VOID *) ClearPtr, 0x400, INITIAL_VALUE_BELOW_1K);
ZeroMem ((VOID *) ((UINTN)ClearPtr + 0x400), 0xC00);
EnableNullDetection ();
//
// Allocate pages for OPROM usage
@ -1104,12 +1237,17 @@ LegacyBiosInstall (
//
// Save Unexpected interrupt vector so can restore it just prior to boot
//
DisableNullDetection ();
BaseVectorMaster = (UINT32 *) (sizeof (UINT32) * PROTECTED_MODE_BASE_VECTOR_MASTER);
Private->BiosUnexpectedInt = BaseVectorMaster[0];
IntRedirCode = (UINT32) (UINTN) Private->IntThunk->InterruptRedirectionCode;
for (Index = 0; Index < 8; Index++) {
BaseVectorMaster[Index] = (EFI_SEGMENT (IntRedirCode + Index * 4) << 16) | EFI_OFFSET (IntRedirCode + Index * 4);
}
EnableNullDetection ();
//
// Save EFI value
//
@ -1133,6 +1271,20 @@ LegacyBiosInstall (
);
ASSERT_EFI_ERROR (Status);
//
// Create callback to update status of EndOfDxe, which is needed by NULL
// pointer detection
//
Status = gBS->CreateEventEx (
EVT_NOTIFY_SIGNAL,
TPL_NOTIFY,
ToggleEndOfDxeStatus,
NULL,
&gEfiEndOfDxeEventGroupGuid,
&EndOfDxeEvent
);
ASSERT_EFI_ERROR (Status);
//
// Make a new handle and install the protocol
//

View File

@ -108,6 +108,7 @@
gEfiDiskInfoIdeInterfaceGuid ## SOMETIMES_CONSUMES ##GUID #Used in LegacyBiosBuildIdeData() to assure device is a disk
gEfiSmbiosTableGuid ## SOMETIMES_CONSUMES ##SystemTable
gEfiLegacyBiosGuid ## SOMETIMES_CONSUMES ##GUID #Used in LegacyBiosInstallVgaRom() to locate handle buffer
gEfiEndOfDxeEventGroupGuid ## CONSUMES
[Guids.IA32]
gEfiAcpi20TableGuid ## SOMETIMES_CONSUMES ##SystemTable
@ -147,6 +148,7 @@
gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdHighPmmMemorySize ## CONSUMES
gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdOpromReservedMemoryBase ## CONSUMES
gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdOpromReservedMemorySize ## CONSUMES
gEfiMdeModulePkgTokenSpaceGuid.PcdNullPointerDetectionPropertyMask ## CONSUMES
[Depex]
gEfiLegacyRegion2ProtocolGuid AND gEfiLegacyInterruptProtocolGuid AND gEfiLegacyBiosPlatformProtocolGuid AND gEfiLegacy8259ProtocolGuid AND gEfiGenericMemTestProtocolGuid AND gEfiCpuArchProtocolGuid AND gEfiTimerArchProtocolGuid AND gEfiVariableWriteArchProtocolGuid

View File

@ -509,6 +509,8 @@ extern BBS_TABLE *mBbsTable;
extern EFI_GENERIC_MEMORY_TEST_PROTOCOL *gGenMemoryTest;
extern BOOLEAN mEndOfDxe;
#define PORT_70 0x70
#define PORT_71 0x71
@ -1542,4 +1544,20 @@ LegacyBiosInstallVgaRom (
IN LEGACY_BIOS_INSTANCE *Private
);
/**
Enable NULL pointer detection
*/
VOID
EnableNullDetection (
VOID
);
/**
Disable NULL pointer detection
*/
VOID
DisableNullDetection (
VOID
);
#endif

View File

@ -1073,8 +1073,10 @@ GenericLegacyBoot (
// Use 182/10 to avoid floating point math.
//
LocalTime = (LocalTime * 182) / 10;
DisableNullDetection ();
BdaPtr = (UINT32 *) (UINTN)0x46C;
*BdaPtr = LocalTime;
EnableNullDetection ();
//
// Shadow PCI ROMs. We must do this near the end since this will kick
@ -1320,6 +1322,7 @@ GenericLegacyBoot (
// set of TIANO vectors) or takes it over.
//
//
DisableNullDetection ();
BaseVectorMaster = (UINT32 *) (sizeof (UINT32) * PROTECTED_MODE_BASE_VECTOR_MASTER);
for (Index = 0; Index < 8; Index++) {
Private->ThunkSavedInt[Index] = BaseVectorMaster[Index];
@ -1327,6 +1330,7 @@ GenericLegacyBoot (
BaseVectorMaster[Index] = (UINT32) (Private->BiosUnexpectedInt);
}
}
EnableNullDetection ();
ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
Regs.X.AX = Legacy16Boot;
@ -1340,10 +1344,12 @@ GenericLegacyBoot (
0
);
DisableNullDetection ();
BaseVectorMaster = (UINT32 *) (sizeof (UINT32) * PROTECTED_MODE_BASE_VECTOR_MASTER);
for (Index = 0; Index < 8; Index++) {
BaseVectorMaster[Index] = Private->ThunkSavedInt[Index];
}
EnableNullDetection ();
}
Private->LegacyBootEntered = TRUE;
if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) {
@ -1731,9 +1737,11 @@ LegacyBiosBuildE820 (
//
// First entry is 0 to (640k - EBDA)
//
DisableNullDetection ();
E820Table[0].BaseAddr = 0;
E820Table[0].Length = (UINT64) ((*(UINT16 *) (UINTN)0x40E) << 4);
E820Table[0].Type = EfiAcpiAddressRangeMemory;
EnableNullDetection ();
//
// Second entry is (640k - EBDA) to 640k
@ -1967,6 +1975,8 @@ LegacyBiosCompleteBdaBeforeBoot (
UINT16 MachineConfig;
DEVICE_PRODUCER_DATA_HEADER *SioPtr;
DisableNullDetection ();
Bda = (BDA_STRUC *) ((UINTN) 0x400);
MachineConfig = 0;
@ -2025,6 +2035,8 @@ LegacyBiosCompleteBdaBeforeBoot (
MachineConfig = (UINT16) (MachineConfig + 0x00 + 0x02 + (SioPtr->MousePresent * 0x04));
Bda->MachineConfig = MachineConfig;
EnableNullDetection ();
return EFI_SUCCESS;
}
@ -2049,15 +2061,20 @@ LegacyBiosUpdateKeyboardLedStatus (
UINT8 LocalLeds;
EFI_IA32_REGISTER_SET Regs;
Bda = (BDA_STRUC *) ((UINTN) 0x400);
Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
DisableNullDetection ();
Bda = (BDA_STRUC *) ((UINTN) 0x400);
LocalLeds = Leds;
Bda->LedStatus = (UINT8) ((Bda->LedStatus &~0x07) | LocalLeds);
LocalLeds = (UINT8) (LocalLeds << 4);
Bda->ShiftStatus = (UINT8) ((Bda->ShiftStatus &~0x70) | LocalLeds);
LocalLeds = (UINT8) (Leds & 0x20);
Bda->KeyboardStatus = (UINT8) ((Bda->KeyboardStatus &~0x20) | LocalLeds);
EnableNullDetection ();
//
// Call into Legacy16 code to allow it to do any processing
//
@ -2102,7 +2119,9 @@ LegacyBiosCompleteStandardCmosBeforeBoot (
// to large capacity drives
// CMOS 14 = BDA 40:10 plus bit 3(display enabled)
//
DisableNullDetection ();
Bda = (UINT8)(*((UINT8 *)((UINTN)0x410)) | BIT3);
EnableNullDetection ();
//
// Force display enabled

View File

@ -2279,6 +2279,7 @@ LegacyBiosInstallRom (
UINTN Function;
EFI_IA32_REGISTER_SET Regs;
UINT8 VideoMode;
UINT8 OldVideoMode;
EFI_TIME BootTime;
UINT32 *BdaPtr;
UINT32 LocalTime;
@ -2299,6 +2300,7 @@ LegacyBiosInstallRom (
Device = 0;
Function = 0;
VideoMode = 0;
OldVideoMode = 0;
PhysicalAddress = 0;
MaxRomAddr = PcdGet32 (PcdEndOpromShadowAddress);
@ -2401,6 +2403,8 @@ LegacyBiosInstallRom (
// 2. BBS compliants drives will not change 40:75 until boot time.
// 3. Onboard IDE controllers will change 40:75
//
DisableNullDetection ();
LocalDiskStart = (UINT8) ((*(UINT8 *) ((UINTN) 0x475)) + 0x80);
if ((Private->Disk4075 + 0x80) < LocalDiskStart) {
//
@ -2426,6 +2430,9 @@ LegacyBiosInstallRom (
//
VideoMode = *(UINT8 *) ((UINTN) (0x400 + BDA_VIDEO_MODE));
}
EnableNullDetection ();
//
// Notify the platform that we are about to scan the ROM
//
@ -2466,9 +2473,11 @@ LegacyBiosInstallRom (
// Multiply result by 18.2 for number of ticks since midnight.
// Use 182/10 to avoid floating point math.
//
DisableNullDetection ();
LocalTime = (LocalTime * 182) / 10;
BdaPtr = (UINT32 *) ((UINTN) 0x46C);
*BdaPtr = LocalTime;
EnableNullDetection ();
//
// Pass in handoff data
@ -2564,7 +2573,11 @@ LegacyBiosInstallRom (
//
// Set mode settings since PrepareToScanRom may change mode
//
if (VideoMode != *(UINT8 *) ((UINTN) (0x400 + BDA_VIDEO_MODE))) {
DisableNullDetection ();
OldVideoMode = *(UINT8 *) ((UINTN) (0x400 + BDA_VIDEO_MODE));
EnableNullDetection ();
if (VideoMode != OldVideoMode) {
//
// The active video mode is changed, restore it to original mode.
//
@ -2604,7 +2617,9 @@ LegacyBiosInstallRom (
}
}
DisableNullDetection ();
LocalDiskEnd = (UINT8) ((*(UINT8 *) ((UINTN) 0x475)) + 0x80);
EnableNullDetection ();
//
// Allow platform to perform any required actions after the

View File

@ -57,7 +57,11 @@ LegacyBiosInt86 (
IN EFI_IA32_REGISTER_SET *Regs
)
{
UINT32 *VectorBase;
UINT16 Segment;
UINT16 Offset;
LEGACY_BIOS_INSTANCE *Private;
Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
Regs->X.Flags.Reserved1 = 1;
Regs->X.Flags.Reserved2 = 0;
@ -72,12 +76,15 @@ LegacyBiosInt86 (
// The base address of legacy interrupt vector table is 0.
// We use this base address to get the legacy interrupt handler.
//
VectorBase = 0;
DisableNullDetection ();
Segment = (UINT16)(((UINT32 *)0)[BiosInt] >> 16);
Offset = (UINT16)((UINT32 *)0)[BiosInt];
EnableNullDetection ();
return InternalLegacyBiosFarCall (
This,
(UINT16) ((VectorBase)[BiosInt] >> 16),
(UINT16) (VectorBase)[BiosInt],
Segment,
Offset,
Regs,
&Regs->X.Flags,
sizeof (Regs->X.Flags)
@ -293,9 +300,15 @@ InternalLegacyBiosFarCall (
UINTN EbdaBaseAddress;
UINTN ReservedEbdaBaseAddress;
EbdaBaseAddress = (*(UINT16 *) (UINTN) 0x40E) << 4;
ReservedEbdaBaseAddress = CONVENTIONAL_MEMORY_TOP - PcdGet32 (PcdEbdaReservedMemorySize);
ASSERT (ReservedEbdaBaseAddress <= EbdaBaseAddress);
//
// Skip this part of debug code if NULL pointer detection is enabled
//
if ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT0) == 0) {
EbdaBaseAddress = (*(UINT16 *) (UINTN) 0x40E) << 4;
ReservedEbdaBaseAddress = CONVENTIONAL_MEMORY_TOP
- PcdGet32 (PcdEbdaReservedMemorySize);
ASSERT (ReservedEbdaBaseAddress <= EbdaBaseAddress);
}
}
);