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 gcSmiIdtr:FWORD
27 EXTERNDEF gcSmiGdtr:FWORD
28 EXTERNDEF gTaskGateDescriptor:QWORD
30 EXTERNDEF FeaturePcdGet (PcdCpuSmmProfileEnable):BYTE
35 NullSeg DQ 0 ; reserved by architecture
43 ProtModeCodeSeg32 LABEL QWORD
50 ProtModeSsSeg32 LABEL QWORD
85 GDT_SIZE = $ - offset NullSeg
88 DW TSS_DESC_SIZE - 1 ; LimitLow
94 ExceptionTssSeg LABEL QWORD
95 DW TSS_DESC_SIZE - 1 ; LimitLow
102 CODE_SEL = offset CodeSeg32 - offset NullSeg
103 DATA_SEL = offset DataSeg32 - offset NullSeg
104 TSS_SEL = offset TssSeg - offset NullSeg
105 EXCEPTION_TSS_SEL = offset ExceptionTssSeg - offset NullSeg
148 ; Create 2 TSS segments just after GDT
149 TssDescriptor LABEL BYTE
150 DW 0 ; PreviousTaskLink
188 TSS_DESC_SIZE = $ - offset TssDescriptor
190 ExceptionTssDescriptor LABEL BYTE
191 DW 0 ; PreviousTaskLink
203 DD offset PFHandlerEntry ; EIP
248 PSD_SIZE = $ - offset gcPsd
250 gcSmiGdtr LABEL FWORD
254 gcSmiIdtr LABEL FWORD
258 gTaskGateDescriptor LABEL QWORD
260 DW EXCEPTION_TSS_SEL ; TSS Segment selector
262 DB 85h ; 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 PageFaultIdtHandlerSmmProfile PROC
289 push 0eh ; 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 ptr [ebp] ; EBP
313 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
316 movzx eax, word ptr [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;
388 db 0fh, 0aeh, 07h ;fxsave [edi]
390 ; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
393 ;; UINT32 ExceptionData;
394 push dword ptr [ebp + 2 * 4]
396 ;; call into exception handler
398 ;; Prepare parameter and call
401 mov edx, dword ptr [ebp + 1 * 4]
405 ; Call External Exception Handler
407 mov eax, SmiPFHandler
411 ;; UINT32 ExceptionData;
414 ;; FX_SAVE_STATE_IA32 FxSaveState;
416 db 0fh, 0aeh, 0eh ; fxrstor [esi]
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 ptr [ebp + 5 * 4]
439 ;; UINT32 Gdtr[2], Idtr[2];
440 ;; Best not let anyone mess with these particular registers...
444 pop dword ptr [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 ptr [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 ptr [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 (IA32_TSS ptr [ecx])._EAX
505 push (IA32_TSS ptr [ecx])._ECX
506 push (IA32_TSS ptr [ecx])._EDX
507 push (IA32_TSS ptr [ecx])._EBX
508 push (IA32_TSS ptr [ecx])._ESP
509 push (IA32_TSS ptr [ecx])._EBP
510 push (IA32_TSS ptr [ecx])._ESI
511 push (IA32_TSS ptr [ecx])._EDI
513 ;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
514 movzx eax, (IA32_TSS ptr [ecx])._SS
516 movzx eax, (IA32_TSS ptr [ecx])._CS
518 movzx eax, (IA32_TSS ptr [ecx])._DS
520 movzx eax, (IA32_TSS ptr [ecx])._ES
522 movzx eax, (IA32_TSS ptr [ecx])._FS
524 movzx eax, (IA32_TSS ptr [ecx])._GS
528 push (IA32_TSS ptr [ecx]).EIP
530 ;; UINT32 Gdtr[2], Idtr[2];
548 movzx eax, (IA32_TSS ptr [ecx]).LDT
552 push (IA32_TSS ptr [ecx]).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
588 db 0fh, 0aeh, 07h ;fxsave [edi]
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, SmiPFHandler
600 ;; Prepare parameter and call
607 ; Call External Exception Handler
613 ;; UINT32 ExceptionData;
616 ;; FX_SAVE_STATE_IA32 FxSaveState;
618 db 0fh, 0aeh, 0eh ; fxrstor [esi]
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 (IA32_TSS ptr [ecx])._CR3, eax
638 pop (IA32_TSS ptr [ecx]).EFLAGS
641 ;; UINT32 Gdtr[2], Idtr[2];
642 ;; Best not let anyone mess with these particular registers...
646 pop (IA32_TSS ptr [ecx]).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 mov (IA32_TSS ptr [ecx])._GS, ax
656 mov (IA32_TSS ptr [ecx])._FS, ax
658 mov (IA32_TSS ptr [ecx])._ES, ax
660 mov (IA32_TSS ptr [ecx])._DS, ax
662 mov (IA32_TSS ptr [ecx])._CS, ax
664 mov (IA32_TSS ptr [ecx])._SS, ax
666 ;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
667 pop (IA32_TSS ptr [ecx])._EDI
668 pop (IA32_TSS ptr [ecx])._ESI
669 add esp, 4 ; not for ebp
670 add esp, 4 ; not for esp
671 pop (IA32_TSS ptr [ecx])._EBX
672 pop (IA32_TSS ptr [ecx])._EDX
673 pop (IA32_TSS ptr [ecx])._ECX
674 pop (IA32_TSS ptr [ecx])._EAX
678 ; Set single step DB# if SMM profile is enabled and page fault exception happens
679 cmp FeaturePcdGet (PcdCpuSmmProfileEnable), 0
682 ; Create return context for iretd in stub function
683 mov eax, (IA32_TSS ptr [ecx])._ESP ; Get old stack pointer
684 mov ebx, (IA32_TSS ptr [ecx]).EIP
685 mov [eax - 0ch], ebx ; create EIP in old stack
686 movzx ebx, (IA32_TSS ptr [ecx])._CS
687 mov [eax - 08h], ebx ; create CS in old stack
688 mov ebx, (IA32_TSS ptr [ecx]).EFLAGS
690 mov [eax - 04h], ebx ; create eflags in old stack
691 mov eax, (IA32_TSS ptr [ecx])._ESP ; Get old stack pointer
692 sub eax, 0ch ; minus 12 byte
693 mov (IA32_TSS ptr [ecx])._ESP, eax ; Set new stack pointer
694 ; Replace the EIP of interrupted task with stub function
695 mov eax, PageFaultStubFunction
696 mov (IA32_TSS ptr [ecx]).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
702 PageFaultIdtHandlerSmmProfile ENDP
704 PageFaultStubFunction PROC
706 ; we need clean TS bit in CR0 to execute
707 ; x87 FPU/MMX/SSE/SSE2/SSE3/SSSE3/SSE4 instructions.
711 PageFaultStubFunction ENDP