1 ;------------------------------------------------------------------------------ ;
2 ; Copyright (c) 2016 - 2022, Intel Corporation. All rights reserved.<BR>
3 ; Copyright (c) 2020, AMD Incorporated. All rights reserved.<BR>
4 ; SPDX-License-Identifier: BSD-2-Clause-Patent
12 ; Code template of the SMI handler for a particular processor
14 ;-------------------------------------------------------------------------------
16 %include "StuffRsbNasm.inc"
20 ; Variables referenced by C code
23 %define MSR_IA32_S_CET 0x6A2
24 %define MSR_IA32_CET_SH_STK_EN 0x1
25 %define MSR_IA32_CET_WR_SHSTK_EN 0x2
26 %define MSR_IA32_CET_ENDBR_EN 0x4
27 %define MSR_IA32_CET_LEG_IW_EN 0x8
28 %define MSR_IA32_CET_NO_TRACK_EN 0x10
29 %define MSR_IA32_CET_SUPPRESS_DIS 0x20
30 %define MSR_IA32_CET_SUPPRESS 0x400
31 %define MSR_IA32_CET_TRACKER 0x800
32 %define MSR_IA32_PL0_SSP 0x6A4
33 %define MSR_IA32_INTERRUPT_SSP_TABLE_ADDR 0x6A8
35 %define CR4_CET 0x800000
37 %define MSR_IA32_MISC_ENABLE 0x1A0
38 %define MSR_EFER 0xc0000080
39 %define MSR_EFER_XD 0x800
42 ; Constants relating to PROCESSOR_SMM_DESCRIPTOR
44 %define DSC_OFFSET 0xfb00
45 %define DSC_GDTPTR 0x30
46 %define DSC_GDTSIZ 0x38
50 %define DSC_OTHERSEG 20
52 ; Constants relating to CPU State Save Area
54 %define SSM_DR6 0xffd0
55 %define SSM_DR7 0xffc8
57 %define PROTECT_MODE_CS 0x8
58 %define PROTECT_MODE_DS 0x20
59 %define LONG_MODE_CS 0x38
60 %define TSS_SEGMENT 0x40
63 extern ASM_PFX(SmiRendezvous)
64 extern ASM_PFX(gSmiHandlerIdtr)
65 extern ASM_PFX(CpuSmmDebugEntry)
66 extern ASM_PFX(CpuSmmDebugExit)
68 global ASM_PFX(gPatchSmbase)
69 extern ASM_PFX(mXdSupported)
70 global ASM_PFX(gPatchXdSupported)
71 global ASM_PFX(gPatchMsrIa32MiscEnableSupported)
72 global ASM_PFX(gPatchSmiStack)
73 global ASM_PFX(gPatchSmiCr3)
74 global ASM_PFX(gPatch5LevelPagingNeeded)
75 global ASM_PFX(gcSmiHandlerTemplate)
76 global ASM_PFX(gcSmiHandlerSize)
78 extern ASM_PFX(mCetSupported)
79 global ASM_PFX(mPatchCetSupported)
80 global ASM_PFX(mPatchCetPl0Ssp)
81 global ASM_PFX(mPatchCetInterruptSsp)
82 global ASM_PFX(mPatchCetInterruptSspTable)
88 ASM_PFX(gcSmiHandlerTemplate):
90 mov bx, _GdtDesc - _SmiEntryPoint + 0x8000
91 mov ax,[cs:DSC_OFFSET + DSC_GDTSIZ]
94 mov eax, [cs:DSC_OFFSET + DSC_GDTPTR]
96 o32 lgdt [cs:bx] ; lgdt fword ptr cs:[bx]
97 mov ax, PROTECT_MODE_CS
99 mov edi, strict dword 0 ; source operand will be patched
100 ASM_PFX(gPatchSmbase):
101 lea eax, [edi + (@ProtectedMode - _SmiEntryPoint) + 0x8000]
114 mov ax, PROTECT_MODE_DS
120 mov esp, strict dword 0 ; source operand will be patched
121 ASM_PFX(gPatchSmiStack):
126 mov eax, strict dword 0 ; source operand will be patched
127 ASM_PFX(gPatchSmiCr3):
129 mov eax, 0x668 ; as cr4.PGE is not set here, refresh cr3
131 mov cl, strict byte 0 ; source operand will be patched
132 ASM_PFX(gPatch5LevelPagingNeeded):
134 je SkipEnable5LevelPaging
136 ; Enable 5-Level Paging bit
138 bts eax, 12 ; Set LA57 bit (bit #12)
139 SkipEnable5LevelPaging:
141 mov cr4, rax ; in PreModifyMtrrs() to flush TLB.
143 sub esp, 8 ; reserve room in stack
145 mov eax, [rsp + 2] ; eax = GDT base
148 mov [rax + TSS_SEGMENT + 5], dl ; clear busy flag
152 ; enable NXE if supported
153 mov al, strict byte 1 ; source operand may be patched
154 ASM_PFX(gPatchXdSupported):
158 ; If MSR_IA32_MISC_ENABLE is supported, clear XD Disable bit
159 mov al, strict byte 1 ; source operand may be patched
160 ASM_PFX(gPatchMsrIa32MiscEnableSupported):
162 jz MsrIa32MiscEnableSupported
164 ; MSR_IA32_MISC_ENABLE not supported
167 push rdx ; don't try to restore the XD Disable bit just before RSM
171 ; Check XD disable bit
173 MsrIa32MiscEnableSupported:
174 mov ecx, MSR_IA32_MISC_ENABLE
177 push rdx ; save MSR_IA32_MISC_ENABLE[63-32]
178 test edx, BIT2 ; MSR_IA32_MISC_ENABLE[34]
180 and dx, 0xFFFB ; clear XD Disable bit if it is set
185 or ax, MSR_EFER_XD ; enable NXE
192 ; Switch into @LongMode
193 push LONG_MODE_CS ; push cs hardcore here
194 call Base ; push return address for retf later
196 add dword [rsp], @LongMode - Base; offset for far retf, seg is the 1st arg
200 or ah, 1 ; enable LME
203 or ebx, 0x80010023 ; enable paging + WP + NE + MP + PE
206 @LongMode: ; long mode (64-bit code) starts here
207 mov rax, strict qword 0 ; mov rax, ASM_PFX(gSmiHandlerIdtr)
208 SmiHandlerIdtrAbsAddr:
210 lea ebx, [rdi + DSC_OFFSET]
211 mov ax, [rbx + DSC_DS]
213 mov ax, [rbx + DSC_OTHERSEG]
217 mov ax, [rbx + DSC_SS]
220 mov rbx, [rsp + 0x8] ; rbx <- CpuIndex
222 ; enable CET if supported
223 mov al, strict byte 1 ; source operand may be patched
224 ASM_PFX(mPatchCetSupported):
228 mov ecx, MSR_IA32_S_CET
233 mov ecx, MSR_IA32_PL0_SSP
238 mov ecx, MSR_IA32_INTERRUPT_SSP_TABLE_ADDR
243 mov ecx, MSR_IA32_S_CET
244 mov eax, MSR_IA32_CET_SH_STK_EN
248 mov ecx, MSR_IA32_PL0_SSP
249 mov eax, strict dword 0 ; source operand will be patched
250 ASM_PFX(mPatchCetPl0Ssp):
254 btr ecx, 16 ; clear WP
256 mov [eax], eax ; reload SSP, and clear busyflag.
260 mov ecx, MSR_IA32_INTERRUPT_SSP_TABLE_ADDR
261 mov eax, strict dword 0 ; source operand will be patched
262 ASM_PFX(mPatchCetInterruptSspTable):
266 mov eax, strict dword 0 ; source operand will be patched
267 ASM_PFX(mPatchCetInterruptSsp):
270 mov [eax], eax ; reload SSP, and clear busyflag.
279 mov eax, 0x668 | CR4_CET
295 mov rax, strict qword 0 ; call ASM_PFX(CpuSmmDebugEntry)
296 CpuSmmDebugEntryAbsAddr:
300 mov rax, strict qword 0 ; call ASM_PFX(SmiRendezvous)
301 SmiRendezvousAbsAddr:
305 mov rax, strict qword 0 ; call ASM_PFX(CpuSmmDebugExit)
306 CpuSmmDebugExitAbsAddr:
312 ; Restore FP registers
318 mov rax, strict qword 0 ; mov rax, ASM_PFX(mCetSupported)
319 mCetSupportedAbsAddr:
325 mov cr4, rax ; disable CET
327 mov ecx, MSR_IA32_INTERRUPT_SSP_TABLE_ADDR
332 mov ecx, MSR_IA32_PL0_SSP
337 mov ecx, MSR_IA32_S_CET
343 mov rax, strict qword 0 ; lea rax, [ASM_PFX(mXdSupported)]
348 pop rdx ; get saved MSR_IA32_MISC_ENABLE[63-32]
351 mov ecx, MSR_IA32_MISC_ENABLE
353 or dx, BIT2 ; set XD Disable bit if it was set before entering into SMM
361 ASM_PFX(gcSmiHandlerSize) DW $ - _SmiEntryPoint
364 ; Retrieve the address and fill it into mov opcode.
366 ; It is called in the driver entry point first.
367 ; It is used to fix up the real address in mov opcode.
368 ; Then, after the code logic is copied to the different location,
369 ; the code can also run.
371 global ASM_PFX(PiSmmCpuSmiEntryFixupAddress)
372 ASM_PFX(PiSmmCpuSmiEntryFixupAddress):
373 lea rax, [ASM_PFX(gSmiHandlerIdtr)]
374 lea rcx, [SmiHandlerIdtrAbsAddr]
375 mov qword [rcx - 8], rax
377 lea rax, [ASM_PFX(CpuSmmDebugEntry)]
378 lea rcx, [CpuSmmDebugEntryAbsAddr]
379 mov qword [rcx - 8], rax
381 lea rax, [ASM_PFX(SmiRendezvous)]
382 lea rcx, [SmiRendezvousAbsAddr]
383 mov qword [rcx - 8], rax
385 lea rax, [ASM_PFX(CpuSmmDebugExit)]
386 lea rcx, [CpuSmmDebugExitAbsAddr]
387 mov qword [rcx - 8], rax
389 lea rax, [ASM_PFX(mXdSupported)]
390 lea rcx, [mXdSupportedAbsAddr]
391 mov qword [rcx - 8], rax
393 lea rax, [ASM_PFX(mCetSupported)]
394 lea rcx, [mCetSupportedAbsAddr]
395 mov qword [rcx - 8], rax