| #------------------------------------------------------------------------------ | |
| # | |
| # 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(gcStmSmiHandlerTemplate) | |
| ASM_GLOBAL ASM_PFX(gcStmSmiHandlerSize) | |
| ASM_GLOBAL ASM_PFX(gcStmSmiHandlerOffset) | |
| ASM_GLOBAL ASM_PFX(gStmSmiCr3) | |
| ASM_GLOBAL ASM_PFX(gStmSmiStack) | |
| ASM_GLOBAL ASM_PFX(gStmSmbase) | |
| ASM_GLOBAL ASM_PFX(gStmXdSupported) | |
| ASM_GLOBAL ASM_PFX(gStmSmiHandlerIdtr) | |
| .equ MSR_IA32_MISC_ENABLE, 0x1A0 | |
| .equ MSR_EFER, 0xc0000080 | |
| .equ MSR_EFER_XD, 0x800 | |
| # | |
| # Constants relating to TXT_PROCESSOR_SMM_DESCRIPTOR | |
| # | |
| .equ DSC_OFFSET, 0xfb00 | |
| .equ DSC_GDTPTR, 0x48 | |
| .equ DSC_GDTSIZ, 0x50 | |
| .equ DSC_CS, 0x14 | |
| .equ DSC_DS, 0x16 | |
| .equ DSC_SS, 0x18 | |
| .equ DSC_OTHERSEG, 0x1a | |
| # | |
| # Constants relating to CPU State Save Area | |
| # | |
| .equ SSM_DR6, 0xffd0 | |
| .equ SSM_DR7, 0xffc8 | |
| .equ PROTECT_MODE_CS, 0x08 | |
| .equ PROTECT_MODE_DS, 0x20 | |
| .equ LONG_MODE_CS, 0x38 | |
| .equ TSS_SEGMENT, 0x40 | |
| .equ GDT_SIZE, 0x50 | |
| .text | |
| ASM_PFX(gcStmSmiHandlerTemplate): | |
| _StmSmiEntryPoint: | |
| # | |
| # The encoding of BX in 16-bit addressing mode is the same as of RDI in 64- | |
| # bit addressing mode. And that coincidence has been used in the following | |
| # "64-bit like" 16-bit code. Be aware that once RDI is referenced as a | |
| # base address register, it is actually BX that is referenced. | |
| # | |
| .byte 0xbb # mov bx, imm16 | |
| .word _StmGdtDesc - _StmSmiEntryPoint + 0x8000 | |
| # | |
| # fix GDT descriptor | |
| # | |
| .byte 0x2e,0xa1 # mov ax, cs:[offset16] | |
| .word DSC_OFFSET + DSC_GDTSIZ | |
| .byte 0x48 # dec ax | |
| .byte 0x2e | |
| movl %eax, (%rdi) # mov cs:[bx], ax | |
| .byte 0x66,0x2e,0xa1 # mov eax, cs:[offset16] | |
| .word DSC_OFFSET + DSC_GDTPTR | |
| .byte 0x2e | |
| movw %ax, 2(%rdi) | |
| .byte 0x66,0x2e | |
| lgdt (%rdi) | |
| # | |
| # Patch ProtectedMode Segment | |
| # | |
| .byte 0xb8 | |
| .word PROTECT_MODE_CS | |
| .byte 0x2e | |
| movl %eax, -2(%rdi) | |
| # | |
| # Patch ProtectedMode entry | |
| # | |
| .byte 0x66, 0xbf # mov edi, SMBASE | |
| ASM_PFX(gStmSmbase): .space 4 | |
| lea ((ProtectedMode - _StmSmiEntryPoint) + 0x8000)(%edi), %ax | |
| .byte 0x2e | |
| movw %ax, -6(%rdi) | |
| # | |
| # Switch into ProtectedMode | |
| # | |
| movq %cr0, %rbx | |
| .byte 0x66 | |
| andl $0x9ffafff3, %ebx | |
| .byte 0x66 | |
| orl $0x00000023, %ebx | |
| movq %rbx, %cr0 | |
| .byte 0x66, 0xea | |
| .space 6 | |
| _StmGdtDesc: .space 6 | |
| ProtectedMode: | |
| 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(gStmSmiStack): .space 4 | |
| jmp ProtFlatMode | |
| ProtFlatMode: | |
| .byte 0xb8 | |
| ASM_PFX(gStmSmiCr3): .space 4 | |
| movq %rax, %cr3 | |
| movl $0x668,%eax # as cr4.PGE is not set here, refresh cr3 | |
| movq %rax, %cr4 # in PreModifyMtrrs() to flush TLB. | |
| # Load TSS | |
| subl $8, %esp # reserve room in stack | |
| sgdt (%rsp) | |
| movl 2(%rsp), %eax # eax = GDT base | |
| addl $8, %esp | |
| movb $0x89, %dl | |
| movb %dl, (TSS_SEGMENT + 5)(%rax) # clear busy flag | |
| movl $TSS_SEGMENT, %eax | |
| ltr %ax | |
| # enable NXE if supported | |
| .byte 0xb0 # mov al, imm8 | |
| ASM_PFX(gStmXdSupported): .byte 1 | |
| cmpb $0, %al | |
| jz SkipXd | |
| # | |
| # Check XD disable bit | |
| # | |
| movl $MSR_IA32_MISC_ENABLE, %ecx | |
| rdmsr | |
| subl $4, %esp | |
| pushq %rdx # 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 | |
| jmp XdDone | |
| SkipXd: | |
| subl $8, %esp | |
| XdDone: | |
| # | |
| # Switch to LongMode | |
| # | |
| pushq $LONG_MODE_CS # push cs hardcore here | |
| call Base # push return address for retf later | |
| Base: | |
| addl $(LongMode - Base), (%rsp) # offset for far retf, seg is the 1st arg | |
| movl $MSR_EFER, %ecx | |
| rdmsr | |
| orb $1,%ah # enable LME | |
| wrmsr | |
| movq %cr0, %rbx | |
| orl $0x080010023, %ebx # enable paging + WP + NE + MP + PE | |
| movq %rbx, %cr0 | |
| retf | |
| LongMode: # long mode (64-bit code) starts here | |
| movabsq $ASM_PFX(gStmSmiHandlerIdtr), %rax | |
| lidt (%rax) | |
| lea (DSC_OFFSET)(%rdi), %ebx | |
| movw DSC_DS(%rbx), %ax | |
| movl %eax,%ds | |
| movw DSC_OTHERSEG(%rbx), %ax | |
| movl %eax,%es | |
| movl %eax,%fs | |
| movl %eax,%gs | |
| movw DSC_SS(%rbx), %ax | |
| movl %eax,%ss | |
| CommonHandler: | |
| movq 8(%rsp), %rbx | |
| # Save FP registers | |
| subq $0x200, %rsp | |
| .byte 0x48 # FXSAVE64 | |
| fxsave (%rsp) | |
| addq $-0x20, %rsp | |
| movq %rbx, %rcx | |
| movabsq $ASM_PFX(CpuSmmDebugEntry), %rax | |
| call *%rax | |
| movq %rbx, %rcx | |
| movabsq $ASM_PFX(SmiRendezvous), %rax | |
| call *%rax | |
| movq %rbx, %rcx | |
| movabsq $ASM_PFX(CpuSmmDebugExit), %rax | |
| call *%rax | |
| addq $0x20, %rsp | |
| # | |
| # Restore FP registers | |
| # | |
| .byte 0x48 # FXRSTOR64 | |
| fxrstor (%rsp) | |
| addq $0x200, %rsp | |
| movabsq $ASM_PFX(gStmXdSupported), %rax | |
| movb (%rax), %al | |
| cmpb $0, %al | |
| jz L16 | |
| popq %rdx # 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 | |
| _StmSmiHandler: | |
| # | |
| # Check XD disable bit | |
| # | |
| xorq %r8, %r8 | |
| movabsq $ASM_PFX(gStmXdSupported), %rax | |
| movb (%rax), %al | |
| cmpb $0, %al | |
| jz StmXdDone | |
| movl $MSR_IA32_MISC_ENABLE, %ecx | |
| rdmsr | |
| movq %rdx, %r8 # save MSR_IA32_MISC_ENABLE[63-32] | |
| testl $BIT2, %edx # MSR_IA32_MISC_ENABLE[34] | |
| jz L14 | |
| andw $0x0FFFB, %dx # clear XD Disable bit if it is set | |
| wrmsr | |
| L14: | |
| movl $MSR_EFER, %ecx | |
| rdmsr | |
| orw $MSR_EFER_XD,%ax # enable NXE | |
| wrmsr | |
| StmXdDone: | |
| pushq %r8 | |
| # below step is needed, because STM does not run above code. | |
| # we have to run below code to set IDT/CR0/CR4 | |
| movabsq $ASM_PFX(gStmSmiHandlerIdtr), %rax | |
| lidt (%rax) | |
| movq %cr0, %rax | |
| orl $0x80010023, %eax | |
| movq %rax, %cr0 | |
| movq %cr4, %rax | |
| movl $0x668, %eax # as cr4.PGE is not set here, refresh cr3 | |
| movq %rax, %cr4 # in PreModifyMtrrs() to flush TLB. | |
| # STM init finish | |
| jmp CommonHandler | |
| ASM_PFX(gcStmSmiHandlerSize) : .word . - _StmSmiEntryPoint | |
| ASM_PFX(gcStmSmiHandlerOffset): .word _StmSmiHandler - _StmSmiEntryPoint |