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