blob: 6390882fac128ab48876714c0f9273151c89a1f9 [file] [log] [blame]
#------------------------------------------------------------------------------
#
# Copyright (c) 2013 Intel Corporation.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Intel Corporation nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Module Name:
#
# SmiException.S
#
# Abstract:
#
# Exception handlers used in SM mode
#
#------------------------------------------------------------------------------
ASM_GLOBAL ASM_PFX(gSmiMtrrs)
ASM_GLOBAL ASM_PFX(gcSmiIdtr)
ASM_GLOBAL ASM_PFX(gcSmiGdtr)
ASM_GLOBAL ASM_PFX(gcPsd)
ASM_GLOBAL ASM_PFX(FeaturePcdGet (PcdCpuSmmStackGuard))
ASM_GLOBAL ASM_PFX(gSavedPageFaultIdtEntry)
ASM_GLOBAL ASM_PFX(gSavedDebugExceptionIdtEntry)
ASM_GLOBAL ASM_PFX(FeaturePcdGet (PcdCpuSmmProfileEnable))
ASM_GLOBAL ASM_PFX(InitializeSmmExternalVectorTablePtr)
.data
NullSeg: .quad 0
.quad 0 # reserved for future use
CodeSeg32:
.word -1 # LimitLow
.word 0 # BaseLow
.byte 0 # BaseMid
.byte 0x9b
.byte 0xcf # LimitHigh
.byte 0 # BaseHigh
DataSeg32:
.word -1 # LimitLow
.word 0 # BaseLow
.byte 0 # BaseMid
.byte 0x93
.byte 0xcf # LimitHigh
.byte 0 # BaseHigh
.quad 0 # reserved for future use
CodeSeg16:
.word -1
.word 0
.byte 0
.byte 0x9b
.byte 0x8f
.byte 0
DataSeg16:
.word -1
.word 0
.byte 0
.byte 0x93
.byte 0x8f
.byte 0
CodeSeg64:
.word -1 # LimitLow
.word 0 # BaseLow
.byte 0 # BaseMid
.byte 0x9b
.byte 0xaf # LimitHigh
.byte 0 # BaseHigh
.equ GDT_SIZE, .- NullSeg
TssSeg:
.word TSS_DESC_SIZE # LimitLow
.word 0 # BaseLow
.byte 0 # BaseMid
.byte 0x89
.byte 0x80 # LimitHigh
.byte 0 # BaseHigh
ExceptionTssSeg:
.word TSS_DESC_SIZE # LimitLow
.word 0 # BaseLow
.byte 0 # BaseMid
.byte 0x89
.byte 0x80 # LimitHigh
.byte 0 # BaseHigh
.equ CODE_SEL, CodeSeg32 - NullSeg
.equ DATA_SEL, DataSeg32 - NullSeg
.equ TSS_SEL, TssSeg - NullSeg
.equ EXCEPTION_TSS_SEL, ExceptionTssSeg - NullSeg
# IA32 TSS fields
.equ TSS_ESP0, 4
.equ TSS_SS0, 8
.equ TSS_ESP1, 12
.equ TSS_SS1, 16
.equ TSS_ESP2, 20
.equ TSS_SS2, 24
.equ TSS_CR3, 28
.equ TSS_EIP, 32
.equ TSS_EFLAGS, 36
.equ TSS_EAX, 40
.equ TSS_ECX, 44
.equ TSS_EDX, 48
.equ TSS_EBX, 52
.equ TSS_ESP, 56
.equ TSS_EBP, 60
.equ TSS_ESI, 64
.equ TSS_EDI, 68
.equ TSS_ES, 72
.equ TSS_CS, 76
.equ TSS_SS, 80
.equ TSS_DS, 84
.equ TSS_FS, 88
.equ TSS_GS, 92
.equ TSS_LDT, 96
# Create 2 TSS segments just after GDT
TssDescriptor:
.word 0 # PreviousTaskLink
.word 0 # Reserved
.long 0 # ESP0
.word 0 # SS0
.word 0 # Reserved
.long 0 # ESP1
.word 0 # SS1
.word 0 # Reserved
.long 0 # ESP2
.word 0 # SS2
.word 0 # Reserved
.long 0 # CR3
.long 0 # EIP
.long 0 # EFLAGS
.long 0 # EAX
.long 0 # ECX
.long 0 # EDX
.long 0 # EBX
.long 0 # ESP
.long 0 # EBP
.long 0 # ESI
.long 0 # EDI
.word 0 # ES
.word 0 # Reserved
.word 0 # CS
.word 0 # Reserved
.word 0 # SS
.word 0 # Reserved
.word 0 # DS
.word 0 # Reserved
.word 0 # FS
.word 0 # Reserved
.word 0 # GS
.word 0 # Reserved
.word 0 # LDT Selector
.word 0 # Reserved
.word 0 # T
.word 0 # I/O Map Base
.equ TSS_DESC_SIZE, . - TssDescriptor
ExceptionTssDescriptor:
.word 0 # PreviousTaskLink
.word 0 # Reserved
.long 0 # ESP0
.word 0 # SS0
.word 0 # Reserved
.long 0 # ESP1
.word 0 # SS1
.word 0 # Reserved
.long 0 # ESP2
.word 0 # SS2
.word 0 # Reserved
.long 0 # CR3
.long PFHandlerEntry # EIP
.long 00000002 # EFLAGS
.long 0 # EAX
.long 0 # ECX
.long 0 # EDX
.long 0 # EBX
.long 0 # ESP
.long 0 # EBP
.long 0 # ESI
.long 0 # EDI
.word DATA_SEL # ES
.word 0 # Reserved
.word CODE_SEL # CS
.word 0 # Reserved
.word DATA_SEL # SS
.word 0 # Reserved
.word DATA_SEL # DS
.word 0 # Reserved
.word DATA_SEL # FS
.word 0 # Reserved
.word DATA_SEL # GS
.word 0 # Reserved
.word 0 # LDT Selector
.word 0 # Reserved
.word 0 # T
.word 0 # I/O Map Base
ASM_PFX(gcPsd):
.ascii "PSDSIG "
.word PSD_SIZE
.word 2
.word 1 << 2
.word CODE_SEL
.word DATA_SEL
.word DATA_SEL
.word DATA_SEL
.word 0
.long 0
.long 0
.long 0
.long 0
.quad 0
.long NullSeg
.long 0
.long GDT_SIZE
.long 0
.space 24, 0
.long ASM_PFX(gSmiMtrrs)
.long 0
.equ PSD_SIZE, . - ASM_PFX(gcPsd)
ASM_PFX(gcSmiGdtr): .word GDT_SIZE - 1
.long NullSeg
ASM_PFX(gcSmiIdtr): .word IDT_SIZE - 1
.long _SmiIDT
_SmiIDT:
# The following segment repeats 32 times:
# No. 1
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 2
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 3
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 4
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 5
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 6
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 7
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 8
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 9
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 10
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 11
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 12
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 13
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 14
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 15
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 16
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 17
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 18
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 19
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 20
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 21
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 22
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 23
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 24
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 25
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 26
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 27
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 28
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 29
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 30
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 31
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 32
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
.equ IDT_SIZE, . - _SmiIDT
TaskGateDescriptor:
.word 0 # Reserved
.word EXCEPTION_TSS_SEL # TSS Segment selector
.byte 0 # Reserved
.byte 0x85 # Task Gate, present, DPL = 0
.word 0 # Reserved
# point to the external interrupt vector table
ExternalVectorTablePtr: .long 0
#
# Saved IDT Entry for Page Fault
#
ASM_PFX(gSavedPageFaultIdtEntry):
.long 0
.long 0
#
# Saved IDT Entry for INT 1
#
ASM_PFX(gSavedDebugExceptionIdtEntry):
.long 0
.long 0
.text
ASM_PFX(InitializeSmmExternalVectorTablePtr):
movl 4(%esp), %eax
movl %eax, ExternalVectorTablePtr
ret
#------------------------------------------------------------------------------
# Exception handlers
#------------------------------------------------------------------------------
_SmiExceptionHandlers:
.equ IHDLRIDX, 0
# The following segment repeats 8 times:
# No. 1
pushl %eax # dummy error code
pushl $IHDLRIDX
.byte 0xe9 # jmp disp32
.long _SmiExceptionEntryPoint - (. + 4)
.equ IHDLRIDX, IHDLRIDX + 1
# No. 2
pushl %eax # dummy error code
pushl $IHDLRIDX
.byte 0xe9 # jmp disp32
.long _SmiExceptionEntryPoint - (. + 4)
.equ IHDLRIDX, IHDLRIDX + 1
# No. 3
pushl %eax # dummy error code
pushl $IHDLRIDX
.byte 0xe9 # jmp disp32
.long _SmiExceptionEntryPoint - (. + 4)
.equ IHDLRIDX, IHDLRIDX + 1
# No. 4
pushl %eax # dummy error code
pushl $IHDLRIDX
.byte 0xe9 # jmp disp32
.long _SmiExceptionEntryPoint - (. + 4)
.equ IHDLRIDX, IHDLRIDX + 1
# No. 5
pushl %eax # dummy error code
pushl $IHDLRIDX
.byte 0xe9 # jmp disp32
.long _SmiExceptionEntryPoint - (. + 4)
.equ IHDLRIDX, IHDLRIDX + 1
# No. 6
pushl %eax # dummy error code
pushl $IHDLRIDX
.byte 0xe9 # jmp disp32
.long _SmiExceptionEntryPoint - (. + 4)
.equ IHDLRIDX, IHDLRIDX + 1
# No. 7
pushl %eax # dummy error code
pushl $IHDLRIDX
.byte 0xe9 # jmp disp32
.long _SmiExceptionEntryPoint - (. + 4)
.equ IHDLRIDX, IHDLRIDX + 1
# No. 8
pushl %eax # dummy error code
pushl $IHDLRIDX
.byte 0xe9 # jmp disp32
.long _SmiExceptionEntryPoint - (. + 4)
.equ IHDLRIDX, IHDLRIDX + 1
pushl $IHDLRIDX
.byte 0xe9 # jmp disp32
.long _SmiExceptionEntryPoint - (. + 4)
int $3
.equ IHDLRIDX, IHDLRIDX + 1
pushl %eax # dummy error code
pushl $IHDLRIDX
.byte 0xe9 # jmp disp32
.long _SmiExceptionEntryPoint - (. + 4)
.equ IHDLRIDX, IHDLRIDX + 1
# The following segment repeats 5 times:
# No. 1
pushl $IHDLRIDX
.byte 0xe9 # jmp disp32
.long _SmiExceptionEntryPoint - (. + 4)
int $3
.equ IHDLRIDX, IHDLRIDX + 1
# No. 2
pushl $IHDLRIDX
.byte 0xe9 # jmp disp32
.long _SmiExceptionEntryPoint - (. + 4)
int $3
.equ IHDLRIDX, IHDLRIDX + 1
# No. 3
pushl $IHDLRIDX
.byte 0xe9 # jmp disp32
.long _SmiExceptionEntryPoint - (. + 4)
int $3
.equ IHDLRIDX, IHDLRIDX + 1
# No. 4
pushl $IHDLRIDX
.byte 0xe9 # jmp disp32
.long _SmiExceptionEntryPoint - (. + 4)
int $3
.equ IHDLRIDX, IHDLRIDX + 1
# No. 5
pushl $IHDLRIDX
.byte 0xe9 # jmp disp32
.long _SmiExceptionEntryPoint - (. + 4)
int $3
.equ IHDLRIDX, IHDLRIDX + 1
# The following segment repeats 2 times:
# No. 1
pushl %eax # dummy error code
pushl $IHDLRIDX
.byte 0xe9 # jmp disp32
.long _SmiExceptionEntryPoint - (. + 4)
.equ IHDLRIDX, IHDLRIDX + 1
# No. 2
pushl %eax # dummy error code
pushl $IHDLRIDX
.byte 0xe9 # jmp disp32
.long _SmiExceptionEntryPoint - (. + 4)
.equ IHDLRIDX, IHDLRIDX + 1
pushl $IHDLRIDX
.byte 0xe9 # jmp disp32
.long _SmiExceptionEntryPoint - (. + 4)
int $3
.equ IHDLRIDX, IHDLRIDX + 1
# The following segment repeats 14 times:
# No. 1
pushl %eax # dummy error code
pushl $IHDLRIDX
.byte 0xe9 # jmp disp32
.long _SmiExceptionEntryPoint - (. + 4)
.equ IHDLRIDX, IHDLRIDX + 1
# No. 2
pushl %eax # dummy error code
pushl $IHDLRIDX
.byte 0xe9 # jmp disp32
.long _SmiExceptionEntryPoint - (. + 4)
.equ IHDLRIDX, IHDLRIDX + 1
# No. 3
pushl %eax # dummy error code
pushl $IHDLRIDX
.byte 0xe9 # jmp disp32
.long _SmiExceptionEntryPoint - (. + 4)
.equ IHDLRIDX, IHDLRIDX + 1
# No. 4
pushl %eax # dummy error code
pushl $IHDLRIDX
.byte 0xe9 # jmp disp32
.long _SmiExceptionEntryPoint - (. + 4)
.equ IHDLRIDX, IHDLRIDX + 1
# No. 5
pushl %eax # dummy error code
pushl $IHDLRIDX
.byte 0xe9 # jmp disp32
.long _SmiExceptionEntryPoint - (. + 4)
.equ IHDLRIDX, IHDLRIDX + 1
# No. 6
pushl %eax # dummy error code
pushl $IHDLRIDX
.byte 0xe9 # jmp disp32
.long _SmiExceptionEntryPoint - (. + 4)
.equ IHDLRIDX, IHDLRIDX + 1
# No. 7
pushl %eax # dummy error code
pushl $IHDLRIDX
.byte 0xe9 # jmp disp32
.long _SmiExceptionEntryPoint - (. + 4)
.equ IHDLRIDX, IHDLRIDX + 1
# No. 8
pushl %eax # dummy error code
pushl $IHDLRIDX
.byte 0xe9 # jmp disp32
.long _SmiExceptionEntryPoint - (. + 4)
.equ IHDLRIDX, IHDLRIDX + 1
# No. 9
pushl %eax # dummy error code
pushl $IHDLRIDX
.byte 0xe9 # jmp disp32
.long _SmiExceptionEntryPoint - (. + 4)
.equ IHDLRIDX, IHDLRIDX + 1
# No. 10
pushl %eax # dummy error code
pushl $IHDLRIDX
.byte 0xe9 # jmp disp32
.long _SmiExceptionEntryPoint - (. + 4)
.equ IHDLRIDX, IHDLRIDX + 1
# No. 11
pushl %eax # dummy error code
pushl $IHDLRIDX
.byte 0xe9 # jmp disp32
.long _SmiExceptionEntryPoint - (. + 4)
.equ IHDLRIDX, IHDLRIDX + 1
# No. 12
pushl %eax # dummy error code
pushl $IHDLRIDX
.byte 0xe9 # jmp disp32
.long _SmiExceptionEntryPoint - (. + 4)
.equ IHDLRIDX, IHDLRIDX + 1
# No. 13
pushl %eax # dummy error code
pushl $IHDLRIDX
.byte 0xe9 # jmp disp32
.long _SmiExceptionEntryPoint - (. + 4)
.equ IHDLRIDX, IHDLRIDX + 1
# No. 14
pushl %eax # dummy error code
pushl $IHDLRIDX
.byte 0xe9 # jmp disp32
.long _SmiExceptionEntryPoint - (. + 4)
.equ IHDLRIDX, IHDLRIDX + 1
#------------------------------------------------------------------------------
# _SmiExceptionEntryPoint is the entry point for all exceptions
#
# Stack:
#+---------------------+
#+ EFlags +
#+---------------------+
#+ CS +
#+---------------------+
#+ EIP +
#+---------------------+
#+ Error Code +
#+---------------------+
#+ Vector Number +
#+---------------------+
#+ EBP +
#+---------------------+ <-- EBP
#
# RSP set to odd multiple of 8 means ErrCode PRESENT
#------------------------------------------------------------------------------
_SmiExceptionEntryPoint:
pushl %ebp
movl %esp, %ebp
#
# Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
# is 16-byte aligned
#
andl $0xfffffff0, %esp
subl $12, %esp
## UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
pushl %eax
pushl %ecx
pushl %edx
pushl %ebx
leal (6*4)(%ebp), %ecx
pushl %ecx # ESP
pushl (%ebp) # EBP
pushl %esi
pushl %edi
## UINT32 Gs, Fs, Es, Ds, Cs, Ss;
movl %ss, %eax
pushl %eax
movzwl (4*4)(%ebp), %eax
pushl %eax
movl %ds, %eax
pushl %eax
movl %es, %eax
pushl %eax
movl %fs, %eax
pushl %eax
movl %gs, %eax
pushl %eax
## UINT32 Eip;
movl (3*4)(%ebp), %eax
pushl %eax
## UINT32 Gdtr[2], Idtr[2];
subl $8, %esp
sidt (%esp)
movl 2(%esp), %eax
xchgl (%esp), %eax
andl $0xffff, %eax
movl %eax, 4(%esp)
subl $8, %esp
sgdt (%esp)
movl 2(%esp), %eax
xchgl (%esp), %eax
andl $0xffff, %eax
movl %eax, 4(%esp)
## UINT32 Ldtr, Tr;
xorl %eax, %eax
strw %ax
pushl %eax
sldtw %ax
pushl %eax
## UINT32 EFlags;
movl (5*4)(%ebp), %eax
pushl %eax
## UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
movl %cr4, %eax
orl $0x208, %eax
movl %eax, %cr4
pushl %eax
movl %cr3, %eax
pushl %eax
movl %cr2, %eax
pushl %eax
xorl %eax, %eax
pushl %eax
movl %cr0, %eax
pushl %eax
## UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
movl %dr7, %eax
pushl %eax
movl %dr6, %eax
pushl %eax
movl %dr3, %eax
pushl %eax
movl %dr2, %eax
pushl %eax
movl %dr1, %eax
pushl %eax
movl %dr0, %eax
pushl %eax
## FX_SAVE_STATE_IA32 FxSaveState;
subl $512, %esp
movl %esp, %edi
.byte 0x0f, 0xae, 0x07 #fxsave [edi]
# UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
cld
## UINT32 ExceptionData;
pushl (2*4)(%ebp)
## call into exception handler
movl ExternalVectorTablePtr, %eax # get the interrupt vectors base
orl %eax, %eax # NULL?
jz nullExternalExceptionHandler
movl 4(%ebp), %ecx
movl (%eax, %ecx, 4), %eax
orl %eax, %eax # NULL?
jz nullExternalExceptionHandler
## Prepare parameter and call
movl %esp, %edx
pushl %edx
movl (1*4)(%ebp), %edx
pushl %edx
#
# Call External Exception Handler
#
call *%eax
addl $8, %esp
jmp L4
nullExternalExceptionHandler:
# CpuDeadLoop() is the default exception handler since it preserves the processor
# branch log.
call ASM_PFX(CpuDeadLoop)
L4:
## UINT32 ExceptionData;
addl $4, %esp
## FX_SAVE_STATE_IA32 FxSaveState;
movl %esp, %esi
.byte 0xf, 0xae, 0xe # fxrstor [esi]
addl $512, %esp
## UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
## Skip restoration of DRx registers to support in-circuit emualators
## or debuggers set breakpoint in interrupt/exception context
addl $4*6, %esp
## UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
popl %eax
movl %eax, %cr0
addl $4, %esp # not for Cr1
popl %eax
movl %eax, %cr2
popl %eax
movl %eax, %cr3
popl %eax
movl %eax, %cr4
## UINT32 EFlags;
popl (5*4)(%ebp)
## UINT32 Ldtr, Tr;
## UINT32 Gdtr[2], Idtr[2];
## Best not let anyone mess with these particular registers...
addl $24, %esp
## UINT32 Eip;
popl (3*4)(%ebp)
## UINT32 Gs, Fs, Es, Ds, Cs, Ss;
## NOTE - modified segment registers could hang the debugger... We
## could attempt to insulate ourselves against this possibility,
## but that poses risks as well.
##
popl %gs
popl %fs
popl %es
popl %ds
popl (4*4)(%ebp)
popl %ss
## UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
popl %edi
popl %esi
addl $4, %esp # not for ebp
addl $4, %esp # not for esp
popl %ebx
popl %edx
popl %ecx
popl %eax
movl %ebp, %esp
popl %ebp
# Set single step DB# if SMM profile is enabled and page fault exception happens
cmpb $0, ASM_PFX(FeaturePcdGet (PcdCpuSmmProfileEnable))
jz Done
# Check if this is page fault exception
cmpl $0xe, (%esp)
jnz L5
# Enable TF bit after page fault handler runs
btsl $8, 16(%esp) # EFLAGS
jmp Done
L5:
# Check if this is INT 1 exception
cmpl $1, (%esp)
jnz Done
# Clear TF bit after INT1 handler runs
btcl $8, 16(%esp) # EFLAGS
Done:
addl $8, %esp # skip INT# & ErrCode
Return:
iret
#
# Page Fault Exception Handler entry when SMM Stack Guard is enabled
# Executiot starts here after a task switch
#
PFHandlerEntry:
#
# Get this processor's TSS
#
subl $8, %esp
sgdt 2(%esp)
movl 4(%esp), %eax # GDT base
addl $8, %esp
movl (TSS_SEL+2)(%eax), %ecx
shll $8, %ecx
movb (TSS_SEL+7)(%eax), %cl
rorl $8, %ecx # ecx = TSS base
movl %esp, %ebp
#
# Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
# is 16-byte aligned
#
andl $0xfffffff0, %esp
subl $12, %esp
## UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
pushl TSS_EAX(%ecx)
pushl TSS_ECX(%ecx)
pushl TSS_EDX(%ecx)
pushl TSS_EBX(%ecx)
pushl TSS_ESP(%ecx)
pushl TSS_EBP(%ecx)
pushl TSS_ESI(%ecx)
pushl TSS_EDI(%ecx)
## UINT32 Gs, Fs, Es, Ds, Cs, Ss;
movzwl TSS_SS(%ecx), %eax
pushl %eax
movzwl TSS_CS(%ecx), %eax
pushl %eax
movzwl TSS_DS(%ecx), %eax
pushl %eax
movzwl TSS_ES(%ecx), %eax
pushl %eax
movzwl TSS_FS(%ecx), %eax
pushl %eax
movzwl TSS_GS(%ecx), %eax
pushl %eax
## UINT32 Eip;
pushl TSS_EIP(%ecx)
## UINT32 Gdtr[2], Idtr[2];
subl $8, %esp
sidt (%esp)
movl 2(%esp), %eax
xchgl (%esp), %eax
andl $0xFFFF, %eax
movl %eax, 4(%esp)
subl $8, %esp
sgdt (%esp)
movl 2(%esp), %eax
xchgl (%esp), %eax
andl $0xFFFF, %eax
movl %eax, 4(%esp)
## UINT32 Ldtr, Tr;
movl TSS_SEL, %eax
pushl %eax
movzwl TSS_LDT(%ecx), %eax
pushl %eax
## UINT32 EFlags;
pushl TSS_EFLAGS(%ecx)
## UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
movl %cr4, %eax
orl $0x208, %eax
movl %eax, %cr4
pushl %eax
movl %cr3, %eax
pushl %eax
movl %cr2, %eax
pushl %eax
xorl %eax, %eax
pushl %eax
movl %cr0, %eax
pushl %eax
## UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
movl %dr7, %eax
pushl %eax
movl %dr6, %eax
pushl %eax
movl %dr3, %eax
pushl %eax
movl %dr2, %eax
pushl %eax
movl %dr1, %eax
pushl %eax
movl %dr0, %eax
pushl %eax
## FX_SAVE_STATE_IA32 FxSaveState;
subl $512, %esp
movl %esp, %edi
.byte 0x0f, 0xae, 0x07 #fxsave [edi]
# UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
cld
## UINT32 ExceptionData;
pushl (%ebp)
## call into exception handler
movl ExternalVectorTablePtr, %eax # get the interrupt vectors base
orl %eax, %eax # NULL?
jz nullExternalExceptionHandler
movl %ecx, %ebx
mov $14, %ecx
movl (%eax, %ecx, 4), %eax
orl %eax, %eax # NULL?
jz nullExternalExceptionHandler
## Prepare parameter and call
movl %esp, %edx
pushl %edx
movl $14, %edx
pushl %edx
#
# Call External Exception Handler
#
call *%eax
addl $8, %esp
movl %ebx, %ecx
## UINT32 ExceptionData;
addl $4, %esp
## FX_SAVE_STATE_IA32 FxSaveState;
movl %esp, %esi
.byte 0xf, 0xae, 0xe # fxrstor [esi]
addl $512, %esp
## UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
## Skip restoration of DRx registers to support in-circuit emualators
## or debuggers set breakpoint in interrupt/exception context
addl $4*6, %esp
## UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
popl %eax
movl %eax, %cr0
addl $4, %esp # not for Cr1
popl %eax
movl %eax, %cr2
popl %eax
movl %eax, TSS_CR3(%ecx)
popl %eax
movl %eax, %cr4
## UINT32 EFlags;
popl TSS_EFLAGS(%ecx)
## UINT32 Ldtr, Tr;
## UINT32 Gdtr[2], Idtr[2];
## Best not let anyone mess with these particular registers...
addl $24, %esp
## UINT32 Eip;
popl TSS_EIP(%ecx)
## UINT32 Gs, Fs, Es, Ds, Cs, Ss;
## NOTE - modified segment registers could hang the debugger... We
## could attempt to insulate ourselves against this possibility,
## but that poses risks as well.
##
popl %eax
movw %ax, TSS_GS(%ecx)
popl %eax
movw %ax, TSS_FS(%ecx)
popl %eax
movw %ax, TSS_ES(%ecx)
popl %eax
movw %ax, TSS_DS(%ecx)
popl %eax
movw %ax, TSS_CS(%ecx)
popl %eax
movw %ax, TSS_SS(%ecx)
## UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
popl TSS_EDI(%ecx)
popl TSS_ESI(%ecx)
addl $4, %esp # not for ebp
addl $4, %esp # not for esp
popl TSS_EBX(%ecx)
popl TSS_EDX(%ecx)
popl TSS_ECX(%ecx)
popl TSS_EAX(%ecx)
movl %ebp, %esp
# Set single step DB# if SMM profile is enabled and page fault exception happens
cmpb $0, ASM_PFX(FeaturePcdGet (PcdCpuSmmProfileEnable))
jz Done2
# Enable TF bit after page fault handler runs
btsl $8, TSS_EFLAGS(%ecx) # EFLAGS
Done2:
addl 4, %esp # skip ErrCode
jmp Return
ASM_GLOBAL ASM_PFX(InitializeIDT)
ASM_PFX(InitializeIDT):
pushl %ebx
lea _SmiIDT - 8, %edx
# push IDT_SIZE / 8
.byte 0x68 # push /id
.long IDT_SIZE / 8
lea _SmiExceptionHandlers - 8, %ebx
popl %ecx
L1:
leal (%ebx,%ecx,8),%eax
movw %ax,(%edx,%ecx,8)
shrl $16,%eax
movw %ax, 6(%edx, %ecx, 8)
loop L1
cmpb $0, ASM_PFX(FeaturePcdGet (PcdCpuSmmStackGuard))
jz L2
#
# If SMM Stack Guard feature is enabled, the Page Fault Exception entry in IDT
# is a Task Gate Descriptor so that when a Page Fault Exception occurrs,
# the processors can use a known good stack in case stack ran out.
#
leal _SmiIDT + 14 * 8, %ebx
leal TaskGateDescriptor, %edx
movl (%edx), %eax
movl %eax, (%ebx)
movl 4(%edx), %eax
movl %eax, 4(%ebx)
L2:
#
# Save Page Fault IDT entry in gPageFaultIdtEntry
#
leal _SmiIDT + 14 * 8, %ebx
leal ASM_PFX(gSavedPageFaultIdtEntry), %edx
movl (%ebx), %eax
movl %eax, (%edx)
movl 4(%ebx), %eax
movl %eax, 4(%edx)
cmpb $0, ASM_PFX(FeaturePcdGet (PcdCpuSmmProfileEnable))
jz L3
#
# Save INT 1 IDT entry in gSavedDebugExceptionIdtEntry
#
leal _SmiIDT + 1 * 8, %ebx
leal ASM_PFX(gSavedDebugExceptionIdtEntry), %edx
movl (%ebx), %eax
movl %eax, (%edx)
movl 4(%ebx), %eax
movl %eax, 4(%edx)
L3:
popl %ebx
ret