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