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.
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.
17 ; Exception handlers used in SM mode
19 ;-------------------------------------------------------------------------------
24 EXTERNDEF SmiPFHandler:PROC
25 EXTERNDEF PageFaultStubFunction:PROC
26 EXTERNDEF gSmiMtrrs:QWORD
27 EXTERNDEF gcSmiIdtr:FWORD
28 EXTERNDEF gcSmiGdtr:FWORD
30 EXTERNDEF FeaturePcdGet (PcdCpuSmmProfileEnable):BYTE
35 NullSeg DQ 0 ; reserved by architecture
43 ProtModeCodeSeg32 LABEL QWORD
50 ProtModeSsSeg32 LABEL QWORD
85 GDT_SIZE = $ - offset NullSeg
88 DW TSS_DESC_SIZE ; LimitLow
94 ExceptionTssSeg LABEL QWORD
95 DW TSS_DESC_SIZE ; LimitLow
102 CODE_SEL = offset CodeSeg32 - offset NullSeg
103 DATA_SEL = offset DataSeg32 - offset NullSeg
104 TSS_SEL = offset TssSeg - offset NullSeg
105 EXCEPTION_TSS_SEL = offset ExceptionTssSeg - offset NullSeg
148 ; Create 2 TSS segments just after GDT
149 TssDescriptor LABEL BYTE
150 DW 0 ; PreviousTaskLink
188 TSS_DESC_SIZE = $ - offset TssDescriptor
190 ExceptionTssDescriptor LABEL BYTE
191 DW 0 ; PreviousTaskLink
203 DD offset PFHandlerEntry ; EIP
248 PSD_SIZE = $ - offset gcPsd
250 gcSmiGdtr LABEL FWORD
254 gcSmiIdtr LABEL FWORD
261 DW CODE_SEL ; Segment selector
263 DB 8eh ; Interrupt Gate, Present
266 IDT_SIZE = $ - offset _SmiIDT
268 TaskGateDescriptor LABEL DWORD
270 DW EXCEPTION_TSS_SEL ; TSS Segment selector
272 DB 85h ; Task Gate, present, DPL = 0
277 ;------------------------------------------------------------------------------
278 ; PageFaultIdtHandlerSmmProfile is the entry point page fault only
282 ; +---------------------+
284 ; +---------------------+
286 ; +---------------------+
288 ; +---------------------+
290 ; +---------------------+
292 ; +---------------------+
294 ; +---------------------+ <-- EBP
297 ;------------------------------------------------------------------------------
298 PageFaultIdtHandlerSmmProfile PROC
299 push 0eh ; Page Fault
306 ; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
312 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
317 lea ecx, [ebp + 6 * 4]
319 push dword ptr [ebp] ; EBP
323 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
326 movzx eax, word ptr [ebp + 4 * 4]
338 mov eax, [ebp + 3 * 4]
341 ;; UINT32 Gdtr[2], Idtr[2];
364 mov eax, [ebp + 5 * 4]
367 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
381 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
395 ;; FX_SAVE_STATE_IA32 FxSaveState;
398 db 0fh, 0aeh, 07h ;fxsave [edi]
400 ; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
403 ;; UINT32 ExceptionData;
404 push dword ptr [ebp + 2 * 4]
406 ;; call into exception handler
408 ;; Prepare parameter and call
411 mov edx, dword ptr [ebp + 1 * 4]
415 ; Call External Exception Handler
417 mov eax, SmiPFHandler
421 ;; UINT32 ExceptionData;
424 ;; FX_SAVE_STATE_IA32 FxSaveState;
426 db 0fh, 0aeh, 0eh ; fxrstor [esi]
429 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
430 ;; Skip restoration of DRx registers to support debuggers
431 ;; that set breakpoint in interrupt/exception context
434 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
437 add esp, 4 ; not for Cr1
446 pop dword ptr [ebp + 5 * 4]
449 ;; UINT32 Gdtr[2], Idtr[2];
450 ;; Best not let anyone mess with these particular registers...
454 pop dword ptr [ebp + 3 * 4]
456 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
457 ;; NOTE - modified segment registers could hang the debugger... We
458 ;; could attempt to insulate ourselves against this possibility,
459 ;; but that poses risks as well.
465 pop dword ptr [ebp + 4 * 4]
468 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
471 add esp, 4 ; not for ebp
472 add esp, 4 ; not for esp
481 ; Enable TF bit after page fault handler runs
482 bts dword ptr [esp + 16], 8 ; EFLAGS
484 add esp, 8 ; skip INT# & ErrCode
488 ; Page Fault Exception Handler entry when SMM Stack Guard is enabled
489 ; Executiot starts here after a task switch
493 ; Get this processor's TSS
497 mov eax, [esp + 4] ; GDT base
499 mov ecx, [eax + TSS_SEL + 2]
501 mov cl, [eax + TSS_SEL + 7]
502 ror ecx, 8 ; ecx = TSS base
507 ; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
513 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
514 push (IA32_TSS ptr [ecx])._EAX
515 push (IA32_TSS ptr [ecx])._ECX
516 push (IA32_TSS ptr [ecx])._EDX
517 push (IA32_TSS ptr [ecx])._EBX
518 push (IA32_TSS ptr [ecx])._ESP
519 push (IA32_TSS ptr [ecx])._EBP
520 push (IA32_TSS ptr [ecx])._ESI
521 push (IA32_TSS ptr [ecx])._EDI
523 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
524 movzx eax, (IA32_TSS ptr [ecx])._SS
526 movzx eax, (IA32_TSS ptr [ecx])._CS
528 movzx eax, (IA32_TSS ptr [ecx])._DS
530 movzx eax, (IA32_TSS ptr [ecx])._ES
532 movzx eax, (IA32_TSS ptr [ecx])._FS
534 movzx eax, (IA32_TSS ptr [ecx])._GS
538 push (IA32_TSS ptr [ecx]).EIP
540 ;; UINT32 Gdtr[2], Idtr[2];
558 movzx eax, (IA32_TSS ptr [ecx]).LDT
562 push (IA32_TSS ptr [ecx]).EFLAGS
564 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
578 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
592 ;; FX_SAVE_STATE_IA32 FxSaveState;
593 ;; Clear TS bit in CR0 to avoid Device Not Available Exception (#NM)
594 ;; when executing fxsave/fxrstor instruction
598 db 0fh, 0aeh, 07h ;fxsave [edi]
600 ; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
603 ;; UINT32 ExceptionData;
606 ;; call into exception handler
608 mov eax, SmiPFHandler
610 ;; Prepare parameter and call
617 ; Call External Exception Handler
623 ;; UINT32 ExceptionData;
626 ;; FX_SAVE_STATE_IA32 FxSaveState;
628 db 0fh, 0aeh, 0eh ; fxrstor [esi]
631 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
632 ;; Skip restoration of DRx registers to support debuggers
633 ;; that set breakpoints in interrupt/exception context
636 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
639 add esp, 4 ; not for Cr1
643 mov (IA32_TSS ptr [ecx])._CR3, eax
648 pop (IA32_TSS ptr [ecx]).EFLAGS
651 ;; UINT32 Gdtr[2], Idtr[2];
652 ;; Best not let anyone mess with these particular registers...
656 pop (IA32_TSS ptr [ecx]).EIP
658 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
659 ;; NOTE - modified segment registers could hang the debugger... We
660 ;; could attempt to insulate ourselves against this possibility,
661 ;; but that poses risks as well.
664 mov (IA32_TSS ptr [ecx])._GS, ax
666 mov (IA32_TSS ptr [ecx])._FS, ax
668 mov (IA32_TSS ptr [ecx])._ES, ax
670 mov (IA32_TSS ptr [ecx])._DS, ax
672 mov (IA32_TSS ptr [ecx])._CS, ax
674 mov (IA32_TSS ptr [ecx])._SS, ax
676 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
677 pop (IA32_TSS ptr [ecx])._EDI
678 pop (IA32_TSS ptr [ecx])._ESI
679 add esp, 4 ; not for ebp
680 add esp, 4 ; not for esp
681 pop (IA32_TSS ptr [ecx])._EBX
682 pop (IA32_TSS ptr [ecx])._EDX
683 pop (IA32_TSS ptr [ecx])._ECX
684 pop (IA32_TSS ptr [ecx])._EAX
688 ; Set single step DB# if SMM profile is enabled and page fault exception happens
689 cmp FeaturePcdGet (PcdCpuSmmProfileEnable), 0
692 ; Create return context for iretd in stub function
693 mov eax, (IA32_TSS ptr [ecx])._ESP ; Get old stack pointer
694 mov ebx, (IA32_TSS ptr [ecx]).EIP
695 mov [eax - 0ch], ebx ; create EIP in old stack
696 movzx ebx, (IA32_TSS ptr [ecx])._CS
697 mov [eax - 08h], ebx ; create CS in old stack
698 mov ebx, (IA32_TSS ptr [ecx]).EFLAGS
700 mov [eax - 04h], ebx ; create eflags in old stack
701 mov eax, (IA32_TSS ptr [ecx])._ESP ; Get old stack pointer
702 sub eax, 0ch ; minus 12 byte
703 mov (IA32_TSS ptr [ecx])._ESP, eax ; Set new stack pointer
704 ; Replace the EIP of interrupted task with stub function
705 mov eax, PageFaultStubFunction
706 mov (IA32_TSS ptr [ecx]).EIP, eax
707 ; Jump to the iretd so next page fault handler as a task will start again after iretd.
709 add esp, 4 ; skip ErrCode
712 PageFaultIdtHandlerSmmProfile ENDP
714 PageFaultStubFunction PROC
716 ; we need clean TS bit in CR0 to execute
717 ; x87 FPU/MMX/SSE/SSE2/SSE3/SSSE3/SSE4 instructions.
721 PageFaultStubFunction ENDP
723 InitializeIDTSmmStackGuard PROC USES ebx
725 ; If SMM Stack Guard feature is enabled, the Page Fault Exception entry in IDT
726 ; is a Task Gate Descriptor so that when a Page Fault Exception occurs,
727 ; the processors can use a known good stack in case stack is ran out.
729 lea ebx, _SmiIDT + 14 * 8
730 lea edx, TaskGateDescriptor
736 InitializeIDTSmmStackGuard ENDP