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 ;-------------------------------------------------------------------------------
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)
31 NullSeg: DQ 0 ; reserved by architecture
81 GDT_SIZE equ $ - NullSeg
84 DW TSS_DESC_SIZE ; LimitLow
91 DW TSS_DESC_SIZE ; LimitLow
98 CODE_SEL equ CodeSeg32 - NullSeg
99 DATA_SEL equ DataSeg32 - NullSeg
100 TSS_SEL equ TssSeg - NullSeg
101 EXCEPTION_TSS_SEL equ ExceptionTssSeg - NullSeg
144 ; Create 2 TSS segments just after GDT
146 DW 0 ; PreviousTaskLink
184 TSS_DESC_SIZE equ $ - TssDescriptor
186 ExceptionTssDescriptor:
187 DW 0 ; PreviousTaskLink
199 DD PFHandlerEntry ; EIP
245 DD ASM_PFX(gSmiMtrrs)
246 PSD_SIZE equ $ - ASM_PFX(gcPsd)
259 DW CODE_SEL ; Segment selector
261 DB 0x8e ; Interrupt Gate, Present
265 IDT_SIZE equ $ - _SmiIDT
269 DW EXCEPTION_TSS_SEL ; TSS Segment selector
271 DB 0x85 ; Task Gate, present, DPL = 0
275 ;------------------------------------------------------------------------------
276 ; PageFaultIdtHandlerSmmProfile is the entry point page fault only
280 ; +---------------------+
282 ; +---------------------+
284 ; +---------------------+
286 ; +---------------------+
288 ; +---------------------+
290 ; +---------------------+
292 ; +---------------------+ <-- EBP
295 ;------------------------------------------------------------------------------
296 global ASM_PFX(PageFaultIdtHandlerSmmProfile)
297 ASM_PFX(PageFaultIdtHandlerSmmProfile):
298 push 0xe ; Page Fault
304 ; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
310 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
315 lea ecx, [ebp + 6 * 4]
317 push dword [ebp] ; EBP
321 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
324 movzx eax, word [ebp + 4 * 4]
336 mov eax, [ebp + 3 * 4]
339 ;; UINT32 Gdtr[2], Idtr[2];
362 mov eax, [ebp + 5 * 4]
365 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
379 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
393 ;; FX_SAVE_STATE_IA32 FxSaveState;
396 db 0xf, 0xae, 0x7 ;fxsave [edi]
398 ; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
401 ;; UINT32 ExceptionData;
402 push dword [ebp + 2 * 4]
404 ;; call into exception handler
406 ;; Prepare parameter and call
409 mov edx, dword [ebp + 1 * 4]
413 ; Call External Exception Handler
415 mov eax, ASM_PFX(SmiPFHandler)
419 ;; UINT32 ExceptionData;
422 ;; FX_SAVE_STATE_IA32 FxSaveState;
424 db 0xf, 0xae, 0xe ; fxrstor [esi]
427 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
428 ;; Skip restoration of DRx registers to support debuggers
429 ;; that set breakpoint in interrupt/exception context
432 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
435 add esp, 4 ; not for Cr1
444 pop dword [ebp + 5 * 4]
447 ;; UINT32 Gdtr[2], Idtr[2];
448 ;; Best not let anyone mess with these particular registers...
452 pop dword [ebp + 3 * 4]
454 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
455 ;; NOTE - modified segment registers could hang the debugger... We
456 ;; could attempt to insulate ourselves against this possibility,
457 ;; but that poses risks as well.
463 pop dword [ebp + 4 * 4]
466 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
469 add esp, 4 ; not for ebp
470 add esp, 4 ; not for esp
479 ; Enable TF bit after page fault handler runs
480 bts dword [esp + 16], 8 ; EFLAGS
482 add esp, 8 ; skip INT# & ErrCode
486 ; Page Fault Exception Handler entry when SMM Stack Guard is enabled
487 ; Executiot starts here after a task switch
491 ; Get this processor's TSS
495 mov eax, [esp + 4] ; GDT base
497 mov ecx, [eax + TSS_SEL + 2]
499 mov cl, [eax + TSS_SEL + 7]
500 ror ecx, 8 ; ecx = TSS base
505 ; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
511 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
512 push dword [ecx + IA32_TSS._EAX]
513 push dword [ecx + IA32_TSS._ECX]
514 push dword [ecx + IA32_TSS._EDX]
515 push dword [ecx + IA32_TSS._EBX]
516 push dword [ecx + IA32_TSS._ESP]
517 push dword [ecx + IA32_TSS._EBP]
518 push dword [ecx + IA32_TSS._ESI]
519 push dword [ecx + IA32_TSS._EDI]
521 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
522 movzx eax, word [ecx + IA32_TSS._SS]
524 movzx eax, word [ecx + IA32_TSS._CS]
526 movzx eax, word [ecx + IA32_TSS._DS]
528 movzx eax, word [ecx + IA32_TSS._ES]
530 movzx eax, word [ecx + IA32_TSS._FS]
532 movzx eax, word [ecx + IA32_TSS._GS]
536 push dword [ecx + IA32_TSS.EIP]
538 ;; UINT32 Gdtr[2], Idtr[2];
556 movzx eax, word [ecx + IA32_TSS.LDT]
560 push dword [ecx + IA32_TSS.EFLAGS]
562 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
576 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
590 ;; FX_SAVE_STATE_IA32 FxSaveState;
591 ;; Clear TS bit in CR0 to avoid Device Not Available Exception (#NM)
592 ;; when executing fxsave/fxrstor instruction
596 db 0xf, 0xae, 0x7 ;fxsave [edi]
598 ; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
601 ;; UINT32 ExceptionData;
604 ;; call into exception handler
606 mov eax, ASM_PFX(SmiPFHandler)
608 ;; Prepare parameter and call
615 ; Call External Exception Handler
621 ;; UINT32 ExceptionData;
624 ;; FX_SAVE_STATE_IA32 FxSaveState;
626 db 0xf, 0xae, 0xe ; fxrstor [esi]
629 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
630 ;; Skip restoration of DRx registers to support debuggers
631 ;; that set breakpoints in interrupt/exception context
634 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
637 add esp, 4 ; not for Cr1
641 mov dword [ecx + IA32_TSS._CR3], eax
646 pop dword [ecx + IA32_TSS.EFLAGS]
649 ;; UINT32 Gdtr[2], Idtr[2];
650 ;; Best not let anyone mess with these particular registers...
654 pop dword [ecx + IA32_TSS.EIP]
656 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
657 ;; NOTE - modified segment registers could hang the debugger... We
658 ;; could attempt to insulate ourselves against this possibility,
659 ;; but that poses risks as well.
662 o16 mov [ecx + IA32_TSS._GS], ax
664 o16 mov [ecx + IA32_TSS._FS], ax
666 o16 mov [ecx + IA32_TSS._ES], ax
668 o16 mov [ecx + IA32_TSS._DS], ax
670 o16 mov [ecx + IA32_TSS._CS], ax
672 o16 mov [ecx + IA32_TSS._SS], ax
674 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
675 pop dword [ecx + IA32_TSS._EDI]
676 pop dword [ecx + IA32_TSS._ESI]
677 add esp, 4 ; not for ebp
678 add esp, 4 ; not for esp
679 pop dword [ecx + IA32_TSS._EBX]
680 pop dword [ecx + IA32_TSS._EDX]
681 pop dword [ecx + IA32_TSS._ECX]
682 pop dword [ecx + IA32_TSS._EAX]
686 ; Set single step DB# if SMM profile is enabled and page fault exception happens
687 cmp byte [dword ASM_PFX(FeaturePcdGet (PcdCpuSmmProfileEnable))], 0
690 ; Create return context for iretd in stub function
691 mov eax, dword [ecx + IA32_TSS._ESP] ; Get old stack pointer
692 mov ebx, dword [ecx + IA32_TSS.EIP]
693 mov [eax - 0xc], ebx ; create EIP in old stack
694 movzx ebx, word [ecx + IA32_TSS._CS]
695 mov [eax - 0x8], ebx ; create CS in old stack
696 mov ebx, dword [ecx + IA32_TSS.EFLAGS]
698 mov [eax - 0x4], ebx ; create eflags in old stack
699 mov eax, dword [ecx + IA32_TSS._ESP] ; Get old stack pointer
700 sub eax, 0xc ; minus 12 byte
701 mov dword [ecx + IA32_TSS._ESP], eax ; Set new stack pointer
702 ; Replace the EIP of interrupted task with stub function
703 mov eax, ASM_PFX(PageFaultStubFunction)
704 mov dword [ecx + IA32_TSS.EIP], eax
705 ; Jump to the iretd so next page fault handler as a task will start again after iretd.
707 add esp, 4 ; skip ErrCode
711 global ASM_PFX(PageFaultStubFunction)
712 ASM_PFX(PageFaultStubFunction):
714 ; we need clean TS bit in CR0 to execute
715 ; x87 FPU/MMX/SSE/SSE2/SSE3/SSSE3/SSE4 instructions.
720 global ASM_PFX(InitializeIDTSmmStackGuard)
721 ASM_PFX(InitializeIDTSmmStackGuard):
724 ; If SMM Stack Guard feature is enabled, the Page Fault Exception entry in IDT
725 ; is a Task Gate Descriptor so that when a Page Fault Exception occurrs,
726 ; the processors can use a known good stack in case stack is ran out.
728 lea ebx, [_SmiIDT + 14 * 8]
729 lea edx, [TaskGateDescriptor]