1#------------------------------------------------------------------------------
2#
3# Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
4# This program and the accompanying materials
5# are licensed and made available under the terms and conditions of the BSD License
6# which accompanies this distribution.  The full text of the license may be found at
7# http://opensource.org/licenses/bsd-license.php.
8#
9# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11#
12# Module Name:
13#
14#   SmiException.S
15#
16# Abstract:
17#
18#   Exception handlers used in SM mode
19#
20#------------------------------------------------------------------------------
21
22ASM_GLOBAL  ASM_PFX(SmiPFHandler)
23ASM_GLOBAL  ASM_PFX(PageFaultStubFunction)
24ASM_GLOBAL  ASM_PFX(gSmiMtrrs)
25ASM_GLOBAL  ASM_PFX(gcSmiIdtr)
26ASM_GLOBAL  ASM_PFX(gcSmiGdtr)
27ASM_GLOBAL  ASM_PFX(gcPsd)
28ASM_GLOBAL  ASM_PFX(FeaturePcdGet (PcdCpuSmmProfileEnable))
29
30    .data
31
32NullSeg:    .quad 0                     # reserved by architecture
33CodeSeg32:
34            .word -1                    # LimitLow
35            .word 0                     # BaseLow
36            .byte 0                     # BaseMid
37            .byte 0x9b
38            .byte 0xcf                  # LimitHigh
39            .byte 0                     # BaseHigh
40ProtModeCodeSeg32:
41            .word -1                    # LimitLow
42            .word 0                     # BaseLow
43            .byte 0                     # BaseMid
44            .byte 0x9b
45            .byte 0xcf                  # LimitHigh
46            .byte 0                     # BaseHigh
47ProtModeSsSeg32:
48            .word -1                    # LimitLow
49            .word 0                     # BaseLow
50            .byte 0                     # BaseMid
51            .byte 0x93
52            .byte 0xcf                  # LimitHigh
53            .byte 0                     # BaseHigh
54DataSeg32:
55            .word -1                    # LimitLow
56            .word 0                     # BaseLow
57            .byte 0                     # BaseMid
58            .byte 0x93
59            .byte 0xcf                  # LimitHigh
60            .byte 0                     # BaseHigh
61CodeSeg16:
62            .word -1
63            .word 0
64            .byte 0
65            .byte 0x9b
66            .byte 0x8f
67            .byte 0
68DataSeg16:
69            .word -1
70            .word 0
71            .byte 0
72            .byte 0x93
73            .byte 0x8f
74            .byte 0
75CodeSeg64:
76            .word -1                    # LimitLow
77            .word 0                     # BaseLow
78            .byte 0                     # BaseMid
79            .byte 0x9b
80            .byte 0xaf                  # LimitHigh
81            .byte 0                     # BaseHigh
82.equ  GDT_SIZE, .- NullSeg
83
84TssSeg:
85            .word      TSS_DESC_SIZE -1    # LimitLow
86            .word      0                   # BaseLow
87            .byte      0                   # BaseMid
88            .byte      0x89
89            .byte      0x00                # LimitHigh
90            .byte      0                   # BaseHigh
91ExceptionTssSeg:
92            .word      TSS_DESC_SIZE - 1   # LimitLow
93            .word      0                   # BaseLow
94            .byte      0                   # BaseMid
95            .byte      0x89
96            .byte      0x00                # LimitHigh
97            .byte      0                   # BaseHigh
98
99.equ  CODE_SEL,          CodeSeg32 - NullSeg
100.equ  DATA_SEL,          DataSeg32 - NullSeg
101.equ  TSS_SEL,           TssSeg - NullSeg
102.equ  EXCEPTION_TSS_SEL, ExceptionTssSeg - NullSeg
103
104# IA32 TSS fields
105.equ  TSS_ESP0,          4
106.equ  TSS_SS0,           8
107.equ  TSS_ESP1,          12
108.equ  TSS_SS1,           16
109.equ  TSS_ESP2,          20
110.equ  TSS_SS2,           24
111.equ  TSS_CR3,           28
112.equ  TSS_EIP,           32
113.equ  TSS_EFLAGS,        36
114.equ  TSS_EAX,           40
115.equ  TSS_ECX,           44
116.equ  TSS_EDX,           48
117.equ  TSS_EBX,           52
118.equ  TSS_ESP,           56
119.equ  TSS_EBP,           60
120.equ  TSS_ESI,           64
121.equ  TSS_EDI,           68
122.equ  TSS_ES,            72
123.equ  TSS_CS,            76
124.equ  TSS_SS,            80
125.equ  TSS_DS,            84
126.equ  TSS_FS,            88
127.equ  TSS_GS,            92
128.equ  TSS_LDT,           96
129
130# Create 2 TSS segments just after GDT
131TssDescriptor:
132            .word      0                   # PreviousTaskLink
133            .word      0                   # Reserved
134            .long      0                   # ESP0
135            .word      0                   # SS0
136            .word      0                   # Reserved
137            .long      0                   # ESP1
138            .word      0                   # SS1
139            .word      0                   # Reserved
140            .long      0                   # ESP2
141            .word      0                   # SS2
142            .word      0                   # Reserved
143            .long      0                   # CR3
144            .long      0                   # EIP
145            .long      0                   # EFLAGS
146            .long      0                   # EAX
147            .long      0                   # ECX
148            .long      0                   # EDX
149            .long      0                   # EBX
150            .long      0                   # ESP
151            .long      0                   # EBP
152            .long      0                   # ESI
153            .long      0                   # EDI
154            .word      0                   # ES
155            .word      0                   # Reserved
156            .word      0                   # CS
157            .word      0                   # Reserved
158            .word      0                   # SS
159            .word      0                   # Reserved
160            .word      0                   # DS
161            .word      0                   # Reserved
162            .word      0                   # FS
163            .word      0                   # Reserved
164            .word      0                   # GS
165            .word      0                   # Reserved
166            .word      0                   # LDT Selector
167            .word      0                   # Reserved
168            .word      0                   # T
169            .word      0                   # I/O Map Base
170.equ TSS_DESC_SIZE, . - TssDescriptor
171
172ExceptionTssDescriptor:
173            .word      0                   # PreviousTaskLink
174            .word      0                   # Reserved
175            .long      0                   # ESP0
176            .word      0                   # SS0
177            .word      0                   # Reserved
178            .long      0                   # ESP1
179            .word      0                   # SS1
180            .word      0                   # Reserved
181            .long      0                   # ESP2
182            .word      0                   # SS2
183            .word      0                   # Reserved
184            .long      0                   # CR3
185            .long      PFHandlerEntry      # EIP
186            .long      00000002            # EFLAGS
187            .long      0                   # EAX
188            .long      0                   # ECX
189            .long      0                   # EDX
190            .long      0                   # EBX
191            .long      0                   # ESP
192            .long      0                   # EBP
193            .long      0                   # ESI
194            .long      0                   # EDI
195            .word      DATA_SEL            # ES
196            .word      0                   # Reserved
197            .word      CODE_SEL            # CS
198            .word      0                   # Reserved
199            .word      DATA_SEL            # SS
200            .word      0                   # Reserved
201            .word      DATA_SEL            # DS
202            .word      0                   # Reserved
203            .word      DATA_SEL            # FS
204            .word      0                   # Reserved
205            .word      DATA_SEL            # GS
206            .word      0                   # Reserved
207            .word      0                   # LDT Selector
208            .word      0                   # Reserved
209            .word      0                   # T
210            .word      0                   # I/O Map Base
211
212ASM_PFX(gcPsd):
213            .ascii  "PSDSIG  "
214            .word      PSD_SIZE
215            .word 2
216            .word      1 << 2
217            .word      CODE_SEL
218            .word      DATA_SEL
219            .word      DATA_SEL
220            .word      DATA_SEL
221            .word 0
222            .long 0
223            .long 0
224            .long 0
225            .long 0
226            .quad 0
227            .long      NullSeg
228            .long 0
229            .long      GDT_SIZE
230            .long 0
231            .space 24, 0
232            .long      ASM_PFX(gSmiMtrrs)
233            .long 0
234.equ  PSD_SIZE,  . - ASM_PFX(gcPsd)
235
236ASM_PFX(gcSmiGdtr):  .word      GDT_SIZE - 1
237                     .long      NullSeg
238
239ASM_PFX(gcSmiIdtr):  .word      IDT_SIZE - 1
240                     .long      _SmiIDT
241
242_SmiIDT:
243# The following segment repeats 32 times:
244# No. 1
245    .word 0                             # Offset 0:15
246    .word      CODE_SEL
247    .byte 0                             # Unused
248    .byte 0x8e                          # Interrupt Gate, Present
249    .word 0                             # Offset 16:31
250# No. 2
251    .word 0                             # Offset 0:15
252    .word      CODE_SEL
253    .byte 0                             # Unused
254    .byte 0x8e                          # Interrupt Gate, Present
255    .word 0                             # Offset 16:31
256# No. 3
257    .word 0                             # Offset 0:15
258    .word      CODE_SEL
259    .byte 0                             # Unused
260    .byte 0x8e                          # Interrupt Gate, Present
261    .word 0                             # Offset 16:31
262# No. 4
263    .word 0                             # Offset 0:15
264    .word      CODE_SEL
265    .byte 0                             # Unused
266    .byte 0x8e                          # Interrupt Gate, Present
267    .word 0                             # Offset 16:31
268# No. 5
269    .word 0                             # Offset 0:15
270    .word      CODE_SEL
271    .byte 0                             # Unused
272    .byte 0x8e                          # Interrupt Gate, Present
273    .word 0                             # Offset 16:31
274# No. 6
275    .word 0                             # Offset 0:15
276    .word      CODE_SEL
277    .byte 0                             # Unused
278    .byte 0x8e                          # Interrupt Gate, Present
279    .word 0                             # Offset 16:31
280# No. 7
281    .word 0                             # Offset 0:15
282    .word      CODE_SEL
283    .byte 0                             # Unused
284    .byte 0x8e                          # Interrupt Gate, Present
285    .word 0                             # Offset 16:31
286# No. 8
287    .word 0                             # Offset 0:15
288    .word      CODE_SEL
289    .byte 0                             # Unused
290    .byte 0x8e                          # Interrupt Gate, Present
291    .word 0                             # Offset 16:31
292# No. 9
293    .word 0                             # Offset 0:15
294    .word      CODE_SEL
295    .byte 0                             # Unused
296    .byte 0x8e                          # Interrupt Gate, Present
297    .word 0                             # Offset 16:31
298# No. 10
299    .word 0                             # Offset 0:15
300    .word      CODE_SEL
301    .byte 0                             # Unused
302    .byte 0x8e                          # Interrupt Gate, Present
303    .word 0                             # Offset 16:31
304# No. 11
305    .word 0                             # Offset 0:15
306    .word      CODE_SEL
307    .byte 0                             # Unused
308    .byte 0x8e                          # Interrupt Gate, Present
309    .word 0                             # Offset 16:31
310# No. 12
311    .word 0                             # Offset 0:15
312    .word      CODE_SEL
313    .byte 0                             # Unused
314    .byte 0x8e                          # Interrupt Gate, Present
315    .word 0                             # Offset 16:31
316# No. 13
317    .word 0                             # Offset 0:15
318    .word      CODE_SEL
319    .byte 0                             # Unused
320    .byte 0x8e                          # Interrupt Gate, Present
321    .word 0                             # Offset 16:31
322# No. 14
323    .word 0                             # Offset 0:15
324    .word      CODE_SEL
325    .byte 0                             # Unused
326    .byte 0x8e                          # Interrupt Gate, Present
327    .word 0                             # Offset 16:31
328# No. 15
329    .word 0                             # Offset 0:15
330    .word      CODE_SEL
331    .byte 0                             # Unused
332    .byte 0x8e                          # Interrupt Gate, Present
333    .word 0                             # Offset 16:31
334# No. 16
335    .word 0                             # Offset 0:15
336    .word      CODE_SEL
337    .byte 0                             # Unused
338    .byte 0x8e                          # Interrupt Gate, Present
339    .word 0                             # Offset 16:31
340# No. 17
341    .word 0                             # Offset 0:15
342    .word      CODE_SEL
343    .byte 0                             # Unused
344    .byte 0x8e                          # Interrupt Gate, Present
345    .word 0                             # Offset 16:31
346# No. 18
347    .word 0                             # Offset 0:15
348    .word      CODE_SEL
349    .byte 0                             # Unused
350    .byte 0x8e                          # Interrupt Gate, Present
351    .word 0                             # Offset 16:31
352# No. 19
353    .word 0                             # Offset 0:15
354    .word      CODE_SEL
355    .byte 0                             # Unused
356    .byte 0x8e                          # Interrupt Gate, Present
357    .word 0                             # Offset 16:31
358# No. 20
359    .word 0                             # Offset 0:15
360    .word      CODE_SEL
361    .byte 0                             # Unused
362    .byte 0x8e                          # Interrupt Gate, Present
363    .word 0                             # Offset 16:31
364# No. 21
365    .word 0                             # Offset 0:15
366    .word      CODE_SEL
367    .byte 0                             # Unused
368    .byte 0x8e                          # Interrupt Gate, Present
369    .word 0                             # Offset 16:31
370# No. 22
371    .word 0                             # Offset 0:15
372    .word      CODE_SEL
373    .byte 0                             # Unused
374    .byte 0x8e                          # Interrupt Gate, Present
375    .word 0                             # Offset 16:31
376# No. 23
377    .word 0                             # Offset 0:15
378    .word      CODE_SEL
379    .byte 0                             # Unused
380    .byte 0x8e                          # Interrupt Gate, Present
381    .word 0                             # Offset 16:31
382# No. 24
383    .word 0                             # Offset 0:15
384    .word      CODE_SEL
385    .byte 0                             # Unused
386    .byte 0x8e                          # Interrupt Gate, Present
387    .word 0                             # Offset 16:31
388# No. 25
389    .word 0                             # Offset 0:15
390    .word      CODE_SEL
391    .byte 0                             # Unused
392    .byte 0x8e                          # Interrupt Gate, Present
393    .word 0                             # Offset 16:31
394# No. 26
395    .word 0                             # Offset 0:15
396    .word      CODE_SEL
397    .byte 0                             # Unused
398    .byte 0x8e                          # Interrupt Gate, Present
399    .word 0                             # Offset 16:31
400# No. 27
401    .word 0                             # Offset 0:15
402    .word      CODE_SEL
403    .byte 0                             # Unused
404    .byte 0x8e                          # Interrupt Gate, Present
405    .word 0                             # Offset 16:31
406# No. 28
407    .word 0                             # Offset 0:15
408    .word      CODE_SEL
409    .byte 0                             # Unused
410    .byte 0x8e                          # Interrupt Gate, Present
411    .word 0                             # Offset 16:31
412# No. 29
413    .word 0                             # Offset 0:15
414    .word      CODE_SEL
415    .byte 0                             # Unused
416    .byte 0x8e                          # Interrupt Gate, Present
417    .word 0                             # Offset 16:31
418# No. 30
419    .word 0                             # Offset 0:15
420    .word      CODE_SEL
421    .byte 0                             # Unused
422    .byte 0x8e                          # Interrupt Gate, Present
423    .word 0                             # Offset 16:31
424# No. 31
425    .word 0                             # Offset 0:15
426    .word      CODE_SEL
427    .byte 0                             # Unused
428    .byte 0x8e                          # Interrupt Gate, Present
429    .word 0                             # Offset 16:31
430# No. 32
431    .word 0                             # Offset 0:15
432    .word      CODE_SEL
433    .byte 0                             # Unused
434    .byte 0x8e                          # Interrupt Gate, Present
435    .word 0                             # Offset 16:31
436
437.equ  IDT_SIZE, . - _SmiIDT
438
439TaskGateDescriptor:
440    .word      0                        # Reserved
441    .word      EXCEPTION_TSS_SEL        # TSS Segment selector
442    .byte      0                        # Reserved
443    .byte      0x85                     # Task Gate, present, DPL = 0
444    .word      0                        # Reserved
445
446    .text
447
448#------------------------------------------------------------------------------
449# PageFaultIdtHandlerSmmProfile is the entry point for all exceptions
450#
451# Stack:
452#+---------------------+
453#+    EFlags           +
454#+---------------------+
455#+    CS               +
456#+---------------------+
457#+    EIP              +
458#+---------------------+
459#+    Error Code       +
460#+---------------------+
461#+    Vector Number    +
462#+---------------------+
463#+    EBP              +
464#+---------------------+ <-- EBP
465#
466# RSP set to odd multiple of 8 means ErrCode PRESENT
467#------------------------------------------------------------------------------
468ASM_GLOBAL ASM_PFX(PageFaultIdtHandlerSmmProfile)
469ASM_PFX(PageFaultIdtHandlerSmmProfile):
470    pushl   $0x0e               # Page Fault
471    pushl   %ebp
472    movl    %esp, %ebp
473
474
475    #
476    # Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
477    # is 16-byte aligned
478    #
479    andl    $0xfffffff0, %esp
480    subl    $12, %esp
481
482## UINT32  Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
483    pushl   %eax
484    pushl   %ecx
485    pushl   %edx
486    pushl   %ebx
487    leal    (6*4)(%ebp), %ecx
488    pushl   %ecx                          # ESP
489    pushl   (%ebp)                        # EBP
490    pushl   %esi
491    pushl   %edi
492
493## UINT32  Gs, Fs, Es, Ds, Cs, Ss;
494    movl    %ss, %eax
495    pushl   %eax
496    movzwl  (4*4)(%ebp), %eax
497    pushl   %eax
498    movl    %ds, %eax
499    pushl   %eax
500    movl    %es, %eax
501    pushl   %eax
502    movl    %fs, %eax
503    pushl   %eax
504    movl    %gs, %eax
505    pushl   %eax
506
507## UINT32  Eip;
508    movl    (3*4)(%ebp), %eax
509    pushl   %eax
510
511## UINT32  Gdtr[2], Idtr[2];
512    subl    $8, %esp
513    sidt    (%esp)
514    movl    2(%esp), %eax
515    xchgl   (%esp), %eax
516    andl    $0xffff, %eax
517    movl    %eax, 4(%esp)
518
519    subl    $8, %esp
520    sgdt    (%esp)
521    movl    2(%esp), %eax
522    xchgl   (%esp), %eax
523    andl    $0xffff, %eax
524    movl    %eax, 4(%esp)
525
526## UINT32  Ldtr, Tr;
527    xorl    %eax, %eax
528    strw    %ax
529    pushl   %eax
530    sldtw   %ax
531    pushl   %eax
532
533## UINT32  EFlags;
534    movl    (5*4)(%ebp), %eax
535    pushl   %eax
536
537## UINT32  Cr0, Cr1, Cr2, Cr3, Cr4;
538    movl    %cr4, %eax
539    orl     $0x208, %eax
540    movl    %eax, %cr4
541    pushl   %eax
542    movl    %cr3, %eax
543    pushl   %eax
544    movl    %cr2, %eax
545    pushl   %eax
546    xorl    %eax, %eax
547    pushl   %eax
548    movl    %cr0, %eax
549    pushl   %eax
550
551## UINT32  Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
552    movl    %dr7, %eax
553    pushl   %eax
554    movl    %dr6, %eax
555    pushl   %eax
556    movl    %dr3, %eax
557    pushl   %eax
558    movl    %dr2, %eax
559    pushl   %eax
560    movl    %dr1, %eax
561    pushl   %eax
562    movl    %dr0, %eax
563    pushl   %eax
564
565## FX_SAVE_STATE_IA32 FxSaveState;
566    subl    $512, %esp
567    movl    %esp, %edi
568    .byte   0x0f, 0xae, 0x07                  #fxsave [edi]
569
570# UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
571    cld
572
573## UINT32  ExceptionData;
574    pushl   (2*4)(%ebp)
575
576## call into exception handler
577
578## Prepare parameter and call
579    movl    %esp, %edx
580    pushl   %edx
581    movl    (1*4)(%ebp), %edx
582    pushl   %edx
583
584    #
585    # Call External Exception Handler
586    #
587    movl    $ASM_PFX(SmiPFHandler), %eax
588    call    *%eax
589    addl    $8, %esp
590    jmp     L4
591
592L4:
593## UINT32  ExceptionData;
594    addl    $4, %esp
595
596## FX_SAVE_STATE_IA32 FxSaveState;
597    movl    %esp, %esi
598    .byte   0xf, 0xae, 0xe                 # fxrstor [esi]
599    addl    $512, %esp
600
601## UINT32  Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
602## Skip restoration of DRx registers to support debuggers
603## that set breakpoints in interrupt/exception context
604    addl    $4*6, %esp
605
606## UINT32  Cr0, Cr1, Cr2, Cr3, Cr4;
607    popl    %eax
608    movl    %eax, %cr0
609    addl    $4, %esp                       # not for Cr1
610    popl    %eax
611    movl    %eax, %cr2
612    popl    %eax
613    movl    %eax, %cr3
614    popl    %eax
615    movl    %eax, %cr4
616
617## UINT32  EFlags;
618    popl    (5*4)(%ebp)
619
620## UINT32  Ldtr, Tr;
621## UINT32  Gdtr[2], Idtr[2];
622## Best not let anyone mess with these particular registers...
623    addl    $24, %esp
624
625## UINT32  Eip;
626    popl    (3*4)(%ebp)
627
628## UINT32  Gs, Fs, Es, Ds, Cs, Ss;
629## NOTE - modified segment registers could hang the debugger...  We
630##        could attempt to insulate ourselves against this possibility,
631##        but that poses risks as well.
632##
633    popl    %gs
634    popl    %fs
635    popl    %es
636    popl    %ds
637    popl    (4*4)(%ebp)
638    popl    %ss
639
640## UINT32  Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
641    popl    %edi
642    popl    %esi
643    addl    $4, %esp                      # not for ebp
644    addl    $4, %esp                      # not for esp
645    popl    %ebx
646    popl    %edx
647    popl    %ecx
648    popl    %eax
649
650    movl    %ebp, %esp
651    popl    %ebp
652
653# Enable TF bit after page fault handler runs
654    btsl    $8, 16(%esp)                  # EFLAGS
655
656    addl    $8, %esp                      # skip INT# & ErrCode
657Return:
658    iret
659#
660# Page Fault Exception Handler entry when SMM Stack Guard is enabled
661# Executiot starts here after a task switch
662#
663PFHandlerEntry:
664#
665# Get this processor's TSS
666#
667    subl    $8, %esp
668    sgdt    2(%esp)
669    movl    4(%esp), %eax                 # GDT base
670    addl    $8, %esp
671    movl    (TSS_SEL+2)(%eax), %ecx
672    shll    $8, %ecx
673    movb    (TSS_SEL+7)(%eax), %cl
674    rorl    $8, %ecx                      # ecx = TSS base
675
676    movl    %esp, %ebp
677
678    #
679    # Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
680    # is 16-byte aligned
681    #
682    andl    $0xfffffff0, %esp
683    subl    $12, %esp
684
685## UINT32  Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
686    pushl   TSS_EAX(%ecx)
687    pushl   TSS_ECX(%ecx)
688    pushl   TSS_EDX(%ecx)
689    pushl   TSS_EBX(%ecx)
690    pushl   TSS_ESP(%ecx)
691    pushl   TSS_EBP(%ecx)
692    pushl   TSS_ESI(%ecx)
693    pushl   TSS_EDI(%ecx)
694
695## UINT32  Gs, Fs, Es, Ds, Cs, Ss;
696    movzwl  TSS_SS(%ecx), %eax
697    pushl   %eax
698    movzwl  TSS_CS(%ecx), %eax
699    pushl   %eax
700    movzwl  TSS_DS(%ecx), %eax
701    pushl   %eax
702    movzwl  TSS_ES(%ecx), %eax
703    pushl   %eax
704    movzwl  TSS_FS(%ecx), %eax
705    pushl   %eax
706    movzwl  TSS_GS(%ecx), %eax
707    pushl   %eax
708
709## UINT32  Eip;
710    pushl   TSS_EIP(%ecx)
711
712## UINT32  Gdtr[2], Idtr[2];
713    subl    $8, %esp
714    sidt    (%esp)
715    movl    2(%esp), %eax
716    xchgl   (%esp), %eax
717    andl    $0xFFFF, %eax
718    movl    %eax, 4(%esp)
719
720    subl    $8, %esp
721    sgdt    (%esp)
722    movl    2(%esp), %eax
723    xchgl   (%esp), %eax
724    andl    $0xFFFF, %eax
725    movl    %eax, 4(%esp)
726
727## UINT32  Ldtr, Tr;
728    movl    $TSS_SEL, %eax
729    pushl   %eax
730    movzwl  TSS_LDT(%ecx), %eax
731    pushl   %eax
732
733## UINT32  EFlags;
734    pushl   TSS_EFLAGS(%ecx)
735
736## UINT32  Cr0, Cr1, Cr2, Cr3, Cr4;
737    movl    %cr4, %eax
738    orl     $0x208, %eax
739    movl    %eax, %cr4
740    pushl   %eax
741    movl    %cr3, %eax
742    pushl   %eax
743    movl    %cr2, %eax
744    pushl   %eax
745    xorl    %eax, %eax
746    pushl   %eax
747    movl    %cr0, %eax
748    pushl   %eax
749
750## UINT32  Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
751    movl    %dr7, %eax
752    pushl   %eax
753    movl    %dr6, %eax
754    pushl   %eax
755    movl    %dr3, %eax
756    pushl   %eax
757    movl    %dr2, %eax
758    pushl   %eax
759    movl    %dr1, %eax
760    pushl   %eax
761    movl    %dr0, %eax
762    pushl   %eax
763
764## FX_SAVE_STATE_IA32 FxSaveState;
765## Clear TS bit in CR0 to avoid Device Not Available Exception (#NM)
766## when executing fxsave/fxrstor instruction
767    clts
768    subl    $512, %esp
769    movl    %esp, %edi
770    .byte   0x0f, 0xae, 0x07                   #fxsave [edi]
771
772# UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
773    cld
774
775## UINT32  ExceptionData;
776    pushl   (%ebp)
777
778## call into exception handler
779    movl    %ecx, %ebx
780    movl    $ASM_PFX(SmiPFHandler), %eax
781
782## Prepare parameter and call
783    movl    %esp, %edx
784    pushl   %edx
785    movl    $14, %edx
786    pushl   %edx
787
788    #
789    # Call External Exception Handler
790    #
791    call    *%eax
792    addl    $8, %esp
793
794    movl    %ebx, %ecx
795## UINT32  ExceptionData;
796    addl    $4, %esp
797
798## FX_SAVE_STATE_IA32 FxSaveState;
799    movl    %esp, %esi
800    .byte   0xf, 0xae, 0xe                     # fxrstor [esi]
801    addl    $512, %esp
802
803## UINT32  Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
804## Skip restoration of DRx registers to support debuggers
805## that set breakpoints in interrupt/exception context
806    addl    $4*6, %esp
807
808## UINT32  Cr0, Cr1, Cr2, Cr3, Cr4;
809    popl    %eax
810    movl    %eax, %cr0
811    addl    $4, %esp                           # not for Cr1
812    popl    %eax
813    movl    %eax, %cr2
814    popl    %eax
815    movl    %eax, TSS_CR3(%ecx)
816    popl    %eax
817    movl    %eax, %cr4
818
819## UINT32  EFlags;
820    popl    TSS_EFLAGS(%ecx)
821
822## UINT32  Ldtr, Tr;
823## UINT32  Gdtr[2], Idtr[2];
824## Best not let anyone mess with these particular registers...
825    addl    $24, %esp
826
827## UINT32  Eip;
828    popl    TSS_EIP(%ecx)
829
830## UINT32  Gs, Fs, Es, Ds, Cs, Ss;
831## NOTE - modified segment registers could hang the debugger...  We
832##        could attempt to insulate ourselves against this possibility,
833##        but that poses risks as well.
834##
835    popl    %eax
836    movw    %ax, TSS_GS(%ecx)
837    popl    %eax
838    movw    %ax, TSS_FS(%ecx)
839    popl    %eax
840    movw    %ax, TSS_ES(%ecx)
841    popl    %eax
842    movw    %ax, TSS_DS(%ecx)
843    popl    %eax
844    movw    %ax, TSS_CS(%ecx)
845    popl    %eax
846    movw    %ax, TSS_SS(%ecx)
847
848## UINT32  Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
849    popl    TSS_EDI(%ecx)
850    popl    TSS_ESI(%ecx)
851    addl    $4, %esp                           # not for ebp
852    addl    $4, %esp                           # not for esp
853    popl    TSS_EBX(%ecx)
854    popl    TSS_EDX(%ecx)
855    popl    TSS_ECX(%ecx)
856    popl    TSS_EAX(%ecx)
857
858    movl    %ebp, %esp
859
860# Set single step DB# if SMM profile is enabled and page fault exception happens
861    cmpb    $0, ASM_PFX(FeaturePcdGet (PcdCpuSmmProfileEnable))
862    jz      Done2
863# Create return context for iret in stub function
864     movl   TSS_ESP(%ecx), %eax                   # Get old stack pointer
865     movl   TSS_EIP(%ecx), %ebx
866     movl   %ebx, -0xc(%eax)                      # create EIP in old stack
867     movzwl TSS_CS(%ecx), %ebx
868     movl   %ebx, -0x8(%eax)                      # create CS in old stack
869     movl   TSS_EFLAGS(%ecx), %ebx
870     btsl   $8,%ebx
871     movl   %ebx, -0x4(%eax)                      # create eflags in old stack
872     movl   TSS_ESP(%ecx), %eax                   # Get old stack pointer
873     subl   $12, %eax                             # minus 12 byte
874     movl   %eax, TSS_ESP(%ecx)                   # Set new stack pointer
875
876# Replace the EIP of interrupted task with stub function
877    movl    $ASM_PFX(PageFaultStubFunction), %eax
878    movl   %eax, TSS_EIP(%ecx)
879# Jump to the iret so next page fault handler as a task will start again after iret.
880
881Done2:
882
883    addl    $4, %esp                            # skip ErrCode
884
885    jmp     Return
886
887ASM_PFX(PageFaultStubFunction):
888#
889# we need clean TS bit in CR0 to execute
890# x87 FPU/MMX/SSE/SSE2/SSE3/SSSE3/SSE4 instructions.
891#
892    clts
893    iret
894
895ASM_GLOBAL ASM_PFX(InitializeIDTSmmStackGuard)
896ASM_PFX(InitializeIDTSmmStackGuard):
897    pushl   %ebx
898#
899# If SMM Stack Guard feature is enabled, the Page Fault Exception entry in IDT
900# is a Task Gate Descriptor so that when a Page Fault Exception occurs,
901# the processors can use a known good stack in case stack ran out.
902#
903    leal    _SmiIDT + 14 * 8, %ebx
904    leal    TaskGateDescriptor, %edx
905    movl    (%edx), %eax
906    movl    %eax, (%ebx)
907    movl    4(%edx), %eax
908    movl    %eax, 4(%ebx)
909
910    popl    %ebx
911    ret
912