]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/SmmCpuFeaturesLib/X64/SmiEntry.S
UefiCpuPkg/SmmCpuFeaturesLibStm: Add STM library instance
[mirror_edk2.git] / UefiCpuPkg / Library / SmmCpuFeaturesLib / X64 / SmiEntry.S
1 #------------------------------------------------------------------------------
2 #
3 # Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
4 # This program and the accompanying materials
5 # are licensed and made available under the terms and conditions of the BSD License
6 # which accompanies this distribution. The full text of the license may be found at
7 # http://opensource.org/licenses/bsd-license.php.
8 #
9 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11 #
12 # Module Name:
13 #
14 # SmiEntry.S
15 #
16 # Abstract:
17 #
18 # Code template of the SMI handler for a particular processor
19 #
20 #------------------------------------------------------------------------------
21
22 ASM_GLOBAL ASM_PFX(gcStmSmiHandlerTemplate)
23 ASM_GLOBAL ASM_PFX(gcStmSmiHandlerSize)
24 ASM_GLOBAL ASM_PFX(gcStmSmiHandlerOffset)
25 ASM_GLOBAL ASM_PFX(gStmSmiCr3)
26 ASM_GLOBAL ASM_PFX(gStmSmiStack)
27 ASM_GLOBAL ASM_PFX(gStmSmbase)
28 ASM_GLOBAL ASM_PFX(gStmXdSupported)
29 ASM_GLOBAL ASM_PFX(gStmSmiHandlerIdtr)
30
31 .equ MSR_IA32_MISC_ENABLE, 0x1A0
32 .equ MSR_EFER, 0xc0000080
33 .equ MSR_EFER_XD, 0x800
34
35 #
36 # Constants relating to TXT_PROCESSOR_SMM_DESCRIPTOR
37 #
38 .equ DSC_OFFSET, 0xfb00
39 .equ DSC_GDTPTR, 0x48
40 .equ DSC_GDTSIZ, 0x50
41 .equ DSC_CS, 0x14
42 .equ DSC_DS, 0x16
43 .equ DSC_SS, 0x18
44 .equ DSC_OTHERSEG, 0x1a
45 #
46 # Constants relating to CPU State Save Area
47 #
48 .equ SSM_DR6, 0xffd0
49 .equ SSM_DR7, 0xffc8
50
51 .equ PROTECT_MODE_CS, 0x08
52 .equ PROTECT_MODE_DS, 0x20
53 .equ LONG_MODE_CS, 0x38
54 .equ TSS_SEGMENT, 0x40
55 .equ GDT_SIZE, 0x50
56
57 .text
58
59 ASM_PFX(gcStmSmiHandlerTemplate):
60
61 _StmSmiEntryPoint:
62 #
63 # The encoding of BX in 16-bit addressing mode is the same as of RDI in 64-
64 # bit addressing mode. And that coincidence has been used in the following
65 # "64-bit like" 16-bit code. Be aware that once RDI is referenced as a
66 # base address register, it is actually BX that is referenced.
67 #
68 .byte 0xbb # mov bx, imm16
69 .word _StmGdtDesc - _StmSmiEntryPoint + 0x8000
70 #
71 # fix GDT descriptor
72 #
73 .byte 0x2e,0xa1 # mov ax, cs:[offset16]
74 .word DSC_OFFSET + DSC_GDTSIZ
75 .byte 0x48 # dec ax
76 .byte 0x2e
77 movl %eax, (%rdi) # mov cs:[bx], ax
78 .byte 0x66,0x2e,0xa1 # mov eax, cs:[offset16]
79 .word DSC_OFFSET + DSC_GDTPTR
80 .byte 0x2e
81 movw %ax, 2(%rdi)
82 .byte 0x66,0x2e
83 lgdt (%rdi)
84 #
85 # Patch ProtectedMode Segment
86 #
87 .byte 0xb8
88 .word PROTECT_MODE_CS
89 .byte 0x2e
90 movl %eax, -2(%rdi)
91 #
92 # Patch ProtectedMode entry
93 #
94 .byte 0x66, 0xbf # mov edi, SMBASE
95 ASM_PFX(gStmSmbase): .space 4
96 lea ((ProtectedMode - _StmSmiEntryPoint) + 0x8000)(%edi), %ax
97 .byte 0x2e
98 movw %ax, -6(%rdi)
99 #
100 # Switch into ProtectedMode
101 #
102 movq %cr0, %rbx
103 .byte 0x66
104 andl $0x9ffafff3, %ebx
105 .byte 0x66
106 orl $0x00000023, %ebx
107
108 movq %rbx, %cr0
109 .byte 0x66, 0xea
110 .space 6
111
112 _StmGdtDesc: .space 6
113
114 ProtectedMode:
115 movw $PROTECT_MODE_DS, %ax
116 movl %eax, %ds
117 movl %eax, %es
118 movl %eax, %fs
119 movl %eax, %gs
120 movl %eax, %ss
121 .byte 0xbc # mov esp, imm32
122 ASM_PFX(gStmSmiStack): .space 4
123 jmp ProtFlatMode
124
125 ProtFlatMode:
126 .byte 0xb8
127 ASM_PFX(gStmSmiCr3): .space 4
128 movq %rax, %cr3
129 movl $0x668,%eax # as cr4.PGE is not set here, refresh cr3
130 movq %rax, %cr4 # in PreModifyMtrrs() to flush TLB.
131 # Load TSS
132 subl $8, %esp # reserve room in stack
133 sgdt (%rsp)
134 movl 2(%rsp), %eax # eax = GDT base
135 addl $8, %esp
136 movb $0x89, %dl
137 movb %dl, (TSS_SEGMENT + 5)(%rax) # clear busy flag
138 movl $TSS_SEGMENT, %eax
139 ltr %ax
140
141 # enable NXE if supported
142 .byte 0xb0 # mov al, imm8
143 ASM_PFX(gStmXdSupported): .byte 1
144 cmpb $0, %al
145 jz SkipXd
146 #
147 # Check XD disable bit
148 #
149 movl $MSR_IA32_MISC_ENABLE, %ecx
150 rdmsr
151 subl $4, %esp
152 pushq %rdx # save MSR_IA32_MISC_ENABLE[63-32]
153 testl $BIT2, %edx # MSR_IA32_MISC_ENABLE[34]
154 jz L13
155 andw $0x0FFFB, %dx # clear XD Disable bit if it is set
156 wrmsr
157 L13:
158 movl $MSR_EFER, %ecx
159 rdmsr
160 orw $MSR_EFER_XD,%ax # enable NXE
161 wrmsr
162 jmp XdDone
163 SkipXd:
164 subl $8, %esp
165 XdDone:
166
167 #
168 # Switch to LongMode
169 #
170 pushq $LONG_MODE_CS # push cs hardcore here
171 call Base # push return address for retf later
172 Base:
173 addl $(LongMode - Base), (%rsp) # offset for far retf, seg is the 1st arg
174
175 movl $MSR_EFER, %ecx
176 rdmsr
177 orb $1,%ah # enable LME
178 wrmsr
179 movq %cr0, %rbx
180 orl $0x080010023, %ebx # enable paging + WP + NE + MP + PE
181 movq %rbx, %cr0
182 retf
183 LongMode: # long mode (64-bit code) starts here
184 movabsq $ASM_PFX(gStmSmiHandlerIdtr), %rax
185 lidt (%rax)
186 lea (DSC_OFFSET)(%rdi), %ebx
187 movw DSC_DS(%rbx), %ax
188 movl %eax,%ds
189 movw DSC_OTHERSEG(%rbx), %ax
190 movl %eax,%es
191 movl %eax,%fs
192 movl %eax,%gs
193 movw DSC_SS(%rbx), %ax
194 movl %eax,%ss
195
196 CommonHandler:
197 movq 8(%rsp), %rbx
198 # Save FP registers
199
200 subq $0x200, %rsp
201 .byte 0x48 # FXSAVE64
202 fxsave (%rsp)
203
204 addq $-0x20, %rsp
205
206 movq %rbx, %rcx
207 movabsq $ASM_PFX(CpuSmmDebugEntry), %rax
208 call *%rax
209
210 movq %rbx, %rcx
211 movabsq $ASM_PFX(SmiRendezvous), %rax
212 call *%rax
213
214 movq %rbx, %rcx
215 movabsq $ASM_PFX(CpuSmmDebugExit), %rax
216 call *%rax
217
218 addq $0x20, %rsp
219
220 #
221 # Restore FP registers
222 #
223 .byte 0x48 # FXRSTOR64
224 fxrstor (%rsp)
225
226 addq $0x200, %rsp
227
228 movabsq $ASM_PFX(gStmXdSupported), %rax
229 movb (%rax), %al
230 cmpb $0, %al
231 jz L16
232 popq %rdx # get saved MSR_IA32_MISC_ENABLE[63-32]
233 testl $BIT2, %edx
234 jz L16
235 movl $MSR_IA32_MISC_ENABLE, %ecx
236 rdmsr
237 orw $BIT2, %dx # set XD Disable bit if it was set before entering into SMM
238 wrmsr
239
240 L16:
241 rsm
242
243 _StmSmiHandler:
244 #
245 # Check XD disable bit
246 #
247 xorq %r8, %r8
248 movabsq $ASM_PFX(gStmXdSupported), %rax
249 movb (%rax), %al
250 cmpb $0, %al
251 jz StmXdDone
252 movl $MSR_IA32_MISC_ENABLE, %ecx
253 rdmsr
254 movq %rdx, %r8 # save MSR_IA32_MISC_ENABLE[63-32]
255 testl $BIT2, %edx # MSR_IA32_MISC_ENABLE[34]
256 jz L14
257 andw $0x0FFFB, %dx # clear XD Disable bit if it is set
258 wrmsr
259 L14:
260 movl $MSR_EFER, %ecx
261 rdmsr
262 orw $MSR_EFER_XD,%ax # enable NXE
263 wrmsr
264 StmXdDone:
265 pushq %r8
266
267 # below step is needed, because STM does not run above code.
268 # we have to run below code to set IDT/CR0/CR4
269 movabsq $ASM_PFX(gStmSmiHandlerIdtr), %rax
270 lidt (%rax)
271
272 movq %cr0, %rax
273 orl $0x80010023, %eax
274 movq %rax, %cr0
275 movq %cr4, %rax
276 movl $0x668, %eax # as cr4.PGE is not set here, refresh cr3
277 movq %rax, %cr4 # in PreModifyMtrrs() to flush TLB.
278 # STM init finish
279 jmp CommonHandler
280
281 ASM_PFX(gcStmSmiHandlerSize) : .word . - _StmSmiEntryPoint
282 ASM_PFX(gcStmSmiHandlerOffset): .word _StmSmiHandler - _StmSmiEntryPoint