]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmiEntry.nasm
271492a9d7220b13c8de2b329e2788a60da26ac3
[mirror_edk2.git] / UefiCpuPkg / PiSmmCpuDxeSmm / X64 / SmiEntry.nasm
1 ;------------------------------------------------------------------------------ ;
2 ; Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
3 ; SPDX-License-Identifier: BSD-2-Clause-Patent
4 ;
5 ; Module Name:
6 ;
7 ; SmiEntry.nasm
8 ;
9 ; Abstract:
10 ;
11 ; Code template of the SMI handler for a particular processor
12 ;
13 ;-------------------------------------------------------------------------------
14
15 %include "StuffRsbNasm.inc"
16 %include "Nasm.inc"
17
18 ;
19 ; Variables referrenced by C code
20 ;
21
22 %define MSR_IA32_S_CET 0x6A2
23 %define MSR_IA32_CET_SH_STK_EN 0x1
24 %define MSR_IA32_CET_WR_SHSTK_EN 0x2
25 %define MSR_IA32_CET_ENDBR_EN 0x4
26 %define MSR_IA32_CET_LEG_IW_EN 0x8
27 %define MSR_IA32_CET_NO_TRACK_EN 0x10
28 %define MSR_IA32_CET_SUPPRESS_DIS 0x20
29 %define MSR_IA32_CET_SUPPRESS 0x400
30 %define MSR_IA32_CET_TRACKER 0x800
31 %define MSR_IA32_PL0_SSP 0x6A4
32 %define MSR_IA32_INTERRUPT_SSP_TABLE_ADDR 0x6A8
33
34 %define CR4_CET 0x800000
35
36 %define MSR_IA32_MISC_ENABLE 0x1A0
37 %define MSR_EFER 0xc0000080
38 %define MSR_EFER_XD 0x800
39
40 ;
41 ; Constants relating to PROCESSOR_SMM_DESCRIPTOR
42 ;
43 %define DSC_OFFSET 0xfb00
44 %define DSC_GDTPTR 0x30
45 %define DSC_GDTSIZ 0x38
46 %define DSC_CS 14
47 %define DSC_DS 16
48 %define DSC_SS 18
49 %define DSC_OTHERSEG 20
50 ;
51 ; Constants relating to CPU State Save Area
52 ;
53 %define SSM_DR6 0xffd0
54 %define SSM_DR7 0xffc8
55
56 %define PROTECT_MODE_CS 0x8
57 %define PROTECT_MODE_DS 0x20
58 %define LONG_MODE_CS 0x38
59 %define TSS_SEGMENT 0x40
60 %define GDT_SIZE 0x50
61
62 extern ASM_PFX(SmiRendezvous)
63 extern ASM_PFX(gSmiHandlerIdtr)
64 extern ASM_PFX(CpuSmmDebugEntry)
65 extern ASM_PFX(CpuSmmDebugExit)
66
67 global ASM_PFX(gPatchSmbase)
68 extern ASM_PFX(mXdSupported)
69 global ASM_PFX(gPatchXdSupported)
70 global ASM_PFX(gPatchSmiStack)
71 global ASM_PFX(gPatchSmiCr3)
72 global ASM_PFX(gPatch5LevelPagingSupport)
73 global ASM_PFX(gcSmiHandlerTemplate)
74 global ASM_PFX(gcSmiHandlerSize)
75
76 extern ASM_PFX(mCetSupported)
77 global ASM_PFX(mPatchCetSupported)
78 global ASM_PFX(mPatchCetPl0Ssp)
79 global ASM_PFX(mPatchCetInterruptSsp)
80 global ASM_PFX(mPatchCetInterruptSspTable)
81
82 DEFAULT REL
83 SECTION .text
84
85 BITS 16
86 ASM_PFX(gcSmiHandlerTemplate):
87 _SmiEntryPoint:
88 mov bx, _GdtDesc - _SmiEntryPoint + 0x8000
89 mov ax,[cs:DSC_OFFSET + DSC_GDTSIZ]
90 dec ax
91 mov [cs:bx], ax
92 mov eax, [cs:DSC_OFFSET + DSC_GDTPTR]
93 mov [cs:bx + 2], eax
94 o32 lgdt [cs:bx] ; lgdt fword ptr cs:[bx]
95 mov ax, PROTECT_MODE_CS
96 mov [cs:bx-0x2],ax
97 mov edi, strict dword 0 ; source operand will be patched
98 ASM_PFX(gPatchSmbase):
99 lea eax, [edi + (@ProtectedMode - _SmiEntryPoint) + 0x8000]
100 mov [cs:bx-0x6],eax
101 mov ebx, cr0
102 and ebx, 0x9ffafff3
103 or ebx, 0x23
104 mov cr0, ebx
105 jmp dword 0x0:0x0
106 _GdtDesc:
107 DW 0
108 DD 0
109
110 BITS 32
111 @ProtectedMode:
112 mov ax, PROTECT_MODE_DS
113 o16 mov ds, ax
114 o16 mov es, ax
115 o16 mov fs, ax
116 o16 mov gs, ax
117 o16 mov ss, ax
118 mov esp, strict dword 0 ; source operand will be patched
119 ASM_PFX(gPatchSmiStack):
120 jmp ProtFlatMode
121
122 BITS 64
123 ProtFlatMode:
124 mov eax, strict dword 0 ; source operand will be patched
125 ASM_PFX(gPatchSmiCr3):
126 mov cr3, rax
127 mov eax, 0x668 ; as cr4.PGE is not set here, refresh cr3
128
129 mov cl, strict byte 0 ; source operand will be patched
130 ASM_PFX(gPatch5LevelPagingSupport):
131 cmp cl, 0
132 je SkipEnable5LevelPaging
133 ;
134 ; Enable 5-Level Paging bit
135 ;
136 bts eax, 12 ; Set LA57 bit (bit #12)
137 SkipEnable5LevelPaging:
138
139 mov cr4, rax ; in PreModifyMtrrs() to flush TLB.
140 ; Load TSS
141 sub esp, 8 ; reserve room in stack
142 sgdt [rsp]
143 mov eax, [rsp + 2] ; eax = GDT base
144 add esp, 8
145 mov dl, 0x89
146 mov [rax + TSS_SEGMENT + 5], dl ; clear busy flag
147 mov eax, TSS_SEGMENT
148 ltr ax
149
150 ; enable NXE if supported
151 mov al, strict byte 1 ; source operand may be patched
152 ASM_PFX(gPatchXdSupported):
153 cmp al, 0
154 jz @SkipXd
155 ;
156 ; Check XD disable bit
157 ;
158 mov ecx, MSR_IA32_MISC_ENABLE
159 rdmsr
160 sub esp, 4
161 push rdx ; save MSR_IA32_MISC_ENABLE[63-32]
162 test edx, BIT2 ; MSR_IA32_MISC_ENABLE[34]
163 jz .0
164 and dx, 0xFFFB ; clear XD Disable bit if it is set
165 wrmsr
166 .0:
167 mov ecx, MSR_EFER
168 rdmsr
169 or ax, MSR_EFER_XD ; enable NXE
170 wrmsr
171 jmp @XdDone
172 @SkipXd:
173 sub esp, 8
174 @XdDone:
175
176 ; Switch into @LongMode
177 push LONG_MODE_CS ; push cs hardcore here
178 call Base ; push return address for retf later
179 Base:
180 add dword [rsp], @LongMode - Base; offset for far retf, seg is the 1st arg
181
182 mov ecx, MSR_EFER
183 rdmsr
184 or ah, 1 ; enable LME
185 wrmsr
186 mov rbx, cr0
187 or ebx, 0x80010023 ; enable paging + WP + NE + MP + PE
188 mov cr0, rbx
189 retf
190 @LongMode: ; long mode (64-bit code) starts here
191 mov rax, strict qword 0 ; mov rax, ASM_PFX(gSmiHandlerIdtr)
192 SmiHandlerIdtrAbsAddr:
193 lidt [rax]
194 lea ebx, [rdi + DSC_OFFSET]
195 mov ax, [rbx + DSC_DS]
196 mov ds, eax
197 mov ax, [rbx + DSC_OTHERSEG]
198 mov es, eax
199 mov fs, eax
200 mov gs, eax
201 mov ax, [rbx + DSC_SS]
202 mov ss, eax
203
204 mov rbx, [rsp + 0x8] ; rbx <- CpuIndex
205
206 ; enable CET if supported
207 mov al, strict byte 1 ; source operand may be patched
208 ASM_PFX(mPatchCetSupported):
209 cmp al, 0
210 jz CetDone
211
212 mov ecx, MSR_IA32_S_CET
213 rdmsr
214 push rdx
215 push rax
216
217 mov ecx, MSR_IA32_PL0_SSP
218 rdmsr
219 push rdx
220 push rax
221
222 mov ecx, MSR_IA32_INTERRUPT_SSP_TABLE_ADDR
223 rdmsr
224 push rdx
225 push rax
226
227 mov ecx, MSR_IA32_S_CET
228 mov eax, MSR_IA32_CET_SH_STK_EN
229 xor edx, edx
230 wrmsr
231
232 mov ecx, MSR_IA32_PL0_SSP
233 mov eax, strict dword 0 ; source operand will be patched
234 ASM_PFX(mPatchCetPl0Ssp):
235 xor edx, edx
236 wrmsr
237 mov rcx, cr0
238 btr ecx, 16 ; clear WP
239 mov cr0, rcx
240 mov [eax], eax ; reload SSP, and clear busyflag.
241 xor ecx, ecx
242 mov [eax + 4], ecx
243
244 mov ecx, MSR_IA32_INTERRUPT_SSP_TABLE_ADDR
245 mov eax, strict dword 0 ; source operand will be patched
246 ASM_PFX(mPatchCetInterruptSspTable):
247 xor edx, edx
248 wrmsr
249
250 mov eax, strict dword 0 ; source operand will be patched
251 ASM_PFX(mPatchCetInterruptSsp):
252 cmp eax, 0
253 jz CetInterruptDone
254 mov [eax], eax ; reload SSP, and clear busyflag.
255 xor ecx, ecx
256 mov [eax + 4], ecx
257 CetInterruptDone:
258
259 mov rcx, cr0
260 bts ecx, 16 ; set WP
261 mov cr0, rcx
262
263 mov eax, 0x668 | CR4_CET
264 mov cr4, rax
265
266 SETSSBSY
267
268 CetDone:
269
270 ;
271 ; Save FP registers
272 ;
273 sub rsp, 0x200
274 fxsave64 [rsp]
275
276 add rsp, -0x20
277
278 mov rcx, rbx
279 mov rax, strict qword 0 ; call ASM_PFX(CpuSmmDebugEntry)
280 CpuSmmDebugEntryAbsAddr:
281 call rax
282
283 mov rcx, rbx
284 mov rax, strict qword 0 ; call ASM_PFX(SmiRendezvous)
285 SmiRendezvousAbsAddr:
286 call rax
287
288 mov rcx, rbx
289 mov rax, strict qword 0 ; call ASM_PFX(CpuSmmDebugExit)
290 CpuSmmDebugExitAbsAddr:
291 call rax
292
293 add rsp, 0x20
294
295 ;
296 ; Restore FP registers
297 ;
298 fxrstor64 [rsp]
299
300 add rsp, 0x200
301
302 mov rax, strict qword 0 ; mov rax, ASM_PFX(mCetSupported)
303 mCetSupportedAbsAddr:
304 mov al, [rax]
305 cmp al, 0
306 jz CetDone2
307
308 mov eax, 0x668
309 mov cr4, rax ; disable CET
310
311 mov ecx, MSR_IA32_INTERRUPT_SSP_TABLE_ADDR
312 pop rax
313 pop rdx
314 wrmsr
315
316 mov ecx, MSR_IA32_PL0_SSP
317 pop rax
318 pop rdx
319 wrmsr
320
321 mov ecx, MSR_IA32_S_CET
322 pop rax
323 pop rdx
324 wrmsr
325 CetDone2:
326
327 mov rax, strict qword 0 ; lea rax, [ASM_PFX(mXdSupported)]
328 mXdSupportedAbsAddr:
329 mov al, [rax]
330 cmp al, 0
331 jz .1
332 pop rdx ; get saved MSR_IA32_MISC_ENABLE[63-32]
333 test edx, BIT2
334 jz .1
335 mov ecx, MSR_IA32_MISC_ENABLE
336 rdmsr
337 or dx, BIT2 ; set XD Disable bit if it was set before entering into SMM
338 wrmsr
339
340 .1:
341
342 StuffRsb64
343 rsm
344
345 ASM_PFX(gcSmiHandlerSize) DW $ - _SmiEntryPoint
346
347 ;
348 ; Retrieve the address and fill it into mov opcode.
349 ;
350 ; It is called in the driver entry point first.
351 ; It is used to fix up the real address in mov opcode.
352 ; Then, after the code logic is copied to the different location,
353 ; the code can also run.
354 ;
355 global ASM_PFX(PiSmmCpuSmiEntryFixupAddress)
356 ASM_PFX(PiSmmCpuSmiEntryFixupAddress):
357 lea rax, [ASM_PFX(gSmiHandlerIdtr)]
358 lea rcx, [SmiHandlerIdtrAbsAddr]
359 mov qword [rcx - 8], rax
360
361 lea rax, [ASM_PFX(CpuSmmDebugEntry)]
362 lea rcx, [CpuSmmDebugEntryAbsAddr]
363 mov qword [rcx - 8], rax
364
365 lea rax, [ASM_PFX(SmiRendezvous)]
366 lea rcx, [SmiRendezvousAbsAddr]
367 mov qword [rcx - 8], rax
368
369 lea rax, [ASM_PFX(CpuSmmDebugExit)]
370 lea rcx, [CpuSmmDebugExitAbsAddr]
371 mov qword [rcx - 8], rax
372
373 lea rax, [ASM_PFX(mXdSupported)]
374 lea rcx, [mXdSupportedAbsAddr]
375 mov qword [rcx - 8], rax
376
377 lea rax, [ASM_PFX(mCetSupported)]
378 lea rcx, [mCetSupportedAbsAddr]
379 mov qword [rcx - 8], rax
380 ret