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