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>
---
UefiCpuPkg/Library/MpInitLib/DxeMpLib.c | 34 ++++++++++
UefiCpuPkg/Library/MpInitLib/Ia32/MpEqu.inc | 5 ++
UefiCpuPkg/Library/MpInitLib/Ia32/MpFuncs.nasm | 32 +++++-----
UefiCpuPkg/Library/MpInitLib/MpLib.c | 45 +++++++++++++
UefiCpuPkg/Library/MpInitLib/MpLib.h | 22 +++++++
UefiCpuPkg/Library/MpInitLib/PeiMpLib.c | 23 +++++++
UefiCpuPkg/Library/MpInitLib/X64/MpEqu.inc | 5 +-
UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm | 87 ++++++++++++++++----------
8 files changed, 204 insertions(+), 49 deletions(-)
diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
index d2bcef53d6..fd2317924f 100644
--- a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
@@ -113,6 +113,40 @@ GetWakeupBuffer (
return (UINTN) StartAddress;
}
+/**
+ Get available EfiBootServicesCode memory below 4GB by specified size.
+
+ This buffer is required to safely transfer AP from real address mode to
+ protected mode or long mode, due to the fact that the buffer returned by
+ GetWakeupBuffer() may be marked as non-executable.
+
+ @param[in] BufferSize Wakeup transition buffer size.
+
+ @retval other Return wakeup transition buffer address below 4GB.
+ @retval 0 Cannot find free memory below 4GB.
+**/
+UINTN
+GetModeTransitionBuffer (
+ IN UINTN BufferSize
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS StartAddress;
+
+ StartAddress = BASE_4GB - 1;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiBootServicesCode,
+ EFI_SIZE_TO_PAGES (BufferSize),
+ &StartAddress
+ );
+ if (EFI_ERROR (Status)) {
+ StartAddress = 0;
+ }
+
+ return (UINTN)StartAddress;
+}
+
/**
Checks APs status and updates APs status if needed.
diff --git a/UefiCpuPkg/Library/MpInitLib/Ia32/MpEqu.inc b/UefiCpuPkg/Library/MpInitLib/Ia32/MpEqu.inc
index bdfe0d33cc..1648f2c4b0 100644
--- a/UefiCpuPkg/Library/MpInitLib/Ia32/MpEqu.inc
+++ b/UefiCpuPkg/Library/MpInitLib/Ia32/MpEqu.inc
@@ -41,4 +41,9 @@ Cr3Location equ LockLocation + 34h
InitFlagLocation equ LockLocation + 38h
CpuInfoLocation equ LockLocation + 3Ch
NumApsExecutingLocation equ LockLocation + 40h
+InitializeFloatingPointUnitsAddress equ LockLocation + 48h
+ModeTransitionMemoryLocation equ LockLocation + 4Ch
+ModeTransitionSegmentLocation equ LockLocation + 50h
+ModeHighMemoryLocation equ LockLocation + 52h
+ModeHighSegmentLocation equ LockLocation + 56h
diff --git a/UefiCpuPkg/Library/MpInitLib/Ia32/MpFuncs.nasm b/UefiCpuPkg/Library/MpInitLib/Ia32/MpFuncs.nasm
index 2b6c27d4ec..bd79be0f5e 100644
--- a/UefiCpuPkg/Library/MpInitLib/Ia32/MpFuncs.nasm
+++ b/UefiCpuPkg/Library/MpInitLib/Ia32/MpFuncs.nasm
@@ -48,34 +48,35 @@ BITS 16
mov si, BufferStartLocation
mov ebx, [si]
- mov si, ModeOffsetLocation
- mov eax, [si]
- mov si, CodeSegmentLocation
- mov edx, [si]
- mov di, ax
- sub di, 02h
- mov [di], dx
- sub di, 04h
- add eax, ebx
- mov [di],eax
-
mov si, DataSegmentLocation
mov edx, [si]
+ ;
+ ; Get start address of 32-bit code in low memory (<1MB)
+ ;
+ mov edi, ModeTransitionMemoryLocation
+
mov si, GdtrLocation
o32 lgdt [cs:si]
mov si, IdtrLocation
o32 lidt [cs:si]
- xor ax, ax
- mov ds, ax
-
+ ;
+ ; Switch to protected mode
+ ;
mov eax, cr0 ; Get control register 0
or eax, 000000003h ; Set PE bit (bit #0) & MP
mov cr0, eax
- jmp 0:strict dword 0 ; far jump to protected mode
+ ; Switch to 32-bit code in executable memory (>1MB)
+o32 jmp far [cs:di]
+
+;
+; Following code may be copied to memory with type of EfiBootServicesCode.
+; This is required at DXE phase if NX is enabled for EfiBootServicesCode of
+; memory.
+;
BITS 32
Flat32Start: ; protected mode entry point
mov ds, dx
@@ -266,6 +267,7 @@ ASM_PFX(AsmGetAddressMap):
mov dword [ebx + 8h], RendezvousFunnelProcEnd - RendezvousFunnelProcStart
mov dword [ebx + 0Ch], AsmRelocateApLoopStart
mov dword [ebx + 10h], AsmRelocateApLoopEnd - AsmRelocateApLoopStart
+ mov dword [ebx + 14h], Flat32Start - RendezvousFunnelProcStart
popad
ret
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
index cdc03113e5..fbcbcc6cc9 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -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);
}
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h
index 685e96cbac..0232fe896a 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.h
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h
@@ -152,6 +152,7 @@ typedef struct {
UINTN RendezvousFunnelSize;
UINT8 *RelocateApLoopFuncAddress;
UINTN RelocateApLoopFuncSize;
+ UINTN ModeTransitionOffset;
} MP_ASSEMBLY_ADDRESS_MAP;
typedef struct _CPU_MP_DATA CPU_MP_DATA;
@@ -182,6 +183,10 @@ typedef struct {
UINTN NumApsExecuting;
CPU_MP_DATA *CpuMpData;
UINTN InitializeFloatingPointUnitsAddress;
+ UINT32 ModeTransitionMemory;
+ UINT16 ModeTransitionSegment;
+ UINT32 ModeHighMemory;
+ UINT16 ModeHighSegment;
} MP_CPU_EXCHANGE_INFO;
#pragma pack()
@@ -329,6 +334,23 @@ GetWakeupBuffer (
IN UINTN WakeupBufferSize
);
+/**
+ Get available EfiBootServicesCode memory below 4GB by specified size.
+
+ This buffer is required to safely transfer AP from real address mode to
+ protected mode or long mode, due to the fact that the buffer returned by
+ GetWakeupBuffer() may be marked as non-executable.
+
+ @param[in] BufferSize Wakeup transition buffer size.
+
+ @retval other Return wakeup transition buffer address below 4GB.
+ @retval 0 Cannot find free memory below 4GB.
+**/
+UINTN
+GetModeTransitionBuffer (
+ IN UINTN BufferSize
+ );
+
/**
This function will be called by BSP to wakeup AP.
diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c b/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
index 70c2bc7323..ad43bd33f5 100644
--- a/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
@@ -187,6 +187,29 @@ GetWakeupBuffer (
return (UINTN) -1;
}
+/**
+ Get available EfiBootServicesCode memory below 4GB by specified size.
+
+ This buffer is required to safely transfer AP from real address mode to
+ protected mode or long mode, due to the fact that the buffer returned by
+ GetWakeupBuffer() may be marked as non-executable.
+
+ @param[in] BufferSize Wakeup transition buffer size.
+
+ @retval other Return wakeup transition buffer address below 4GB.
+ @retval 0 Cannot find free memory below 4GB.
+**/
+UINTN
+GetModeTransitionBuffer (
+ IN UINTN BufferSize
+ )
+{
+ //
+ // PEI phase doesn't need to do such transition. So simply return 0.
+ //
+ return 0;
+}
+
/**
Checks APs status and updates APs status if needed.
diff --git a/UefiCpuPkg/Library/MpInitLib/X64/MpEqu.inc b/UefiCpuPkg/Library/MpInitLib/X64/MpEqu.inc
index d255ca5e1b..b5e09c6bc1 100644
--- a/UefiCpuPkg/Library/MpInitLib/X64/MpEqu.inc
+++ b/UefiCpuPkg/Library/MpInitLib/X64/MpEqu.inc
@@ -42,4 +42,7 @@ InitFlagLocation equ LockLocation + 6Ch
CpuInfoLocation equ LockLocation + 74h
NumApsExecutingLocation equ LockLocation + 7Ch
InitializeFloatingPointUnitsAddress equ LockLocation + 8Ch
-
+ModeTransitionMemoryLocation equ LockLocation + 94h
+ModeTransitionSegmentLocation equ LockLocation + 98h
+ModeHighMemoryLocation equ LockLocation + 9Ah
+ModeHighSegmentLocation equ LockLocation + 9Eh
diff --git a/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm b/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
index 21d278600d..7595988884 100644
--- a/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
+++ b/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
@@ -52,16 +52,13 @@ BITS 16
mov si, BufferStartLocation
mov ebx, [si]
- mov di, ModeOffsetLocation
- mov eax, [di]
- mov di, CodeSegmentLocation
- mov edx, [di]
- mov di, ax
- sub di, 02h
- mov [di],dx ; Patch long mode CS
- sub di, 04h
- add eax, ebx
- mov [di],eax ; Patch address
+ mov si, DataSegmentLocation
+ mov edx, [si]
+
+ ;
+ ; Get start address of 32-bit code in low memory (<1MB)
+ ;
+ mov edi, ModeTransitionMemoryLocation
mov si, GdtrLocation
o32 lgdt [cs:si]
@@ -69,56 +66,79 @@ o32 lgdt [cs:si]
mov si, IdtrLocation
o32 lidt [cs:si]
- mov si, EnableExecuteDisableLocation
- cmp byte [si], 0
- jz SkipEnableExecuteDisableBit
+ ;
+ ; Switch to protected mode
+ ;
+ mov eax, cr0 ; Get control register 0
+ or eax, 000000003h ; Set PE bit (bit #0) & MP
+ mov cr0, eax
+
+ ; Switch to 32-bit code (>1MB)
+o32 jmp far [cs:di]
+
+;
+; Following code must be copied to memory with type of EfiBootServicesCode.
+; This is required if NX is enabled for EfiBootServicesCode of memory.
+;
+BITS 32
+Flat32Start: ; protected mode entry point
+ mov ds, dx
+ mov es, dx
+ mov fs, dx
+ mov gs, dx
+ mov ss, dx
;
; Enable execute disable bit
;
+ mov esi, EnableExecuteDisableLocation
+ cmp byte [ebx + esi], 0
+ jz SkipEnableExecuteDisableBit
+
mov ecx, 0c0000080h ; EFER MSR number
rdmsr ; Read EFER
bts eax, 11 ; Enable Execute Disable Bit
wrmsr ; Write EFER
SkipEnableExecuteDisableBit:
-
- mov di, DataSegmentLocation
- mov edi, [di] ; Save long mode DS in edi
-
- mov si, Cr3Location ; Save CR3 in ecx
- mov ecx, [si]
-
- xor ax, ax
- mov ds, ax ; Clear data segment
-
- mov eax, cr0 ; Get control register 0
- or eax, 000000003h ; Set PE bit (bit #0) & MP
- mov cr0, eax
-
+ ;
+ ; Enable PAE
+ ;
mov eax, cr4
bts eax, 5
mov cr4, eax
+ ;
+ ; Load page table
+ ;
+ mov esi, Cr3Location ; Save CR3 in ecx
+ mov ecx, [ebx + esi]
mov cr3, ecx ; Load CR3
+ ;
+ ; Enable long mode
+ ;
mov ecx, 0c0000080h ; EFER MSR number
rdmsr ; Read EFER
bts eax, 8 ; Set LME=1
wrmsr ; Write EFER
+ ;
+ ; Enable paging
+ ;
mov eax, cr0 ; Read CR0
bts eax, 31 ; Set PG=1
mov cr0, eax ; Write CR0
- jmp 0:strict dword 0 ; far jump to long mode
+ ;
+ ; Far jump to 64-bit code
+ ;
+ mov edi, ModeHighMemoryLocation
+ add edi, ebx
+ jmp far [edi]
+
BITS 64
LongModeStart:
- mov eax, edi
- mov ds, ax
- mov es, ax
- mov ss, ax
-
mov esi, ebx
lea edi, [esi + InitFlagLocation]
cmp qword [edi], 1 ; ApInitConfig
@@ -295,6 +315,7 @@ ASM_PFX(AsmGetAddressMap):
lea rax, [ASM_PFX(AsmRelocateApLoop)]
mov qword [rcx + 18h], rax
mov qword [rcx + 20h], AsmRelocateApLoopEnd - AsmRelocateApLoopStart
+ mov qword [rcx + 28h], Flat32Start - RendezvousFunnelProcStart
ret
;-------------------------------------------------------------------------------------
--
2.15.1.windows.2
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
Reviewed-by: Eric Dong <eric.dong@intel.com> -----Original Message----- From: Wang, Jian J Sent: Monday, January 15, 2018 4:54 PM To: edk2-devel@lists.01.org Cc: Yao, Jiewen <jiewen.yao@intel.com>; Ni, Ruiyu <ruiyu.ni@intel.com>; Dong, Eric <eric.dong@intel.com>; Laszlo Ersek <lersek@redhat.com> Subject: [PATCH 1/6] 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> --- UefiCpuPkg/Library/MpInitLib/DxeMpLib.c | 34 ++++++++++ UefiCpuPkg/Library/MpInitLib/Ia32/MpEqu.inc | 5 ++ UefiCpuPkg/Library/MpInitLib/Ia32/MpFuncs.nasm | 32 +++++----- UefiCpuPkg/Library/MpInitLib/MpLib.c | 45 +++++++++++++ UefiCpuPkg/Library/MpInitLib/MpLib.h | 22 +++++++ UefiCpuPkg/Library/MpInitLib/PeiMpLib.c | 23 +++++++ UefiCpuPkg/Library/MpInitLib/X64/MpEqu.inc | 5 +- UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm | 87 ++++++++++++++++---------- 8 files changed, 204 insertions(+), 49 deletions(-) diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c index d2bcef53d6..fd2317924f 100644 --- a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c +++ b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c @@ -113,6 +113,40 @@ GetWakeupBuffer ( return (UINTN) StartAddress; } +/** + Get available EfiBootServicesCode memory below 4GB by specified size. + + This buffer is required to safely transfer AP from real address mode + to protected mode or long mode, due to the fact that the buffer + returned by + GetWakeupBuffer() may be marked as non-executable. + + @param[in] BufferSize Wakeup transition buffer size. + + @retval other Return wakeup transition buffer address below 4GB. + @retval 0 Cannot find free memory below 4GB. +**/ +UINTN +GetModeTransitionBuffer ( + IN UINTN BufferSize + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS StartAddress; + + StartAddress = BASE_4GB - 1; + Status = gBS->AllocatePages ( + AllocateMaxAddress, + EfiBootServicesCode, + EFI_SIZE_TO_PAGES (BufferSize), + &StartAddress + ); + if (EFI_ERROR (Status)) { + StartAddress = 0; + } + + return (UINTN)StartAddress; +} + /** Checks APs status and updates APs status if needed. diff --git a/UefiCpuPkg/Library/MpInitLib/Ia32/MpEqu.inc b/UefiCpuPkg/Library/MpInitLib/Ia32/MpEqu.inc index bdfe0d33cc..1648f2c4b0 100644 --- a/UefiCpuPkg/Library/MpInitLib/Ia32/MpEqu.inc +++ b/UefiCpuPkg/Library/MpInitLib/Ia32/MpEqu.inc @@ -41,4 +41,9 @@ Cr3Location equ LockLocation + 34h InitFlagLocation equ LockLocation + 38h CpuInfoLocation equ LockLocation + 3Ch NumApsExecutingLocation equ LockLocation + 40h +InitializeFloatingPointUnitsAddress equ LockLocation + 48h +ModeTransitionMemoryLocation equ LockLocation + 4Ch +ModeTransitionSegmentLocation equ LockLocation + 50h +ModeHighMemoryLocation equ LockLocation + 52h +ModeHighSegmentLocation equ LockLocation + 56h diff --git a/UefiCpuPkg/Library/MpInitLib/Ia32/MpFuncs.nasm b/UefiCpuPkg/Library/MpInitLib/Ia32/MpFuncs.nasm index 2b6c27d4ec..bd79be0f5e 100644 --- a/UefiCpuPkg/Library/MpInitLib/Ia32/MpFuncs.nasm +++ b/UefiCpuPkg/Library/MpInitLib/Ia32/MpFuncs.nasm @@ -48,34 +48,35 @@ BITS 16 mov si, BufferStartLocation mov ebx, [si] - mov si, ModeOffsetLocation - mov eax, [si] - mov si, CodeSegmentLocation - mov edx, [si] - mov di, ax - sub di, 02h - mov [di], dx - sub di, 04h - add eax, ebx - mov [di],eax - mov si, DataSegmentLocation mov edx, [si] + ; + ; Get start address of 32-bit code in low memory (<1MB) + ; + mov edi, ModeTransitionMemoryLocation + mov si, GdtrLocation o32 lgdt [cs:si] mov si, IdtrLocation o32 lidt [cs:si] - xor ax, ax - mov ds, ax - + ; + ; Switch to protected mode + ; mov eax, cr0 ; Get control register 0 or eax, 000000003h ; Set PE bit (bit #0) & MP mov cr0, eax - jmp 0:strict dword 0 ; far jump to protected mode + ; Switch to 32-bit code in executable memory (>1MB) +o32 jmp far [cs:di] + +; +; Following code may be copied to memory with type of EfiBootServicesCode. +; This is required at DXE phase if NX is enabled for +EfiBootServicesCode of ; memory. +; BITS 32 Flat32Start: ; protected mode entry point mov ds, dx @@ -266,6 +267,7 @@ ASM_PFX(AsmGetAddressMap): mov dword [ebx + 8h], RendezvousFunnelProcEnd - RendezvousFunnelProcStart mov dword [ebx + 0Ch], AsmRelocateApLoopStart mov dword [ebx + 10h], AsmRelocateApLoopEnd - AsmRelocateApLoopStart + mov dword [ebx + 14h], Flat32Start - RendezvousFunnelProcStart popad ret diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c index cdc03113e5..fbcbcc6cc9 100644 --- a/UefiCpuPkg/Library/MpInitLib/MpLib.c +++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c @@ -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); } diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h index 685e96cbac..0232fe896a 100644 --- a/UefiCpuPkg/Library/MpInitLib/MpLib.h +++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h @@ -152,6 +152,7 @@ typedef struct { UINTN RendezvousFunnelSize; UINT8 *RelocateApLoopFuncAddress; UINTN RelocateApLoopFuncSize; + UINTN ModeTransitionOffset; } MP_ASSEMBLY_ADDRESS_MAP; typedef struct _CPU_MP_DATA CPU_MP_DATA; @@ -182,6 +183,10 @@ typedef struct { UINTN NumApsExecuting; CPU_MP_DATA *CpuMpData; UINTN InitializeFloatingPointUnitsAddress; + UINT32 ModeTransitionMemory; + UINT16 ModeTransitionSegment; + UINT32 ModeHighMemory; + UINT16 ModeHighSegment; } MP_CPU_EXCHANGE_INFO; #pragma pack() @@ -329,6 +334,23 @@ GetWakeupBuffer ( IN UINTN WakeupBufferSize ); +/** + Get available EfiBootServicesCode memory below 4GB by specified size. + + This buffer is required to safely transfer AP from real address mode + to protected mode or long mode, due to the fact that the buffer + returned by + GetWakeupBuffer() may be marked as non-executable. + + @param[in] BufferSize Wakeup transition buffer size. + + @retval other Return wakeup transition buffer address below 4GB. + @retval 0 Cannot find free memory below 4GB. +**/ +UINTN +GetModeTransitionBuffer ( + IN UINTN BufferSize + ); + /** This function will be called by BSP to wakeup AP. diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c b/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c index 70c2bc7323..ad43bd33f5 100644 --- a/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c +++ b/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c @@ -187,6 +187,29 @@ GetWakeupBuffer ( return (UINTN) -1; } +/** + Get available EfiBootServicesCode memory below 4GB by specified size. + + This buffer is required to safely transfer AP from real address mode + to protected mode or long mode, due to the fact that the buffer + returned by + GetWakeupBuffer() may be marked as non-executable. + + @param[in] BufferSize Wakeup transition buffer size. + + @retval other Return wakeup transition buffer address below 4GB. + @retval 0 Cannot find free memory below 4GB. +**/ +UINTN +GetModeTransitionBuffer ( + IN UINTN BufferSize + ) +{ + // + // PEI phase doesn't need to do such transition. So simply return 0. + // + return 0; +} + /** Checks APs status and updates APs status if needed. diff --git a/UefiCpuPkg/Library/MpInitLib/X64/MpEqu.inc b/UefiCpuPkg/Library/MpInitLib/X64/MpEqu.inc index d255ca5e1b..b5e09c6bc1 100644 --- a/UefiCpuPkg/Library/MpInitLib/X64/MpEqu.inc +++ b/UefiCpuPkg/Library/MpInitLib/X64/MpEqu.inc @@ -42,4 +42,7 @@ InitFlagLocation equ LockLocation + 6Ch CpuInfoLocation equ LockLocation + 74h NumApsExecutingLocation equ LockLocation + 7Ch InitializeFloatingPointUnitsAddress equ LockLocation + 8Ch - +ModeTransitionMemoryLocation equ LockLocation + 94h +ModeTransitionSegmentLocation equ LockLocation + 98h +ModeHighMemoryLocation equ LockLocation + 9Ah +ModeHighSegmentLocation equ LockLocation + 9Eh diff --git a/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm b/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm index 21d278600d..7595988884 100644 --- a/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm +++ b/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm @@ -52,16 +52,13 @@ BITS 16 mov si, BufferStartLocation mov ebx, [si] - mov di, ModeOffsetLocation - mov eax, [di] - mov di, CodeSegmentLocation - mov edx, [di] - mov di, ax - sub di, 02h - mov [di],dx ; Patch long mode CS - sub di, 04h - add eax, ebx - mov [di],eax ; Patch address + mov si, DataSegmentLocation + mov edx, [si] + + ; + ; Get start address of 32-bit code in low memory (<1MB) + ; + mov edi, ModeTransitionMemoryLocation mov si, GdtrLocation o32 lgdt [cs:si] @@ -69,56 +66,79 @@ o32 lgdt [cs:si] mov si, IdtrLocation o32 lidt [cs:si] - mov si, EnableExecuteDisableLocation - cmp byte [si], 0 - jz SkipEnableExecuteDisableBit + ; + ; Switch to protected mode + ; + mov eax, cr0 ; Get control register 0 + or eax, 000000003h ; Set PE bit (bit #0) & MP + mov cr0, eax + + ; Switch to 32-bit code (>1MB) +o32 jmp far [cs:di] + +; +; Following code must be copied to memory with type of EfiBootServicesCode. +; This is required if NX is enabled for EfiBootServicesCode of memory. +; +BITS 32 +Flat32Start: ; protected mode entry point + mov ds, dx + mov es, dx + mov fs, dx + mov gs, dx + mov ss, dx ; ; Enable execute disable bit ; + mov esi, EnableExecuteDisableLocation + cmp byte [ebx + esi], 0 + jz SkipEnableExecuteDisableBit + mov ecx, 0c0000080h ; EFER MSR number rdmsr ; Read EFER bts eax, 11 ; Enable Execute Disable Bit wrmsr ; Write EFER SkipEnableExecuteDisableBit: - - mov di, DataSegmentLocation - mov edi, [di] ; Save long mode DS in edi - - mov si, Cr3Location ; Save CR3 in ecx - mov ecx, [si] - - xor ax, ax - mov ds, ax ; Clear data segment - - mov eax, cr0 ; Get control register 0 - or eax, 000000003h ; Set PE bit (bit #0) & MP - mov cr0, eax - + ; + ; Enable PAE + ; mov eax, cr4 bts eax, 5 mov cr4, eax + ; + ; Load page table + ; + mov esi, Cr3Location ; Save CR3 in ecx + mov ecx, [ebx + esi] mov cr3, ecx ; Load CR3 + ; + ; Enable long mode + ; mov ecx, 0c0000080h ; EFER MSR number rdmsr ; Read EFER bts eax, 8 ; Set LME=1 wrmsr ; Write EFER + ; + ; Enable paging + ; mov eax, cr0 ; Read CR0 bts eax, 31 ; Set PG=1 mov cr0, eax ; Write CR0 - jmp 0:strict dword 0 ; far jump to long mode + ; + ; Far jump to 64-bit code + ; + mov edi, ModeHighMemoryLocation + add edi, ebx + jmp far [edi] + BITS 64 LongModeStart: - mov eax, edi - mov ds, ax - mov es, ax - mov ss, ax - mov esi, ebx lea edi, [esi + InitFlagLocation] cmp qword [edi], 1 ; ApInitConfig @@ -295,6 +315,7 @@ ASM_PFX(AsmGetAddressMap): lea rax, [ASM_PFX(AsmRelocateApLoop)] mov qword [rcx + 18h], rax mov qword [rcx + 20h], AsmRelocateApLoopEnd - AsmRelocateApLoopStart + mov qword [rcx + 28h], Flat32Start - RendezvousFunnelProcStart ret ;------------------------------------------------------------------------------------- -- 2.15.1.windows.2 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel
Hello Jian, On 01/15/18 09:54, Jian J Wang wrote: > 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> > --- > UefiCpuPkg/Library/MpInitLib/DxeMpLib.c | 34 ++++++++++ > UefiCpuPkg/Library/MpInitLib/Ia32/MpEqu.inc | 5 ++ > UefiCpuPkg/Library/MpInitLib/Ia32/MpFuncs.nasm | 32 +++++----- > UefiCpuPkg/Library/MpInitLib/MpLib.c | 45 +++++++++++++ > UefiCpuPkg/Library/MpInitLib/MpLib.h | 22 +++++++ > UefiCpuPkg/Library/MpInitLib/PeiMpLib.c | 23 +++++++ > UefiCpuPkg/Library/MpInitLib/X64/MpEqu.inc | 5 +- > UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm | 87 ++++++++++++++++---------- > 8 files changed, 204 insertions(+), 49 deletions(-) This patch breaks OVMF on KVM. The symptom is that the guest crashes and reboots as follows (infinite reboot loop): > Loading PEIM at 0x0007FEB0000 EntryPoint=0x0007FEB5C96 CpuMpPei.efi > AP Loop Mode is 1 > WakeupBufferStart = 9F000, WakeupBufferSize = 1000 > -- crash & reboot here -- > SecCoreStartupWithStack(0xFFFCC000, 0x820000) Here's the bisection log: git bisect start # bad: [06c1f423e17fe5ddef824d688d21c83730238ba6] BeagleBoardPkg: reroute Firmware Vendor Pcd to MdeModulePkg git bisect bad 06c1f423e17fe5ddef824d688d21c83730238ba6 # good: [018432f0ce1b42541977f61f9c7607257a4bf43a] MdeModulePkg/Ip4Dxe: Add an independent timer for reconfig checking git bisect good 018432f0ce1b42541977f61f9c7607257a4bf43a # bad: [8ab0bd2397c9d3922e0c7dbb1aa6f7e08799079f] MdePkg/DMAR: Add the definition for DMA_CTRL_PLATFORM_OPT_IN_FLAG bit git bisect bad 8ab0bd2397c9d3922e0c7dbb1aa6f7e08799079f # good: [24a105a7d8b4b8312743cf265f869dc049b7ff92] BaseTools: Disable warning varargs in XCODE5 align to CLANG38 git bisect good 24a105a7d8b4b8312743cf265f869dc049b7ff92 # good: [b2725f57c7a1e6feeb176f1563a4f1a8c2eb6c6f] IntelSiliconPkg IntelVTdPmrPei: Get high top by host address width git bisect good b2725f57c7a1e6feeb176f1563a4f1a8c2eb6c6f # good: [4f10654e04601fe67a750c9b5a4242efd4141569] UefiCpuPkg/CpuDxe: fix SetMemoryAttributes issue in 32-bit mode git bisect good 4f10654e04601fe67a750c9b5a4242efd4141569 # bad: [fbe2c4b9be98a5c2b9c1f6976f51e2456467e752] UefiCpuPkg/CpuDxe: clear NX attr for page directory git bisect bad fbe2c4b9be98a5c2b9c1f6976f51e2456467e752 # bad: [fceafda5185af0445d83f8c819b65417b981c485] UefiCpuPkg/CpuExceptionHandlerLib: alloc code memory for exception handlers git bisect bad fceafda5185af0445d83f8c819b65417b981c485 # bad: [f32bfe6d061420a15bac6083063d227c567e6388] UefiCpuPkg/MpInitLib: split wake up buffer into two parts git bisect bad f32bfe6d061420a15bac6083063d227c567e6388 # first bad commit: [f32bfe6d061420a15bac6083063d227c567e6388] UefiCpuPkg/MpInitLib: split wake up buffer into two parts Thanks Laszlo _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel
On 01/27/18 17:17, Laszlo Ersek wrote: > Hello Jian, > > On 01/15/18 09:54, Jian J Wang wrote: >> 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> >> --- >> UefiCpuPkg/Library/MpInitLib/DxeMpLib.c | 34 ++++++++++ >> UefiCpuPkg/Library/MpInitLib/Ia32/MpEqu.inc | 5 ++ >> UefiCpuPkg/Library/MpInitLib/Ia32/MpFuncs.nasm | 32 +++++----- >> UefiCpuPkg/Library/MpInitLib/MpLib.c | 45 +++++++++++++ >> UefiCpuPkg/Library/MpInitLib/MpLib.h | 22 +++++++ >> UefiCpuPkg/Library/MpInitLib/PeiMpLib.c | 23 +++++++ >> UefiCpuPkg/Library/MpInitLib/X64/MpEqu.inc | 5 +- >> UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm | 87 ++++++++++++++++---------- >> 8 files changed, 204 insertions(+), 49 deletions(-) > > This patch breaks OVMF on KVM. The symptom is that the guest crashes > and reboots as follows (infinite reboot loop): > >> Loading PEIM at 0x0007FEB0000 EntryPoint=0x0007FEB5C96 CpuMpPei.efi >> AP Loop Mode is 1 >> WakeupBufferStart = 9F000, WakeupBufferSize = 1000 >> -- crash & reboot here -- >> SecCoreStartupWithStack(0xFFFCC000, 0x820000) The following build options were used for this build: $ build -a X64 -p OvmfPkg/OvmfPkgX64.dsc -D SECURE_BOOT_ENABLE \ -t GCC48 -b NOOPT -D HTTP_BOOT_ENABLE The tree was built at 06c1f423e17f ("BeagleBoardPkg: reroute Firmware Vendor Pcd to MdeModulePkg", 2018-01-26). (This commit is listed at the top of the bisection log in my previous email.) Here's the KVM log up to the triple fault: > CPU-32283 [004] 13652.374591: kvm_entry: vcpu 2 > CPU-32283 [004] 13652.374594: kvm_exit: reason CR_ACCESS rip 0x3a info 0 0 > CPU-32283 [004] 13652.374595: kvm_cr: cr_write 0 = 0x60000013 > CPU-32283 [004] 13652.374596: kvm_entry: vcpu 2 > CPU-32283 [004] 13652.374597: kvm_exit: reason CR_ACCESS rip 0x9f06a info 4 0 > CPU-32283 [004] 13652.374598: kvm_cr: cr_write 4 = 0x20 > CPU-32283 [004] 13652.374603: kvm_entry: vcpu 2 > CPU-32283 [004] 13652.374604: kvm_exit: reason CR_ACCESS rip 0x9f075 info 103 0 > CPU-32283 [004] 13652.374605: kvm_cr: cr_write 3 = 0x800000 > CPU-32283 [004] 13652.374606: kvm_entry: vcpu 2 > CPU-32283 [004] 13652.374607: kvm_exit: reason MSR_READ rip 0x9f07d info 0 0 > CPU-32283 [004] 13652.374608: kvm_msr: msr_read c0000080 = 0x0 > CPU-32283 [004] 13652.374608: kvm_entry: vcpu 2 > CPU-32283 [004] 13652.374609: kvm_exit: reason MSR_WRITE rip 0x9f083 info 0 0 > CPU-32283 [004] 13652.374611: kvm_msr: msr_write c0000080 = 0x100 > CPU-32283 [004] 13652.374612: kvm_entry: vcpu 2 > CPU-32283 [004] 13652.374613: kvm_exit: reason CR_ACCESS rip 0x9f08c info 0 0 > CPU-32283 [004] 13652.374613: kvm_cr: cr_write 0 = 0xe0000013 > CPU-32283 [004] 13652.374620: kvm_entry: vcpu 2 > CPU-32283 [004] 13652.374622: kvm_exit: reason TRIPLE_FAULT rip 0x9f096 info 0 0 Offset 0x96 (relative to 0x9F000) is from "UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm": > 5c66d125eaae5 (Jeff Fan 2016-07-29 21:13:34 +0800 103) SkipEnableExecuteDisableBit: > f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 104) ; > f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 105) ; Enable PAE > f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 106) ; > d94e5f672994f (Jeff Fan 2016-07-20 22:44:39 +0800 107) mov eax, cr4 > d94e5f672994f (Jeff Fan 2016-07-20 22:44:39 +0800 108) bts eax, 5 > d94e5f672994f (Jeff Fan 2016-07-20 22:44:39 +0800 109) mov cr4, eax > d94e5f672994f (Jeff Fan 2016-07-20 22:44:39 +0800 110) > f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 111) ; > f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 112) ; Load page table > f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 113) ; > f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 114) mov esi, Cr3Location ; Save CR3 in ecx > f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 115) mov ecx, [ebx + esi] > d94e5f672994f (Jeff Fan 2016-07-20 22:44:39 +0800 116) mov cr3, ecx ; Load CR3 > d94e5f672994f (Jeff Fan 2016-07-20 22:44:39 +0800 117) > f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 118) ; > f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 119) ; Enable long mode > f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 120) ; > d94e5f672994f (Jeff Fan 2016-07-20 22:44:39 +0800 121) mov ecx, 0c0000080h ; EFER MSR number > d94e5f672994f (Jeff Fan 2016-07-20 22:44:39 +0800 122) rdmsr ; Read EFER > d94e5f672994f (Jeff Fan 2016-07-20 22:44:39 +0800 123) bts eax, 8 ; Set LME=1 > d94e5f672994f (Jeff Fan 2016-07-20 22:44:39 +0800 124) wrmsr ; Write EFER > d94e5f672994f (Jeff Fan 2016-07-20 22:44:39 +0800 125) > f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 126) ; > f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 127) ; Enable paging > f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 128) ; > d94e5f672994f (Jeff Fan 2016-07-20 22:44:39 +0800 129) mov eax, cr0 ; Read CR0 > d94e5f672994f (Jeff Fan 2016-07-20 22:44:39 +0800 130) bts eax, 31 ; Set PG=1 > d94e5f672994f (Jeff Fan 2016-07-20 22:44:39 +0800 131) mov cr0, eax ; Write CR0 > d94e5f672994f (Jeff Fan 2016-07-20 22:44:39 +0800 132) > f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 133) ; > f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 134) ; Far jump to 64-bit code > f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 135) ; > f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 136) mov edi, ModeHighMemoryLocation > f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 137) add edi, ebx > f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 138) jmp far [edi] <- here Thanks Laszlo _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel
Hi Laszlo, We've found this issue. The patch for it has sent out at https://lists.01.org/pipermail/edk2-devel/2018-January/020467.html It will be checked in soon. Regards, Jian > -----Original Message----- > From: Laszlo Ersek [mailto:lersek@redhat.com] > Sent: Monday, January 29, 2018 5:44 AM > To: Wang, Jian J <jian.j.wang@intel.com>; edk2-devel@lists.01.org > Cc: Ni, Ruiyu <ruiyu.ni@intel.com>; Yao, Jiewen <jiewen.yao@intel.com>; Dong, > Eric <eric.dong@intel.com> > Subject: Re: [edk2] [PATCH 1/6] UefiCpuPkg/MpInitLib: split wake up buffer into > two parts > > On 01/27/18 17:17, Laszlo Ersek wrote: > > Hello Jian, > > > > On 01/15/18 09:54, Jian J Wang wrote: > >> 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> > >> --- > >> UefiCpuPkg/Library/MpInitLib/DxeMpLib.c | 34 ++++++++++ > >> UefiCpuPkg/Library/MpInitLib/Ia32/MpEqu.inc | 5 ++ > >> UefiCpuPkg/Library/MpInitLib/Ia32/MpFuncs.nasm | 32 +++++----- > >> UefiCpuPkg/Library/MpInitLib/MpLib.c | 45 +++++++++++++ > >> UefiCpuPkg/Library/MpInitLib/MpLib.h | 22 +++++++ > >> UefiCpuPkg/Library/MpInitLib/PeiMpLib.c | 23 +++++++ > >> UefiCpuPkg/Library/MpInitLib/X64/MpEqu.inc | 5 +- > >> UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm | 87 ++++++++++++++++- > --------- > >> 8 files changed, 204 insertions(+), 49 deletions(-) > > > > This patch breaks OVMF on KVM. The symptom is that the guest crashes > > and reboots as follows (infinite reboot loop): > > > >> Loading PEIM at 0x0007FEB0000 EntryPoint=0x0007FEB5C96 CpuMpPei.efi > >> AP Loop Mode is 1 > >> WakeupBufferStart = 9F000, WakeupBufferSize = 1000 > >> -- crash & reboot here -- > >> SecCoreStartupWithStack(0xFFFCC000, 0x820000) > > The following build options were used for this build: > > $ build -a X64 -p OvmfPkg/OvmfPkgX64.dsc -D SECURE_BOOT_ENABLE \ > -t GCC48 -b NOOPT -D HTTP_BOOT_ENABLE > > The tree was built at 06c1f423e17f ("BeagleBoardPkg: reroute Firmware > Vendor Pcd to MdeModulePkg", 2018-01-26). (This commit is listed at the > top of the bisection log in my previous email.) > > Here's the KVM log up to the triple fault: > > > CPU-32283 [004] 13652.374591: kvm_entry: vcpu 2 > > CPU-32283 [004] 13652.374594: kvm_exit: reason CR_ACCESS > rip 0x3a info 0 0 > > CPU-32283 [004] 13652.374595: kvm_cr: cr_write 0 = > 0x60000013 > > CPU-32283 [004] 13652.374596: kvm_entry: vcpu 2 > > CPU-32283 [004] 13652.374597: kvm_exit: reason CR_ACCESS > rip 0x9f06a info 4 0 > > CPU-32283 [004] 13652.374598: kvm_cr: cr_write 4 = 0x20 > > CPU-32283 [004] 13652.374603: kvm_entry: vcpu 2 > > CPU-32283 [004] 13652.374604: kvm_exit: reason CR_ACCESS > rip 0x9f075 info 103 0 > > CPU-32283 [004] 13652.374605: kvm_cr: cr_write 3 = 0x800000 > > CPU-32283 [004] 13652.374606: kvm_entry: vcpu 2 > > CPU-32283 [004] 13652.374607: kvm_exit: reason MSR_READ > rip 0x9f07d info 0 0 > > CPU-32283 [004] 13652.374608: kvm_msr: msr_read c0000080 > = 0x0 > > CPU-32283 [004] 13652.374608: kvm_entry: vcpu 2 > > CPU-32283 [004] 13652.374609: kvm_exit: reason MSR_WRITE > rip 0x9f083 info 0 0 > > CPU-32283 [004] 13652.374611: kvm_msr: msr_write c0000080 > = 0x100 > > CPU-32283 [004] 13652.374612: kvm_entry: vcpu 2 > > CPU-32283 [004] 13652.374613: kvm_exit: reason CR_ACCESS > rip 0x9f08c info 0 0 > > CPU-32283 [004] 13652.374613: kvm_cr: cr_write 0 = > 0xe0000013 > > CPU-32283 [004] 13652.374620: kvm_entry: vcpu 2 > > CPU-32283 [004] 13652.374622: kvm_exit: reason > TRIPLE_FAULT rip 0x9f096 info 0 0 > > Offset 0x96 (relative to 0x9F000) is from > "UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm": > > > 5c66d125eaae5 (Jeff Fan 2016-07-29 21:13:34 +0800 103) > SkipEnableExecuteDisableBit: > > f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 104) ; > > f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 105) ; Enable PAE > > f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 106) ; > > d94e5f672994f (Jeff Fan 2016-07-20 22:44:39 +0800 107) mov eax, > cr4 > > d94e5f672994f (Jeff Fan 2016-07-20 22:44:39 +0800 108) bts eax, 5 > > d94e5f672994f (Jeff Fan 2016-07-20 22:44:39 +0800 109) mov cr4, > eax > > d94e5f672994f (Jeff Fan 2016-07-20 22:44:39 +0800 110) > > f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 111) ; > > f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 112) ; Load page > table > > f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 113) ; > > f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 114) mov esi, > Cr3Location ; Save CR3 in ecx > > f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 115) mov ecx, > [ebx + esi] > > d94e5f672994f (Jeff Fan 2016-07-20 22:44:39 +0800 116) mov cr3, > ecx ; Load CR3 > > d94e5f672994f (Jeff Fan 2016-07-20 22:44:39 +0800 117) > > f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 118) ; > > f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 119) ; Enable long > mode > > f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 120) ; > > d94e5f672994f (Jeff Fan 2016-07-20 22:44:39 +0800 121) mov ecx, > 0c0000080h ; EFER MSR number > > d94e5f672994f (Jeff Fan 2016-07-20 22:44:39 +0800 122) > rdmsr ; Read EFER > > d94e5f672994f (Jeff Fan 2016-07-20 22:44:39 +0800 123) bts eax, > 8 ; Set LME=1 > > d94e5f672994f (Jeff Fan 2016-07-20 22:44:39 +0800 124) > wrmsr ; Write EFER > > d94e5f672994f (Jeff Fan 2016-07-20 22:44:39 +0800 125) > > f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 126) ; > > f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 127) ; Enable > paging > > f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 128) ; > > d94e5f672994f (Jeff Fan 2016-07-20 22:44:39 +0800 129) mov eax, > cr0 ; Read CR0 > > d94e5f672994f (Jeff Fan 2016-07-20 22:44:39 +0800 130) bts eax, > 31 ; Set PG=1 > > d94e5f672994f (Jeff Fan 2016-07-20 22:44:39 +0800 131) mov cr0, > eax ; Write CR0 > > d94e5f672994f (Jeff Fan 2016-07-20 22:44:39 +0800 132) > > f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 133) ; > > f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 134) ; Far jump to > 64-bit code > > f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 135) ; > > f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 136) mov edi, > ModeHighMemoryLocation > > f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 137) add edi, > ebx > > f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 138) jmp far [edi] > <- here > > Thanks > Laszlo _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel
On 01/29/18 02:06, Wang, Jian J wrote: > Hi Laszlo, > > We've found this issue. The patch for it has sent out at > > https://lists.01.org/pipermail/edk2-devel/2018-January/020467.html > > It will be checked in soon. I've rebuilt OVMF @ c4122dcaadb9 ("SecurityPkg: Tcg2Smm: Enable TPM2.0 interrupt support", 2018-01-29) and indeed it works fine. Thank you! Laszlo >> -----Original Message----- >> From: Laszlo Ersek [mailto:lersek@redhat.com] >> Sent: Monday, January 29, 2018 5:44 AM >> To: Wang, Jian J <jian.j.wang@intel.com>; edk2-devel@lists.01.org >> Cc: Ni, Ruiyu <ruiyu.ni@intel.com>; Yao, Jiewen <jiewen.yao@intel.com>; Dong, >> Eric <eric.dong@intel.com> >> Subject: Re: [edk2] [PATCH 1/6] UefiCpuPkg/MpInitLib: split wake up buffer into >> two parts >> >> On 01/27/18 17:17, Laszlo Ersek wrote: >>> Hello Jian, >>> >>> On 01/15/18 09:54, Jian J Wang wrote: >>>> 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> >>>> --- >>>> UefiCpuPkg/Library/MpInitLib/DxeMpLib.c | 34 ++++++++++ >>>> UefiCpuPkg/Library/MpInitLib/Ia32/MpEqu.inc | 5 ++ >>>> UefiCpuPkg/Library/MpInitLib/Ia32/MpFuncs.nasm | 32 +++++----- >>>> UefiCpuPkg/Library/MpInitLib/MpLib.c | 45 +++++++++++++ >>>> UefiCpuPkg/Library/MpInitLib/MpLib.h | 22 +++++++ >>>> UefiCpuPkg/Library/MpInitLib/PeiMpLib.c | 23 +++++++ >>>> UefiCpuPkg/Library/MpInitLib/X64/MpEqu.inc | 5 +- >>>> UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm | 87 ++++++++++++++++- >> --------- >>>> 8 files changed, 204 insertions(+), 49 deletions(-) >>> >>> This patch breaks OVMF on KVM. The symptom is that the guest crashes >>> and reboots as follows (infinite reboot loop): >>> >>>> Loading PEIM at 0x0007FEB0000 EntryPoint=0x0007FEB5C96 CpuMpPei.efi >>>> AP Loop Mode is 1 >>>> WakeupBufferStart = 9F000, WakeupBufferSize = 1000 >>>> -- crash & reboot here -- >>>> SecCoreStartupWithStack(0xFFFCC000, 0x820000) >> >> The following build options were used for this build: >> >> $ build -a X64 -p OvmfPkg/OvmfPkgX64.dsc -D SECURE_BOOT_ENABLE \ >> -t GCC48 -b NOOPT -D HTTP_BOOT_ENABLE >> >> The tree was built at 06c1f423e17f ("BeagleBoardPkg: reroute Firmware >> Vendor Pcd to MdeModulePkg", 2018-01-26). (This commit is listed at the >> top of the bisection log in my previous email.) >> >> Here's the KVM log up to the triple fault: >> >>> CPU-32283 [004] 13652.374591: kvm_entry: vcpu 2 >>> CPU-32283 [004] 13652.374594: kvm_exit: reason CR_ACCESS >> rip 0x3a info 0 0 >>> CPU-32283 [004] 13652.374595: kvm_cr: cr_write 0 = >> 0x60000013 >>> CPU-32283 [004] 13652.374596: kvm_entry: vcpu 2 >>> CPU-32283 [004] 13652.374597: kvm_exit: reason CR_ACCESS >> rip 0x9f06a info 4 0 >>> CPU-32283 [004] 13652.374598: kvm_cr: cr_write 4 = 0x20 >>> CPU-32283 [004] 13652.374603: kvm_entry: vcpu 2 >>> CPU-32283 [004] 13652.374604: kvm_exit: reason CR_ACCESS >> rip 0x9f075 info 103 0 >>> CPU-32283 [004] 13652.374605: kvm_cr: cr_write 3 = 0x800000 >>> CPU-32283 [004] 13652.374606: kvm_entry: vcpu 2 >>> CPU-32283 [004] 13652.374607: kvm_exit: reason MSR_READ >> rip 0x9f07d info 0 0 >>> CPU-32283 [004] 13652.374608: kvm_msr: msr_read c0000080 >> = 0x0 >>> CPU-32283 [004] 13652.374608: kvm_entry: vcpu 2 >>> CPU-32283 [004] 13652.374609: kvm_exit: reason MSR_WRITE >> rip 0x9f083 info 0 0 >>> CPU-32283 [004] 13652.374611: kvm_msr: msr_write c0000080 >> = 0x100 >>> CPU-32283 [004] 13652.374612: kvm_entry: vcpu 2 >>> CPU-32283 [004] 13652.374613: kvm_exit: reason CR_ACCESS >> rip 0x9f08c info 0 0 >>> CPU-32283 [004] 13652.374613: kvm_cr: cr_write 0 = >> 0xe0000013 >>> CPU-32283 [004] 13652.374620: kvm_entry: vcpu 2 >>> CPU-32283 [004] 13652.374622: kvm_exit: reason >> TRIPLE_FAULT rip 0x9f096 info 0 0 >> >> Offset 0x96 (relative to 0x9F000) is from >> "UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm": >> >>> 5c66d125eaae5 (Jeff Fan 2016-07-29 21:13:34 +0800 103) >> SkipEnableExecuteDisableBit: >>> f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 104) ; >>> f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 105) ; Enable PAE >>> f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 106) ; >>> d94e5f672994f (Jeff Fan 2016-07-20 22:44:39 +0800 107) mov eax, >> cr4 >>> d94e5f672994f (Jeff Fan 2016-07-20 22:44:39 +0800 108) bts eax, 5 >>> d94e5f672994f (Jeff Fan 2016-07-20 22:44:39 +0800 109) mov cr4, >> eax >>> d94e5f672994f (Jeff Fan 2016-07-20 22:44:39 +0800 110) >>> f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 111) ; >>> f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 112) ; Load page >> table >>> f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 113) ; >>> f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 114) mov esi, >> Cr3Location ; Save CR3 in ecx >>> f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 115) mov ecx, >> [ebx + esi] >>> d94e5f672994f (Jeff Fan 2016-07-20 22:44:39 +0800 116) mov cr3, >> ecx ; Load CR3 >>> d94e5f672994f (Jeff Fan 2016-07-20 22:44:39 +0800 117) >>> f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 118) ; >>> f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 119) ; Enable long >> mode >>> f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 120) ; >>> d94e5f672994f (Jeff Fan 2016-07-20 22:44:39 +0800 121) mov ecx, >> 0c0000080h ; EFER MSR number >>> d94e5f672994f (Jeff Fan 2016-07-20 22:44:39 +0800 122) >> rdmsr ; Read EFER >>> d94e5f672994f (Jeff Fan 2016-07-20 22:44:39 +0800 123) bts eax, >> 8 ; Set LME=1 >>> d94e5f672994f (Jeff Fan 2016-07-20 22:44:39 +0800 124) >> wrmsr ; Write EFER >>> d94e5f672994f (Jeff Fan 2016-07-20 22:44:39 +0800 125) >>> f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 126) ; >>> f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 127) ; Enable >> paging >>> f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 128) ; >>> d94e5f672994f (Jeff Fan 2016-07-20 22:44:39 +0800 129) mov eax, >> cr0 ; Read CR0 >>> d94e5f672994f (Jeff Fan 2016-07-20 22:44:39 +0800 130) bts eax, >> 31 ; Set PG=1 >>> d94e5f672994f (Jeff Fan 2016-07-20 22:44:39 +0800 131) mov cr0, >> eax ; Write CR0 >>> d94e5f672994f (Jeff Fan 2016-07-20 22:44:39 +0800 132) >>> f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 133) ; >>> f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 134) ; Far jump to >> 64-bit code >>> f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 135) ; >>> f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 136) mov edi, >> ModeHighMemoryLocation >>> f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 137) add edi, >> ebx >>> f32bfe6d06142 (Jian J Wang 2017-12-29 09:12:54 +0800 138) jmp far [edi] >> <- here >> >> Thanks >> Laszlo > _______________________________________________ > edk2-devel mailing list > edk2-devel@lists.01.org > https://lists.01.org/mailman/listinfo/edk2-devel > _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel
© 2016 - 2024 Red Hat, Inc.