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.
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 ;-------------------------------------------------------------------------------
21 extern ASM_PFX(FeaturePcdGet (PcdCpuSmmProfileEnable))
22 extern ASM_PFX(gSmiMtrrs)
23 extern ASM_PFX(SmiPFHandler)
25 global ASM_PFX(gcSmiIdtr)
26 global ASM_PFX(gcSmiGdtr)
27 global ASM_PFX(gTaskGateDescriptor)
32 NullSeg: DQ 0 ; reserved by architecture
82 GDT_SIZE equ $ - NullSeg
85 DW TSS_DESC_SIZE ; LimitLow
92 DW TSS_DESC_SIZE ; LimitLow
99 CODE_SEL equ CodeSeg32 - NullSeg
100 DATA_SEL equ DataSeg32 - NullSeg
101 TSS_SEL equ TssSeg - NullSeg
102 EXCEPTION_TSS_SEL equ ExceptionTssSeg - NullSeg
145 ; Create 2 TSS segments just after GDT
147 DW 0 ; PreviousTaskLink
185 TSS_DESC_SIZE equ $ - TssDescriptor
187 ExceptionTssDescriptor:
188 DW 0 ; PreviousTaskLink
200 DD PFHandlerEntry ; EIP
246 DD ASM_PFX(gSmiMtrrs)
247 PSD_SIZE equ $ - ASM_PFX(gcPsd)
257 ASM_PFX(gTaskGateDescriptor):
259 DW EXCEPTION_TSS_SEL ; TSS Segment selector
261 DB 0x85 ; Task Gate, present, DPL = 0
265 ;------------------------------------------------------------------------------
266 ; PageFaultIdtHandlerSmmProfile is the entry point page fault only
270 ; +---------------------+
272 ; +---------------------+
274 ; +---------------------+
276 ; +---------------------+
278 ; +---------------------+
280 ; +---------------------+
282 ; +---------------------+ <-- EBP
285 ;------------------------------------------------------------------------------
286 global ASM_PFX(PageFaultIdtHandlerSmmProfile)
287 ASM_PFX(PageFaultIdtHandlerSmmProfile):
288 push 0xe ; Page Fault
294 ; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
300 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
305 lea ecx, [ebp + 6 * 4]
307 push dword [ebp] ; EBP
311 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
314 movzx eax, word [ebp + 4 * 4]
326 mov eax, [ebp + 3 * 4]
329 ;; UINT32 Gdtr[2], Idtr[2];
352 mov eax, [ebp + 5 * 4]
355 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
369 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
383 ;; FX_SAVE_STATE_IA32 FxSaveState;
386 db 0xf, 0xae, 0x7 ;fxsave [edi]
388 ; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
391 ;; UINT32 ExceptionData;
392 push dword [ebp + 2 * 4]
394 ;; call into exception handler
396 ;; Prepare parameter and call
399 mov edx, dword [ebp + 1 * 4]
403 ; Call External Exception Handler
405 mov eax, ASM_PFX(SmiPFHandler)
409 ;; UINT32 ExceptionData;
412 ;; FX_SAVE_STATE_IA32 FxSaveState;
414 db 0xf, 0xae, 0xe ; fxrstor [esi]
417 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
418 ;; Skip restoration of DRx registers to support debuggers
419 ;; that set breakpoint in interrupt/exception context
422 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
425 add esp, 4 ; not for Cr1
434 pop dword [ebp + 5 * 4]
437 ;; UINT32 Gdtr[2], Idtr[2];
438 ;; Best not let anyone mess with these particular registers...
442 pop dword [ebp + 3 * 4]
444 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
445 ;; NOTE - modified segment registers could hang the debugger... We
446 ;; could attempt to insulate ourselves against this possibility,
447 ;; but that poses risks as well.
453 pop dword [ebp + 4 * 4]
456 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
459 add esp, 4 ; not for ebp
460 add esp, 4 ; not for esp
469 ; Enable TF bit after page fault handler runs
470 bts dword [esp + 16], 8 ; EFLAGS
472 add esp, 8 ; skip INT# & ErrCode
476 ; Page Fault Exception Handler entry when SMM Stack Guard is enabled
477 ; Executiot starts here after a task switch
481 ; Get this processor's TSS
485 mov eax, [esp + 4] ; GDT base
487 mov ecx, [eax + TSS_SEL + 2]
489 mov cl, [eax + TSS_SEL + 7]
490 ror ecx, 8 ; ecx = TSS base
495 ; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
501 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
502 push dword [ecx + IA32_TSS._EAX]
503 push dword [ecx + IA32_TSS._ECX]
504 push dword [ecx + IA32_TSS._EDX]
505 push dword [ecx + IA32_TSS._EBX]
506 push dword [ecx + IA32_TSS._ESP]
507 push dword [ecx + IA32_TSS._EBP]
508 push dword [ecx + IA32_TSS._ESI]
509 push dword [ecx + IA32_TSS._EDI]
511 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
512 movzx eax, word [ecx + IA32_TSS._SS]
514 movzx eax, word [ecx + IA32_TSS._CS]
516 movzx eax, word [ecx + IA32_TSS._DS]
518 movzx eax, word [ecx + IA32_TSS._ES]
520 movzx eax, word [ecx + IA32_TSS._FS]
522 movzx eax, word [ecx + IA32_TSS._GS]
526 push dword [ecx + IA32_TSS.EIP]
528 ;; UINT32 Gdtr[2], Idtr[2];
546 movzx eax, word [ecx + IA32_TSS.LDT]
550 push dword [ecx + IA32_TSS.EFLAGS]
552 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
566 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
580 ;; FX_SAVE_STATE_IA32 FxSaveState;
581 ;; Clear TS bit in CR0 to avoid Device Not Available Exception (#NM)
582 ;; when executing fxsave/fxrstor instruction
586 db 0xf, 0xae, 0x7 ;fxsave [edi]
588 ; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
591 ;; UINT32 ExceptionData;
594 ;; call into exception handler
596 mov eax, ASM_PFX(SmiPFHandler)
598 ;; Prepare parameter and call
605 ; Call External Exception Handler
611 ;; UINT32 ExceptionData;
614 ;; FX_SAVE_STATE_IA32 FxSaveState;
616 db 0xf, 0xae, 0xe ; fxrstor [esi]
619 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
620 ;; Skip restoration of DRx registers to support debuggers
621 ;; that set breakpoints in interrupt/exception context
624 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
627 add esp, 4 ; not for Cr1
631 mov dword [ecx + IA32_TSS._CR3], eax
636 pop dword [ecx + IA32_TSS.EFLAGS]
639 ;; UINT32 Gdtr[2], Idtr[2];
640 ;; Best not let anyone mess with these particular registers...
644 pop dword [ecx + IA32_TSS.EIP]
646 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
647 ;; NOTE - modified segment registers could hang the debugger... We
648 ;; could attempt to insulate ourselves against this possibility,
649 ;; but that poses risks as well.
652 o16 mov [ecx + IA32_TSS._GS], ax
654 o16 mov [ecx + IA32_TSS._FS], ax
656 o16 mov [ecx + IA32_TSS._ES], ax
658 o16 mov [ecx + IA32_TSS._DS], ax
660 o16 mov [ecx + IA32_TSS._CS], ax
662 o16 mov [ecx + IA32_TSS._SS], ax
664 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
665 pop dword [ecx + IA32_TSS._EDI]
666 pop dword [ecx + IA32_TSS._ESI]
667 add esp, 4 ; not for ebp
668 add esp, 4 ; not for esp
669 pop dword [ecx + IA32_TSS._EBX]
670 pop dword [ecx + IA32_TSS._EDX]
671 pop dword [ecx + IA32_TSS._ECX]
672 pop dword [ecx + IA32_TSS._EAX]
676 ; Set single step DB# if SMM profile is enabled and page fault exception happens
677 cmp byte [dword ASM_PFX(FeaturePcdGet (PcdCpuSmmProfileEnable))], 0
680 ; Create return context for iretd in stub function
681 mov eax, dword [ecx + IA32_TSS._ESP] ; Get old stack pointer
682 mov ebx, dword [ecx + IA32_TSS.EIP]
683 mov [eax - 0xc], ebx ; create EIP in old stack
684 movzx ebx, word [ecx + IA32_TSS._CS]
685 mov [eax - 0x8], ebx ; create CS in old stack
686 mov ebx, dword [ecx + IA32_TSS.EFLAGS]
688 mov [eax - 0x4], ebx ; create eflags in old stack
689 mov eax, dword [ecx + IA32_TSS._ESP] ; Get old stack pointer
690 sub eax, 0xc ; minus 12 byte
691 mov dword [ecx + IA32_TSS._ESP], eax ; Set new stack pointer
692 ; Replace the EIP of interrupted task with stub function
693 mov eax, ASM_PFX(PageFaultStubFunction)
694 mov dword [ecx + IA32_TSS.EIP], eax
695 ; Jump to the iretd so next page fault handler as a task will start again after iretd.
697 add esp, 4 ; skip ErrCode
701 global ASM_PFX(PageFaultStubFunction)
702 ASM_PFX(PageFaultStubFunction):
704 ; we need clean TS bit in CR0 to execute
705 ; x87 FPU/MMX/SSE/SSE2/SSE3/SSSE3/SSE4 instructions.