1;------------------------------------------------------------------------------ ;
2; Copyright (c) 2009 - 2015, 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;   SmiException.asm
14;
15; Abstract:
16;
17;   Exception handlers used in SM mode
18;
19;-------------------------------------------------------------------------------
20
21EXTERNDEF   SmiPFHandler:PROC
22EXTERNDEF   gSmiMtrrs:QWORD
23EXTERNDEF   gcSmiIdtr:FWORD
24EXTERNDEF   gcSmiGdtr:FWORD
25EXTERNDEF   gcPsd:BYTE
26
27    .const
28
29NullSeg     DQ      0                   ; reserved by architecture
30CodeSeg32   LABEL   QWORD
31            DW      -1                  ; LimitLow
32            DW      0                   ; BaseLow
33            DB      0                   ; BaseMid
34            DB      9bh
35            DB      0cfh                ; LimitHigh
36            DB      0                   ; BaseHigh
37ProtModeCodeSeg32   LABEL   QWORD
38            DW      -1                  ; LimitLow
39            DW      0                   ; BaseLow
40            DB      0                   ; BaseMid
41            DB      9bh
42            DB      0cfh                ; LimitHigh
43            DB      0                   ; BaseHigh
44ProtModeSsSeg32     LABEL   QWORD
45            DW      -1                  ; LimitLow
46            DW      0                   ; BaseLow
47            DB      0                   ; BaseMid
48            DB      93h
49            DB      0cfh                ; LimitHigh
50            DB      0                   ; BaseHigh
51DataSeg32   LABEL   QWORD
52            DW      -1                  ; LimitLow
53            DW      0                   ; BaseLow
54            DB      0                   ; BaseMid
55            DB      93h
56            DB      0cfh                ; LimitHigh
57            DB      0                   ; BaseHigh
58CodeSeg16   LABEL   QWORD
59            DW      -1
60            DW      0
61            DB      0
62            DB      9bh
63            DB      8fh
64            DB      0
65DataSeg16   LABEL   QWORD
66            DW      -1
67            DW      0
68            DB      0
69            DB      93h
70            DB      8fh
71            DB      0
72CodeSeg64   LABEL   QWORD
73            DW      -1                  ; LimitLow
74            DW      0                   ; BaseLow
75            DB      0                   ; BaseMid
76            DB      9bh
77            DB      0afh                ; LimitHigh
78            DB      0                   ; BaseHigh
79; TSS Segment for X64 specially
80TssSeg      LABEL   QWORD
81            DW      TSS_DESC_SIZE - 1   ; LimitLow
82            DW      0                   ; BaseLow
83            DB      0                   ; BaseMid
84            DB      89h
85            DB      00h                 ; LimitHigh
86            DB      0                   ; BaseHigh
87            DD      0                   ; BaseUpper
88            DD      0                   ; Reserved
89GDT_SIZE = $ - offset NullSeg
90
91; Create TSS Descriptor just after GDT
92TssDescriptor LABEL BYTE
93            DD      0                   ; Reserved
94            DQ      0                   ; RSP0
95            DQ      0                   ; RSP1
96            DQ      0                   ; RSP2
97            DD      0                   ; Reserved
98            DD      0                   ; Reserved
99            DQ      0                   ; IST1
100            DQ      0                   ; IST2
101            DQ      0                   ; IST3
102            DQ      0                   ; IST4
103            DQ      0                   ; IST5
104            DQ      0                   ; IST6
105            DQ      0                   ; IST7
106            DD      0                   ; Reserved
107            DD      0                   ; Reserved
108            DW      0                   ; Reserved
109            DW      0                   ; I/O Map Base Address
110TSS_DESC_SIZE = $ - offset TssDescriptor
111
112;
113; This structure serves as a template for all processors.
114;
115gcPsd     LABEL   BYTE
116            DB      'PSDSIG  '
117            DW      PSD_SIZE
118            DW      2
119            DW      1 SHL 2
120            DW      CODE_SEL
121            DW      DATA_SEL
122            DW      DATA_SEL
123            DW      DATA_SEL
124            DW      0
125            DQ      0
126            DQ      0
127            DQ      0                   ; fixed in InitializeMpServiceData()
128            DQ      offset NullSeg
129            DD      GDT_SIZE
130            DD      0
131            DB      24 dup (0)
132            DQ      offset gSmiMtrrs
133PSD_SIZE  = $ - offset gcPsd
134
135;
136; CODE & DATA segments for SMM runtime
137;
138CODE_SEL    = offset CodeSeg64 - offset NullSeg
139DATA_SEL    = offset DataSeg32 - offset NullSeg
140CODE32_SEL  = offset CodeSeg32 - offset NullSeg
141
142gcSmiGdtr   LABEL   FWORD
143    DW      GDT_SIZE - 1
144    DQ      offset NullSeg
145
146gcSmiIdtr   LABEL   FWORD
147    DW      IDT_SIZE - 1
148    DQ      offset _SmiIDT
149
150    .data
151
152;
153; Here is the IDT. There are 32 (not 255) entries in it since only processor
154; generated exceptions will be handled.
155;
156_SmiIDT:
157REPEAT      32
158    DW      0                           ; Offset 0:15
159    DW      CODE_SEL                    ; Segment selector
160    DB      0                           ; Unused
161    DB      8eh                         ; Interrupt Gate, Present
162    DW      0                           ; Offset 16:31
163    DQ      0                           ; Offset 32:63
164            ENDM
165_SmiIDTEnd:
166
167IDT_SIZE = (offset _SmiIDTEnd - offset _SmiIDT)
168
169    .code
170
171;------------------------------------------------------------------------------
172; _SmiExceptionEntryPoints is the collection of exception entry points followed
173; by a common exception handler.
174;
175; Stack frame would be as follows as specified in IA32 manuals:
176;
177; +---------------------+ <-- 16-byte aligned ensured by processor
178; +    Old SS           +
179; +---------------------+
180; +    Old RSP          +
181; +---------------------+
182; +    RFlags           +
183; +---------------------+
184; +    CS               +
185; +---------------------+
186; +    RIP              +
187; +---------------------+
188; +    Error Code       +
189; +---------------------+
190; +   Vector Number     +
191; +---------------------+
192; +    RBP              +
193; +---------------------+ <-- RBP, 16-byte aligned
194;
195; RSP set to odd multiple of 8 at @CommonEntryPoint means ErrCode PRESENT
196;------------------------------------------------------------------------------
197PageFaultIdtHandlerSmmProfile    PROC
198    push    0eh                         ; Page Fault
199    test    spl, 8                      ; odd multiple of 8 => ErrCode present
200    jnz     @F
201    push    [rsp]                       ; duplicate INT# if no ErrCode
202    mov     qword ptr [rsp + 8], 0
203@@:
204    push    rbp
205    mov     rbp, rsp
206
207    ;
208    ; Since here the stack pointer is 16-byte aligned, so
209    ; EFI_FX_SAVE_STATE_X64 of EFI_SYSTEM_CONTEXT_x64
210    ; is 16-byte aligned
211    ;
212
213;; UINT64  Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
214;; UINT64  R8, R9, R10, R11, R12, R13, R14, R15;
215    push    r15
216    push    r14
217    push    r13
218    push    r12
219    push    r11
220    push    r10
221    push    r9
222    push    r8
223    push    rax
224    push    rcx
225    push    rdx
226    push    rbx
227    push    qword ptr [rbp + 48]  ; RSP
228    push    qword ptr [rbp]       ; RBP
229    push    rsi
230    push    rdi
231
232;; UINT64  Gs, Fs, Es, Ds, Cs, Ss;  insure high 16 bits of each is zero
233    movzx   rax, word ptr [rbp + 56]
234    push    rax                      ; for ss
235    movzx   rax, word ptr [rbp + 32]
236    push    rax                      ; for cs
237    mov     rax, ds
238    push    rax
239    mov     rax, es
240    push    rax
241    mov     rax, fs
242    push    rax
243    mov     rax, gs
244    push    rax
245
246;; UINT64  Rip;
247    push    qword ptr [rbp + 24]
248
249;; UINT64  Gdtr[2], Idtr[2];
250    sub     rsp, 16
251    sidt    fword ptr [rsp]
252    sub     rsp, 16
253    sgdt    fword ptr [rsp]
254
255;; UINT64  Ldtr, Tr;
256    xor     rax, rax
257    str     ax
258    push    rax
259    sldt    ax
260    push    rax
261
262;; UINT64  RFlags;
263    push    qword ptr [rbp + 40]
264
265;; UINT64  Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
266    mov     rax, cr8
267    push    rax
268    mov     rax, cr4
269    or      rax, 208h
270    mov     cr4, rax
271    push    rax
272    mov     rax, cr3
273    push    rax
274    mov     rax, cr2
275    push    rax
276    xor     rax, rax
277    push    rax
278    mov     rax, cr0
279    push    rax
280
281;; UINT64  Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
282    mov     rax, dr7
283    push    rax
284    mov     rax, dr6
285    push    rax
286    mov     rax, dr3
287    push    rax
288    mov     rax, dr2
289    push    rax
290    mov     rax, dr1
291    push    rax
292    mov     rax, dr0
293    push    rax
294
295;; FX_SAVE_STATE_X64 FxSaveState;
296
297    sub rsp, 512
298    mov rdi, rsp
299    db 0fh, 0aeh, 00000111y ;fxsave [rdi]
300
301; UEFI calling convention for x64 requires that Direction flag in EFLAGs is clear
302    cld
303
304;; UINT32  ExceptionData;
305    push    qword ptr [rbp + 16]
306
307;; call into exception handler
308    mov     rcx, [rbp + 8]
309    mov     rax, SmiPFHandler
310
311;; Prepare parameter and call
312    mov     rdx, rsp
313    ;
314    ; Per X64 calling convention, allocate maximum parameter stack space
315    ; and make sure RSP is 16-byte aligned
316    ;
317    sub     rsp, 4 * 8 + 8
318    call    rax
319    add     rsp, 4 * 8 + 8
320    jmp     @F
321
322@@:
323;; UINT64  ExceptionData;
324    add     rsp, 8
325
326;; FX_SAVE_STATE_X64 FxSaveState;
327
328    mov rsi, rsp
329    db 0fh, 0aeh, 00001110y ; fxrstor [rsi]
330    add rsp, 512
331
332;; UINT64  Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
333;; Skip restoration of DRx registers to support debuggers
334;; that set breakpoints in interrupt/exception context
335  add     rsp, 8 * 6
336
337;; UINT64  Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
338    pop     rax
339    mov     cr0, rax
340    add     rsp, 8   ; not for Cr1
341    pop     rax
342    mov     cr2, rax
343    pop     rax
344    mov     cr3, rax
345    pop     rax
346    mov     cr4, rax
347    pop     rax
348    mov     cr8, rax
349
350;; UINT64  RFlags;
351    pop     qword ptr [rbp + 40]
352
353;; UINT64  Ldtr, Tr;
354;; UINT64  Gdtr[2], Idtr[2];
355;; Best not let anyone mess with these particular registers...
356    add     rsp, 48
357
358;; UINT64  Rip;
359    pop     qword ptr [rbp + 24]
360
361;; UINT64  Gs, Fs, Es, Ds, Cs, Ss;
362    pop     rax
363    ; mov     gs, rax ; not for gs
364    pop     rax
365    ; mov     fs, rax ; not for fs
366    ; (X64 will not use fs and gs, so we do not restore it)
367    pop     rax
368    mov     es, rax
369    pop     rax
370    mov     ds, rax
371    pop     qword ptr [rbp + 32]  ; for cs
372    pop     qword ptr [rbp + 56]  ; for ss
373
374;; UINT64  Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
375;; UINT64  R8, R9, R10, R11, R12, R13, R14, R15;
376    pop     rdi
377    pop     rsi
378    add     rsp, 8               ; not for rbp
379    pop     qword ptr [rbp + 48] ; for rsp
380    pop     rbx
381    pop     rdx
382    pop     rcx
383    pop     rax
384    pop     r8
385    pop     r9
386    pop     r10
387    pop     r11
388    pop     r12
389    pop     r13
390    pop     r14
391    pop     r15
392
393    mov     rsp, rbp
394
395; Enable TF bit after page fault handler runs
396    bts     dword ptr [rsp + 40], 8  ;RFLAGS
397
398    pop     rbp
399    add     rsp, 16           ; skip INT# & ErrCode
400    iretq
401PageFaultIdtHandlerSmmProfile ENDP
402
403InitializeIDTSmmStackGuard   PROC
404;
405; If SMM Stack Guard feature is enabled, set the IST field of
406; the interrupt gate for Page Fault Exception to be 1
407;
408    lea     rax, _SmiIDT + 14 * 16
409    mov     byte ptr [rax + 4], 1
410    ret
411InitializeIDTSmmStackGuard   ENDP
412
413    END
414