]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm.nasm
UefiCpuPkg/CpuExceptionHandlerLib: Setup single step in #PF handler
[mirror_edk2.git] / UefiCpuPkg / Library / CpuExceptionHandlerLib / Ia32 / ExceptionHandlerAsm.nasm
1 ;------------------------------------------------------------------------------ ;
2 ; Copyright (c) 2016, 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 ; ExceptionHandlerAsm.Asm
14 ;
15 ; Abstract:
16 ;
17 ; IA32 CPU Exception Handler
18 ;
19 ; Notes:
20 ;
21 ;------------------------------------------------------------------------------
22
23 ;
24 ; CommonExceptionHandler()
25 ;
26 extern ASM_PFX(CommonExceptionHandler)
27
28 SECTION .data
29
30 extern ASM_PFX(mErrorCodeFlag) ; Error code flags for exceptions
31 extern ASM_PFX(mDoFarReturnFlag) ; Do far return flag
32
33 SECTION .text
34
35 ALIGN 8
36
37 ;
38 ; exception handler stub table
39 ;
40 AsmIdtVectorBegin:
41 %rep 32
42 db 0x6a ; push #VectorNum
43 db ($ - AsmIdtVectorBegin) / ((AsmIdtVectorEnd - AsmIdtVectorBegin) / 32) ; VectorNum
44 push eax
45 mov eax, ASM_PFX(CommonInterruptEntry)
46 jmp eax
47 %endrep
48 AsmIdtVectorEnd:
49
50 HookAfterStubBegin:
51 db 0x6a ; push
52 VectorNum:
53 db 0 ; 0 will be fixed
54 push eax
55 mov eax, HookAfterStubHeaderEnd
56 jmp eax
57 HookAfterStubHeaderEnd:
58 pop eax
59 sub esp, 8 ; reserve room for filling exception data later
60 push dword [esp + 8]
61 xchg ecx, [esp] ; get vector number
62 bt [ASM_PFX(mErrorCodeFlag)], ecx
63 jnc .0
64 push dword [esp] ; addition push if exception data needed
65 .0:
66 xchg ecx, [esp] ; restore ecx
67 push eax
68
69 ;----------------------------------------------------------------------------;
70 ; CommonInterruptEntry ;
71 ;----------------------------------------------------------------------------;
72 ; The follow algorithm is used for the common interrupt routine.
73 ; Entry from each interrupt with a push eax and eax=interrupt number
74 ; Stack:
75 ; +---------------------+
76 ; + EFlags +
77 ; +---------------------+
78 ; + CS +
79 ; +---------------------+
80 ; + EIP +
81 ; +---------------------+
82 ; + Error Code +
83 ; +---------------------+
84 ; + Vector Number +
85 ; +---------------------+
86 ; + EBP +
87 ; +---------------------+ <-- EBP
88 global ASM_PFX(CommonInterruptEntry)
89 ASM_PFX(CommonInterruptEntry):
90 cli
91 pop eax
92 ;
93 ; All interrupt handlers are invoked through interrupt gates, so
94 ; IF flag automatically cleared at the entry point
95 ;
96
97 ;
98 ; Get vector number from top of stack
99 ;
100 xchg ecx, [esp]
101 and ecx, 0xFF ; Vector number should be less than 256
102 cmp ecx, 32 ; Intel reserved vector for exceptions?
103 jae NoErrorCode
104 bt [ASM_PFX(mErrorCodeFlag)], ecx
105 jc HasErrorCode
106
107 NoErrorCode:
108
109 ;
110 ; Stack:
111 ; +---------------------+
112 ; + EFlags +
113 ; +---------------------+
114 ; + CS +
115 ; +---------------------+
116 ; + EIP +
117 ; +---------------------+
118 ; + ECX +
119 ; +---------------------+ <-- ESP
120 ;
121 ; Registers:
122 ; ECX - Vector Number
123 ;
124
125 ;
126 ; Put Vector Number on stack
127 ;
128 push ecx
129
130 ;
131 ; Put 0 (dummy) error code on stack, and restore ECX
132 ;
133 xor ecx, ecx ; ECX = 0
134 xchg ecx, [esp+4]
135
136 jmp ErrorCodeAndVectorOnStack
137
138 HasErrorCode:
139
140 ;
141 ; Stack:
142 ; +---------------------+
143 ; + EFlags +
144 ; +---------------------+
145 ; + CS +
146 ; +---------------------+
147 ; + EIP +
148 ; +---------------------+
149 ; + Error Code +
150 ; +---------------------+
151 ; + ECX +
152 ; +---------------------+ <-- ESP
153 ;
154 ; Registers:
155 ; ECX - Vector Number
156 ;
157
158 ;
159 ; Put Vector Number on stack and restore ECX
160 ;
161 xchg ecx, [esp]
162
163 ErrorCodeAndVectorOnStack:
164 push ebp
165 mov ebp, esp
166
167 ;
168 ; Stack:
169 ; +---------------------+
170 ; + EFlags +
171 ; +---------------------+
172 ; + CS +
173 ; +---------------------+
174 ; + EIP +
175 ; +---------------------+
176 ; + Error Code +
177 ; +---------------------+
178 ; + Vector Number +
179 ; +---------------------+
180 ; + EBP +
181 ; +---------------------+ <-- EBP
182 ;
183
184 ;
185 ; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
186 ; is 16-byte aligned
187 ;
188 and esp, 0xfffffff0
189 sub esp, 12
190
191 sub esp, 8
192 push 0 ; clear EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
193 push 0 ; clear EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
194
195 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
196 push eax
197 push ecx
198 push edx
199 push ebx
200 lea ecx, [ebp + 6 * 4]
201 push ecx ; ESP
202 push dword [ebp] ; EBP
203 push esi
204 push edi
205
206 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
207 mov eax, ss
208 push eax
209 movzx eax, word [ebp + 4 * 4]
210 push eax
211 mov eax, ds
212 push eax
213 mov eax, es
214 push eax
215 mov eax, fs
216 push eax
217 mov eax, gs
218 push eax
219
220 ;; UINT32 Eip;
221 mov eax, [ebp + 3 * 4]
222 push eax
223
224 ;; UINT32 Gdtr[2], Idtr[2];
225 sub esp, 8
226 sidt [esp]
227 mov eax, [esp + 2]
228 xchg eax, [esp]
229 and eax, 0xFFFF
230 mov [esp+4], eax
231
232 sub esp, 8
233 sgdt [esp]
234 mov eax, [esp + 2]
235 xchg eax, [esp]
236 and eax, 0xFFFF
237 mov [esp+4], eax
238
239 ;; UINT32 Ldtr, Tr;
240 xor eax, eax
241 str ax
242 push eax
243 sldt ax
244 push eax
245
246 ;; UINT32 EFlags;
247 mov eax, [ebp + 5 * 4]
248 push eax
249
250 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
251 mov eax, 1
252 push ebx ; temporarily save value of ebx on stack
253 cpuid ; use CPUID to determine if FXSAVE/FXRESTOR and DE
254 ; are supported
255 pop ebx ; retore value of ebx that was overwritten by CPUID
256 mov eax, cr4
257 push eax ; push cr4 firstly
258 test edx, BIT24 ; Test for FXSAVE/FXRESTOR support
259 jz .1
260 or eax, BIT9 ; Set CR4.OSFXSR
261 .1:
262 test edx, BIT2 ; Test for Debugging Extensions support
263 jz .2
264 or eax, BIT3 ; Set CR4.DE
265 .2:
266 mov cr4, eax
267 mov eax, cr3
268 push eax
269 mov eax, cr2
270 push eax
271 xor eax, eax
272 push eax
273 mov eax, cr0
274 push eax
275
276 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
277 mov eax, dr7
278 push eax
279 mov eax, dr6
280 push eax
281 mov eax, dr3
282 push eax
283 mov eax, dr2
284 push eax
285 mov eax, dr1
286 push eax
287 mov eax, dr0
288 push eax
289
290 ;; FX_SAVE_STATE_IA32 FxSaveState;
291 sub esp, 512
292 mov edi, esp
293 test edx, BIT24 ; Test for FXSAVE/FXRESTOR support.
294 ; edx still contains result from CPUID above
295 jz .3
296 db 0xf, 0xae, 0x7 ;fxsave [edi]
297 .3:
298
299 ;; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
300 cld
301
302 ;; UINT32 ExceptionData;
303 push dword [ebp + 2 * 4]
304
305 ;; Prepare parameter and call
306 mov edx, esp
307 push edx
308 mov edx, dword [ebp + 1 * 4]
309 push edx
310
311 ;
312 ; Call External Exception Handler
313 ;
314 mov eax, ASM_PFX(CommonExceptionHandler)
315 call eax
316 add esp, 8
317
318 cli
319 ;; UINT32 ExceptionData;
320 add esp, 4
321
322 ;; FX_SAVE_STATE_IA32 FxSaveState;
323 mov esi, esp
324 mov eax, 1
325 cpuid ; use CPUID to determine if FXSAVE/FXRESTOR
326 ; are supported
327 test edx, BIT24 ; Test for FXSAVE/FXRESTOR support
328 jz .4
329 db 0xf, 0xae, 0xe ; fxrstor [esi]
330 .4:
331 add esp, 512
332
333 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
334 ;; Skip restoration of DRx registers to support in-circuit emualators
335 ;; or debuggers set breakpoint in interrupt/exception context
336 add esp, 4 * 6
337
338 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
339 pop eax
340 mov cr0, eax
341 add esp, 4 ; not for Cr1
342 pop eax
343 mov cr2, eax
344 pop eax
345 mov cr3, eax
346 pop eax
347 mov cr4, eax
348
349 ;; UINT32 EFlags;
350 pop dword [ebp + 5 * 4]
351
352 ;; UINT32 Ldtr, Tr;
353 ;; UINT32 Gdtr[2], Idtr[2];
354 ;; Best not let anyone mess with these particular registers...
355 add esp, 24
356
357 ;; UINT32 Eip;
358 pop dword [ebp + 3 * 4]
359
360 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
361 ;; NOTE - modified segment registers could hang the debugger... We
362 ;; could attempt to insulate ourselves against this possibility,
363 ;; but that poses risks as well.
364 ;;
365 pop gs
366 pop fs
367 pop es
368 pop ds
369 pop dword [ebp + 4 * 4]
370 pop ss
371
372 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
373 pop edi
374 pop esi
375 add esp, 4 ; not for ebp
376 add esp, 4 ; not for esp
377 pop ebx
378 pop edx
379 pop ecx
380 pop eax
381
382 pop dword [ebp - 8]
383 pop dword [ebp - 4]
384 mov esp, ebp
385 pop ebp
386
387 ; Enable TF bit after page fault handler runs
388 cmp dword [esp], 14 ; #PF?
389 jne .5
390 bts dword [esp + 16], 8 ; EFLAGS
391
392 .5:
393 add esp, 8
394 cmp dword [esp - 16], 0 ; check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
395 jz DoReturn
396 cmp dword [esp - 20], 1 ; check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
397 jz ErrorCode
398 jmp dword [esp - 16]
399 ErrorCode:
400 sub esp, 4
401 jmp dword [esp - 12]
402
403 DoReturn:
404 cmp dword [ASM_PFX(mDoFarReturnFlag)], 0 ; Check if need to do far return instead of IRET
405 jz DoIret
406 push dword [esp + 8] ; save EFLAGS
407 add esp, 16
408 push dword [esp - 8] ; save CS in new location
409 push dword [esp - 8] ; save EIP in new location
410 push dword [esp - 8] ; save EFLAGS in new location
411 popfd ; restore EFLAGS
412 retf ; far return
413
414 DoIret:
415 iretd
416
417 ;---------------------------------------;
418 ; _AsmGetTemplateAddressMap ;
419 ;----------------------------------------------------------------------------;
420 ;
421 ; Protocol prototype
422 ; AsmGetTemplateAddressMap (
423 ; EXCEPTION_HANDLER_TEMPLATE_MAP *AddressMap
424 ; );
425 ;
426 ; Routine Description:
427 ;
428 ; Return address map of interrupt handler template so that C code can generate
429 ; interrupt table.
430 ;
431 ; Arguments:
432 ;
433 ;
434 ; Returns:
435 ;
436 ; Nothing
437 ;
438 ;
439 ; Input: [ebp][0] = Original ebp
440 ; [ebp][4] = Return address
441 ;
442 ; Output: Nothing
443 ;
444 ; Destroys: Nothing
445 ;-----------------------------------------------------------------------------;
446 global ASM_PFX(AsmGetTemplateAddressMap)
447 ASM_PFX(AsmGetTemplateAddressMap):
448 push ebp ; C prolog
449 mov ebp, esp
450 pushad
451
452 mov ebx, dword [ebp + 0x8]
453 mov dword [ebx], AsmIdtVectorBegin
454 mov dword [ebx + 0x4], (AsmIdtVectorEnd - AsmIdtVectorBegin) / 32
455 mov dword [ebx + 0x8], HookAfterStubBegin
456
457 popad
458 pop ebp
459 ret
460
461 ;-------------------------------------------------------------------------------------
462 ; AsmVectorNumFixup (*NewVectorAddr, VectorNum, *OldVectorAddr);
463 ;-------------------------------------------------------------------------------------
464 global ASM_PFX(AsmVectorNumFixup)
465 ASM_PFX(AsmVectorNumFixup):
466 mov eax, dword [esp + 8]
467 mov ecx, [esp + 4]
468 mov [ecx + (VectorNum - HookAfterStubBegin)], al
469 ret