]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm.S
UefiCpuPkg/CpuExceptionHandlerLib: Add stack switch support
[mirror_edk2.git] / UefiCpuPkg / Library / CpuExceptionHandlerLib / Ia32 / ExceptionHandlerAsm.S
1 #------------------------------------------------------------------------------
2 #*
3 #* Copyright (c) 2012 - 2015, Intel Corporation. All rights reserved.<BR>
4 #* This program and the accompanying materials
5 #* are licensed and made available under the terms and conditions of the BSD License
6 #* which accompanies this distribution. The full text of the license may be found at
7 #* http://opensource.org/licenses/bsd-license.php
8 #*
9 #* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 #* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11 #*
12 #* ExceptionHandlerAsm.S
13 #*
14 #* Abstract:
15 #*
16 #* IA32 CPU Exception Handler
17 #
18 #------------------------------------------------------------------------------
19
20
21 #.MMX
22 #.XMM
23
24 ASM_GLOBAL ASM_PFX(CommonExceptionHandler)
25 ASM_GLOBAL ASM_PFX(CommonInterruptEntry)
26 ASM_GLOBAL ASM_PFX(HookAfterStubHeaderEnd)
27
28 #EXTRN ASM_PFX(mErrorCodeFlag):DWORD # Error code flags for exceptions
29 #EXTRN ASM_PFX(mDoFarReturnFlag):DWORD # Do far return flag
30
31 .text
32
33 #
34 # exception handler stub table
35 #
36 Exception0Handle:
37 .byte 0x6a # push #VectorNum
38 .byte 0
39 pushl %eax
40 .byte 0xB8
41 .long ASM_PFX(CommonInterruptEntry)
42 jmp *%eax
43 Exception1Handle:
44 .byte 0x6a # push #VectorNum
45 .byte 1
46 pushl %eax
47 .byte 0xB8
48 .long ASM_PFX(CommonInterruptEntry)
49 jmp *%eax
50 Exception2Handle:
51 .byte 0x6a # push #VectorNum
52 .byte 2
53 pushl %eax
54 .byte 0xB8
55 .long ASM_PFX(CommonInterruptEntry)
56 jmp *%eax
57 Exception3Handle:
58 .byte 0x6a # push #VectorNum
59 .byte 3
60 pushl %eax
61 .byte 0xB8
62 .long ASM_PFX(CommonInterruptEntry)
63 jmp *%eax
64 Exception4Handle:
65 .byte 0x6a # push #VectorNum
66 .byte 4
67 pushl %eax
68 .byte 0xB8
69 .long ASM_PFX(CommonInterruptEntry)
70 jmp *%eax
71 Exception5Handle:
72 .byte 0x6a # push #VectorNum
73 .byte 5
74 pushl %eax
75 .byte 0xB8
76 .long ASM_PFX(CommonInterruptEntry)
77 jmp *%eax
78 Exception6Handle:
79 .byte 0x6a # push #VectorNum
80 .byte 6
81 pushl %eax
82 .byte 0xB8
83 .long ASM_PFX(CommonInterruptEntry)
84 jmp *%eax
85 Exception7Handle:
86 .byte 0x6a # push #VectorNum
87 .byte 7
88 pushl %eax
89 .byte 0xB8
90 .long ASM_PFX(CommonInterruptEntry)
91 jmp *%eax
92 Exception8Handle:
93 .byte 0x6a # push #VectorNum
94 .byte 8
95 pushl %eax
96 .byte 0xB8
97 .long ASM_PFX(CommonInterruptEntry)
98 jmp *%eax
99 Exception9Handle:
100 .byte 0x6a # push #VectorNum
101 .byte 9
102 pushl %eax
103 .byte 0xB8
104 .long ASM_PFX(CommonInterruptEntry)
105 jmp *%eax
106 Exception10Handle:
107 .byte 0x6a # push #VectorNum
108 .byte 10
109 pushl %eax
110 .byte 0xB8
111 .long ASM_PFX(CommonInterruptEntry)
112 jmp *%eax
113 Exception11Handle:
114 .byte 0x6a # push #VectorNum
115 .byte 11
116 pushl %eax
117 .byte 0xB8
118 .long ASM_PFX(CommonInterruptEntry)
119 jmp *%eax
120 Exception12Handle:
121 .byte 0x6a # push #VectorNum
122 .byte 12
123 pushl %eax
124 .byte 0xB8
125 .long ASM_PFX(CommonInterruptEntry)
126 jmp *%eax
127 Exception13Handle:
128 .byte 0x6a # push #VectorNum
129 .byte 13
130 pushl %eax
131 .byte 0xB8
132 .long ASM_PFX(CommonInterruptEntry)
133 jmp *%eax
134 Exception14Handle:
135 .byte 0x6a # push #VectorNum
136 .byte 14
137 pushl %eax
138 .byte 0xB8
139 .long ASM_PFX(CommonInterruptEntry)
140 jmp *%eax
141 Exception15Handle:
142 .byte 0x6a # push #VectorNum
143 .byte 15
144 pushl %eax
145 .byte 0xB8
146 .long ASM_PFX(CommonInterruptEntry)
147 jmp *%eax
148 Exception16Handle:
149 .byte 0x6a # push #VectorNum
150 .byte 16
151 pushl %eax
152 .byte 0xB8
153 .long ASM_PFX(CommonInterruptEntry)
154 jmp *%eax
155 Exception17Handle:
156 .byte 0x6a # push #VectorNum
157 .byte 17
158 pushl %eax
159 .byte 0xB8
160 .long ASM_PFX(CommonInterruptEntry)
161 jmp *%eax
162 Exception18Handle:
163 .byte 0x6a # push #VectorNum
164 .byte 18
165 pushl %eax
166 .byte 0xB8
167 .long ASM_PFX(CommonInterruptEntry)
168 jmp *%eax
169 Exception19Handle:
170 .byte 0x6a # push #VectorNum
171 .byte 19
172 pushl %eax
173 .byte 0xB8
174 .long ASM_PFX(CommonInterruptEntry)
175 jmp *%eax
176 Exception20Handle:
177 .byte 0x6a # push #VectorNum
178 .byte 20
179 pushl %eax
180 .byte 0xB8
181 .long ASM_PFX(CommonInterruptEntry)
182 jmp *%eax
183 Exception21Handle:
184 .byte 0x6a # push #VectorNum
185 .byte 21
186 pushl %eax
187 .byte 0xB8
188 .long ASM_PFX(CommonInterruptEntry)
189 jmp *%eax
190 Exception22Handle:
191 .byte 0x6a # push #VectorNum
192 .byte 22
193 pushl %eax
194 .byte 0xB8
195 .long ASM_PFX(CommonInterruptEntry)
196 jmp *%eax
197 Exception23Handle:
198 .byte 0x6a # push #VectorNum
199 .byte 23
200 pushl %eax
201 .byte 0xB8
202 .long ASM_PFX(CommonInterruptEntry)
203 jmp *%eax
204 Exception24Handle:
205 .byte 0x6a # push #VectorNum
206 .byte 24
207 pushl %eax
208 .byte 0xB8
209 .long ASM_PFX(CommonInterruptEntry)
210 jmp *%eax
211 Exception25Handle:
212 .byte 0x6a # push #VectorNum
213 .byte 25
214 pushl %eax
215 .byte 0xB8
216 .long ASM_PFX(CommonInterruptEntry)
217 jmp *%eax
218 Exception26Handle:
219 .byte 0x6a # push #VectorNum
220 .byte 26
221 pushl %eax
222 .byte 0xB8
223 .long ASM_PFX(CommonInterruptEntry)
224 jmp *%eax
225 Exception27Handle:
226 .byte 0x6a # push #VectorNum
227 .byte 27
228 pushl %eax
229 .byte 0xB8
230 .long ASM_PFX(CommonInterruptEntry)
231 jmp *%eax
232 Exception28Handle:
233 .byte 0x6a # push #VectorNum
234 .byte 28
235 pushl %eax
236 .byte 0xB8
237 .long ASM_PFX(CommonInterruptEntry)
238 jmp *%eax
239 Exception29Handle:
240 .byte 0x6a # push #VectorNum
241 .byte 29
242 pushl %eax
243 .byte 0xB8
244 .long ASM_PFX(CommonInterruptEntry)
245 jmp *%eax
246 Exception30Handle:
247 .byte 0x6a # push #VectorNum
248 .byte 30
249 pushl %eax
250 .byte 0xB8
251 .long ASM_PFX(CommonInterruptEntry)
252 jmp *%eax
253 Exception31Handle:
254 .byte 0x6a # push #VectorNum
255 .byte 31
256 pushl %eax
257 .byte 0xB8
258 .long ASM_PFX(CommonInterruptEntry)
259 jmp *%eax
260
261 HookAfterStubBegin:
262 .byte 0x6a # push
263 VectorNum:
264 .byte 0 # 0 will be fixed
265 pushl %eax
266 .byte 0xB8 # movl ASM_PFX(HookAfterStubHeaderEnd), %eax
267 .long ASM_PFX(HookAfterStubHeaderEnd)
268 jmp *%eax
269 ASM_GLOBAL ASM_PFX(HookAfterStubHeaderEnd)
270 ASM_PFX(HookAfterStubHeaderEnd):
271 popl %eax
272 subl $8, %esp # reserve room for filling exception data later
273 pushl 8(%esp)
274 xchgl (%esp), %ecx # get vector number
275 bt %ecx, ASM_PFX(mErrorCodeFlag)
276 jnc NoErrorData
277 pushl (%esp) # addition push if exception data needed
278 NoErrorData:
279 xchg (%esp), %ecx # restore ecx
280 pushl %eax
281
282 #---------------------------------------;
283 # CommonInterruptEntry ;
284 #---------------------------------------;
285 # The follow algorithm is used for the common interrupt routine.
286
287 ASM_GLOBAL ASM_PFX(CommonInterruptEntry)
288 ASM_PFX(CommonInterruptEntry):
289 cli
290 popl %eax
291 #
292 # All interrupt handlers are invoked through interrupt gates, so
293 # IF flag automatically cleared at the entry point
294 #
295
296 #
297 # Get vector number from top of stack
298 #
299 xchgl (%esp), %ecx
300 andl $0x0FF, %ecx # Vector number should be less than 256
301 cmpl $32, %ecx # Intel reserved vector for exceptions?
302 jae NoErrorCode
303 bt %ecx, ASM_PFX(mErrorCodeFlag)
304 jc HasErrorCode
305
306 NoErrorCode:
307
308 #
309 # Stack:
310 # +---------------------+
311 # + EFlags +
312 # +---------------------+
313 # + CS +
314 # +---------------------+
315 # + EIP +
316 # +---------------------+
317 # + ECX +
318 # +---------------------+ <-- ESP
319 #
320 # Registers:
321 # ECX - Vector Number
322 #
323
324 #
325 # Put Vector Number on stack
326 #
327 pushl %ecx
328
329 #
330 # Put 0 (dummy) error code on stack, and restore ECX
331 #
332 xorl %ecx, %ecx # ECX = 0
333 xchgl 4(%esp), %ecx
334
335 jmp ErrorCodeAndVectorOnStack
336
337 HasErrorCode:
338
339 #
340 # Stack:
341 # +---------------------+
342 # + EFlags +
343 # +---------------------+
344 # + CS +
345 # +---------------------+
346 # + EIP +
347 # +---------------------+
348 # + Error Code +
349 # +---------------------+
350 # + ECX +
351 # +---------------------+ <-- ESP
352 #
353 # Registers:
354 # ECX - Vector Number
355 #
356
357 #
358 # Put Vector Number on stack and restore ECX
359 #
360 xchgl (%esp), %ecx
361
362 ErrorCodeAndVectorOnStack:
363 pushl %ebp
364 movl %esp, %ebp
365
366 #
367 # Stack:
368 # +---------------------+
369 # + EFlags +
370 # +---------------------+
371 # + CS +
372 # +---------------------+
373 # + EIP +
374 # +---------------------+
375 # + Error Code +
376 # +---------------------+
377 # + Vector Number +
378 # +---------------------+
379 # + EBP +
380 # +---------------------+ <-- EBP
381 #
382
383 #
384 # Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
385 # is 16-byte aligned
386 #
387 andl $0x0fffffff0, %esp
388 subl $12, %esp
389
390 subl $8, %esp
391 pushl $0 # check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
392 pushl $0 # check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
393
394 #; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
395 pushl %eax
396 pushl %ecx
397 pushl %edx
398 pushl %ebx
399 leal 24(%ebp), %ecx
400 pushl %ecx # ESP
401 pushl (%ebp) # EBP
402 pushl %esi
403 pushl %edi
404
405 #; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
406 movl %ss, %eax
407 pushl %eax
408 movzwl 16(%ebp), %eax
409 pushl %eax
410 movl %ds, %eax
411 pushl %eax
412 movl %es, %eax
413 pushl %eax
414 movl %fs, %eax
415 pushl %eax
416 movl %gs, %eax
417 pushl %eax
418
419 #; UINT32 Eip;
420 movl 12(%ebp), %eax
421 pushl %eax
422
423 #; UINT32 Gdtr[2], Idtr[2];
424 subl $8, %esp
425 sidt (%esp)
426 movl 2(%esp), %eax
427 xchgl (%esp), %eax
428 andl $0x0FFFF, %eax
429 movl %eax, 4(%esp)
430
431 subl $8, %esp
432 sgdt (%esp)
433 movl 2(%esp), %eax
434 xchgl (%esp), %eax
435 andl $0x0FFFF, %eax
436 movl %eax, 4(%esp)
437
438 #; UINT32 Ldtr, Tr;
439 xorl %eax, %eax
440 str %ax
441 pushl %eax
442 sldt %ax
443 pushl %eax
444
445 #; UINT32 EFlags;
446 movl 20(%ebp), %eax
447 pushl %eax
448
449 #; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
450 ## insure FXSAVE/FXRSTOR is enabled in CR4...
451 ## ... while we're at it, make sure DE is also enabled...
452 mov $1, %eax
453 pushl %ebx # temporarily save value of ebx on stack
454 cpuid # use CPUID to determine if FXSAVE/FXRESTOR
455 # and DE are supported
456 popl %ebx # retore value of ebx that was overwritten
457 # by CPUID
458 movl %cr4, %eax
459 pushl %eax # push cr4 firstly
460 testl $BIT24, %edx # Test for FXSAVE/FXRESTOR support
461 jz L1
462 orl $BIT9, %eax # Set CR4.OSFXSR
463 L1:
464 testl $BIT2, %edx # Test for Debugging Extensions support
465 jz L2
466 orl $BIT3, %eax # Set CR4.DE
467 L2:
468 movl %eax, %cr4
469 movl %cr3, %eax
470 pushl %eax
471 movl %cr2, %eax
472 pushl %eax
473 xorl %eax, %eax
474 pushl %eax
475 movl %cr0, %eax
476 pushl %eax
477
478 #; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
479 movl %dr7, %eax
480 pushl %eax
481 movl %dr6, %eax
482 pushl %eax
483 movl %dr3, %eax
484 pushl %eax
485 movl %dr2, %eax
486 pushl %eax
487 movl %dr1, %eax
488 pushl %eax
489 movl %dr0, %eax
490 pushl %eax
491
492 #; FX_SAVE_STATE_IA32 FxSaveState;
493 subl $512, %esp
494 movl %esp, %edi
495 testl $BIT24, %edx # Test for FXSAVE/FXRESTOR support.
496 # edx still contains result from CPUID above
497 jz L3
498 .byte 0x0f, 0x0ae, 0x07 #fxsave [edi]
499 L3:
500
501 #; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
502 cld
503
504 #; UINT32 ExceptionData;
505 pushl 8(%ebp)
506
507 #; Prepare parameter and call
508 movl %esp, %edx
509 pushl %edx
510 movl 4(%ebp), %edx
511 pushl %edx
512
513 #
514 # Call External Exception Handler
515 #
516 call ASM_PFX(CommonExceptionHandler)
517 addl $8, %esp
518
519 cli
520 #; UINT32 ExceptionData;
521 addl $4, %esp
522
523 #; FX_SAVE_STATE_IA32 FxSaveState;
524 movl %esp, %esi
525 movl $1, %eax
526 cpuid # use CPUID to determine if FXSAVE/FXRESTOR
527 # are supported
528 testl $BIT24, %edx # Test for FXSAVE/FXRESTOR support
529 jz L4
530 .byte 0x0f, 0x0ae, 0x0e # fxrstor [esi]
531 L4:
532 addl $512, %esp
533
534 #; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
535 #; Skip restoration of DRx registers to support in-circuit emualators
536 #; or debuggers set breakpoint in interrupt/exception context
537 addl $24, %esp
538
539 #; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
540 popl %eax
541 movl %eax, %cr0
542 addl $4, %esp # not for Cr1
543 popl %eax
544 movl %eax, %cr2
545 popl %eax
546 movl %eax, %cr3
547 popl %eax
548 movl %eax, %cr4
549
550 #; UINT32 EFlags;
551 popl 20(%ebp)
552
553 #; UINT32 Ldtr, Tr;
554 #; UINT32 Gdtr[2], Idtr[2];
555 #; Best not let anyone mess with these particular registers...
556 addl $24, %esp
557
558 #; UINT32 Eip;
559 popl 12(%ebp)
560
561 #; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
562 #; NOTE - modified segment registers could hang the debugger... We
563 #; could attempt to insulate ourselves against this possibility,
564 #; but that poses risks as well.
565 #;
566 popl %gs
567 popl %fs
568 popl %es
569 popl %ds
570 popl 16(%ebp)
571 popl %ss
572
573 #; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
574 popl %edi
575 popl %esi
576 addl $4, %esp # not for ebp
577 addl $4, %esp # not for esp
578 popl %ebx
579 popl %edx
580 popl %ecx
581 popl %eax
582
583 popl -8(%ebp)
584 popl -4(%ebp)
585 movl %ebp, %esp
586 popl %ebp
587 addl $8, %esp
588 cmpl $0, -16(%esp) # check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
589 jz DoReturn
590 cmpl $1, -20(%esp) # check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
591 jz ErrorCode
592 jmp *-16(%esp)
593 ErrorCode:
594 subl $4, %esp
595 jmp *-12(%esp)
596
597 DoReturn:
598 cmpl $0, ASM_PFX(mDoFarReturnFlag)
599 jz DoIret
600 pushl 8(%esp) # save EFLAGS
601 addl $16, %esp
602 pushl -8(%esp) # save CS in new location
603 pushl -8(%esp) # save EIP in new location
604 pushl -8(%esp) # save EFLAGS in new location
605 popfl # restore EFLAGS
606 lret # far return
607
608 DoIret:
609 iretl
610
611
612 #---------------------------------------;
613 # _AsmGetTemplateAddressMap ;
614 #---------------------------------------;
615 #
616 # Protocol prototype
617 # AsmGetTemplateAddressMap (
618 # EXCEPTION_HANDLER_TEMPLATE_MAP *AddressMap
619 # );
620 #
621 # Routine Description:
622 #
623 # Return address map of interrupt handler template so that C code can generate
624 # interrupt table.
625 #
626 # Arguments:
627 #
628 #
629 # Returns:
630 #
631 # Nothing
632 #
633 #
634 # Input: [ebp][0] = Original ebp
635 # [ebp][4] = Return address
636 #
637 # Output: Nothing
638 #
639 # Destroys: Nothing
640 #-----------------------------------------------------------------------------;
641 #-------------------------------------------------------------------------------------
642 # AsmGetAddressMap (&AddressMap);
643 #-------------------------------------------------------------------------------------
644 ASM_GLOBAL ASM_PFX(AsmGetTemplateAddressMap)
645 ASM_PFX(AsmGetTemplateAddressMap):
646
647 pushl %ebp
648 movl %esp,%ebp
649 pushal
650
651 movl 0x8(%ebp), %ebx
652 movl $Exception0Handle, (%ebx)
653 movl $(Exception1Handle - Exception0Handle), 0x4(%ebx)
654 movl $(HookAfterStubBegin), 0x8(%ebx)
655
656 popal
657 popl %ebp
658 ret
659 #-------------------------------------------------------------------------------------
660 # AsmVectorNumFixup (*NewVectorAddr, VectorNum, *OldVectorAddr);
661 #-------------------------------------------------------------------------------------
662 ASM_GLOBAL ASM_PFX(AsmVectorNumFixup)
663 ASM_PFX(AsmVectorNumFixup):
664 movl 8(%esp), %eax
665 movl 4(%esp), %ecx
666 movb %al, (VectorNum - HookAfterStubBegin)(%ecx)
667 ret