]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm.nasm
45d647409172717fdec1e275addf4fbe7e5f68ce
[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 add esp, 8
387 cmp dword [esp - 16], 0 ; check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
388 jz DoReturn
389 cmp dword [esp - 20], 1 ; check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
390 jz ErrorCode
391 jmp dword [esp - 16]
392 ErrorCode:
393 sub esp, 4
394 jmp dword [esp - 12]
395
396 DoReturn:
397 cmp dword [ASM_PFX(mDoFarReturnFlag)], 0 ; Check if need to do far return instead of IRET
398 jz DoIret
399 push dword [esp + 8] ; save EFLAGS
400 add esp, 16
401 push dword [esp - 8] ; save CS in new location
402 push dword [esp - 8] ; save EIP in new location
403 push dword [esp - 8] ; save EFLAGS in new location
404 popfd ; restore EFLAGS
405 retf ; far return
406
407 DoIret:
408 iretd
409
410 ;---------------------------------------;
411 ; _AsmGetTemplateAddressMap ;
412 ;----------------------------------------------------------------------------;
413 ;
414 ; Protocol prototype
415 ; AsmGetTemplateAddressMap (
416 ; EXCEPTION_HANDLER_TEMPLATE_MAP *AddressMap
417 ; );
418 ;
419 ; Routine Description:
420 ;
421 ; Return address map of interrupt handler template so that C code can generate
422 ; interrupt table.
423 ;
424 ; Arguments:
425 ;
426 ;
427 ; Returns:
428 ;
429 ; Nothing
430 ;
431 ;
432 ; Input: [ebp][0] = Original ebp
433 ; [ebp][4] = Return address
434 ;
435 ; Output: Nothing
436 ;
437 ; Destroys: Nothing
438 ;-----------------------------------------------------------------------------;
439 global ASM_PFX(AsmGetTemplateAddressMap)
440 ASM_PFX(AsmGetTemplateAddressMap):
441 push ebp ; C prolog
442 mov ebp, esp
443 pushad
444
445 mov ebx, dword [ebp + 0x8]
446 mov dword [ebx], AsmIdtVectorBegin
447 mov dword [ebx + 0x4], (AsmIdtVectorEnd - AsmIdtVectorBegin) / 32
448 mov dword [ebx + 0x8], HookAfterStubBegin
449
450 popad
451 pop ebp
452 ret
453
454 ;-------------------------------------------------------------------------------------
455 ; AsmVectorNumFixup (*NewVectorAddr, VectorNum, *OldVectorAddr);
456 ;-------------------------------------------------------------------------------------
457 global ASM_PFX(AsmVectorNumFixup)
458 ASM_PFX(AsmVectorNumFixup):
459 mov eax, dword [esp + 8]
460 mov ecx, [esp + 4]
461 mov [ecx + (VectorNum - HookAfterStubBegin)], al
462 ret