#------------------------------------------------------------------------------ | |
# | |
# 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: | |
# | |
# SmiEntry.S | |
# | |
# Abstract: | |
# | |
# Code template of the SMI handler for a particular processor | |
# | |
#------------------------------------------------------------------------------ | |
ASM_GLOBAL ASM_PFX(gcSmiHandlerTemplate) | |
ASM_GLOBAL ASM_PFX(gcSmiHandlerSize) | |
ASM_GLOBAL ASM_PFX(gSmiCr3) | |
ASM_GLOBAL ASM_PFX(gSmiStack) | |
ASM_GLOBAL ASM_PFX(gSmbase) | |
ASM_GLOBAL ASM_PFX(mXdSupported) | |
ASM_GLOBAL ASM_PFX(FeaturePcdGet (PcdCpuSmmStackGuard)) | |
ASM_GLOBAL ASM_PFX(gSmiHandlerIdtr) | |
.equ MSR_EFER, 0xc0000080 | |
.equ MSR_EFER_XD, 0x800 | |
.equ DSC_OFFSET, 0xfb00 | |
.equ DSC_GDTPTR, 0x30 | |
.equ DSC_GDTSIZ, 0x38 | |
.equ DSC_CS, 14 | |
.equ DSC_DS, 16 | |
.equ DSC_SS, 18 | |
.equ DSC_OTHERSEG, 20 | |
.equ PROTECT_MODE_CS, 0x08 | |
.equ PROTECT_MODE_DS, 0x20 | |
.equ TSS_SEGMENT, 0x40 | |
.text | |
ASM_PFX(gcSmiHandlerTemplate): | |
_SmiEntryPoint: | |
.byte 0xbb # mov bx, imm16 | |
.word _GdtDesc - _SmiEntryPoint + 0x8000 | |
.byte 0x2e,0xa1 # mov ax, cs:[offset16] | |
.word DSC_OFFSET + DSC_GDTSIZ | |
decl %eax | |
movl %eax, %cs:(%edi) # mov cs:[bx], ax | |
.byte 0x66,0x2e,0xa1 # mov eax, cs:[offset16] | |
.word DSC_OFFSET + DSC_GDTPTR | |
movw %ax, %cs:2(%edi) | |
movw %ax, %bp # ebp = GDT base | |
.byte 0x66 | |
lgdt %cs:(%edi) | |
# Patch ProtectedMode Segment | |
.byte 0xb8 # mov ax, imm16 | |
.word PROTECT_MODE_CS # set AX for segment directly | |
movl %eax, %cs:-2(%edi) # mov cs:[bx - 2], ax | |
# Patch ProtectedMode entry | |
.byte 0x66, 0xbf # mov edi, SMBASE | |
ASM_PFX(gSmbase): .space 4 | |
.byte 0x67 | |
lea ((Start32bit - _SmiEntryPoint) + 0x8000)(%edi), %ax | |
movw %ax, %cs:-6(%edi) | |
movl %cr0, %ebx | |
.byte 0x66 | |
andl $0x9ffafff3, %ebx | |
.byte 0x66 | |
orl $0x23, %ebx | |
movl %ebx, %cr0 | |
.byte 0x66,0xea | |
.space 4 | |
.space 2 | |
_GdtDesc: .space 4 | |
.space 2 | |
Start32bit: | |
movw $PROTECT_MODE_DS, %ax | |
movl %eax,%ds | |
movl %eax,%es | |
movl %eax,%fs | |
movl %eax,%gs | |
movl %eax,%ss | |
.byte 0xbc # mov esp, imm32 | |
ASM_PFX(gSmiStack): .space 4 | |
movl $ASM_PFX(gSmiHandlerIdtr), %eax | |
lidt (%eax) | |
jmp ProtFlatMode | |
ProtFlatMode: | |
.byte 0xb8 # mov eax, imm32 | |
ASM_PFX(gSmiCr3): .space 4 | |
movl %eax, %cr3 | |
# | |
# Need to test for CR4 specific bit support | |
# | |
movl $1, %eax | |
cpuid # use CPUID to determine if specific CR4 bits are supported | |
xorl %eax, %eax # Clear EAX | |
testl $BIT2, %edx # Check for DE capabilities | |
jz L8 | |
orl $BIT3, %eax | |
L8: | |
testl $BIT6, %edx # Check for PAE capabilities | |
jz L9 | |
orl $BIT5, %eax | |
L9: | |
testl $BIT7, %edx # Check for MCE capabilities | |
jz L10 | |
orl $BIT6, %eax | |
L10: | |
testl $BIT24, %edx # Check for FXSR capabilities | |
jz L11 | |
orl $BIT9, %eax | |
L11: | |
testl $BIT25, %edx # Check for SSE capabilities | |
jz L12 | |
orl $BIT10, %eax | |
L12: # as cr4.PGE is not set here, refresh cr3 | |
movl %eax, %cr4 # in PreModifyMtrrs() to flush TLB. | |
cmpb $0, ASM_PFX(FeaturePcdGet (PcdCpuSmmStackGuard)) | |
jz L5 | |
# Load TSS | |
movb $0x89, (TSS_SEGMENT + 5)(%ebp) # clear busy flag | |
movl $TSS_SEGMENT, %eax | |
ltrw %ax | |
L5: | |
# enable NXE if supported | |
.byte 0xb0 # mov al, imm8 | |
ASM_PFX(mXdSupported): .byte 1 | |
cmpb $0, %al | |
jz SkipNxe | |
# | |
# Check XD disable bit | |
# | |
movl $MSR_IA32_MISC_ENABLE, %ecx | |
rdmsr | |
pushl %edx # save MSR_IA32_MISC_ENABLE[63-32] | |
testl $BIT2, %edx # MSR_IA32_MISC_ENABLE[34] | |
jz L13 | |
andw $0x0FFFB, %dx # clear XD Disable bit if it is set | |
wrmsr | |
L13: | |
movl $MSR_EFER, %ecx | |
rdmsr | |
orw $MSR_EFER_XD,%ax # enable NXE | |
wrmsr | |
SkipNxe: | |
subl $4, %esp | |
NxeDone: | |
movl %cr0, %ebx | |
orl $0x080010023, %ebx # enable paging + WP + NE + MP + PE | |
movl %ebx, %cr0 | |
leal DSC_OFFSET(%edi),%ebx | |
movw DSC_DS(%ebx),%ax | |
movl %eax, %ds | |
movw DSC_OTHERSEG(%ebx),%ax | |
movl %eax, %es | |
movl %eax, %fs | |
movl %eax, %gs | |
movw DSC_SS(%ebx),%ax | |
movl %eax, %ss | |
# jmp _SmiHandler # instruction is not needed | |
_SmiHandler: | |
movl 4(%esp), %ebx | |
pushl %ebx | |
movl $ASM_PFX(CpuSmmDebugEntry), %eax | |
call *%eax | |
addl $4, %esp | |
pushl %ebx | |
movl $ASM_PFX(SmiRendezvous), %eax | |
call *%eax | |
addl $4, %esp | |
pushl %ebx | |
movl $ASM_PFX(CpuSmmDebugExit), %eax | |
call *%eax | |
addl $4, %esp | |
movl $ASM_PFX(mXdSupported), %eax | |
movb (%eax), %al | |
cmpb $0, %al | |
jz L16 | |
popl %edx # get saved MSR_IA32_MISC_ENABLE[63-32] | |
testl $BIT2, %edx | |
jz L16 | |
movl $MSR_IA32_MISC_ENABLE, %ecx | |
rdmsr | |
orw $BIT2, %dx # set XD Disable bit if it was set before entering into SMM | |
wrmsr | |
L16: | |
rsm | |
ASM_PFX(gcSmiHandlerSize): .word . - _SmiEntryPoint |