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