UefiCpuPkg/MpInitLib: split wake up buffer into two parts

If PcdDxeNxMemoryProtectionPolicy is set to enable protection for memory
of EfiBootServicesCode, EfiConventionalMemory, the BIOS will hang at a page
fault exception during MP initialization.

The root cause is that the AP wake up buffer, which is below 1MB and used
to hold both AP init code and data, is type of EfiConventionalMemory (not
really allocated because of potential conflict with legacy code), and is
marked as non-executable. During the transition from real address mode
to long mode, the AP init code has to enable paging which will then cause
itself a page fault exception because it's just running in non-executable
memory.

The solution is splitting AP wake up buffer into two part: lower part is
still below 1MB and shared with legacy system, higher part is really
allocated memory of BootServicesCode type. The init code in the memory
below 1MB will not enable paging but just switch to protected mode and
jump to higher memory, in which the init code will enable paging and
switch to long mode.

Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Ruiyu Ni <ruiyu.ni@intel.com>
Cc: Eric Dong <eric.dong@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Reviewed-by: Eric Dong <eric.dong@intel.com>
This commit is contained in:
Jian J Wang
2017-12-29 09:12:54 +08:00
committed by Ruiyu Ni
parent 4f10654e04
commit f32bfe6d06
8 changed files with 204 additions and 49 deletions

View File

@@ -772,6 +772,8 @@ FillExchangeInfoData (
)
{
volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;
UINTN Size;
IA32_SEGMENT_DESCRIPTOR *Selector;
ExchangeInfo = CpuMpData->MpCpuExchangeInfo;
ExchangeInfo->Lock = 0;
@@ -801,6 +803,44 @@ FillExchangeInfoData (
//
AsmReadGdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->GdtrProfile);
AsmReadIdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->IdtrProfile);
//
// Find a 32-bit code segment
//
Selector = (IA32_SEGMENT_DESCRIPTOR *)ExchangeInfo->GdtrProfile.Base;
Size = ExchangeInfo->GdtrProfile.Limit + 1;
while (Size > 0) {
if (Selector->Bits.L == 0 && Selector->Bits.Type >= 8) {
ExchangeInfo->ModeTransitionSegment =
(UINT16)((UINTN)Selector - ExchangeInfo->GdtrProfile.Base);
break;
}
Selector += 1;
Size -= sizeof (IA32_SEGMENT_DESCRIPTOR);
}
//
// Copy all 32-bit code and 64-bit code into memory with type of
// EfiBootServicesCode to avoid page fault if NX memory protection is enabled.
//
if (ExchangeInfo->ModeTransitionMemory != 0) {
Size = CpuMpData->AddressMap.RendezvousFunnelSize -
CpuMpData->AddressMap.ModeTransitionOffset;
CopyMem (
(VOID *)(UINTN)ExchangeInfo->ModeTransitionMemory,
CpuMpData->AddressMap.RendezvousFunnelAddress +
CpuMpData->AddressMap.ModeTransitionOffset,
Size
);
ExchangeInfo->ModeHighMemory = ExchangeInfo->ModeTransitionMemory;
ExchangeInfo->ModeHighMemory += (UINT32)ExchangeInfo->ModeOffset -
(UINT32)CpuMpData->AddressMap.ModeTransitionOffset;
ExchangeInfo->ModeHighSegment = (UINT16)ExchangeInfo->CodeSegment;
} else {
ExchangeInfo->ModeTransitionMemory = (UINT32)
(ExchangeInfo->BufferStart + CpuMpData->AddressMap.ModeTransitionOffset);
}
}
/**
@@ -876,6 +916,11 @@ AllocateResetVector (
CpuMpData->WakeupBuffer = GetWakeupBuffer (ApResetVectorSize);
CpuMpData->MpCpuExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN)
(CpuMpData->WakeupBuffer + CpuMpData->AddressMap.RendezvousFunnelSize);
CpuMpData->MpCpuExchangeInfo->ModeTransitionMemory = (UINT32)
GetModeTransitionBuffer (
CpuMpData->AddressMap.RendezvousFunnelSize -
CpuMpData->AddressMap.ModeTransitionOffset
);
}
BackupAndPrepareWakeupBuffer (CpuMpData);
}