#------------------------------------------------------------------------------ | |
# | |
# Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR> | |
# This program and the accompanying materials | |
# are licensed and made available under the terms and conditions of the BSD License | |
# which accompanies this distribution. The full text of the license may be found at | |
# http://opensource.org/licenses/bsd-license.php. | |
# | |
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
# | |
# Module Name: | |
# | |
# SmiException.S | |
# | |
# Abstract: | |
# | |
# Exception handlers used in SM mode | |
# | |
#------------------------------------------------------------------------------ | |
ASM_GLOBAL ASM_PFX(SmiPFHandler) | |
ASM_GLOBAL ASM_PFX(gcSmiIdtr) | |
ASM_GLOBAL ASM_PFX(gcSmiGdtr) | |
ASM_GLOBAL ASM_PFX(gcPsd) | |
.data | |
NullSeg: .quad 0 # reserved by architecture | |
CodeSeg32: | |
.word -1 # LimitLow | |
.word 0 # BaseLow | |
.byte 0 # BaseMid | |
.byte 0x9b | |
.byte 0xcf # LimitHigh | |
.byte 0 # BaseHigh | |
ProtModeCodeSeg32: | |
.word -1 # LimitLow | |
.word 0 # BaseLow | |
.byte 0 # BaseMid | |
.byte 0x9b | |
.byte 0xcf # LimitHigh | |
.byte 0 # BaseHigh | |
ProtModeSsSeg32: | |
.word -1 # LimitLow | |
.word 0 # BaseLow | |
.byte 0 # BaseMid | |
.byte 0x93 | |
.byte 0xcf # LimitHigh | |
.byte 0 # BaseHigh | |
DataSeg32: | |
.word -1 # LimitLow | |
.word 0 # BaseLow | |
.byte 0 # BaseMid | |
.byte 0x93 | |
.byte 0xcf # LimitHigh | |
.byte 0 # BaseHigh | |
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 | |
# TSS Segment for X64 specially | |
TssSeg: | |
.word TSS_DESC_SIZE - 1 # LimitLow | |
.word 0 # BaseLow | |
.byte 0 # BaseMid | |
.byte 0x89 | |
.byte 0x00 # LimitHigh | |
.byte 0 # BaseHigh | |
.long 0 # BaseUpper | |
.long 0 # Reserved | |
.equ GDT_SIZE, .- NullSeg | |
TssDescriptor: | |
.space 104, 0 | |
.equ TSS_DESC_SIZE, .- TssDescriptor | |
# | |
# This structure serves as a template for all processors. | |
# | |
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 | |
.quad 0 | |
.quad 0 | |
.quad 0 # fixed in InitializeMpServiceData() | |
.quad NullSeg | |
.long GDT_SIZE | |
.long 0 | |
.space 24, 0 | |
.quad 0 | |
.equ PSD_SIZE, . - ASM_PFX(gcPsd) | |
# | |
# CODE & DATA segments for SMM runtime | |
# | |
.equ CODE_SEL, CodeSeg64 - NullSeg | |
.equ DATA_SEL, DataSeg32 - NullSeg | |
.equ CODE32_SEL, CodeSeg32 - NullSeg | |
ASM_PFX(gcSmiGdtr): | |
.word GDT_SIZE - 1 | |
.quad NullSeg | |
ASM_PFX(gcSmiIdtr): | |
.word 0 | |
.quad 0 | |
.text | |
#------------------------------------------------------------------------------ | |
# _SmiExceptionEntryPoints is the collection of exception entry points followed | |
# by a common exception handler. | |
# | |
# Stack frame would be as follows as specified in IA32 manuals: | |
# +---------------------+ <-- 16-byte aligned ensured by processor | |
# + Old SS + | |
# +---------------------+ | |
# + Old RSP + | |
# +---------------------+ | |
# + RFlags + | |
# +---------------------+ | |
# + CS + | |
# +---------------------+ | |
# + RIP + | |
# +---------------------+ | |
# + Error Code + | |
# +---------------------+ | |
# + Vector Number + | |
# +---------------------+ | |
# + RBP + | |
# +---------------------+ <-- RBP, 16-byte aligned | |
# | |
# RSP set to odd multiple of 8 at @CommonEntryPoint means ErrCode PRESENT | |
#------------------------------------------------------------------------------ | |
ASM_GLOBAL ASM_PFX(PageFaultIdtHandlerSmmProfile) | |
ASM_PFX(PageFaultIdtHandlerSmmProfile): | |
pushq $0x0e # Page Fault | |
.byte 0x40, 0xf6, 0xc4, 0x08 #test spl, 8 | |
jnz L1 | |
pushq (%rsp) | |
movq $0, 8(%rsp) | |
L1: | |
pushq %rbp | |
movq %rsp, %rbp | |
# | |
# Since here the stack pointer is 16-byte aligned, so | |
# EFI_FX_SAVE_STATE_X64 of EFI_SYSTEM_CONTEXT_x64 | |
# is 16-byte aligned | |
# | |
## UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax; | |
## UINT64 R8, R9, R10, R11, R12, R13, R14, R15; | |
pushq %r15 | |
pushq %r14 | |
pushq %r13 | |
pushq %r12 | |
pushq %r11 | |
pushq %r10 | |
pushq %r9 | |
pushq %r8 | |
pushq %rax | |
pushq %rcx | |
pushq %rdx | |
pushq %rbx | |
pushq 48(%rbp) # RSP | |
pushq (%rbp) # RBP | |
pushq %rsi | |
pushq %rdi | |
## UINT64 Gs, Fs, Es, Ds, Cs, Ss; insure high 16 bits of each is zero | |
movzwq 56(%rbp), %rax | |
pushq %rax # for ss | |
movzwq 32(%rbp), %rax | |
pushq %rax # for cs | |
movq %ds, %rax | |
pushq %rax | |
movq %es, %rax | |
pushq %rax | |
movq %fs, %rax | |
pushq %rax | |
movq %gs, %rax | |
pushq %rax | |
## UINT64 Rip; | |
pushq 24(%rbp) | |
## UINT64 Gdtr[2], Idtr[2]; | |
subq $16, %rsp | |
sidt (%rsp) | |
subq $16, %rsp | |
sgdt (%rsp) | |
## UINT64 Ldtr, Tr; | |
xorq %rax, %rax | |
strw %ax | |
pushq %rax | |
sldtw %ax | |
pushq %rax | |
## UINT64 RFlags; | |
pushq 40(%rbp) | |
## UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8; | |
movq %cr8, %rax | |
pushq %rax | |
movq %cr4, %rax | |
orq $0x208, %rax | |
movq %rax, %cr4 | |
pushq %rax | |
movq %cr3, %rax | |
pushq %rax | |
movq %cr2, %rax | |
pushq %rax | |
xorq %rax, %rax | |
pushq %rax | |
movq %cr0, %rax | |
pushq %rax | |
## UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; | |
movq %dr7, %rax | |
pushq %rax | |
movq %dr6, %rax | |
pushq %rax | |
movq %dr3, %rax | |
pushq %rax | |
movq %dr2, %rax | |
pushq %rax | |
movq %dr1, %rax | |
pushq %rax | |
movq %dr0, %rax | |
pushq %rax | |
## FX_SAVE_STATE_X64 FxSaveState; | |
subq $512, %rsp | |
movq %rsp, %rdi | |
.byte 0xf, 0xae, 0x7 # fxsave [rdi] | |
# UEFI calling convention for x64 requires that Direction flag in EFLAGs is clear | |
cld | |
## UINT32 ExceptionData; | |
pushq 16(%rbp) | |
## call into exception handler | |
movq 8(%rbp), %rcx | |
movabsq $ASM_PFX(SmiPFHandler), %rax | |
## Prepare parameter and call | |
movq %rsp, %rdx | |
# | |
# Per X64 calling convention, allocate maximum parameter stack space | |
# and make sure RSP is 16-byte aligned | |
# | |
subq $4 * 8 + 8, %rsp | |
call *%rax | |
addq $4 * 8 + 8, %rsp | |
jmp L5 | |
L5: | |
## UINT64 ExceptionData; | |
addq $8, %rsp | |
## FX_SAVE_STATE_X64 FxSaveState; | |
movq %rsp, %rsi | |
.byte 0xf, 0xae, 0xe # fxrstor [rsi] | |
addq $512, %rsp | |
## UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7; | |
## Skip restoration of DRx registers to support debuggers | |
## that set breakpoints in interrupt/exception context | |
addq $8 * 6, %rsp | |
## UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8; | |
popq %rax | |
movq %rax, %cr0 | |
addq $8, %rsp # not for Cr1 | |
popq %rax | |
movq %rax, %cr2 | |
popq %rax | |
movq %rax, %cr3 | |
popq %rax | |
movq %rax, %cr4 | |
popq %rax | |
movq %rax, %cr8 | |
## UINT64 RFlags; | |
popq 40(%rbp) | |
## UINT64 Ldtr, Tr; | |
## UINT64 Gdtr[2], Idtr[2]; | |
## Best not let anyone mess with these particular registers... | |
addq $48, %rsp | |
## UINT64 Rip; | |
popq 24(%rbp) | |
## UINT64 Gs, Fs, Es, Ds, Cs, Ss; | |
popq %rax | |
# mov gs, rax ; not for gs | |
popq %rax | |
# mov fs, rax ; not for fs | |
# (X64 will not use fs and gs, so we do not restore it) | |
popq %rax | |
movq %rax, %es | |
popq %rax | |
movq %rax, %ds | |
popq 32(%rbp) # for cs | |
popq 56(%rbp) # for ss | |
## UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax; | |
## UINT64 R8, R9, R10, R11, R12, R13, R14, R15; | |
popq %rdi | |
popq %rsi | |
addq $8, %rsp # not for rbp | |
popq 48(%rbp) # for rsp | |
popq %rbx | |
popq %rdx | |
popq %rcx | |
popq %rax | |
popq %r8 | |
popq %r9 | |
popq %r10 | |
popq %r11 | |
popq %r12 | |
popq %r13 | |
popq %r14 | |
popq %r15 | |
movq %rbp, %rsp | |
# Enable TF bit after page fault handler runs | |
btsl $8, 40(%rsp) #RFLAGS | |
popq %rbp | |
addq $16, %rsp # skip INT# & ErrCode | |
iretq | |