1 ;------------------------------------------------------------------------------ ;
2 ; Copyright (c) 2009 - 2019, 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(SmiPFHandler)
23 extern ASM_PFX(mSetupDebugTrap)
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 EXCEPTION_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
227 EXCEPTION_TSS_DESC_SIZE equ $ - ExceptionTssDescriptor
249 PSD_SIZE equ $ - ASM_PFX(gcPsd)
259 ASM_PFX(gTaskGateDescriptor):
261 DW EXCEPTION_TSS_SEL ; TSS Segment selector
263 DB 0x85 ; Task Gate, present, DPL = 0
267 ;------------------------------------------------------------------------------
268 ; PageFaultIdtHandlerSmmProfile is the entry point page fault only
272 ; +---------------------+
274 ; +---------------------+
276 ; +---------------------+
278 ; +---------------------+
280 ; +---------------------+
282 ; +---------------------+
284 ; +---------------------+ <-- EBP
287 ;------------------------------------------------------------------------------
288 global ASM_PFX(PageFaultIdtHandlerSmmProfile)
289 ASM_PFX(PageFaultIdtHandlerSmmProfile):
290 push 0xe ; Page Fault
296 ; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
302 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
307 lea ecx, [ebp + 6 * 4]
309 push dword [ebp] ; EBP
313 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
316 movzx eax, word [ebp + 4 * 4]
328 mov eax, [ebp + 3 * 4]
331 ;; UINT32 Gdtr[2], Idtr[2];
354 mov eax, [ebp + 5 * 4]
357 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
371 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
385 ;; FX_SAVE_STATE_IA32 FxSaveState;
390 ; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
393 ;; UINT32 ExceptionData;
394 push dword [ebp + 2 * 4]
396 ;; call into exception handler
398 ;; Prepare parameter and call
401 mov edx, dword [ebp + 1 * 4]
405 ; Call External Exception Handler
407 mov eax, ASM_PFX(SmiPFHandler)
411 ;; UINT32 ExceptionData;
414 ;; FX_SAVE_STATE_IA32 FxSaveState;
419 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
420 ;; Skip restoration of DRx registers to support debuggers
421 ;; that set breakpoint in interrupt/exception context
424 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
427 add esp, 4 ; not for Cr1
436 pop dword [ebp + 5 * 4]
439 ;; UINT32 Gdtr[2], Idtr[2];
440 ;; Best not let anyone mess with these particular registers...
444 pop dword [ebp + 3 * 4]
446 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
447 ;; NOTE - modified segment registers could hang the debugger... We
448 ;; could attempt to insulate ourselves against this possibility,
449 ;; but that poses risks as well.
455 pop dword [ebp + 4 * 4]
458 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
461 add esp, 4 ; not for ebp
462 add esp, 4 ; not for esp
471 ; Enable TF bit after page fault handler runs
472 bts dword [esp + 16], 8 ; EFLAGS
474 add esp, 8 ; skip INT# & ErrCode
478 ; Page Fault Exception Handler entry when SMM Stack Guard is enabled
479 ; Executiot starts here after a task switch
483 ; Get this processor's TSS
487 mov eax, [esp + 4] ; GDT base
489 mov ecx, [eax + TSS_SEL + 2]
491 mov cl, [eax + TSS_SEL + 7]
492 ror ecx, 8 ; ecx = TSS base
497 ; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
503 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
504 push dword [ecx + IA32_TSS._EAX]
505 push dword [ecx + IA32_TSS._ECX]
506 push dword [ecx + IA32_TSS._EDX]
507 push dword [ecx + IA32_TSS._EBX]
508 push dword [ecx + IA32_TSS._ESP]
509 push dword [ecx + IA32_TSS._EBP]
510 push dword [ecx + IA32_TSS._ESI]
511 push dword [ecx + IA32_TSS._EDI]
513 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
514 movzx eax, word [ecx + IA32_TSS._SS]
516 movzx eax, word [ecx + IA32_TSS._CS]
518 movzx eax, word [ecx + IA32_TSS._DS]
520 movzx eax, word [ecx + IA32_TSS._ES]
522 movzx eax, word [ecx + IA32_TSS._FS]
524 movzx eax, word [ecx + IA32_TSS._GS]
528 push dword [ecx + IA32_TSS.EIP]
530 ;; UINT32 Gdtr[2], Idtr[2];
548 movzx eax, word [ecx + IA32_TSS.LDT]
552 push dword [ecx + IA32_TSS.EFLAGS]
554 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
568 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
582 ;; FX_SAVE_STATE_IA32 FxSaveState;
583 ;; Clear TS bit in CR0 to avoid Device Not Available Exception (#NM)
584 ;; when executing fxsave/fxrstor instruction
590 ; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
593 ;; UINT32 ExceptionData;
596 ;; call into exception handler
598 mov eax, ASM_PFX(SmiPFHandler)
600 ;; Prepare parameter and call
607 ; Call External Exception Handler
613 ;; UINT32 ExceptionData;
616 ;; FX_SAVE_STATE_IA32 FxSaveState;
621 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
622 ;; Skip restoration of DRx registers to support debuggers
623 ;; that set breakpoints in interrupt/exception context
626 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
629 add esp, 4 ; not for Cr1
633 mov dword [ecx + IA32_TSS._CR3], eax
638 pop dword [ecx + IA32_TSS.EFLAGS]
641 ;; UINT32 Gdtr[2], Idtr[2];
642 ;; Best not let anyone mess with these particular registers...
646 pop dword [ecx + IA32_TSS.EIP]
648 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
649 ;; NOTE - modified segment registers could hang the debugger... We
650 ;; could attempt to insulate ourselves against this possibility,
651 ;; but that poses risks as well.
654 o16 mov [ecx + IA32_TSS._GS], ax
656 o16 mov [ecx + IA32_TSS._FS], ax
658 o16 mov [ecx + IA32_TSS._ES], ax
660 o16 mov [ecx + IA32_TSS._DS], ax
662 o16 mov [ecx + IA32_TSS._CS], ax
664 o16 mov [ecx + IA32_TSS._SS], ax
666 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
667 pop dword [ecx + IA32_TSS._EDI]
668 pop dword [ecx + IA32_TSS._ESI]
669 add esp, 4 ; not for ebp
670 add esp, 4 ; not for esp
671 pop dword [ecx + IA32_TSS._EBX]
672 pop dword [ecx + IA32_TSS._EDX]
673 pop dword [ecx + IA32_TSS._ECX]
674 pop dword [ecx + IA32_TSS._EAX]
678 ; Set single step DB# if SMM profile is enabled and page fault exception happens
679 cmp byte [dword ASM_PFX(mSetupDebugTrap)], 0
682 ; Create return context for iretd in stub function
683 mov eax, dword [ecx + IA32_TSS._ESP] ; Get old stack pointer
684 mov ebx, dword [ecx + IA32_TSS.EIP]
685 mov [eax - 0xc], ebx ; create EIP in old stack
686 movzx ebx, word [ecx + IA32_TSS._CS]
687 mov [eax - 0x8], ebx ; create CS in old stack
688 mov ebx, dword [ecx + IA32_TSS.EFLAGS]
690 mov [eax - 0x4], ebx ; create eflags in old stack
691 mov eax, dword [ecx + IA32_TSS._ESP] ; Get old stack pointer
692 sub eax, 0xc ; minus 12 byte
693 mov dword [ecx + IA32_TSS._ESP], eax ; Set new stack pointer
694 ; Replace the EIP of interrupted task with stub function
695 mov eax, ASM_PFX(PageFaultStubFunction)
696 mov dword [ecx + IA32_TSS.EIP], eax
697 ; Jump to the iretd so next page fault handler as a task will start again after iretd.
699 add esp, 4 ; skip ErrCode
703 global ASM_PFX(PageFaultStubFunction)
704 ASM_PFX(PageFaultStubFunction):
706 ; we need clean TS bit in CR0 to execute
707 ; x87 FPU/MMX/SSE/SSE2/SSE3/SSSE3/SSE4 instructions.