1 #------------------------------------------------------------------------------
3 # Copyright (c) 2009 - 2016, 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(gTaskGateDescriptor)
28 ASM_GLOBAL ASM_PFX(gcPsd)
29 ASM_GLOBAL ASM_PFX(FeaturePcdGet (PcdCpuSmmProfileEnable))
33 NullSeg: .quad 0 # reserved by architecture
39 .byte 0xcf # LimitHigh
46 .byte 0xcf # LimitHigh
53 .byte 0xcf # LimitHigh
60 .byte 0xcf # LimitHigh
81 .byte 0xaf # LimitHigh
83 .equ GDT_SIZE, .- NullSeg
86 .word TSS_DESC_SIZE -1 # LimitLow
90 .byte 0x00 # LimitHigh
93 .word TSS_DESC_SIZE - 1 # LimitLow
97 .byte 0x00 # LimitHigh
100 .equ CODE_SEL, CodeSeg32 - NullSeg
101 .equ DATA_SEL, DataSeg32 - NullSeg
102 .equ TSS_SEL, TssSeg - NullSeg
103 .equ EXCEPTION_TSS_SEL, ExceptionTssSeg - NullSeg
131 # Create 2 TSS segments just after GDT
133 .word 0 # PreviousTaskLink
167 .word 0 # LDT Selector
170 .word 0 # I/O Map Base
171 .equ TSS_DESC_SIZE, . - TssDescriptor
173 ExceptionTssDescriptor:
174 .word 0 # PreviousTaskLink
186 .long PFHandlerEntry # EIP
187 .long 00000002 # EFLAGS
208 .word 0 # LDT Selector
211 .word 0 # I/O Map Base
233 .long ASM_PFX(gSmiMtrrs)
235 .equ PSD_SIZE, . - ASM_PFX(gcPsd)
237 ASM_PFX(gcSmiGdtr): .word GDT_SIZE - 1
240 ASM_PFX(gcSmiIdtr): .word 0
243 ASM_PFX(gTaskGateDescriptor):
245 .word EXCEPTION_TSS_SEL # TSS Segment selector
247 .byte 0x85 # Task Gate, present, DPL = 0
252 #------------------------------------------------------------------------------
253 # PageFaultIdtHandlerSmmProfile is the entry point for all exceptions
256 #+---------------------+
258 #+---------------------+
260 #+---------------------+
262 #+---------------------+
264 #+---------------------+
266 #+---------------------+
268 #+---------------------+ <-- EBP
270 # RSP set to odd multiple of 8 means ErrCode PRESENT
271 #------------------------------------------------------------------------------
272 ASM_GLOBAL ASM_PFX(PageFaultIdtHandlerSmmProfile)
273 ASM_PFX(PageFaultIdtHandlerSmmProfile):
274 pushl $0x0e # Page Fault
280 # Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
283 andl $0xfffffff0, %esp
286 ## UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
291 leal (6*4)(%ebp), %ecx
297 ## UINT32 Gs, Fs, Es, Ds, Cs, Ss;
300 movzwl (4*4)(%ebp), %eax
312 movl (3*4)(%ebp), %eax
315 ## UINT32 Gdtr[2], Idtr[2];
338 movl (5*4)(%ebp), %eax
341 ## UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
355 ## UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
369 ## FX_SAVE_STATE_IA32 FxSaveState;
372 .byte 0x0f, 0xae, 0x07 #fxsave [edi]
374 # UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
377 ## UINT32 ExceptionData;
380 ## call into exception handler
382 ## Prepare parameter and call
385 movl (1*4)(%ebp), %edx
389 # Call External Exception Handler
391 movl $ASM_PFX(SmiPFHandler), %eax
397 ## UINT32 ExceptionData;
400 ## FX_SAVE_STATE_IA32 FxSaveState;
402 .byte 0xf, 0xae, 0xe # fxrstor [esi]
405 ## UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
406 ## Skip restoration of DRx registers to support debuggers
407 ## that set breakpoints in interrupt/exception context
410 ## UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
413 addl $4, %esp # not for Cr1
425 ## UINT32 Gdtr[2], Idtr[2];
426 ## Best not let anyone mess with these particular registers...
432 ## UINT32 Gs, Fs, Es, Ds, Cs, Ss;
433 ## NOTE - modified segment registers could hang the debugger... We
434 ## could attempt to insulate ourselves against this possibility,
435 ## but that poses risks as well.
444 ## UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
447 addl $4, %esp # not for ebp
448 addl $4, %esp # not for esp
457 # Enable TF bit after page fault handler runs
458 btsl $8, 16(%esp) # EFLAGS
460 addl $8, %esp # skip INT# & ErrCode
464 # Page Fault Exception Handler entry when SMM Stack Guard is enabled
465 # Executiot starts here after a task switch
469 # Get this processor's TSS
473 movl 4(%esp), %eax # GDT base
475 movl (TSS_SEL+2)(%eax), %ecx
477 movb (TSS_SEL+7)(%eax), %cl
478 rorl $8, %ecx # ecx = TSS base
483 # Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
486 andl $0xfffffff0, %esp
489 ## UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
499 ## UINT32 Gs, Fs, Es, Ds, Cs, Ss;
500 movzwl TSS_SS(%ecx), %eax
502 movzwl TSS_CS(%ecx), %eax
504 movzwl TSS_DS(%ecx), %eax
506 movzwl TSS_ES(%ecx), %eax
508 movzwl TSS_FS(%ecx), %eax
510 movzwl TSS_GS(%ecx), %eax
516 ## UINT32 Gdtr[2], Idtr[2];
534 movzwl TSS_LDT(%ecx), %eax
538 pushl TSS_EFLAGS(%ecx)
540 ## UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
554 ## UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
568 ## FX_SAVE_STATE_IA32 FxSaveState;
569 ## Clear TS bit in CR0 to avoid Device Not Available Exception (#NM)
570 ## when executing fxsave/fxrstor instruction
574 .byte 0x0f, 0xae, 0x07 #fxsave [edi]
576 # UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
579 ## UINT32 ExceptionData;
582 ## call into exception handler
584 movl $ASM_PFX(SmiPFHandler), %eax
586 ## Prepare parameter and call
593 # Call External Exception Handler
599 ## UINT32 ExceptionData;
602 ## FX_SAVE_STATE_IA32 FxSaveState;
604 .byte 0xf, 0xae, 0xe # fxrstor [esi]
607 ## UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
608 ## Skip restoration of DRx registers to support debuggers
609 ## that set breakpoints in interrupt/exception context
612 ## UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
615 addl $4, %esp # not for Cr1
619 movl %eax, TSS_CR3(%ecx)
624 popl TSS_EFLAGS(%ecx)
627 ## UINT32 Gdtr[2], Idtr[2];
628 ## Best not let anyone mess with these particular registers...
634 ## UINT32 Gs, Fs, Es, Ds, Cs, Ss;
635 ## NOTE - modified segment registers could hang the debugger... We
636 ## could attempt to insulate ourselves against this possibility,
637 ## but that poses risks as well.
640 movw %ax, TSS_GS(%ecx)
642 movw %ax, TSS_FS(%ecx)
644 movw %ax, TSS_ES(%ecx)
646 movw %ax, TSS_DS(%ecx)
648 movw %ax, TSS_CS(%ecx)
650 movw %ax, TSS_SS(%ecx)
652 ## UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
655 addl $4, %esp # not for ebp
656 addl $4, %esp # not for esp
664 # Set single step DB# if SMM profile is enabled and page fault exception happens
665 cmpb $0, ASM_PFX(FeaturePcdGet (PcdCpuSmmProfileEnable))
667 # Create return context for iret in stub function
668 movl TSS_ESP(%ecx), %eax # Get old stack pointer
669 movl TSS_EIP(%ecx), %ebx
670 movl %ebx, -0xc(%eax) # create EIP in old stack
671 movzwl TSS_CS(%ecx), %ebx
672 movl %ebx, -0x8(%eax) # create CS in old stack
673 movl TSS_EFLAGS(%ecx), %ebx
675 movl %ebx, -0x4(%eax) # create eflags in old stack
676 movl TSS_ESP(%ecx), %eax # Get old stack pointer
677 subl $12, %eax # minus 12 byte
678 movl %eax, TSS_ESP(%ecx) # Set new stack pointer
680 # Replace the EIP of interrupted task with stub function
681 movl $ASM_PFX(PageFaultStubFunction), %eax
682 movl %eax, TSS_EIP(%ecx)
683 # Jump to the iret so next page fault handler as a task will start again after iret.
687 addl $4, %esp # skip ErrCode
691 ASM_PFX(PageFaultStubFunction):
693 # we need clean TS bit in CR0 to execute
694 # x87 FPU/MMX/SSE/SSE2/SSE3/SSSE3/SSE4 instructions.