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