1;------------------------------------------------------------------------------ ;
2; Copyright (c) 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.nasm
14;
15; Abstract:
16;
17;   Code template of the SMI handler for a particular processor
18;
19;-------------------------------------------------------------------------------
20
21;
22; Variables referrenced by C code
23;
24
25%define MSR_IA32_MISC_ENABLE 0x1A0
26%define MSR_EFER      0xc0000080
27%define MSR_EFER_XD   0x800
28
29;
30; Constants relating to PROCESSOR_SMM_DESCRIPTOR
31;
32%define DSC_OFFSET 0xfb00
33%define DSC_GDTPTR 0x30
34%define DSC_GDTSIZ 0x38
35%define DSC_CS 14
36%define DSC_DS 16
37%define DSC_SS 18
38%define DSC_OTHERSEG 20
39;
40; Constants relating to CPU State Save Area
41;
42%define SSM_DR6 0xffd0
43%define SSM_DR7 0xffc8
44
45%define PROTECT_MODE_CS 0x8
46%define PROTECT_MODE_DS 0x20
47%define LONG_MODE_CS 0x38
48%define TSS_SEGMENT 0x40
49%define GDT_SIZE 0x50
50
51extern ASM_PFX(SmiRendezvous)
52extern ASM_PFX(gSmiHandlerIdtr)
53extern ASM_PFX(CpuSmmDebugEntry)
54extern ASM_PFX(CpuSmmDebugExit)
55
56global ASM_PFX(gSmbase)
57global ASM_PFX(mXdSupported)
58global ASM_PFX(gSmiStack)
59global ASM_PFX(gSmiCr3)
60global ASM_PFX(gcSmiHandlerTemplate)
61global ASM_PFX(gcSmiHandlerSize)
62
63    DEFAULT REL
64    SECTION .text
65
66BITS 16
67ASM_PFX(gcSmiHandlerTemplate):
68_SmiEntryPoint:
69    mov     bx, _GdtDesc - _SmiEntryPoint + 0x8000
70    mov     ax,[cs:DSC_OFFSET + DSC_GDTSIZ]
71    dec     ax
72    mov     [cs:bx], ax
73    mov     eax, [cs:DSC_OFFSET + DSC_GDTPTR]
74    mov     [cs:bx + 2], eax
75o32 lgdt    [cs:bx]                       ; lgdt fword ptr cs:[bx]
76    mov     ax, PROTECT_MODE_CS
77    mov     [cs:bx-0x2],ax
78    DB      0x66, 0xbf                   ; mov edi, SMBASE
79ASM_PFX(gSmbase): DD 0
80    lea     eax, [edi + (@ProtectedMode - _SmiEntryPoint) + 0x8000]
81    mov     [cs:bx-0x6],eax
82    mov     ebx, cr0
83    and     ebx, 0x9ffafff3
84    or      ebx, 0x23
85    mov     cr0, ebx
86    jmp     dword 0x0:0x0
87_GdtDesc:
88    DW 0
89    DD 0
90
91BITS 32
92@ProtectedMode:
93    mov     ax, PROTECT_MODE_DS
94o16 mov     ds, ax
95o16 mov     es, ax
96o16 mov     fs, ax
97o16 mov     gs, ax
98o16 mov     ss, ax
99    DB      0xbc                   ; mov esp, imm32
100ASM_PFX(gSmiStack): DD 0
101    jmp     ProtFlatMode
102
103BITS 64
104ProtFlatMode:
105    DB      0xb8                        ; mov eax, offset gSmiCr3
106ASM_PFX(gSmiCr3): DD 0
107    mov     cr3, rax
108    mov     eax, 0x668                   ; as cr4.PGE is not set here, refresh cr3
109    mov     cr4, rax                    ; in PreModifyMtrrs() to flush TLB.
110; Load TSS
111    sub     esp, 8                      ; reserve room in stack
112    sgdt    [rsp]
113    mov     eax, [rsp + 2]              ; eax = GDT base
114    add     esp, 8
115    mov     dl, 0x89
116    mov     [rax + TSS_SEGMENT + 5], dl ; clear busy flag
117    mov     eax, TSS_SEGMENT
118    ltr     ax
119
120; enable NXE if supported
121    DB      0xb0                        ; mov al, imm8
122ASM_PFX(mXdSupported):     DB      1
123    cmp     al, 0
124    jz      @SkipXd
125;
126; Check XD disable bit
127;
128    mov     ecx, MSR_IA32_MISC_ENABLE
129    rdmsr
130    sub     esp, 4
131    push    rdx                        ; save MSR_IA32_MISC_ENABLE[63-32]
132    test    edx, BIT2                  ; MSR_IA32_MISC_ENABLE[34]
133    jz      .0
134    and     dx, 0xFFFB                 ; clear XD Disable bit if it is set
135    wrmsr
136.0:
137    mov     ecx, MSR_EFER
138    rdmsr
139    or      ax, MSR_EFER_XD            ; enable NXE
140    wrmsr
141    jmp     @XdDone
142@SkipXd:
143    sub     esp, 8
144@XdDone:
145
146; Switch into @LongMode
147    push    LONG_MODE_CS                ; push cs hardcore here
148    call    Base                       ; push return address for retf later
149Base:
150    add     dword [rsp], @LongMode - Base; offset for far retf, seg is the 1st arg
151
152    mov     ecx, MSR_EFER
153    rdmsr
154    or      ah, 1                      ; enable LME
155    wrmsr
156    mov     rbx, cr0
157    or      ebx, 0x80010023            ; enable paging + WP + NE + MP + PE
158    mov     cr0, rbx
159    retf
160@LongMode:                              ; long mode (64-bit code) starts here
161    mov     rax, ASM_PFX(gSmiHandlerIdtr)
162    lidt    [rax]
163    lea     ebx, [rdi + DSC_OFFSET]
164    mov     ax, [rbx + DSC_DS]
165    mov     ds, eax
166    mov     ax, [rbx + DSC_OTHERSEG]
167    mov     es, eax
168    mov     fs, eax
169    mov     gs, eax
170    mov     ax, [rbx + DSC_SS]
171    mov     ss, eax
172;   jmp     _SmiHandler                 ; instruction is not needed
173
174_SmiHandler:
175    mov     rbx, [rsp + 0x8]             ; rcx <- CpuIndex
176
177    ;
178    ; Save FP registers
179    ;
180    sub     rsp, 0x200
181    DB      0x48                         ; FXSAVE64
182    fxsave  [rsp]
183
184    add     rsp, -0x20
185
186    mov     rcx, rbx
187    mov     rax, CpuSmmDebugEntry
188    call    rax
189
190    mov     rcx, rbx
191    mov     rax, SmiRendezvous          ; rax <- absolute addr of SmiRedezvous
192    call    rax
193
194    mov     rcx, rbx
195    mov     rax, CpuSmmDebugExit
196    call    rax
197
198    add     rsp, 0x20
199
200    ;
201    ; Restore FP registers
202    ;
203    DB      0x48                         ; FXRSTOR64
204    fxrstor [rsp]
205
206    add     rsp, 0x200
207
208    mov     rax, ASM_PFX(mXdSupported)
209    mov     al, [rax]
210    cmp     al, 0
211    jz      .1
212    pop     rdx                       ; get saved MSR_IA32_MISC_ENABLE[63-32]
213    test    edx, BIT2
214    jz      .1
215    mov     ecx, MSR_IA32_MISC_ENABLE
216    rdmsr
217    or      dx, BIT2                  ; set XD Disable bit if it was set before entering into SMM
218    wrmsr
219
220.1:
221    rsm
222
223gcSmiHandlerSize    DW      $ - _SmiEntryPoint
224
225