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 ;-------------------------------------------------------------------------------
24 EXTERNDEF SmiPFHandler:PROC
25 EXTERNDEF PageFaultStubFunction:PROC
26 EXTERNDEF gSmiMtrrs:QWORD
27 EXTERNDEF gcSmiIdtr:FWORD
28 EXTERNDEF gcSmiGdtr:FWORD
29 EXTERNDEF gTaskGateDescriptor:QWORD
31 EXTERNDEF FeaturePcdGet (PcdCpuSmmProfileEnable):BYTE
36 NullSeg DQ 0 ; reserved by architecture
44 ProtModeCodeSeg32 LABEL QWORD
51 ProtModeSsSeg32 LABEL QWORD
86 GDT_SIZE = $ - offset NullSeg
89 DW TSS_DESC_SIZE - 1 ; LimitLow
95 ExceptionTssSeg LABEL QWORD
96 DW TSS_DESC_SIZE - 1 ; LimitLow
103 CODE_SEL = offset CodeSeg32 - offset NullSeg
104 DATA_SEL = offset DataSeg32 - offset NullSeg
105 TSS_SEL = offset TssSeg - offset NullSeg
106 EXCEPTION_TSS_SEL = offset ExceptionTssSeg - offset NullSeg
149 ; Create 2 TSS segments just after GDT
150 TssDescriptor LABEL BYTE
151 DW 0 ; PreviousTaskLink
189 TSS_DESC_SIZE = $ - offset TssDescriptor
191 ExceptionTssDescriptor LABEL BYTE
192 DW 0 ; PreviousTaskLink
204 DD offset PFHandlerEntry ; EIP
249 PSD_SIZE = $ - offset gcPsd
251 gcSmiGdtr LABEL FWORD
255 gcSmiIdtr LABEL FWORD
259 gTaskGateDescriptor LABEL QWORD
261 DW EXCEPTION_TSS_SEL ; TSS Segment selector
263 DB 85h ; Task Gate, present, DPL = 0
268 ;------------------------------------------------------------------------------
269 ; PageFaultIdtHandlerSmmProfile is the entry point page fault only
273 ; +---------------------+
275 ; +---------------------+
277 ; +---------------------+
279 ; +---------------------+
281 ; +---------------------+
283 ; +---------------------+
285 ; +---------------------+ <-- EBP
288 ;------------------------------------------------------------------------------
289 PageFaultIdtHandlerSmmProfile PROC
290 push 0eh ; Page Fault
297 ; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
303 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
308 lea ecx, [ebp + 6 * 4]
310 push dword ptr [ebp] ; EBP
314 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
317 movzx eax, word ptr [ebp + 4 * 4]
329 mov eax, [ebp + 3 * 4]
332 ;; UINT32 Gdtr[2], Idtr[2];
355 mov eax, [ebp + 5 * 4]
358 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
372 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
386 ;; FX_SAVE_STATE_IA32 FxSaveState;
389 db 0fh, 0aeh, 07h ;fxsave [edi]
391 ; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
394 ;; UINT32 ExceptionData;
395 push dword ptr [ebp + 2 * 4]
397 ;; call into exception handler
399 ;; Prepare parameter and call
402 mov edx, dword ptr [ebp + 1 * 4]
406 ; Call External Exception Handler
408 mov eax, SmiPFHandler
412 ;; UINT32 ExceptionData;
415 ;; FX_SAVE_STATE_IA32 FxSaveState;
417 db 0fh, 0aeh, 0eh ; fxrstor [esi]
420 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
421 ;; Skip restoration of DRx registers to support debuggers
422 ;; that set breakpoint in interrupt/exception context
425 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
428 add esp, 4 ; not for Cr1
437 pop dword ptr [ebp + 5 * 4]
440 ;; UINT32 Gdtr[2], Idtr[2];
441 ;; Best not let anyone mess with these particular registers...
445 pop dword ptr [ebp + 3 * 4]
447 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
448 ;; NOTE - modified segment registers could hang the debugger... We
449 ;; could attempt to insulate ourselves against this possibility,
450 ;; but that poses risks as well.
456 pop dword ptr [ebp + 4 * 4]
459 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
462 add esp, 4 ; not for ebp
463 add esp, 4 ; not for esp
472 ; Enable TF bit after page fault handler runs
473 bts dword ptr [esp + 16], 8 ; EFLAGS
475 add esp, 8 ; skip INT# & ErrCode
479 ; Page Fault Exception Handler entry when SMM Stack Guard is enabled
480 ; Executiot starts here after a task switch
484 ; Get this processor's TSS
488 mov eax, [esp + 4] ; GDT base
490 mov ecx, [eax + TSS_SEL + 2]
492 mov cl, [eax + TSS_SEL + 7]
493 ror ecx, 8 ; ecx = TSS base
498 ; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
504 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
505 push (IA32_TSS ptr [ecx])._EAX
506 push (IA32_TSS ptr [ecx])._ECX
507 push (IA32_TSS ptr [ecx])._EDX
508 push (IA32_TSS ptr [ecx])._EBX
509 push (IA32_TSS ptr [ecx])._ESP
510 push (IA32_TSS ptr [ecx])._EBP
511 push (IA32_TSS ptr [ecx])._ESI
512 push (IA32_TSS ptr [ecx])._EDI
514 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
515 movzx eax, (IA32_TSS ptr [ecx])._SS
517 movzx eax, (IA32_TSS ptr [ecx])._CS
519 movzx eax, (IA32_TSS ptr [ecx])._DS
521 movzx eax, (IA32_TSS ptr [ecx])._ES
523 movzx eax, (IA32_TSS ptr [ecx])._FS
525 movzx eax, (IA32_TSS ptr [ecx])._GS
529 push (IA32_TSS ptr [ecx]).EIP
531 ;; UINT32 Gdtr[2], Idtr[2];
549 movzx eax, (IA32_TSS ptr [ecx]).LDT
553 push (IA32_TSS ptr [ecx]).EFLAGS
555 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
569 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
583 ;; FX_SAVE_STATE_IA32 FxSaveState;
584 ;; Clear TS bit in CR0 to avoid Device Not Available Exception (#NM)
585 ;; when executing fxsave/fxrstor instruction
589 db 0fh, 0aeh, 07h ;fxsave [edi]
591 ; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
594 ;; UINT32 ExceptionData;
597 ;; call into exception handler
599 mov eax, SmiPFHandler
601 ;; Prepare parameter and call
608 ; Call External Exception Handler
614 ;; UINT32 ExceptionData;
617 ;; FX_SAVE_STATE_IA32 FxSaveState;
619 db 0fh, 0aeh, 0eh ; fxrstor [esi]
622 ;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
623 ;; Skip restoration of DRx registers to support debuggers
624 ;; that set breakpoints in interrupt/exception context
627 ;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
630 add esp, 4 ; not for Cr1
634 mov (IA32_TSS ptr [ecx])._CR3, eax
639 pop (IA32_TSS ptr [ecx]).EFLAGS
642 ;; UINT32 Gdtr[2], Idtr[2];
643 ;; Best not let anyone mess with these particular registers...
647 pop (IA32_TSS ptr [ecx]).EIP
649 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
650 ;; NOTE - modified segment registers could hang the debugger... We
651 ;; could attempt to insulate ourselves against this possibility,
652 ;; but that poses risks as well.
655 mov (IA32_TSS ptr [ecx])._GS, ax
657 mov (IA32_TSS ptr [ecx])._FS, ax
659 mov (IA32_TSS ptr [ecx])._ES, ax
661 mov (IA32_TSS ptr [ecx])._DS, ax
663 mov (IA32_TSS ptr [ecx])._CS, ax
665 mov (IA32_TSS ptr [ecx])._SS, ax
667 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
668 pop (IA32_TSS ptr [ecx])._EDI
669 pop (IA32_TSS ptr [ecx])._ESI
670 add esp, 4 ; not for ebp
671 add esp, 4 ; not for esp
672 pop (IA32_TSS ptr [ecx])._EBX
673 pop (IA32_TSS ptr [ecx])._EDX
674 pop (IA32_TSS ptr [ecx])._ECX
675 pop (IA32_TSS ptr [ecx])._EAX
679 ; Set single step DB# if SMM profile is enabled and page fault exception happens
680 cmp FeaturePcdGet (PcdCpuSmmProfileEnable), 0
683 ; Create return context for iretd in stub function
684 mov eax, (IA32_TSS ptr [ecx])._ESP ; Get old stack pointer
685 mov ebx, (IA32_TSS ptr [ecx]).EIP
686 mov [eax - 0ch], ebx ; create EIP in old stack
687 movzx ebx, (IA32_TSS ptr [ecx])._CS
688 mov [eax - 08h], ebx ; create CS in old stack
689 mov ebx, (IA32_TSS ptr [ecx]).EFLAGS
691 mov [eax - 04h], ebx ; create eflags in old stack
692 mov eax, (IA32_TSS ptr [ecx])._ESP ; Get old stack pointer
693 sub eax, 0ch ; minus 12 byte
694 mov (IA32_TSS ptr [ecx])._ESP, eax ; Set new stack pointer
695 ; Replace the EIP of interrupted task with stub function
696 mov eax, PageFaultStubFunction
697 mov (IA32_TSS ptr [ecx]).EIP, eax
698 ; Jump to the iretd so next page fault handler as a task will start again after iretd.
700 add esp, 4 ; skip ErrCode
703 PageFaultIdtHandlerSmmProfile ENDP
705 PageFaultStubFunction PROC
707 ; we need clean TS bit in CR0 to execute
708 ; x87 FPU/MMX/SSE/SSE2/SSE3/SSSE3/SSE4 instructions.
712 PageFaultStubFunction ENDP