UefiCpuPkg/PiSmmCpuDxeSmm: patch "gSmiCr3" with PatchInstructionX86()
[mirror_edk2.git] / UefiCpuPkg / PiSmmCpuDxeSmm / X64 / SmiEntry.nasm
1 ;------------------------------------------------------------------------------ ;
2 ; Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
3 ; This program and the accompanying materials
4 ; are licensed and made available under the terms and conditions of the BSD License
5 ; which accompanies this distribution. The full text of the license may be found at
6 ; http://opensource.org/licenses/bsd-license.php.
7 ;
8 ; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
9 ; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
10 ;
11 ; Module Name:
12 ;
13 ; SmiEntry.nasm
14 ;
15 ; Abstract:
16 ;
17 ; Code template of the SMI handler for a particular processor
18 ;
19 ;-------------------------------------------------------------------------------
20
21 ;
22 ; Variables referrenced by C code
23 ;
24
25 %define MSR_IA32_MISC_ENABLE 0x1A0
26 %define MSR_EFER 0xc0000080
27 %define MSR_EFER_XD 0x800
28
29 ;
30 ; Constants relating to PROCESSOR_SMM_DESCRIPTOR
31 ;
32 %define DSC_OFFSET 0xfb00
33 %define DSC_GDTPTR 0x30
34 %define DSC_GDTSIZ 0x38
35 %define DSC_CS 14
36 %define DSC_DS 16
37 %define DSC_SS 18
38 %define DSC_OTHERSEG 20
39 ;
40 ; Constants relating to CPU State Save Area
41 ;
42 %define SSM_DR6 0xffd0
43 %define SSM_DR7 0xffc8
44
45 %define PROTECT_MODE_CS 0x8
46 %define PROTECT_MODE_DS 0x20
47 %define LONG_MODE_CS 0x38
48 %define TSS_SEGMENT 0x40
49 %define GDT_SIZE 0x50
50
51 extern ASM_PFX(SmiRendezvous)
52 extern ASM_PFX(gSmiHandlerIdtr)
53 extern ASM_PFX(CpuSmmDebugEntry)
54 extern ASM_PFX(CpuSmmDebugExit)
55
56 global ASM_PFX(gPatchSmbase)
57 global ASM_PFX(mXdSupported)
58 global ASM_PFX(gPatchSmiStack)
59 global ASM_PFX(gPatchSmiCr3)
60 global ASM_PFX(gcSmiHandlerTemplate)
61 global ASM_PFX(gcSmiHandlerSize)
62
63 DEFAULT REL
64 SECTION .text
65
66 BITS 16
67 ASM_PFX(gcSmiHandlerTemplate):
68 _SmiEntryPoint:
69 mov bx, _GdtDesc - _SmiEntryPoint + 0x8000
70 mov ax,[cs:DSC_OFFSET + DSC_GDTSIZ]
71 dec ax
72 mov [cs:bx], ax
73 mov eax, [cs:DSC_OFFSET + DSC_GDTPTR]
74 mov [cs:bx + 2], eax
75 o32 lgdt [cs:bx] ; lgdt fword ptr cs:[bx]
76 mov ax, PROTECT_MODE_CS
77 mov [cs:bx-0x2],ax
78 mov edi, strict dword 0 ; source operand will be patched
79 ASM_PFX(gPatchSmbase):
80 lea eax, [edi + (@ProtectedMode - _SmiEntryPoint) + 0x8000]
81 mov [cs:bx-0x6],eax
82 mov ebx, cr0
83 and ebx, 0x9ffafff3
84 or ebx, 0x23
85 mov cr0, ebx
86 jmp dword 0x0:0x0
87 _GdtDesc:
88 DW 0
89 DD 0
90
91 BITS 32
92 @ProtectedMode:
93 mov ax, PROTECT_MODE_DS
94 o16 mov ds, ax
95 o16 mov es, ax
96 o16 mov fs, ax
97 o16 mov gs, ax
98 o16 mov ss, ax
99 mov esp, strict dword 0 ; source operand will be patched
100 ASM_PFX(gPatchSmiStack):
101 jmp ProtFlatMode
102
103 BITS 64
104 ProtFlatMode:
105 mov eax, strict dword 0 ; source operand will be patched
106 ASM_PFX(gPatchSmiCr3):
107 mov cr3, rax
108 mov eax, 0x668 ; as cr4.PGE is not set here, refresh cr3
109 mov cr4, rax ; in PreModifyMtrrs() to flush TLB.
110 ; Load TSS
111 sub esp, 8 ; reserve room in stack
112 sgdt [rsp]
113 mov eax, [rsp + 2] ; eax = GDT base
114 add esp, 8
115 mov dl, 0x89
116 mov [rax + TSS_SEGMENT + 5], dl ; clear busy flag
117 mov eax, TSS_SEGMENT
118 ltr ax
119
120 ; enable NXE if supported
121 DB 0xb0 ; mov al, imm8
122 ASM_PFX(mXdSupported): DB 1
123 cmp al, 0
124 jz @SkipXd
125 ;
126 ; Check XD disable bit
127 ;
128 mov ecx, MSR_IA32_MISC_ENABLE
129 rdmsr
130 sub esp, 4
131 push rdx ; save MSR_IA32_MISC_ENABLE[63-32]
132 test edx, BIT2 ; MSR_IA32_MISC_ENABLE[34]
133 jz .0
134 and dx, 0xFFFB ; clear XD Disable bit if it is set
135 wrmsr
136 .0:
137 mov ecx, MSR_EFER
138 rdmsr
139 or ax, MSR_EFER_XD ; enable NXE
140 wrmsr
141 jmp @XdDone
142 @SkipXd:
143 sub esp, 8
144 @XdDone:
145
146 ; Switch into @LongMode
147 push LONG_MODE_CS ; push cs hardcore here
148 call Base ; push return address for retf later
149 Base:
150 add dword [rsp], @LongMode - Base; offset for far retf, seg is the 1st arg
151
152 mov ecx, MSR_EFER
153 rdmsr
154 or ah, 1 ; enable LME
155 wrmsr
156 mov rbx, cr0
157 or ebx, 0x80010023 ; enable paging + WP + NE + MP + PE
158 mov cr0, rbx
159 retf
160 @LongMode: ; long mode (64-bit code) starts here
161 mov rax, strict qword 0 ; mov rax, ASM_PFX(gSmiHandlerIdtr)
162 SmiHandlerIdtrAbsAddr:
163 lidt [rax]
164 lea ebx, [rdi + DSC_OFFSET]
165 mov ax, [rbx + DSC_DS]
166 mov ds, eax
167 mov ax, [rbx + DSC_OTHERSEG]
168 mov es, eax
169 mov fs, eax
170 mov gs, eax
171 mov ax, [rbx + DSC_SS]
172 mov ss, eax
173 mov rax, strict qword 0 ; mov rax, _SmiHandler
174 _SmiHandlerAbsAddr:
175 jmp rax
176
177 _SmiHandler:
178 mov rbx, [rsp + 0x8] ; rcx <- CpuIndex
179
180 ;
181 ; Save FP registers
182 ;
183 sub rsp, 0x200
184 DB 0x48 ; FXSAVE64
185 fxsave [rsp]
186
187 add rsp, -0x20
188
189 mov rcx, rbx
190 call ASM_PFX(CpuSmmDebugEntry)
191
192 mov rcx, rbx
193 call ASM_PFX(SmiRendezvous)
194
195 mov rcx, rbx
196 call ASM_PFX(CpuSmmDebugExit)
197
198 add rsp, 0x20
199
200 ;
201 ; Restore FP registers
202 ;
203 DB 0x48 ; FXRSTOR64
204 fxrstor [rsp]
205
206 add rsp, 0x200
207
208 lea rax, [ASM_PFX(mXdSupported)]
209 mov al, [rax]
210 cmp al, 0
211 jz .1
212 pop rdx ; get saved MSR_IA32_MISC_ENABLE[63-32]
213 test edx, BIT2
214 jz .1
215 mov ecx, MSR_IA32_MISC_ENABLE
216 rdmsr
217 or dx, BIT2 ; set XD Disable bit if it was set before entering into SMM
218 wrmsr
219
220 .1:
221 rsm
222
223 ASM_PFX(gcSmiHandlerSize) DW $ - _SmiEntryPoint
224
225 global ASM_PFX(PiSmmCpuSmiEntryFixupAddress)
226 ASM_PFX(PiSmmCpuSmiEntryFixupAddress):
227 lea rax, [ASM_PFX(gSmiHandlerIdtr)]
228 lea rcx, [SmiHandlerIdtrAbsAddr]
229 mov qword [rcx - 8], rax
230
231 lea rax, [_SmiHandler]
232 lea rcx, [_SmiHandlerAbsAddr]
233 mov qword [rcx - 8], rax
234 ret