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;   SmiException.asm
14;
15; Abstract:
16;
17;   Exception handlers used in SM mode
18;
19;-------------------------------------------------------------------------------
20
21    .686p
22    .model  flat,C
23
24EXTERNDEF   SmiPFHandler:PROC
25EXTERNDEF   PageFaultStubFunction:PROC
26EXTERNDEF   gcSmiIdtr:FWORD
27EXTERNDEF   gcSmiGdtr:FWORD
28EXTERNDEF   gTaskGateDescriptor:QWORD
29EXTERNDEF   gcPsd:BYTE
30EXTERNDEF   FeaturePcdGet (PcdCpuSmmProfileEnable):BYTE
31
32
33    .data
34
35NullSeg     DQ      0                   ; reserved by architecture
36CodeSeg32   LABEL   QWORD
37            DW      -1                  ; LimitLow
38            DW      0                   ; BaseLow
39            DB      0                   ; BaseMid
40            DB      9bh
41            DB      0cfh                ; LimitHigh
42            DB      0                   ; BaseHigh
43ProtModeCodeSeg32   LABEL   QWORD
44            DW      -1                  ; LimitLow
45            DW      0                   ; BaseLow
46            DB      0                   ; BaseMid
47            DB      9bh
48            DB      0cfh                ; LimitHigh
49            DB      0                   ; BaseHigh
50ProtModeSsSeg32     LABEL   QWORD
51            DW      -1                  ; LimitLow
52            DW      0                   ; BaseLow
53            DB      0                   ; BaseMid
54            DB      93h
55            DB      0cfh                ; LimitHigh
56            DB      0                   ; BaseHigh
57DataSeg32   LABEL   QWORD
58            DW      -1                  ; LimitLow
59            DW      0                   ; BaseLow
60            DB      0                   ; BaseMid
61            DB      93h
62            DB      0cfh                ; LimitHigh
63            DB      0                   ; BaseHigh
64CodeSeg16   LABEL   QWORD
65            DW      -1
66            DW      0
67            DB      0
68            DB      9bh
69            DB      8fh
70            DB      0
71DataSeg16   LABEL   QWORD
72            DW      -1
73            DW      0
74            DB      0
75            DB      93h
76            DB      8fh
77            DB      0
78CodeSeg64   LABEL   QWORD
79            DW      -1                  ; LimitLow
80            DW      0                   ; BaseLow
81            DB      0                   ; BaseMid
82            DB      9bh
83            DB      0afh                ; LimitHigh
84            DB      0                   ; BaseHigh
85GDT_SIZE = $ - offset NullSeg
86
87TssSeg      LABEL   QWORD
88            DW      TSS_DESC_SIZE - 1   ; LimitLow
89            DW      0                   ; BaseLow
90            DB      0                   ; BaseMid
91            DB      89h
92            DB      00h                 ; LimitHigh
93            DB      0                   ; BaseHigh
94ExceptionTssSeg     LABEL   QWORD
95            DW      TSS_DESC_SIZE - 1   ; LimitLow
96            DW      0                   ; BaseLow
97            DB      0                   ; BaseMid
98            DB      89h
99            DB      00h                 ; LimitHigh
100            DB      0                   ; BaseHigh
101
102CODE_SEL          = offset CodeSeg32 - offset NullSeg
103DATA_SEL          = offset DataSeg32 - offset NullSeg
104TSS_SEL           = offset TssSeg - offset NullSeg
105EXCEPTION_TSS_SEL = offset ExceptionTssSeg - offset NullSeg
106
107IA32_TSS STRUC
108                    DW ?
109                    DW ?
110  ESP0              DD ?
111  SS0               DW ?
112                    DW ?
113  ESP1              DD ?
114  SS1               DW ?
115                    DW ?
116  ESP2              DD ?
117  SS2               DW ?
118                    DW ?
119  _CR3              DD ?
120  EIP               DD ?
121  EFLAGS            DD ?
122  _EAX              DD ?
123  _ECX              DD ?
124  _EDX              DD ?
125  _EBX              DD ?
126  _ESP              DD ?
127  _EBP              DD ?
128  _ESI              DD ?
129  _EDI              DD ?
130  _ES               DW ?
131                    DW ?
132  _CS               DW ?
133                    DW ?
134  _SS               DW ?
135                    DW ?
136  _DS               DW ?
137                    DW ?
138  _FS               DW ?
139                    DW ?
140  _GS               DW ?
141                    DW ?
142  LDT               DW ?
143                    DW ?
144                    DW ?
145                    DW ?
146IA32_TSS ENDS
147
148; Create 2 TSS segments just after GDT
149TssDescriptor LABEL BYTE
150            DW      0                   ; PreviousTaskLink
151            DW      0                   ; Reserved
152            DD      0                   ; ESP0
153            DW      0                   ; SS0
154            DW      0                   ; Reserved
155            DD      0                   ; ESP1
156            DW      0                   ; SS1
157            DW      0                   ; Reserved
158            DD      0                   ; ESP2
159            DW      0                   ; SS2
160            DW      0                   ; Reserved
161            DD      0                   ; CR3
162            DD      0                   ; EIP
163            DD      0                   ; EFLAGS
164            DD      0                   ; EAX
165            DD      0                   ; ECX
166            DD      0                   ; EDX
167            DD      0                   ; EBX
168            DD      0                   ; ESP
169            DD      0                   ; EBP
170            DD      0                   ; ESI
171            DD      0                   ; EDI
172            DW      0                   ; ES
173            DW      0                   ; Reserved
174            DW      0                   ; CS
175            DW      0                   ; Reserved
176            DW      0                   ; SS
177            DW      0                   ; Reserved
178            DW      0                   ; DS
179            DW      0                   ; Reserved
180            DW      0                   ; FS
181            DW      0                   ; Reserved
182            DW      0                   ; GS
183            DW      0                   ; Reserved
184            DW      0                   ; LDT Selector
185            DW      0                   ; Reserved
186            DW      0                   ; T
187            DW      0                   ; I/O Map Base
188TSS_DESC_SIZE = $ - offset TssDescriptor
189
190ExceptionTssDescriptor LABEL BYTE
191            DW      0                   ; PreviousTaskLink
192            DW      0                   ; Reserved
193            DD      0                   ; ESP0
194            DW      0                   ; SS0
195            DW      0                   ; Reserved
196            DD      0                   ; ESP1
197            DW      0                   ; SS1
198            DW      0                   ; Reserved
199            DD      0                   ; ESP2
200            DW      0                   ; SS2
201            DW      0                   ; Reserved
202            DD      0                   ; CR3
203            DD      offset PFHandlerEntry ; EIP
204            DD      00000002            ; EFLAGS
205            DD      0                   ; EAX
206            DD      0                   ; ECX
207            DD      0                   ; EDX
208            DD      0                   ; EBX
209            DD      0                   ; ESP
210            DD      0                   ; EBP
211            DD      0                   ; ESI
212            DD      0                   ; EDI
213            DW      DATA_SEL            ; ES
214            DW      0                   ; Reserved
215            DW      CODE_SEL            ; CS
216            DW      0                   ; Reserved
217            DW      DATA_SEL            ; SS
218            DW      0                   ; Reserved
219            DW      DATA_SEL            ; DS
220            DW      0                   ; Reserved
221            DW      DATA_SEL            ; FS
222            DW      0                   ; Reserved
223            DW      DATA_SEL            ; GS
224            DW      0                   ; Reserved
225            DW      0                   ; LDT Selector
226            DW      0                   ; Reserved
227            DW      0                   ; T
228            DW      0                   ; I/O Map Base
229
230gcPsd     LABEL   BYTE
231            DB      'PSDSIG  '
232            DW      PSD_SIZE
233            DW      2
234            DW      1 SHL 2
235            DW      CODE_SEL
236            DW      DATA_SEL
237            DW      DATA_SEL
238            DW      DATA_SEL
239            DW      0
240            DQ      0
241            DQ      0
242            DQ      0
243            DQ      offset NullSeg
244            DD      GDT_SIZE
245            DD      0
246            DB      24 dup (0)
247            DQ      0
248PSD_SIZE  = $ - offset gcPsd
249
250gcSmiGdtr   LABEL   FWORD
251    DW      GDT_SIZE - 1
252    DD      offset NullSeg
253
254gcSmiIdtr   LABEL   FWORD
255    DW      0
256    DD      0
257
258gTaskGateDescriptor LABEL QWORD
259    DW      0                           ; Reserved
260    DW      EXCEPTION_TSS_SEL           ; TSS Segment selector
261    DB      0                           ; Reserved
262    DB      85h                         ; Task Gate, present, DPL = 0
263    DW      0                           ; Reserved
264
265
266    .code
267;------------------------------------------------------------------------------
268; PageFaultIdtHandlerSmmProfile is the entry point page fault only
269;
270;
271; Stack:
272; +---------------------+
273; +    EFlags           +
274; +---------------------+
275; +    CS               +
276; +---------------------+
277; +    EIP              +
278; +---------------------+
279; +    Error Code       +
280; +---------------------+
281; +    Vector Number    +
282; +---------------------+
283; +    EBP              +
284; +---------------------+ <-- EBP
285;
286;
287;------------------------------------------------------------------------------
288PageFaultIdtHandlerSmmProfile PROC
289    push    0eh                         ; Page Fault
290
291    push    ebp
292    mov     ebp, esp
293
294
295    ;
296    ; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
297    ; is 16-byte aligned
298    ;
299    and     esp, 0fffffff0h
300    sub     esp, 12
301
302;; UINT32  Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
303    push    eax
304    push    ecx
305    push    edx
306    push    ebx
307    lea     ecx, [ebp + 6 * 4]
308    push    ecx                          ; ESP
309    push    dword ptr [ebp]              ; EBP
310    push    esi
311    push    edi
312
313;; UINT32  Gs, Fs, Es, Ds, Cs, Ss;
314    mov     eax, ss
315    push    eax
316    movzx   eax, word ptr [ebp + 4 * 4]
317    push    eax
318    mov     eax, ds
319    push    eax
320    mov     eax, es
321    push    eax
322    mov     eax, fs
323    push    eax
324    mov     eax, gs
325    push    eax
326
327;; UINT32  Eip;
328    mov     eax, [ebp + 3 * 4]
329    push    eax
330
331;; UINT32  Gdtr[2], Idtr[2];
332    sub     esp, 8
333    sidt    [esp]
334    mov     eax, [esp + 2]
335    xchg    eax, [esp]
336    and     eax, 0FFFFh
337    mov     [esp+4], eax
338
339    sub     esp, 8
340    sgdt    [esp]
341    mov     eax, [esp + 2]
342    xchg    eax, [esp]
343    and     eax, 0FFFFh
344    mov     [esp+4], eax
345
346;; UINT32  Ldtr, Tr;
347    xor     eax, eax
348    str     ax
349    push    eax
350    sldt    ax
351    push    eax
352
353;; UINT32  EFlags;
354    mov     eax, [ebp + 5 * 4]
355    push    eax
356
357;; UINT32  Cr0, Cr1, Cr2, Cr3, Cr4;
358    mov     eax, cr4
359    or      eax, 208h
360    mov     cr4, eax
361    push    eax
362    mov     eax, cr3
363    push    eax
364    mov     eax, cr2
365    push    eax
366    xor     eax, eax
367    push    eax
368    mov     eax, cr0
369    push    eax
370
371;; UINT32  Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
372    mov     eax, dr7
373    push    eax
374    mov     eax, dr6
375    push    eax
376    mov     eax, dr3
377    push    eax
378    mov     eax, dr2
379    push    eax
380    mov     eax, dr1
381    push    eax
382    mov     eax, dr0
383    push    eax
384
385;; FX_SAVE_STATE_IA32 FxSaveState;
386    sub     esp, 512
387    mov     edi, esp
388    db      0fh, 0aeh, 07h ;fxsave [edi]
389
390; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
391    cld
392
393;; UINT32  ExceptionData;
394    push    dword ptr [ebp + 2 * 4]
395
396;; call into exception handler
397
398;; Prepare parameter and call
399    mov     edx, esp
400    push    edx
401    mov     edx, dword ptr [ebp + 1 * 4]
402    push    edx
403
404    ;
405    ; Call External Exception Handler
406    ;
407    mov     eax, SmiPFHandler
408    call    eax
409    add     esp, 8
410
411;; UINT32  ExceptionData;
412    add     esp, 4
413
414;; FX_SAVE_STATE_IA32 FxSaveState;
415    mov     esi, esp
416    db      0fh, 0aeh, 0eh ; fxrstor [esi]
417    add     esp, 512
418
419;; UINT32  Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
420;; Skip restoration of DRx registers to support debuggers
421;; that set breakpoint in interrupt/exception context
422    add     esp, 4 * 6
423
424;; UINT32  Cr0, Cr1, Cr2, Cr3, Cr4;
425    pop     eax
426    mov     cr0, eax
427    add     esp, 4    ; not for Cr1
428    pop     eax
429    mov     cr2, eax
430    pop     eax
431    mov     cr3, eax
432    pop     eax
433    mov     cr4, eax
434
435;; UINT32  EFlags;
436    pop     dword ptr [ebp + 5 * 4]
437
438;; UINT32  Ldtr, Tr;
439;; UINT32  Gdtr[2], Idtr[2];
440;; Best not let anyone mess with these particular registers...
441    add     esp, 24
442
443;; UINT32  Eip;
444    pop     dword ptr [ebp + 3 * 4]
445
446;; UINT32  Gs, Fs, Es, Ds, Cs, Ss;
447;; NOTE - modified segment registers could hang the debugger...  We
448;;        could attempt to insulate ourselves against this possibility,
449;;        but that poses risks as well.
450;;
451    pop     gs
452    pop     fs
453    pop     es
454    pop     ds
455    pop     dword ptr [ebp + 4 * 4]
456    pop     ss
457
458;; UINT32  Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
459    pop     edi
460    pop     esi
461    add     esp, 4   ; not for ebp
462    add     esp, 4   ; not for esp
463    pop     ebx
464    pop     edx
465    pop     ecx
466    pop     eax
467
468    mov     esp, ebp
469    pop     ebp
470
471; Enable TF bit after page fault handler runs
472    bts     dword ptr [esp + 16], 8  ; EFLAGS
473
474    add     esp, 8                      ; skip INT# & ErrCode
475Return:
476    iretd
477;
478; Page Fault Exception Handler entry when SMM Stack Guard is enabled
479; Executiot starts here after a task switch
480;
481PFHandlerEntry::
482;
483; Get this processor's TSS
484;
485    sub     esp, 8
486    sgdt    [esp + 2]
487    mov     eax, [esp + 4]              ; GDT base
488    add     esp, 8
489    mov     ecx, [eax + TSS_SEL + 2]
490    shl     ecx, 8
491    mov     cl, [eax + TSS_SEL + 7]
492    ror     ecx, 8                      ; ecx = TSS base
493
494    mov     ebp, esp
495
496    ;
497    ; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
498    ; is 16-byte aligned
499    ;
500    and     esp, 0fffffff0h
501    sub     esp, 12
502
503;; UINT32  Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
504    push    (IA32_TSS ptr [ecx])._EAX
505    push    (IA32_TSS ptr [ecx])._ECX
506    push    (IA32_TSS ptr [ecx])._EDX
507    push    (IA32_TSS ptr [ecx])._EBX
508    push    (IA32_TSS ptr [ecx])._ESP
509    push    (IA32_TSS ptr [ecx])._EBP
510    push    (IA32_TSS ptr [ecx])._ESI
511    push    (IA32_TSS ptr [ecx])._EDI
512
513;; UINT32  Gs, Fs, Es, Ds, Cs, Ss;
514    movzx   eax, (IA32_TSS ptr [ecx])._SS
515    push    eax
516    movzx   eax, (IA32_TSS ptr [ecx])._CS
517    push    eax
518    movzx   eax, (IA32_TSS ptr [ecx])._DS
519    push    eax
520    movzx   eax, (IA32_TSS ptr [ecx])._ES
521    push    eax
522    movzx   eax, (IA32_TSS ptr [ecx])._FS
523    push    eax
524    movzx   eax, (IA32_TSS ptr [ecx])._GS
525    push    eax
526
527;; UINT32  Eip;
528    push    (IA32_TSS ptr [ecx]).EIP
529
530;; UINT32  Gdtr[2], Idtr[2];
531    sub     esp, 8
532    sidt    [esp]
533    mov     eax, [esp + 2]
534    xchg    eax, [esp]
535    and     eax, 0FFFFh
536    mov     [esp+4], eax
537
538    sub     esp, 8
539    sgdt    [esp]
540    mov     eax, [esp + 2]
541    xchg    eax, [esp]
542    and     eax, 0FFFFh
543    mov     [esp+4], eax
544
545;; UINT32  Ldtr, Tr;
546    mov     eax, TSS_SEL
547    push    eax
548    movzx   eax, (IA32_TSS ptr [ecx]).LDT
549    push    eax
550
551;; UINT32  EFlags;
552    push    (IA32_TSS ptr [ecx]).EFLAGS
553
554;; UINT32  Cr0, Cr1, Cr2, Cr3, Cr4;
555    mov     eax, cr4
556    or      eax, 208h
557    mov     cr4, eax
558    push    eax
559    mov     eax, cr3
560    push    eax
561    mov     eax, cr2
562    push    eax
563    xor     eax, eax
564    push    eax
565    mov     eax, cr0
566    push    eax
567
568;; UINT32  Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
569    mov     eax, dr7
570    push    eax
571    mov     eax, dr6
572    push    eax
573    mov     eax, dr3
574    push    eax
575    mov     eax, dr2
576    push    eax
577    mov     eax, dr1
578    push    eax
579    mov     eax, dr0
580    push    eax
581
582;; FX_SAVE_STATE_IA32 FxSaveState;
583;; Clear TS bit in CR0 to avoid Device Not Available Exception (#NM)
584;; when executing fxsave/fxrstor instruction
585    clts
586    sub     esp, 512
587    mov     edi, esp
588    db      0fh, 0aeh, 07h ;fxsave [edi]
589
590; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
591    cld
592
593;; UINT32  ExceptionData;
594    push    dword ptr [ebp]
595
596;; call into exception handler
597    mov     ebx, ecx
598    mov     eax, SmiPFHandler
599
600;; Prepare parameter and call
601    mov     edx, esp
602    push    edx
603    mov     edx, 14
604    push    edx
605
606    ;
607    ; Call External Exception Handler
608    ;
609    call    eax
610    add     esp, 8
611
612    mov     ecx, ebx
613;; UINT32  ExceptionData;
614    add     esp, 4
615
616;; FX_SAVE_STATE_IA32 FxSaveState;
617    mov     esi, esp
618    db      0fh, 0aeh, 0eh ; fxrstor [esi]
619    add     esp, 512
620
621;; UINT32  Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
622;; Skip restoration of DRx registers to support debuggers
623;; that set breakpoints in interrupt/exception context
624    add     esp, 4 * 6
625
626;; UINT32  Cr0, Cr1, Cr2, Cr3, Cr4;
627    pop     eax
628    mov     cr0, eax
629    add     esp, 4    ; not for Cr1
630    pop     eax
631    mov     cr2, eax
632    pop     eax
633    mov     (IA32_TSS ptr [ecx])._CR3, eax
634    pop     eax
635    mov     cr4, eax
636
637;; UINT32  EFlags;
638    pop     (IA32_TSS ptr [ecx]).EFLAGS
639
640;; UINT32  Ldtr, Tr;
641;; UINT32  Gdtr[2], Idtr[2];
642;; Best not let anyone mess with these particular registers...
643    add     esp, 24
644
645;; UINT32  Eip;
646    pop     (IA32_TSS ptr [ecx]).EIP
647
648;; UINT32  Gs, Fs, Es, Ds, Cs, Ss;
649;; NOTE - modified segment registers could hang the debugger...  We
650;;        could attempt to insulate ourselves against this possibility,
651;;        but that poses risks as well.
652;;
653    pop     eax
654    mov     (IA32_TSS ptr [ecx])._GS, ax
655    pop     eax
656    mov     (IA32_TSS ptr [ecx])._FS, ax
657    pop     eax
658    mov     (IA32_TSS ptr [ecx])._ES, ax
659    pop     eax
660    mov     (IA32_TSS ptr [ecx])._DS, ax
661    pop     eax
662    mov     (IA32_TSS ptr [ecx])._CS, ax
663    pop     eax
664    mov     (IA32_TSS ptr [ecx])._SS, ax
665
666;; UINT32  Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
667    pop     (IA32_TSS ptr [ecx])._EDI
668    pop     (IA32_TSS ptr [ecx])._ESI
669    add     esp, 4   ; not for ebp
670    add     esp, 4   ; not for esp
671    pop     (IA32_TSS ptr [ecx])._EBX
672    pop     (IA32_TSS ptr [ecx])._EDX
673    pop     (IA32_TSS ptr [ecx])._ECX
674    pop     (IA32_TSS ptr [ecx])._EAX
675
676    mov     esp, ebp
677
678; Set single step DB# if SMM profile is enabled and page fault exception happens
679    cmp     FeaturePcdGet (PcdCpuSmmProfileEnable), 0
680    jz      @Done2
681
682; Create return context for iretd in stub function
683    mov    eax, (IA32_TSS ptr [ecx])._ESP        ; Get old stack pointer
684    mov    ebx, (IA32_TSS ptr [ecx]).EIP
685    mov    [eax - 0ch], ebx                      ; create EIP in old stack
686    movzx  ebx, (IA32_TSS ptr [ecx])._CS
687    mov    [eax - 08h], ebx                      ; create CS in old stack
688    mov    ebx, (IA32_TSS ptr [ecx]).EFLAGS
689    bts    ebx, 8
690    mov    [eax - 04h], ebx                      ; create eflags in old stack
691    mov    eax, (IA32_TSS ptr [ecx])._ESP        ; Get old stack pointer
692    sub    eax, 0ch                              ; minus 12 byte
693    mov    (IA32_TSS ptr [ecx])._ESP, eax        ; Set new stack pointer
694; Replace the EIP of interrupted task with stub function
695    mov    eax, PageFaultStubFunction
696    mov    (IA32_TSS ptr [ecx]).EIP, eax
697; Jump to the iretd so next page fault handler as a task will start again after iretd.
698@Done2:
699    add     esp, 4                      ; skip ErrCode
700
701    jmp     Return
702PageFaultIdtHandlerSmmProfile ENDP
703
704PageFaultStubFunction   PROC
705;
706; we need clean TS bit in CR0 to execute
707; x87 FPU/MMX/SSE/SSE2/SSE3/SSSE3/SSE4 instructions.
708;
709    clts
710    iretd
711PageFaultStubFunction   ENDP
712
713    END
714