1#------------------------------------------------------------------------------
2#
3# Copyright (c) 2009 - 2015, 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.
8#
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.
11#
12# Module Name:
13#
14#   SmiEntry.S
15#
16# Abstract:
17#
18#   Code template of the SMI handler for a particular processor
19#
20#------------------------------------------------------------------------------
21
22ASM_GLOBAL  ASM_PFX(gcSmiHandlerTemplate)
23ASM_GLOBAL  ASM_PFX(gcSmiHandlerSize)
24ASM_GLOBAL  ASM_PFX(gSmiCr3)
25ASM_GLOBAL  ASM_PFX(gSmiStack)
26ASM_GLOBAL  ASM_PFX(gSmbase)
27ASM_GLOBAL  ASM_PFX(gSmiHandlerIdtr)
28
29#
30# Constants relating to PROCESSOR_SMM_DESCRIPTOR
31#
32.equ            DSC_OFFSET, 0xfb00
33.equ            DSC_GDTPTR, 0x30
34.equ            DSC_GDTSIZ, 0x38
35.equ            DSC_CS, 14
36.equ            DSC_DS, 16
37.equ            DSC_SS, 18
38.equ            DSC_OTHERSEG, 20
39#
40# Constants relating to CPU State Save Area
41#
42.equ            SSM_DR6,   0xffd0
43.equ            SSM_DR7,   0xffc8
44
45.equ            PROTECT_MODE_CS, 0x08
46.equ            PROTECT_MODE_DS, 0x20
47.equ            LONG_MODE_CS, 0x38
48.equ            TSS_SEGMENT, 0x40
49.equ            GDT_SIZE, 0x50
50
51    .text
52
53ASM_PFX(gcSmiHandlerTemplate):
54
55_SmiEntryPoint:
56    #
57    # The encoding of BX in 16-bit addressing mode is the same as of RDI in 64-
58    # bit addressing mode. And that coincidence has been used in the following
59    # "64-bit like" 16-bit code. Be aware that once RDI is referenced as a
60    # base address register, it is actually BX that is referenced.
61    #
62    .byte 0xbb                          # mov bx, imm16
63    .word _GdtDesc - _SmiEntryPoint + 0x8000
64    #
65    # fix GDT descriptor
66    #
67    .byte 0x2e,0xa1                     # mov ax, cs:[offset16]
68    .word      DSC_OFFSET + DSC_GDTSIZ
69    .byte 0x48                          # dec ax
70    .byte 0x2e
71    movl    %eax, (%rdi)                # mov cs:[bx], ax
72    .byte 0x66,0x2e,0xa1                # mov eax, cs:[offset16]
73    .word      DSC_OFFSET + DSC_GDTPTR
74    .byte 0x2e
75    movw    %ax, 2(%rdi)
76    .byte 0x66,0x2e
77    lgdt    (%rdi)
78    #
79    # Patch ProtectedMode Segment
80    #
81    .byte 0xb8
82    .word PROTECT_MODE_CS
83    .byte 0x2e
84    movl    %eax, -2(%rdi)
85    #
86    # Patch ProtectedMode entry
87    #
88    .byte 0x66, 0xbf                    # mov edi, SMBASE
89ASM_PFX(gSmbase): .space 4
90    lea     ((ProtectedMode - _SmiEntryPoint) + 0x8000)(%edi), %ax
91    .byte 0x2e
92    movw    %ax, -6(%rdi)
93    #
94    # Switch into ProtectedMode
95    #
96    movq    %cr0, %rbx
97    .byte 0x66
98    andl    $0x9ffafff3, %ebx
99    .byte 0x66
100    orl     $0x00000023, %ebx
101
102    movq    %rbx, %cr0
103    .byte 0x66, 0xea
104    .space 6
105
106_GdtDesc:    .space  6
107
108ProtectedMode:
109    movw    $PROTECT_MODE_DS, %ax
110    movl    %eax, %ds
111    movl    %eax, %es
112    movl    %eax, %fs
113    movl    %eax, %gs
114    movl    %eax, %ss
115    .byte   0xbc                       # mov esp, imm32
116ASM_PFX(gSmiStack):   .space  4
117    jmp     ProtFlatMode
118
119ProtFlatMode:
120    .byte   0xb8
121ASM_PFX(gSmiCr3):    .space  4
122    movq    %rax, %cr3
123    movl    $0x668,%eax                 # as cr4.PGE is not set here, refresh cr3
124    movq    %rax, %cr4                  # in PreModifyMtrrs() to flush TLB.
125# Load TSS
126    subl    $8, %esp                    # reserve room in stack
127    sgdt    (%rsp)
128    movl    2(%rsp), %eax               # eax = GDT base
129    addl    $8, %esp
130    movb    $0x89, %dl
131    movb    %dl, (TSS_SEGMENT + 5)(%rax) # clear busy flag
132    movl    $TSS_SEGMENT, %eax
133    ltr     %ax
134
135    #
136    # Switch to LongMode
137    #
138    pushq    $LONG_MODE_CS                # push cs hardcore here
139    call     Base                         # push return address for retf later
140Base:
141    addl    $(LongMode - Base), (%rsp)  # offset for far retf, seg is the 1st arg
142    movl    $0xc0000080, %ecx
143    rdmsr
144    orb     $1,%ah
145    wrmsr
146    movq    %cr0, %rbx
147    orl     $0x080010000, %ebx          # enable paging + WP
148    movq    %rbx, %cr0
149    retf
150LongMode:                               # long mode (64-bit code) starts here
151    movabsq $ASM_PFX(gSmiHandlerIdtr), %rax
152    lidt    (%rax)
153    lea     (DSC_OFFSET)(%rdi), %ebx
154    movw    DSC_DS(%rbx), %ax
155    movl    %eax,%ds
156    movw    DSC_OTHERSEG(%rbx), %ax
157    movl    %eax,%es
158    movl    %eax,%fs
159    movl    %eax,%gs
160    movw    DSC_SS(%rbx), %ax
161    movl    %eax,%ss
162#   jmp     _SmiHandler                 ; instruction is not needed
163
164_SmiHandler:
165    movq    (%rsp), %rbx
166    # Save FP registers
167
168    subq    $0x208, %rsp
169    .byte   0x48                        # FXSAVE64
170    fxsave  (%rsp)
171
172    addq    $-0x20, %rsp
173
174    movq    %rbx, %rcx
175    movabsq $ASM_PFX(CpuSmmDebugEntry), %rax
176    call    *%rax
177
178    movq    %rbx, %rcx
179    movabsq $ASM_PFX(SmiRendezvous), %rax
180    call    *%rax
181
182    movq    %rbx, %rcx
183    movabsq $ASM_PFX(CpuSmmDebugExit), %rax
184    call    *%rax
185
186    addq    $0x20, %rsp
187
188    #
189    # Restore FP registers
190    #
191    .byte   0x48                        # FXRSTOR64
192    fxrstor (%rsp)
193
194    rsm
195
196ASM_PFX(gcSmiHandlerSize):    .word      . - _SmiEntryPoint
197