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(SmiPFHandler)
24 global ASM_PFX(gcSmiIdtr)
25 global ASM_PFX(gcSmiGdtr)
26 global ASM_PFX(gTaskGateDescriptor)
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
246 PSD_SIZE equ $ - ASM_PFX(gcPsd)
256 ASM_PFX(gTaskGateDescriptor):
258 DW EXCEPTION_TSS_SEL ; TSS Segment selector
260 DB 0x85 ; Task Gate, present, DPL = 0
264 ;------------------------------------------------------------------------------
265 ; PageFaultIdtHandlerSmmProfile is the entry point page fault only
269 ; +---------------------+
271 ; +---------------------+
273 ; +---------------------+
275 ; +---------------------+
277 ; +---------------------+
279 ; +---------------------+
281 ; +---------------------+ <-- EBP
284 ;------------------------------------------------------------------------------
285 global ASM_PFX(PageFaultIdtHandlerSmmProfile)
286 ASM_PFX(PageFaultIdtHandlerSmmProfile):
287 push 0xe ; Page Fault
293 ; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
299 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
304 lea ecx, [ebp + 6 * 4]
306 push dword [ebp] ; EBP
310 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
313 movzx eax, word [ebp + 4 * 4]
325 mov eax, [ebp + 3 * 4]
328 ;; UINT32 Gdtr[2], Idtr[2];
351 mov eax, [ebp + 5 * 4]
354 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
368 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
382 ;; FX_SAVE_STATE_IA32 FxSaveState;
385 db 0xf, 0xae, 0x7 ;fxsave [edi]
387 ; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
390 ;; UINT32 ExceptionData;
391 push dword [ebp + 2 * 4]
393 ;; call into exception handler
395 ;; Prepare parameter and call
398 mov edx, dword [ebp + 1 * 4]
402 ; Call External Exception Handler
404 mov eax, ASM_PFX(SmiPFHandler)
408 ;; UINT32 ExceptionData;
411 ;; FX_SAVE_STATE_IA32 FxSaveState;
413 db 0xf, 0xae, 0xe ; fxrstor [esi]
416 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
417 ;; Skip restoration of DRx registers to support debuggers
418 ;; that set breakpoint in interrupt/exception context
421 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
424 add esp, 4 ; not for Cr1
433 pop dword [ebp + 5 * 4]
436 ;; UINT32 Gdtr[2], Idtr[2];
437 ;; Best not let anyone mess with these particular registers...
441 pop dword [ebp + 3 * 4]
443 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
444 ;; NOTE - modified segment registers could hang the debugger... We
445 ;; could attempt to insulate ourselves against this possibility,
446 ;; but that poses risks as well.
452 pop dword [ebp + 4 * 4]
455 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
458 add esp, 4 ; not for ebp
459 add esp, 4 ; not for esp
468 ; Enable TF bit after page fault handler runs
469 bts dword [esp + 16], 8 ; EFLAGS
471 add esp, 8 ; skip INT# & ErrCode
475 ; Page Fault Exception Handler entry when SMM Stack Guard is enabled
476 ; Executiot starts here after a task switch
480 ; Get this processor's TSS
484 mov eax, [esp + 4] ; GDT base
486 mov ecx, [eax + TSS_SEL + 2]
488 mov cl, [eax + TSS_SEL + 7]
489 ror ecx, 8 ; ecx = TSS base
494 ; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
500 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
501 push dword [ecx + IA32_TSS._EAX]
502 push dword [ecx + IA32_TSS._ECX]
503 push dword [ecx + IA32_TSS._EDX]
504 push dword [ecx + IA32_TSS._EBX]
505 push dword [ecx + IA32_TSS._ESP]
506 push dword [ecx + IA32_TSS._EBP]
507 push dword [ecx + IA32_TSS._ESI]
508 push dword [ecx + IA32_TSS._EDI]
510 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
511 movzx eax, word [ecx + IA32_TSS._SS]
513 movzx eax, word [ecx + IA32_TSS._CS]
515 movzx eax, word [ecx + IA32_TSS._DS]
517 movzx eax, word [ecx + IA32_TSS._ES]
519 movzx eax, word [ecx + IA32_TSS._FS]
521 movzx eax, word [ecx + IA32_TSS._GS]
525 push dword [ecx + IA32_TSS.EIP]
527 ;; UINT32 Gdtr[2], Idtr[2];
545 movzx eax, word [ecx + IA32_TSS.LDT]
549 push dword [ecx + IA32_TSS.EFLAGS]
551 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
565 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
579 ;; FX_SAVE_STATE_IA32 FxSaveState;
580 ;; Clear TS bit in CR0 to avoid Device Not Available Exception (#NM)
581 ;; when executing fxsave/fxrstor instruction
585 db 0xf, 0xae, 0x7 ;fxsave [edi]
587 ; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
590 ;; UINT32 ExceptionData;
593 ;; call into exception handler
595 mov eax, ASM_PFX(SmiPFHandler)
597 ;; Prepare parameter and call
604 ; Call External Exception Handler
610 ;; UINT32 ExceptionData;
613 ;; FX_SAVE_STATE_IA32 FxSaveState;
615 db 0xf, 0xae, 0xe ; fxrstor [esi]
618 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
619 ;; Skip restoration of DRx registers to support debuggers
620 ;; that set breakpoints in interrupt/exception context
623 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
626 add esp, 4 ; not for Cr1
630 mov dword [ecx + IA32_TSS._CR3], eax
635 pop dword [ecx + IA32_TSS.EFLAGS]
638 ;; UINT32 Gdtr[2], Idtr[2];
639 ;; Best not let anyone mess with these particular registers...
643 pop dword [ecx + IA32_TSS.EIP]
645 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
646 ;; NOTE - modified segment registers could hang the debugger... We
647 ;; could attempt to insulate ourselves against this possibility,
648 ;; but that poses risks as well.
651 o16 mov [ecx + IA32_TSS._GS], ax
653 o16 mov [ecx + IA32_TSS._FS], ax
655 o16 mov [ecx + IA32_TSS._ES], ax
657 o16 mov [ecx + IA32_TSS._DS], ax
659 o16 mov [ecx + IA32_TSS._CS], ax
661 o16 mov [ecx + IA32_TSS._SS], ax
663 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
664 pop dword [ecx + IA32_TSS._EDI]
665 pop dword [ecx + IA32_TSS._ESI]
666 add esp, 4 ; not for ebp
667 add esp, 4 ; not for esp
668 pop dword [ecx + IA32_TSS._EBX]
669 pop dword [ecx + IA32_TSS._EDX]
670 pop dword [ecx + IA32_TSS._ECX]
671 pop dword [ecx + IA32_TSS._EAX]
675 ; Set single step DB# if SMM profile is enabled and page fault exception happens
676 cmp byte [dword ASM_PFX(FeaturePcdGet (PcdCpuSmmProfileEnable))], 0
679 ; Create return context for iretd in stub function
680 mov eax, dword [ecx + IA32_TSS._ESP] ; Get old stack pointer
681 mov ebx, dword [ecx + IA32_TSS.EIP]
682 mov [eax - 0xc], ebx ; create EIP in old stack
683 movzx ebx, word [ecx + IA32_TSS._CS]
684 mov [eax - 0x8], ebx ; create CS in old stack
685 mov ebx, dword [ecx + IA32_TSS.EFLAGS]
687 mov [eax - 0x4], ebx ; create eflags in old stack
688 mov eax, dword [ecx + IA32_TSS._ESP] ; Get old stack pointer
689 sub eax, 0xc ; minus 12 byte
690 mov dword [ecx + IA32_TSS._ESP], eax ; Set new stack pointer
691 ; Replace the EIP of interrupted task with stub function
692 mov eax, ASM_PFX(PageFaultStubFunction)
693 mov dword [ecx + IA32_TSS.EIP], eax
694 ; Jump to the iretd so next page fault handler as a task will start again after iretd.
696 add esp, 4 ; skip ErrCode
700 global ASM_PFX(PageFaultStubFunction)
701 ASM_PFX(PageFaultStubFunction):
703 ; we need clean TS bit in CR0 to execute
704 ; x87 FPU/MMX/SSE/SSE2/SSE3/SSSE3/SSE4 instructions.