[Patch v4 09/46] UefiCpuPkg/MpInitLib: Add AsmRelocateApLoop() assembly code


Jeff Fan <jeff.fan@...>
 

AsmRelocateApLoop() is used to place APs into MWAIT-loop if MonitorMwait
feature is supported before hand-off to OS, or place APs into HLT-loop if
MonitorMwait feature is not supported.

If the current mode is long mode, we will switch APs to protected mode
before placing APs in MWAIT-loop or HLT-loop. Thus, once APs wakeup from
loop, APs needn't the page table that may be crashed by OS.

v3:
1. Rename AsmRellocateApLoop to AsmRelocateApLoop.
2. Fix typo Proteced to Protected.
3. Fix typo segement to segment
4. Use word MONITOR instead of mwait-monitor.

Cc: Michael Kinney <michael.d.kinney@intel.com>
Cc: Feng Tian <feng.tian@intel.com>
Cc: Giri P Mudusuru <giri.p.mudusuru@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <jeff.fan@intel.com>
Reviewed-by: Giri P Mudusuru <giri.p.mudusuru@intel.com>
---
UefiCpuPkg/Library/MpInitLib/Ia32/MpFuncs.nasm | 24 ++++++++++++
UefiCpuPkg/Library/MpInitLib/MpLib.h | 21 ++++++++++
UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm | 54 ++++++++++++++++++++++++++
3 files changed, 99 insertions(+)

diff --git a/UefiCpuPkg/Library/MpInitLib/Ia32/MpFuncs.nasm b/UefiCpuPkg/Library/MpInitLib/Ia32/MpFuncs.nasm
index 8bacb42..49f5503 100644
--- a/UefiCpuPkg/Library/MpInitLib/Ia32/MpFuncs.nasm
+++ b/UefiCpuPkg/Library/MpInitLib/Ia32/MpFuncs.nasm
@@ -169,6 +169,30 @@ CProcedureInvoke:
RendezvousFunnelProcEnd:

;-------------------------------------------------------------------------------------
+; AsmRelocateApLoop (MwaitSupport, ApTargetCState, PmCodeSegment);
+;-------------------------------------------------------------------------------------
+global ASM_PFX(AsmRelocateApLoop)
+ASM_PFX(AsmRelocateApLoop):
+AsmRelocateApLoopStart:
+ cmp byte [esp + 4], 1
+ jnz HltLoop
+MwaitLoop:
+ mov eax, esp
+ xor ecx, ecx
+ xor edx, edx
+ monitor
+ mov eax, [esp + 8] ; Mwait Cx, Target C-State per eax[7:4]
+ shl eax, 4
+ mwait
+ jmp MwaitLoop
+HltLoop:
+ cli
+ hlt
+ jmp HltLoop
+ ret
+AsmRelocateApLoopEnd:
+
+;-------------------------------------------------------------------------------------
; AsmGetAddressMap (&AddressMap);
;-------------------------------------------------------------------------------------
global ASM_PFX(AsmGetAddressMap)
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h
index 28a3cd4..39ec5de 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.h
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h
@@ -60,5 +60,26 @@ typedef struct {
} MP_CPU_EXCHANGE_INFO;

#pragma pack()
+/**
+ Assembly code to place AP into safe loop mode.
+
+ Place AP into targeted C-State if MONITOR is supported, otherwise
+ place AP into hlt state.
+ Place AP in protected mode if the current is long mode. Due to AP maybe
+ wakeup by some hardware event. It could avoid accessing page table that
+ may not available during booting to OS.
+
+ @param[in] MwaitSupport TRUE indicates MONITOR is supported.
+ FALSE indicates MONITOR is not supported.
+ @param[in] ApTargetCState Target C-State value.
+ @param[in] PmCodeSegment Protected mode code segment value.
+**/
+typedef
+VOID
+(EFIAPI * ASM_RELOCATE_AP_LOOP) (
+ IN BOOLEAN MwaitSupport,
+ IN UINTN ApTargetCState,
+ IN UINTN PmCodeSegment
+ );
#endif

diff --git a/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm b/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
index 3c55ffa..d5d7efe 100644
--- a/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
+++ b/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
@@ -177,6 +177,60 @@ CProcedureInvoke:
RendezvousFunnelProcEnd:

;-------------------------------------------------------------------------------------
+; AsmRelocateApLoop (MwaitSupport, ApTargetCState, PmCodeSegment);
+;-------------------------------------------------------------------------------------
+global ASM_PFX(AsmRelocateApLoop)
+ASM_PFX(AsmRelocateApLoop):
+AsmRelocateApLoopStart:
+ push rcx
+ push rdx
+
+ lea rsi, [PmEntry] ; rsi <- The start address of transition code
+
+ push r8
+ push rsi
+ DB 0x48
+ retf
+BITS 32
+PmEntry:
+ mov eax, cr0
+ btr eax, 31 ; Clear CR0.PG
+ mov cr0, eax ; Disable paging and caches
+
+ mov ebx, edx ; Save EntryPoint to rbx, for rdmsr will overwrite rdx
+ mov ecx, 0xc0000080
+ rdmsr
+ and ah, ~ 1 ; Clear LME
+ wrmsr
+ mov eax, cr4
+ and al, ~ (1 << 5) ; Clear PAE
+ mov cr4, eax
+
+ pop edx
+ add esp, 4
+ pop ecx,
+ add esp, 4
+ cmp cl, 1 ; Check mwait-monitor support
+ jnz HltLoop
+ mov ebx, edx ; Save C-State to ebx
+MwaitLoop:
+ mov eax, esp ; Set Monitor Address
+ xor ecx, ecx ; ecx = 0
+ xor edx, edx ; edx = 0
+ monitor
+ shl ebx, 4
+ mov eax, ebx ; Mwait Cx, Target C-State per eax[7:4]
+ mwait
+ jmp MwaitLoop
+HltLoop:
+ cli
+ hlt
+ jmp HltLoop
+ ret
+BITS 64
+AsmRelocateApLoopEnd:
+
+;-------------------------------------------------------------------------------------
; AsmGetAddressMap (&AddressMap);
;-------------------------------------------------------------------------------------
global ASM_PFX(AsmGetAddressMap)
--
2.7.4.windows.1