1;------------------------------------------------------------------------------ ;
2; Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
3; This program and the accompanying materials
4; are licensed and made available under the terms and conditions of the BSD License
5; which accompanies this distribution.  The full text of the license may be found at
6; http://opensource.org/licenses/bsd-license.php.
7;
8; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
9; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
10;
11; Module Name:
12;
13;   SmiEntry.asm
14;
15; Abstract:
16;
17;   Code template of the SMI handler for a particular processor
18;
19;-------------------------------------------------------------------------------
20
21;
22; Variables referenced by C code
23;
24EXTERNDEF   SmiRendezvous:PROC
25EXTERNDEF   CpuSmmDebugEntry:PROC
26EXTERNDEF   CpuSmmDebugExit:PROC
27EXTERNDEF   gcStmSmiHandlerTemplate:BYTE
28EXTERNDEF   gcStmSmiHandlerSize:WORD
29EXTERNDEF   gcStmSmiHandlerOffset:WORD
30EXTERNDEF   gStmSmiCr3:DWORD
31EXTERNDEF   gStmSmiStack:DWORD
32EXTERNDEF   gStmSmbase:DWORD
33EXTERNDEF   gStmXdSupported:BYTE
34EXTERNDEF   gStmSmiHandlerIdtr:FWORD
35
36MSR_IA32_MISC_ENABLE  EQU     1A0h
37MSR_EFER      EQU     0c0000080h
38MSR_EFER_XD   EQU     0800h
39
40;
41; Constants relating to TXT_PROCESSOR_SMM_DESCRIPTOR
42;
43DSC_OFFSET    EQU     0fb00h
44DSC_GDTPTR    EQU     48h
45DSC_GDTSIZ    EQU     50h
46DSC_CS        EQU     14h
47DSC_DS        EQU     16h
48DSC_SS        EQU     18h
49DSC_OTHERSEG  EQU     1ah
50;
51; Constants relating to CPU State Save Area
52;
53SSM_DR6         EQU     0ffd0h
54SSM_DR7         EQU     0ffc8h
55
56PROTECT_MODE_CS EQU     08h
57PROTECT_MODE_DS EQU     20h
58LONG_MODE_CS    EQU     38h
59TSS_SEGMENT     EQU     40h
60GDT_SIZE        EQU     50h
61
62    .code
63
64gcStmSmiHandlerTemplate    LABEL   BYTE
65
66_StmSmiEntryPoint:
67    ;
68    ; The encoding of BX in 16-bit addressing mode is the same as of RDI in 64-
69    ; bit addressing mode. And that coincidence has been used in the following
70    ; "64-bit like" 16-bit code. Be aware that once RDI is referenced as a
71    ; base address register, it is actually BX that is referenced.
72    ;
73    DB      0bbh                        ; mov bx, imm16
74    DW      offset _StmGdtDesc - _StmSmiEntryPoint + 8000h  ; bx = GdtDesc offset
75; fix GDT descriptor
76    DB      2eh, 0a1h                   ; mov ax, cs:[offset16]
77    DW      DSC_OFFSET + DSC_GDTSIZ
78    DB      48h                         ; dec ax
79    DB      2eh
80    mov     [rdi], eax                  ; mov cs:[bx], ax
81    DB      66h, 2eh, 0a1h              ; mov eax, cs:[offset16]
82    DW      DSC_OFFSET + DSC_GDTPTR
83    DB      2eh
84    mov     [rdi + 2], ax               ; mov cs:[bx + 2], eax
85    DB      66h, 2eh
86    lgdt    fword ptr [rdi]             ; lgdt fword ptr cs:[bx]
87; Patch ProtectedMode Segment
88    DB      0b8h                        ; mov ax, imm16
89    DW      PROTECT_MODE_CS             ; set AX for segment directly
90    DB      2eh
91    mov     [rdi - 2], eax              ; mov cs:[bx - 2], ax
92; Patch ProtectedMode entry
93    DB      66h, 0bfh                   ; mov edi, SMBASE
94gStmSmbase    DD    ?
95    lea     ax, [edi + (@ProtectedMode - _StmSmiEntryPoint) + 8000h]
96    DB      2eh
97    mov     [rdi - 6], ax               ; mov cs:[bx - 6], eax
98; Switch into @ProtectedMode
99    mov     rbx, cr0
100    DB      66h
101    and     ebx, 9ffafff3h
102    DB      66h
103    or      ebx, 00000023h
104
105    mov     cr0, rbx
106    DB      66h, 0eah
107    DD      ?
108    DW      ?
109
110_StmGdtDesc    FWORD   ?
111@ProtectedMode:
112    mov     ax, PROTECT_MODE_DS
113    mov     ds, ax
114    mov     es, ax
115    mov     fs, ax
116    mov     gs, ax
117    mov     ss, ax
118    DB      0bch                   ; mov esp, imm32
119gStmSmiStack   DD      ?
120    jmp     ProtFlatMode
121
122ProtFlatMode:
123    DB      0b8h                        ; mov eax, offset gStmSmiCr3
124gStmSmiCr3     DD      ?
125    mov     cr3, rax
126    mov     eax, 668h                   ; as cr4.PGE is not set here, refresh cr3
127    mov     cr4, rax                    ; in PreModifyMtrrs() to flush TLB.
128; Load TSS
129    sub     esp, 8                      ; reserve room in stack
130    sgdt    fword ptr [rsp]
131    mov     eax, [rsp + 2]              ; eax = GDT base
132    add     esp, 8
133    mov     dl, 89h
134    mov     [rax + TSS_SEGMENT + 5], dl ; clear busy flag
135    mov     eax, TSS_SEGMENT
136    ltr     ax
137
138; enable NXE if supported
139    DB      0b0h                        ; mov al, imm8
140gStmXdSupported     DB      1
141    cmp     al, 0
142    jz      @SkipXd
143;
144; Check XD disable bit
145;
146    mov     ecx, MSR_IA32_MISC_ENABLE
147    rdmsr
148    sub     esp, 4
149    push    rdx                        ; save MSR_IA32_MISC_ENABLE[63-32]
150    test    edx, BIT2                  ; MSR_IA32_MISC_ENABLE[34]
151    jz      @f
152    and     dx, 0FFFBh                 ; clear XD Disable bit if it is set
153    wrmsr
154@@:
155    mov     ecx, MSR_EFER
156    rdmsr
157    or      ax, MSR_EFER_XD            ; enable NXE
158    wrmsr
159    jmp     @XdDone
160@SkipXd:
161    sub     esp, 8
162@XdDone:
163
164; Switch into @LongMode
165    push    LONG_MODE_CS                ; push cs hardcore here
166    call    Base                       ; push return address for retf later
167Base:
168    add     dword ptr [rsp], @LongMode - Base; offset for far retf, seg is the 1st arg
169
170    mov     ecx, MSR_EFER
171    rdmsr
172    or      ah, 1                      ; enable LME
173    wrmsr
174    mov     rbx, cr0
175    or      ebx, 080010023h            ; enable paging + WP + NE + MP + PE
176    mov     cr0, rbx
177    retf
178@LongMode:                              ; long mode (64-bit code) starts here
179    mov     rax, offset gStmSmiHandlerIdtr
180    lidt    fword ptr [rax]
181    lea     ebx, [rdi + DSC_OFFSET]
182    mov     ax, [rbx + DSC_DS]
183    mov     ds, eax
184    mov     ax, [rbx + DSC_OTHERSEG]
185    mov     es, eax
186    mov     fs, eax
187    mov     gs, eax
188    mov     ax, [rbx + DSC_SS]
189    mov     ss, eax
190
191CommonHandler:
192    mov     rbx, [rsp + 0x08]           ; rbx <- CpuIndex
193
194    ;
195    ; Save FP registers
196    ;
197    sub     rsp, 200h
198    DB      48h                         ; FXSAVE64
199    fxsave  [rsp]
200
201    add     rsp, -20h
202
203    mov     rcx, rbx
204    mov     rax, CpuSmmDebugEntry
205    call    rax
206
207    mov     rcx, rbx
208    mov     rax, SmiRendezvous          ; rax <- absolute addr of SmiRedezvous
209    call    rax
210
211    mov     rcx, rbx
212    mov     rax, CpuSmmDebugExit
213    call    rax
214
215    add     rsp, 20h
216
217    ;
218    ; Restore FP registers
219    ;
220    DB      48h                         ; FXRSTOR64
221    fxrstor [rsp]
222
223    add     rsp, 200h
224
225    mov     rax, offset ASM_PFX(gStmXdSupported)
226    mov     al, [rax]
227    cmp     al, 0
228    jz      @f
229    pop     rdx                       ; get saved MSR_IA32_MISC_ENABLE[63-32]
230    test    edx, BIT2
231    jz      @f
232    mov     ecx, MSR_IA32_MISC_ENABLE
233    rdmsr
234    or      dx, BIT2                  ; set XD Disable bit if it was set before entering into SMM
235    wrmsr
236
237@@:
238    rsm
239
240_StmSmiHandler:
241;
242; Check XD disable bit
243;
244    xor     r8, r8
245    mov     rax, offset ASM_PFX(gStmXdSupported)
246    mov     al, [rax]
247    cmp     al, 0
248    jz      @StmXdDone
249    mov     ecx, MSR_IA32_MISC_ENABLE
250    rdmsr
251    mov     r8, rdx                   ; save MSR_IA32_MISC_ENABLE[63-32]
252    test    edx, BIT2                  ; MSR_IA32_MISC_ENABLE[34]
253    jz      @f
254    and     dx, 0FFFBh                 ; clear XD Disable bit if it is set
255    wrmsr
256@@:
257    mov     ecx, MSR_EFER
258    rdmsr
259    or      ax, MSR_EFER_XD            ; enable NXE
260    wrmsr
261@StmXdDone:
262    push    r8
263
264    ; below step is needed, because STM does not run above code.
265    ; we have to run below code to set IDT/CR0/CR4
266    mov     rax, offset gStmSmiHandlerIdtr
267    lidt    fword ptr [rax]
268
269    mov     rax, cr0
270    or      eax, 80010023h              ; enable paging + WP + NE + MP + PE
271    mov     cr0, rax
272    mov     rax, cr4
273    mov     eax, 668h                   ; as cr4.PGE is not set here, refresh cr3
274    mov     cr4, rax                    ; in PreModifyMtrrs() to flush TLB.
275    ; STM init finish
276    jmp     CommonHandler
277
278gcStmSmiHandlerSize    DW      $ - _StmSmiEntryPoint
279gcStmSmiHandlerOffset  DW      _StmSmiHandler - _StmSmiEntryPoint
280
281    END
282