]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionTssEntryAsm.nasm
UefiCpuPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / UefiCpuPkg / Library / CpuExceptionHandlerLib / Ia32 / ExceptionTssEntryAsm.nasm
1 ;------------------------------------------------------------------------------ ;
2 ; Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
3 ; SPDX-License-Identifier: BSD-2-Clause-Patent
4 ;
5 ; Module Name:
6 ;
7 ; ExceptionTssEntryAsm.Asm
8 ;
9 ; Abstract:
10 ;
11 ; IA32 CPU Exception Handler with Separate Stack
12 ;
13 ; Notes:
14 ;
15 ;------------------------------------------------------------------------------
16
17 ;
18 ; IA32 TSS Memory Layout Description
19 ;
20 struc IA32_TSS
21 resw 1
22 resw 1
23 .ESP0: resd 1
24 .SS0: resw 1
25 resw 1
26 .ESP1: resd 1
27 .SS1: resw 1
28 resw 1
29 .ESP2: resd 1
30 .SS2: resw 1
31 resw 1
32 ._CR3: resd 1
33 .EIP: resd 1
34 .EFLAGS: resd 1
35 ._EAX: resd 1
36 ._ECX: resd 1
37 ._EDX: resd 1
38 ._EBX: resd 1
39 ._ESP: resd 1
40 ._EBP: resd 1
41 ._ESI: resd 1
42 ._EDI: resd 1
43 ._ES: resw 1
44 resw 1
45 ._CS: resw 1
46 resw 1
47 ._SS: resw 1
48 resw 1
49 ._DS: resw 1
50 resw 1
51 ._FS: resw 1
52 resw 1
53 ._GS: resw 1
54 resw 1
55 .LDT: resw 1
56 resw 1
57 resw 1
58 resw 1
59 endstruc
60
61 ;
62 ; CommonExceptionHandler()
63 ;
64 extern ASM_PFX(CommonExceptionHandler)
65
66 SECTION .data
67
68 SECTION .text
69
70 ALIGN 8
71
72 ;
73 ; Exception handler stub table
74 ;
75 AsmExceptionEntryBegin:
76 %assign Vector 0
77 %rep 32
78
79 DoIret%[Vector]:
80 iretd
81 ASM_PFX(ExceptionTaskSwtichEntry%[Vector]):
82 db 0x6a ; push #VectorNum
83 db %[Vector]
84 mov eax, ASM_PFX(CommonTaskSwtichEntryPoint)
85 call eax
86 mov esp, eax ; Restore stack top
87 jmp DoIret%[Vector]
88
89 %assign Vector Vector+1
90 %endrep
91 AsmExceptionEntryEnd:
92
93 ;
94 ; Common part of exception handler
95 ;
96 global ASM_PFX(CommonTaskSwtichEntryPoint)
97 ASM_PFX(CommonTaskSwtichEntryPoint):
98 ;
99 ; Stack:
100 ; +---------------------+ <-- EBP - 8
101 ; + TSS Base +
102 ; +---------------------+ <-- EBP - 4
103 ; + CPUID.EDX +
104 ; +---------------------+ <-- EBP
105 ; + EIP +
106 ; +---------------------+ <-- EBP + 4
107 ; + Vector Number +
108 ; +---------------------+ <-- EBP + 8
109 ; + Error Code +
110 ; +---------------------+
111 ;
112
113 mov ebp, esp ; Stack frame
114
115 ; Use CPUID to determine if FXSAVE/FXRESTOR and DE are supported
116 mov eax, 1
117 cpuid
118 push edx
119
120 ; Get TSS base of interrupted task through PreviousTaskLink field in
121 ; current TSS base
122 sub esp, 8
123 sgdt [esp + 2]
124 mov eax, [esp + 4] ; GDT base
125 add esp, 8
126
127 xor ebx, ebx
128 str bx ; Current TR
129
130 mov ecx, [eax + ebx + 2]
131 shl ecx, 8
132 mov cl, [eax + ebx + 7]
133 ror ecx, 8 ; ecx = Current TSS base
134 push ecx ; keep it in stack for later use
135
136 movzx ebx, word [ecx] ; Previous Task Link
137 mov ecx, [eax + ebx + 2]
138 shl ecx, 8
139 mov cl, [eax + ebx + 7]
140 ror ecx, 8 ; ecx = Previous TSS base
141
142 ;
143 ; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
144 ; is 16-byte aligned
145 ;
146 and esp, 0xfffffff0
147 sub esp, 12
148
149 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
150 push dword [ecx + IA32_TSS._EAX]
151 push dword [ecx + IA32_TSS._ECX]
152 push dword [ecx + IA32_TSS._EDX]
153 push dword [ecx + IA32_TSS._EBX]
154 push dword [ecx + IA32_TSS._ESP]
155 push dword [ecx + IA32_TSS._EBP]
156 push dword [ecx + IA32_TSS._ESI]
157 push dword [ecx + IA32_TSS._EDI]
158
159 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
160 movzx eax, word [ecx + IA32_TSS._SS]
161 push eax
162 movzx eax, word [ecx + IA32_TSS._CS]
163 push eax
164 movzx eax, word [ecx + IA32_TSS._DS]
165 push eax
166 movzx eax, word [ecx + IA32_TSS._ES]
167 push eax
168 movzx eax, word [ecx + IA32_TSS._FS]
169 push eax
170 movzx eax, word [ecx + IA32_TSS._GS]
171 push eax
172
173 ;; UINT32 Eip;
174 push dword [ecx + IA32_TSS.EIP]
175
176 ;; UINT32 Gdtr[2], Idtr[2];
177 sub esp, 8
178 sidt [esp]
179 mov eax, [esp + 2]
180 xchg eax, [esp]
181 and eax, 0xFFFF
182 mov [esp+4], eax
183
184 sub esp, 8
185 sgdt [esp]
186 mov eax, [esp + 2]
187 xchg eax, [esp]
188 and eax, 0xFFFF
189 mov [esp+4], eax
190
191 ;; UINT32 Ldtr, Tr;
192 mov eax, ebx ; ebx still keeps selector of interrupted task
193 push eax
194 movzx eax, word [ecx + IA32_TSS.LDT]
195 push eax
196
197 ;; UINT32 EFlags;
198 push dword [ecx + IA32_TSS.EFLAGS]
199
200 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
201 mov eax, cr4
202 push eax ; push cr4 firstly
203
204 mov edx, [ebp - 4] ; cpuid.edx
205 test edx, BIT24 ; Test for FXSAVE/FXRESTOR support
206 jz .1
207 or eax, BIT9 ; Set CR4.OSFXSR
208 .1:
209 test edx, BIT2 ; Test for Debugging Extensions support
210 jz .2
211 or eax, BIT3 ; Set CR4.DE
212 .2:
213 mov cr4, eax
214
215 mov eax, cr3
216 push eax
217 mov eax, cr2
218 push eax
219 xor eax, eax
220 push eax
221 mov eax, cr0
222 push eax
223
224 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
225 mov eax, dr7
226 push eax
227 mov eax, dr6
228 push eax
229 mov eax, dr3
230 push eax
231 mov eax, dr2
232 push eax
233 mov eax, dr1
234 push eax
235 mov eax, dr0
236 push eax
237
238 ;; FX_SAVE_STATE_IA32 FxSaveState;
239 ;; Clear TS bit in CR0 to avoid Device Not Available Exception (#NM)
240 ;; when executing fxsave/fxrstor instruction
241 test edx, BIT24 ; Test for FXSAVE/FXRESTOR support.
242 ; edx still contains result from CPUID above
243 jz .3
244 clts
245 sub esp, 512
246 mov edi, esp
247 db 0xf, 0xae, 0x7 ;fxsave [edi]
248 .3:
249
250 ;; UINT32 ExceptionData;
251 push dword [ebp + 8]
252
253 ;; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
254 cld
255
256 ;; call into exception handler
257 mov esi, ecx ; Keep TSS base to avoid overwrite
258 mov eax, ASM_PFX(CommonExceptionHandler)
259
260 ;; Prepare parameter and call
261 mov edx, esp
262 push edx ; EFI_SYSTEM_CONTEXT
263 push dword [ebp + 4] ; EFI_EXCEPTION_TYPE (vector number)
264
265 ;
266 ; Call External Exception Handler
267 ;
268 call eax
269 add esp, 8 ; Restore stack before calling
270 mov ecx, esi ; Restore TSS base
271
272 ;; UINT32 ExceptionData;
273 add esp, 4
274
275 ;; FX_SAVE_STATE_IA32 FxSaveState;
276 mov edx, [ebp - 4] ; cpuid.edx
277 test edx, BIT24 ; Test for FXSAVE/FXRESTOR support
278 jz .4
279 mov esi, esp
280 db 0xf, 0xae, 0xe ; fxrstor [esi]
281 .4:
282 add esp, 512
283
284 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
285 ;; Skip restoration of DRx registers to support debuggers
286 ;; that set breakpoints in interrupt/exception context
287 add esp, 4 * 6
288
289 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
290 pop eax
291 mov cr0, eax
292 add esp, 4 ; not for Cr1
293 pop eax
294 mov cr2, eax
295 pop eax
296 mov dword [ecx + IA32_TSS._CR3], eax
297 pop eax
298 mov cr4, eax
299
300 ;; UINT32 EFlags;
301 pop dword [ecx + IA32_TSS.EFLAGS]
302 mov ebx, dword [ecx + IA32_TSS.EFLAGS]
303 btr ebx, 9 ; Do 'cli'
304 mov dword [ecx + IA32_TSS.EFLAGS], ebx
305
306 ;; UINT32 Ldtr, Tr;
307 ;; UINT32 Gdtr[2], Idtr[2];
308 ;; Best not let anyone mess with these particular registers...
309 add esp, 24
310
311 ;; UINT32 Eip;
312 pop dword [ecx + IA32_TSS.EIP]
313
314 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
315 ;; NOTE - modified segment registers could hang the debugger... We
316 ;; could attempt to insulate ourselves against this possibility,
317 ;; but that poses risks as well.
318 ;;
319 pop eax
320 o16 mov [ecx + IA32_TSS._GS], ax
321 pop eax
322 o16 mov [ecx + IA32_TSS._FS], ax
323 pop eax
324 o16 mov [ecx + IA32_TSS._ES], ax
325 pop eax
326 o16 mov [ecx + IA32_TSS._DS], ax
327 pop eax
328 o16 mov [ecx + IA32_TSS._CS], ax
329 pop eax
330 o16 mov [ecx + IA32_TSS._SS], ax
331
332 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
333 pop dword [ecx + IA32_TSS._EDI]
334 pop dword [ecx + IA32_TSS._ESI]
335 add esp, 4 ; not for ebp
336 add esp, 4 ; not for esp
337 pop dword [ecx + IA32_TSS._EBX]
338 pop dword [ecx + IA32_TSS._EDX]
339 pop dword [ecx + IA32_TSS._ECX]
340 pop dword [ecx + IA32_TSS._EAX]
341
342 ; Set single step DB# to allow debugger to able to go back to the EIP
343 ; where the exception is triggered.
344
345 ;; Create return context for iretd in stub function
346 mov eax, dword [ecx + IA32_TSS._ESP] ; Get old stack pointer
347 mov ebx, dword [ecx + IA32_TSS.EIP]
348 mov [eax - 0xc], ebx ; create EIP in old stack
349 movzx ebx, word [ecx + IA32_TSS._CS]
350 mov [eax - 0x8], ebx ; create CS in old stack
351 mov ebx, dword [ecx + IA32_TSS.EFLAGS]
352 bts ebx, 8 ; Set TF
353 mov [eax - 0x4], ebx ; create eflags in old stack
354 sub eax, 0xc ; minus 12 byte
355 mov dword [ecx + IA32_TSS._ESP], eax ; Set new stack pointer
356
357 ;; Replace the EIP of interrupted task with stub function
358 mov eax, ASM_PFX(SingleStepStubFunction)
359 mov dword [ecx + IA32_TSS.EIP], eax
360
361 mov ecx, [ebp - 8] ; Get current TSS base
362 mov eax, dword [ecx + IA32_TSS._ESP] ; Return current stack top
363 mov esp, ebp
364
365 ret
366
367 global ASM_PFX(SingleStepStubFunction)
368 ASM_PFX(SingleStepStubFunction):
369 ;
370 ; we need clean TS bit in CR0 to execute
371 ; x87 FPU/MMX/SSE/SSE2/SSE3/SSSE3/SSE4 instructions.
372 ;
373 clts
374 iretd
375
376 global ASM_PFX(AsmGetTssTemplateMap)
377 ASM_PFX(AsmGetTssTemplateMap):
378 push ebp ; C prolog
379 mov ebp, esp
380 pushad
381
382 mov ebx, dword [ebp + 0x8]
383 mov dword [ebx], ASM_PFX(ExceptionTaskSwtichEntry0)
384 mov dword [ebx + 0x4], (AsmExceptionEntryEnd - AsmExceptionEntryBegin) / 32
385 mov dword [ebx + 0x8], 0
386
387 popad
388 pop ebp
389 ret
390