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(gcSmiIdtr)
25 ASM_GLOBAL ASM_PFX(gcSmiGdtr)
26 ASM_GLOBAL ASM_PFX(gTaskGateDescriptor)
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
234 .equ PSD_SIZE, . - ASM_PFX(gcPsd)
236 ASM_PFX(gcSmiGdtr): .word GDT_SIZE - 1
239 ASM_PFX(gcSmiIdtr): .word 0
242 ASM_PFX(gTaskGateDescriptor):
244 .word EXCEPTION_TSS_SEL # TSS Segment selector
246 .byte 0x85 # Task Gate, present, DPL = 0
251 #------------------------------------------------------------------------------
252 # PageFaultIdtHandlerSmmProfile is the entry point for all exceptions
255 #+---------------------+
257 #+---------------------+
259 #+---------------------+
261 #+---------------------+
263 #+---------------------+
265 #+---------------------+
267 #+---------------------+ <-- EBP
269 # RSP set to odd multiple of 8 means ErrCode PRESENT
270 #------------------------------------------------------------------------------
271 ASM_GLOBAL ASM_PFX(PageFaultIdtHandlerSmmProfile)
272 ASM_PFX(PageFaultIdtHandlerSmmProfile):
273 pushl $0x0e # Page Fault
279 # Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
282 andl $0xfffffff0, %esp
285 ## UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
290 leal (6*4)(%ebp), %ecx
296 ## UINT32 Gs, Fs, Es, Ds, Cs, Ss;
299 movzwl (4*4)(%ebp), %eax
311 movl (3*4)(%ebp), %eax
314 ## UINT32 Gdtr[2], Idtr[2];
337 movl (5*4)(%ebp), %eax
340 ## UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
354 ## UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
368 ## FX_SAVE_STATE_IA32 FxSaveState;
371 .byte 0x0f, 0xae, 0x07 #fxsave [edi]
373 # UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
376 ## UINT32 ExceptionData;
379 ## call into exception handler
381 ## Prepare parameter and call
384 movl (1*4)(%ebp), %edx
388 # Call External Exception Handler
390 movl $ASM_PFX(SmiPFHandler), %eax
396 ## UINT32 ExceptionData;
399 ## FX_SAVE_STATE_IA32 FxSaveState;
401 .byte 0xf, 0xae, 0xe # fxrstor [esi]
404 ## UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
405 ## Skip restoration of DRx registers to support debuggers
406 ## that set breakpoints in interrupt/exception context
409 ## UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
412 addl $4, %esp # not for Cr1
424 ## UINT32 Gdtr[2], Idtr[2];
425 ## Best not let anyone mess with these particular registers...
431 ## UINT32 Gs, Fs, Es, Ds, Cs, Ss;
432 ## NOTE - modified segment registers could hang the debugger... We
433 ## could attempt to insulate ourselves against this possibility,
434 ## but that poses risks as well.
443 ## UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
446 addl $4, %esp # not for ebp
447 addl $4, %esp # not for esp
456 # Enable TF bit after page fault handler runs
457 btsl $8, 16(%esp) # EFLAGS
459 addl $8, %esp # skip INT# & ErrCode
463 # Page Fault Exception Handler entry when SMM Stack Guard is enabled
464 # Executiot starts here after a task switch
468 # Get this processor's TSS
472 movl 4(%esp), %eax # GDT base
474 movl (TSS_SEL+2)(%eax), %ecx
476 movb (TSS_SEL+7)(%eax), %cl
477 rorl $8, %ecx # ecx = TSS base
482 # Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
485 andl $0xfffffff0, %esp
488 ## UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
498 ## UINT32 Gs, Fs, Es, Ds, Cs, Ss;
499 movzwl TSS_SS(%ecx), %eax
501 movzwl TSS_CS(%ecx), %eax
503 movzwl TSS_DS(%ecx), %eax
505 movzwl TSS_ES(%ecx), %eax
507 movzwl TSS_FS(%ecx), %eax
509 movzwl TSS_GS(%ecx), %eax
515 ## UINT32 Gdtr[2], Idtr[2];
533 movzwl TSS_LDT(%ecx), %eax
537 pushl TSS_EFLAGS(%ecx)
539 ## UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
553 ## UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
567 ## FX_SAVE_STATE_IA32 FxSaveState;
568 ## Clear TS bit in CR0 to avoid Device Not Available Exception (#NM)
569 ## when executing fxsave/fxrstor instruction
573 .byte 0x0f, 0xae, 0x07 #fxsave [edi]
575 # UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
578 ## UINT32 ExceptionData;
581 ## call into exception handler
583 movl $ASM_PFX(SmiPFHandler), %eax
585 ## Prepare parameter and call
592 # Call External Exception Handler
598 ## UINT32 ExceptionData;
601 ## FX_SAVE_STATE_IA32 FxSaveState;
603 .byte 0xf, 0xae, 0xe # fxrstor [esi]
606 ## UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
607 ## Skip restoration of DRx registers to support debuggers
608 ## that set breakpoints in interrupt/exception context
611 ## UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
614 addl $4, %esp # not for Cr1
618 movl %eax, TSS_CR3(%ecx)
623 popl TSS_EFLAGS(%ecx)
626 ## UINT32 Gdtr[2], Idtr[2];
627 ## Best not let anyone mess with these particular registers...
633 ## UINT32 Gs, Fs, Es, Ds, Cs, Ss;
634 ## NOTE - modified segment registers could hang the debugger... We
635 ## could attempt to insulate ourselves against this possibility,
636 ## but that poses risks as well.
639 movw %ax, TSS_GS(%ecx)
641 movw %ax, TSS_FS(%ecx)
643 movw %ax, TSS_ES(%ecx)
645 movw %ax, TSS_DS(%ecx)
647 movw %ax, TSS_CS(%ecx)
649 movw %ax, TSS_SS(%ecx)
651 ## UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
654 addl $4, %esp # not for ebp
655 addl $4, %esp # not for esp
663 # Set single step DB# if SMM profile is enabled and page fault exception happens
664 cmpb $0, ASM_PFX(FeaturePcdGet (PcdCpuSmmProfileEnable))
666 # Create return context for iret in stub function
667 movl TSS_ESP(%ecx), %eax # Get old stack pointer
668 movl TSS_EIP(%ecx), %ebx
669 movl %ebx, -0xc(%eax) # create EIP in old stack
670 movzwl TSS_CS(%ecx), %ebx
671 movl %ebx, -0x8(%eax) # create CS in old stack
672 movl TSS_EFLAGS(%ecx), %ebx
674 movl %ebx, -0x4(%eax) # create eflags in old stack
675 movl TSS_ESP(%ecx), %eax # Get old stack pointer
676 subl $12, %eax # minus 12 byte
677 movl %eax, TSS_ESP(%ecx) # Set new stack pointer
679 # Replace the EIP of interrupted task with stub function
680 movl $ASM_PFX(PageFaultStubFunction), %eax
681 movl %eax, TSS_EIP(%ecx)
682 # Jump to the iret so next page fault handler as a task will start again after iret.
686 addl $4, %esp # skip ErrCode
690 ASM_PFX(PageFaultStubFunction):
692 # we need clean TS bit in CR0 to execute
693 # x87 FPU/MMX/SSE/SSE2/SSE3/SSSE3/SSE4 instructions.