1 #------------------------------------------------------------------------------
3 # Copyright (c) 2009 - 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.
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.
18 # Exception handlers used in SM mode
20 #------------------------------------------------------------------------------
22 ASM_GLOBAL ASM_PFX(SmiPFHandler)
23 ASM_GLOBAL ASM_PFX(PageFaultStubFunction)
24 ASM_GLOBAL ASM_PFX(gSmiMtrrs)
25 ASM_GLOBAL ASM_PFX(gcSmiIdtr)
26 ASM_GLOBAL ASM_PFX(gcSmiGdtr)
27 ASM_GLOBAL ASM_PFX(gcPsd)
28 ASM_GLOBAL ASM_PFX(FeaturePcdGet (PcdCpuSmmProfileEnable))
32 NullSeg: .quad 0 # reserved by architecture
38 .byte 0xcf # LimitHigh
45 .byte 0xcf # LimitHigh
52 .byte 0xcf # LimitHigh
59 .byte 0xcf # LimitHigh
80 .byte 0xaf # LimitHigh
82 .equ GDT_SIZE, .- NullSeg
85 .word TSS_DESC_SIZE -1 # LimitLow
89 .byte 0x00 # LimitHigh
92 .word TSS_DESC_SIZE - 1 # LimitLow
96 .byte 0x00 # LimitHigh
99 .equ CODE_SEL, CodeSeg32 - NullSeg
100 .equ DATA_SEL, DataSeg32 - NullSeg
101 .equ TSS_SEL, TssSeg - NullSeg
102 .equ EXCEPTION_TSS_SEL, ExceptionTssSeg - NullSeg
130 # Create 2 TSS segments just after GDT
132 .word 0 # PreviousTaskLink
166 .word 0 # LDT Selector
169 .word 0 # I/O Map Base
170 .equ TSS_DESC_SIZE, . - TssDescriptor
172 ExceptionTssDescriptor:
173 .word 0 # PreviousTaskLink
185 .long PFHandlerEntry # EIP
186 .long 00000002 # EFLAGS
207 .word 0 # LDT Selector
210 .word 0 # I/O Map Base
232 .long ASM_PFX(gSmiMtrrs)
234 .equ PSD_SIZE, . - ASM_PFX(gcPsd)
236 ASM_PFX(gcSmiGdtr): .word GDT_SIZE - 1
239 ASM_PFX(gcSmiIdtr): .word IDT_SIZE - 1
243 # The following segment repeats 32 times:
245 .word 0 # Offset 0:15
248 .byte 0x8e # Interrupt Gate, Present
249 .word 0 # Offset 16:31
251 .word 0 # Offset 0:15
254 .byte 0x8e # Interrupt Gate, Present
255 .word 0 # Offset 16:31
257 .word 0 # Offset 0:15
260 .byte 0x8e # Interrupt Gate, Present
261 .word 0 # Offset 16:31
263 .word 0 # Offset 0:15
266 .byte 0x8e # Interrupt Gate, Present
267 .word 0 # Offset 16:31
269 .word 0 # Offset 0:15
272 .byte 0x8e # Interrupt Gate, Present
273 .word 0 # Offset 16:31
275 .word 0 # Offset 0:15
278 .byte 0x8e # Interrupt Gate, Present
279 .word 0 # Offset 16:31
281 .word 0 # Offset 0:15
284 .byte 0x8e # Interrupt Gate, Present
285 .word 0 # Offset 16:31
287 .word 0 # Offset 0:15
290 .byte 0x8e # Interrupt Gate, Present
291 .word 0 # Offset 16:31
293 .word 0 # Offset 0:15
296 .byte 0x8e # Interrupt Gate, Present
297 .word 0 # Offset 16:31
299 .word 0 # Offset 0:15
302 .byte 0x8e # Interrupt Gate, Present
303 .word 0 # Offset 16:31
305 .word 0 # Offset 0:15
308 .byte 0x8e # Interrupt Gate, Present
309 .word 0 # Offset 16:31
311 .word 0 # Offset 0:15
314 .byte 0x8e # Interrupt Gate, Present
315 .word 0 # Offset 16:31
317 .word 0 # Offset 0:15
320 .byte 0x8e # Interrupt Gate, Present
321 .word 0 # Offset 16:31
323 .word 0 # Offset 0:15
326 .byte 0x8e # Interrupt Gate, Present
327 .word 0 # Offset 16:31
329 .word 0 # Offset 0:15
332 .byte 0x8e # Interrupt Gate, Present
333 .word 0 # Offset 16:31
335 .word 0 # Offset 0:15
338 .byte 0x8e # Interrupt Gate, Present
339 .word 0 # Offset 16:31
341 .word 0 # Offset 0:15
344 .byte 0x8e # Interrupt Gate, Present
345 .word 0 # Offset 16:31
347 .word 0 # Offset 0:15
350 .byte 0x8e # Interrupt Gate, Present
351 .word 0 # Offset 16:31
353 .word 0 # Offset 0:15
356 .byte 0x8e # Interrupt Gate, Present
357 .word 0 # Offset 16:31
359 .word 0 # Offset 0:15
362 .byte 0x8e # Interrupt Gate, Present
363 .word 0 # Offset 16:31
365 .word 0 # Offset 0:15
368 .byte 0x8e # Interrupt Gate, Present
369 .word 0 # Offset 16:31
371 .word 0 # Offset 0:15
374 .byte 0x8e # Interrupt Gate, Present
375 .word 0 # Offset 16:31
377 .word 0 # Offset 0:15
380 .byte 0x8e # Interrupt Gate, Present
381 .word 0 # Offset 16:31
383 .word 0 # Offset 0:15
386 .byte 0x8e # Interrupt Gate, Present
387 .word 0 # Offset 16:31
389 .word 0 # Offset 0:15
392 .byte 0x8e # Interrupt Gate, Present
393 .word 0 # Offset 16:31
395 .word 0 # Offset 0:15
398 .byte 0x8e # Interrupt Gate, Present
399 .word 0 # Offset 16:31
401 .word 0 # Offset 0:15
404 .byte 0x8e # Interrupt Gate, Present
405 .word 0 # Offset 16:31
407 .word 0 # Offset 0:15
410 .byte 0x8e # Interrupt Gate, Present
411 .word 0 # Offset 16:31
413 .word 0 # Offset 0:15
416 .byte 0x8e # Interrupt Gate, Present
417 .word 0 # Offset 16:31
419 .word 0 # Offset 0:15
422 .byte 0x8e # Interrupt Gate, Present
423 .word 0 # Offset 16:31
425 .word 0 # Offset 0:15
428 .byte 0x8e # Interrupt Gate, Present
429 .word 0 # Offset 16:31
431 .word 0 # Offset 0:15
434 .byte 0x8e # Interrupt Gate, Present
435 .word 0 # Offset 16:31
437 .equ IDT_SIZE, . - _SmiIDT
441 .word EXCEPTION_TSS_SEL # TSS Segment selector
443 .byte 0x85 # Task Gate, present, DPL = 0
448 #------------------------------------------------------------------------------
449 # PageFaultIdtHandlerSmmProfile is the entry point for all exceptions
452 #+---------------------+
454 #+---------------------+
456 #+---------------------+
458 #+---------------------+
460 #+---------------------+
462 #+---------------------+
464 #+---------------------+ <-- EBP
466 # RSP set to odd multiple of 8 means ErrCode PRESENT
467 #------------------------------------------------------------------------------
468 ASM_GLOBAL ASM_PFX(PageFaultIdtHandlerSmmProfile)
469 ASM_PFX(PageFaultIdtHandlerSmmProfile):
470 pushl $0x0e # Page Fault
476 # Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
479 andl $0xfffffff0, %esp
482 ## UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
487 leal (6*4)(%ebp), %ecx
493 ## UINT32 Gs, Fs, Es, Ds, Cs, Ss;
496 movzwl (4*4)(%ebp), %eax
508 movl (3*4)(%ebp), %eax
511 ## UINT32 Gdtr[2], Idtr[2];
534 movl (5*4)(%ebp), %eax
537 ## UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
551 ## UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
565 ## FX_SAVE_STATE_IA32 FxSaveState;
568 .byte 0x0f, 0xae, 0x07 #fxsave [edi]
570 # UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
573 ## UINT32 ExceptionData;
576 ## call into exception handler
578 ## Prepare parameter and call
581 movl (1*4)(%ebp), %edx
585 # Call External Exception Handler
587 movl $ASM_PFX(SmiPFHandler), %eax
593 ## UINT32 ExceptionData;
596 ## FX_SAVE_STATE_IA32 FxSaveState;
598 .byte 0xf, 0xae, 0xe # fxrstor [esi]
601 ## UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
602 ## Skip restoration of DRx registers to support debuggers
603 ## that set breakpoints in interrupt/exception context
606 ## UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
609 addl $4, %esp # not for Cr1
621 ## UINT32 Gdtr[2], Idtr[2];
622 ## Best not let anyone mess with these particular registers...
628 ## UINT32 Gs, Fs, Es, Ds, Cs, Ss;
629 ## NOTE - modified segment registers could hang the debugger... We
630 ## could attempt to insulate ourselves against this possibility,
631 ## but that poses risks as well.
640 ## UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
643 addl $4, %esp # not for ebp
644 addl $4, %esp # not for esp
653 # Enable TF bit after page fault handler runs
654 btsl $8, 16(%esp) # EFLAGS
656 addl $8, %esp # skip INT# & ErrCode
660 # Page Fault Exception Handler entry when SMM Stack Guard is enabled
661 # Executiot starts here after a task switch
665 # Get this processor's TSS
669 movl 4(%esp), %eax # GDT base
671 movl (TSS_SEL+2)(%eax), %ecx
673 movb (TSS_SEL+7)(%eax), %cl
674 rorl $8, %ecx # ecx = TSS base
679 # Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
682 andl $0xfffffff0, %esp
685 ## UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
695 ## UINT32 Gs, Fs, Es, Ds, Cs, Ss;
696 movzwl TSS_SS(%ecx), %eax
698 movzwl TSS_CS(%ecx), %eax
700 movzwl TSS_DS(%ecx), %eax
702 movzwl TSS_ES(%ecx), %eax
704 movzwl TSS_FS(%ecx), %eax
706 movzwl TSS_GS(%ecx), %eax
712 ## UINT32 Gdtr[2], Idtr[2];
730 movzwl TSS_LDT(%ecx), %eax
734 pushl TSS_EFLAGS(%ecx)
736 ## UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
750 ## UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
764 ## FX_SAVE_STATE_IA32 FxSaveState;
765 ## Clear TS bit in CR0 to avoid Device Not Available Exception (#NM)
766 ## when executing fxsave/fxrstor instruction
770 .byte 0x0f, 0xae, 0x07 #fxsave [edi]
772 # UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
775 ## UINT32 ExceptionData;
778 ## call into exception handler
780 movl $ASM_PFX(SmiPFHandler), %eax
782 ## Prepare parameter and call
789 # Call External Exception Handler
795 ## UINT32 ExceptionData;
798 ## FX_SAVE_STATE_IA32 FxSaveState;
800 .byte 0xf, 0xae, 0xe # fxrstor [esi]
803 ## UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
804 ## Skip restoration of DRx registers to support debuggers
805 ## that set breakpoints in interrupt/exception context
808 ## UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
811 addl $4, %esp # not for Cr1
815 movl %eax, TSS_CR3(%ecx)
820 popl TSS_EFLAGS(%ecx)
823 ## UINT32 Gdtr[2], Idtr[2];
824 ## Best not let anyone mess with these particular registers...
830 ## UINT32 Gs, Fs, Es, Ds, Cs, Ss;
831 ## NOTE - modified segment registers could hang the debugger... We
832 ## could attempt to insulate ourselves against this possibility,
833 ## but that poses risks as well.
836 movw %ax, TSS_GS(%ecx)
838 movw %ax, TSS_FS(%ecx)
840 movw %ax, TSS_ES(%ecx)
842 movw %ax, TSS_DS(%ecx)
844 movw %ax, TSS_CS(%ecx)
846 movw %ax, TSS_SS(%ecx)
848 ## UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
851 addl $4, %esp # not for ebp
852 addl $4, %esp # not for esp
860 # Set single step DB# if SMM profile is enabled and page fault exception happens
861 cmpb $0, ASM_PFX(FeaturePcdGet (PcdCpuSmmProfileEnable))
863 # Create return context for iret in stub function
864 movl TSS_ESP(%ecx), %eax # Get old stack pointer
865 movl TSS_EIP(%ecx), %ebx
866 movl %ebx, -0xc(%eax) # create EIP in old stack
867 movzwl TSS_CS(%ecx), %ebx
868 movl %ebx, -0x8(%eax) # create CS in old stack
869 movl TSS_EFLAGS(%ecx), %ebx
871 movl %ebx, -0x4(%eax) # create eflags in old stack
872 movl TSS_ESP(%ecx), %eax # Get old stack pointer
873 subl $12, %eax # minus 12 byte
874 movl %eax, TSS_ESP(%ecx) # Set new stack pointer
876 # Replace the EIP of interrupted task with stub function
877 movl $ASM_PFX(PageFaultStubFunction), %eax
878 movl %eax, TSS_EIP(%ecx)
879 # Jump to the iret so next page fault handler as a task will start again after iret.
883 addl $4, %esp # skip ErrCode
887 ASM_PFX(PageFaultStubFunction):
889 # we need clean TS bit in CR0 to execute
890 # x87 FPU/MMX/SSE/SSE2/SSE3/SSSE3/SSE4 instructions.
895 ASM_GLOBAL ASM_PFX(InitializeIDTSmmStackGuard)
896 ASM_PFX(InitializeIDTSmmStackGuard):
899 # If SMM Stack Guard feature is enabled, the Page Fault Exception entry in IDT
900 # is a Task Gate Descriptor so that when a Page Fault Exception occurs,
901 # the processors can use a known good stack in case stack ran out.
903 leal _SmiIDT + 14 * 8, %ebx
904 leal TaskGateDescriptor, %edx