1 ;------------------------------------------------------------------------------ ;
2 ; Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR>
3 ; SPDX-License-Identifier: BSD-2-Clause-Patent
11 ; Exception handlers used in SM mode
13 ;-------------------------------------------------------------------------------
15 extern ASM_PFX(FeaturePcdGet (PcdCpuSmmProfileEnable))
16 extern ASM_PFX(SmiPFHandler)
17 extern ASM_PFX(mSetupDebugTrap)
19 global ASM_PFX(gcSmiIdtr)
20 global ASM_PFX(gcSmiGdtr)
21 global ASM_PFX(gTaskGateDescriptor)
26 NullSeg: DQ 0 ; reserved by architecture
76 GDT_SIZE equ $ - NullSeg
79 DW TSS_DESC_SIZE ; LimitLow
86 DW EXCEPTION_TSS_DESC_SIZE ; LimitLow
93 CODE_SEL equ CodeSeg32 - NullSeg
94 DATA_SEL equ DataSeg32 - NullSeg
95 TSS_SEL equ TssSeg - NullSeg
96 EXCEPTION_TSS_SEL equ ExceptionTssSeg - NullSeg
139 ; Create 2 TSS segments just after GDT
141 DW 0 ; PreviousTaskLink
179 TSS_DESC_SIZE equ $ - TssDescriptor
181 ExceptionTssDescriptor:
182 DW 0 ; PreviousTaskLink
194 DD PFHandlerEntry ; EIP
221 EXCEPTION_TSS_DESC_SIZE equ $ - ExceptionTssDescriptor
243 PSD_SIZE equ $ - ASM_PFX(gcPsd)
253 ASM_PFX(gTaskGateDescriptor):
255 DW EXCEPTION_TSS_SEL ; TSS Segment selector
257 DB 0x85 ; Task Gate, present, DPL = 0
261 ;------------------------------------------------------------------------------
262 ; PageFaultIdtHandlerSmmProfile is the entry point page fault only
266 ; +---------------------+
268 ; +---------------------+
270 ; +---------------------+
272 ; +---------------------+
274 ; +---------------------+
276 ; +---------------------+
278 ; +---------------------+ <-- EBP
281 ;------------------------------------------------------------------------------
282 global ASM_PFX(PageFaultIdtHandlerSmmProfile)
283 ASM_PFX(PageFaultIdtHandlerSmmProfile):
284 push 0xe ; Page Fault
290 ; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
296 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
301 lea ecx, [ebp + 6 * 4]
303 push dword [ebp] ; EBP
307 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
310 movzx eax, word [ebp + 4 * 4]
322 mov eax, [ebp + 3 * 4]
325 ;; UINT32 Gdtr[2], Idtr[2];
348 mov eax, [ebp + 5 * 4]
351 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
365 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
379 ;; FX_SAVE_STATE_IA32 FxSaveState;
384 ; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
387 ;; UINT32 ExceptionData;
388 push dword [ebp + 2 * 4]
390 ;; call into exception handler
392 ;; Prepare parameter and call
395 mov edx, dword [ebp + 1 * 4]
399 ; Call External Exception Handler
401 mov eax, ASM_PFX(SmiPFHandler)
405 ;; UINT32 ExceptionData;
408 ;; FX_SAVE_STATE_IA32 FxSaveState;
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
418 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
421 add esp, 4 ; not for Cr1
430 pop dword [ebp + 5 * 4]
433 ;; UINT32 Gdtr[2], Idtr[2];
434 ;; Best not let anyone mess with these particular registers...
438 pop dword [ebp + 3 * 4]
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.
449 pop dword [ebp + 4 * 4]
452 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
455 add esp, 4 ; not for ebp
456 add esp, 4 ; not for esp
465 ; Enable TF bit after page fault handler runs
466 bts dword [esp + 16], 8 ; EFLAGS
468 add esp, 8 ; skip INT# & ErrCode
472 ; Page Fault Exception Handler entry when SMM Stack Guard is enabled
473 ; Executiot starts here after a task switch
477 ; Get this processor's TSS
481 mov eax, [esp + 4] ; GDT base
483 mov ecx, [eax + TSS_SEL + 2]
485 mov cl, [eax + TSS_SEL + 7]
486 ror ecx, 8 ; ecx = TSS base
491 ; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
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]
507 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
508 movzx eax, word [ecx + IA32_TSS._SS]
510 movzx eax, word [ecx + IA32_TSS._CS]
512 movzx eax, word [ecx + IA32_TSS._DS]
514 movzx eax, word [ecx + IA32_TSS._ES]
516 movzx eax, word [ecx + IA32_TSS._FS]
518 movzx eax, word [ecx + IA32_TSS._GS]
522 push dword [ecx + IA32_TSS.EIP]
524 ;; UINT32 Gdtr[2], Idtr[2];
542 movzx eax, word [ecx + IA32_TSS.LDT]
546 push dword [ecx + IA32_TSS.EFLAGS]
548 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
562 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
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
584 ; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
587 ;; UINT32 ExceptionData;
590 ;; call into exception handler
592 mov eax, ASM_PFX(SmiPFHandler)
594 ;; Prepare parameter and call
601 ; Call External Exception Handler
607 ;; UINT32 ExceptionData;
610 ;; FX_SAVE_STATE_IA32 FxSaveState;
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
620 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
623 add esp, 4 ; not for Cr1
627 mov dword [ecx + IA32_TSS._CR3], eax
632 pop dword [ecx + IA32_TSS.EFLAGS]
635 ;; UINT32 Gdtr[2], Idtr[2];
636 ;; Best not let anyone mess with these particular registers...
640 pop dword [ecx + IA32_TSS.EIP]
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.
648 o16 mov [ecx + IA32_TSS._GS], ax
650 o16 mov [ecx + IA32_TSS._FS], ax
652 o16 mov [ecx + IA32_TSS._ES], ax
654 o16 mov [ecx + IA32_TSS._DS], ax
656 o16 mov [ecx + IA32_TSS._CS], ax
658 o16 mov [ecx + IA32_TSS._SS], ax
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]
672 ; Set single step DB# if SMM profile is enabled and page fault exception happens
673 cmp byte [dword ASM_PFX(mSetupDebugTrap)], 0
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]
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.
693 add esp, 4 ; skip ErrCode
697 global ASM_PFX(PageFaultStubFunction)
698 ASM_PFX(PageFaultStubFunction):
700 ; we need clean TS bit in CR0 to execute
701 ; x87 FPU/MMX/SSE/SSE2/SSE3/SSSE3/SSE4 instructions.