https://bugzilla.tianocore.org/show_bug.cgi?id=1373 Replace BSD 2-Clause License with BSD+Patent License. This change is based on the following emails: https://lists.01.org/pipermail/edk2-devel/2019-February/036260.html https://lists.01.org/pipermail/edk2-devel/2018-October/030385.html RFCs with detailed process for the license change: V3: https://lists.01.org/pipermail/edk2-devel/2019-March/038116.html V2: https://lists.01.org/pipermail/edk2-devel/2019-March/037669.html V1: https://lists.01.org/pipermail/edk2-devel/2019-March/037500.html Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Michael D Kinney <michael.d.kinney@intel.com> Reviewed-by: Eric Dong <eric.dong@intel.com> Reviewed-by: Ray Ni <ray.ni@intel.com>
		
			
				
	
	
		
			391 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			NASM
		
	
	
	
	
	
			
		
		
	
	
			391 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			NASM
		
	
	
	
	
	
;------------------------------------------------------------------------------ ;
 | 
						|
; Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
 | 
						|
; SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
						|
;
 | 
						|
; Module Name:
 | 
						|
;
 | 
						|
;   ExceptionTssEntryAsm.Asm
 | 
						|
;
 | 
						|
; Abstract:
 | 
						|
;
 | 
						|
;   IA32 CPU Exception Handler with Separate Stack
 | 
						|
;
 | 
						|
; Notes:
 | 
						|
;
 | 
						|
;------------------------------------------------------------------------------
 | 
						|
 | 
						|
;
 | 
						|
; IA32 TSS Memory Layout Description
 | 
						|
;
 | 
						|
struc IA32_TSS
 | 
						|
                    resw 1
 | 
						|
                    resw 1
 | 
						|
  .ESP0:    resd 1
 | 
						|
  .SS0:     resw 1
 | 
						|
                    resw 1
 | 
						|
  .ESP1:    resd 1
 | 
						|
  .SS1:     resw 1
 | 
						|
                    resw 1
 | 
						|
  .ESP2:    resd 1
 | 
						|
  .SS2:     resw 1
 | 
						|
                    resw 1
 | 
						|
  ._CR3:    resd 1
 | 
						|
  .EIP:     resd 1
 | 
						|
  .EFLAGS:  resd 1
 | 
						|
  ._EAX:    resd 1
 | 
						|
  ._ECX:    resd 1
 | 
						|
  ._EDX:    resd 1
 | 
						|
  ._EBX:    resd 1
 | 
						|
  ._ESP:    resd 1
 | 
						|
  ._EBP:    resd 1
 | 
						|
  ._ESI:    resd 1
 | 
						|
  ._EDI:    resd 1
 | 
						|
  ._ES:     resw 1
 | 
						|
                    resw 1
 | 
						|
  ._CS:     resw 1
 | 
						|
                    resw 1
 | 
						|
  ._SS:     resw 1
 | 
						|
                    resw 1
 | 
						|
  ._DS:     resw 1
 | 
						|
                    resw 1
 | 
						|
  ._FS:     resw 1
 | 
						|
                    resw 1
 | 
						|
  ._GS:     resw 1
 | 
						|
                    resw 1
 | 
						|
  .LDT:     resw 1
 | 
						|
                    resw 1
 | 
						|
                    resw 1
 | 
						|
                    resw 1
 | 
						|
endstruc
 | 
						|
 | 
						|
;
 | 
						|
; CommonExceptionHandler()
 | 
						|
;
 | 
						|
extern ASM_PFX(CommonExceptionHandler)
 | 
						|
 | 
						|
SECTION .data
 | 
						|
 | 
						|
SECTION .text
 | 
						|
 | 
						|
ALIGN   8
 | 
						|
 | 
						|
;
 | 
						|
; Exception handler stub table
 | 
						|
;
 | 
						|
AsmExceptionEntryBegin:
 | 
						|
%assign Vector 0
 | 
						|
%rep  32
 | 
						|
 | 
						|
DoIret%[Vector]:
 | 
						|
    iretd
 | 
						|
ASM_PFX(ExceptionTaskSwtichEntry%[Vector]):
 | 
						|
    db      0x6a        ; push  #VectorNum
 | 
						|
    db      %[Vector]
 | 
						|
    mov     eax, ASM_PFX(CommonTaskSwtichEntryPoint)
 | 
						|
    call    eax
 | 
						|
    mov     esp, eax    ; Restore stack top
 | 
						|
    jmp     DoIret%[Vector]
 | 
						|
 | 
						|
%assign Vector Vector+1
 | 
						|
%endrep
 | 
						|
AsmExceptionEntryEnd:
 | 
						|
 | 
						|
;
 | 
						|
; Common part of exception handler
 | 
						|
;
 | 
						|
global ASM_PFX(CommonTaskSwtichEntryPoint)
 | 
						|
ASM_PFX(CommonTaskSwtichEntryPoint):
 | 
						|
    ;
 | 
						|
    ; Stack:
 | 
						|
    ; +---------------------+ <-- EBP - 8
 | 
						|
    ; +       TSS Base      +
 | 
						|
    ; +---------------------+ <-- EBP - 4
 | 
						|
    ; +      CPUID.EDX      +
 | 
						|
    ; +---------------------+ <-- EBP
 | 
						|
    ; +         EIP         +
 | 
						|
    ; +---------------------+ <-- EBP + 4
 | 
						|
    ; +    Vector Number    +
 | 
						|
    ; +---------------------+ <-- EBP + 8
 | 
						|
    ; +    Error Code       +
 | 
						|
    ; +---------------------+
 | 
						|
    ;
 | 
						|
 | 
						|
    mov     ebp, esp                    ; Stack frame
 | 
						|
 | 
						|
; Use CPUID to determine if FXSAVE/FXRESTOR and DE are supported
 | 
						|
    mov     eax, 1
 | 
						|
    cpuid
 | 
						|
    push    edx
 | 
						|
 | 
						|
; Get TSS base of interrupted task through PreviousTaskLink field in
 | 
						|
; current TSS base
 | 
						|
    sub     esp, 8
 | 
						|
    sgdt    [esp + 2]
 | 
						|
    mov     eax, [esp + 4]              ; GDT base
 | 
						|
    add     esp, 8
 | 
						|
 | 
						|
    xor     ebx, ebx
 | 
						|
    str     bx                          ; Current TR
 | 
						|
 | 
						|
    mov     ecx, [eax + ebx + 2]
 | 
						|
    shl     ecx, 8
 | 
						|
    mov     cl, [eax + ebx + 7]
 | 
						|
    ror     ecx, 8                      ; ecx = Current TSS base
 | 
						|
    push    ecx                         ; keep it in stack for later use
 | 
						|
 | 
						|
    movzx   ebx, word [ecx]             ; Previous Task Link
 | 
						|
    mov     ecx, [eax + ebx + 2]
 | 
						|
    shl     ecx, 8
 | 
						|
    mov     cl, [eax + ebx + 7]
 | 
						|
    ror     ecx, 8                      ; ecx = Previous TSS base
 | 
						|
 | 
						|
;
 | 
						|
; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
 | 
						|
; is 16-byte aligned
 | 
						|
;
 | 
						|
    and     esp, 0xfffffff0
 | 
						|
    sub     esp, 12
 | 
						|
 | 
						|
;; UINT32  Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
 | 
						|
    push    dword [ecx + IA32_TSS._EAX]
 | 
						|
    push    dword [ecx + IA32_TSS._ECX]
 | 
						|
    push    dword [ecx + IA32_TSS._EDX]
 | 
						|
    push    dword [ecx + IA32_TSS._EBX]
 | 
						|
    push    dword [ecx + IA32_TSS._ESP]
 | 
						|
    push    dword [ecx + IA32_TSS._EBP]
 | 
						|
    push    dword [ecx + IA32_TSS._ESI]
 | 
						|
    push    dword [ecx + IA32_TSS._EDI]
 | 
						|
 | 
						|
;; UINT32  Gs, Fs, Es, Ds, Cs, Ss;
 | 
						|
    movzx   eax, word [ecx + IA32_TSS._SS]
 | 
						|
    push    eax
 | 
						|
    movzx   eax, word [ecx + IA32_TSS._CS]
 | 
						|
    push    eax
 | 
						|
    movzx   eax, word [ecx + IA32_TSS._DS]
 | 
						|
    push    eax
 | 
						|
    movzx   eax, word [ecx + IA32_TSS._ES]
 | 
						|
    push    eax
 | 
						|
    movzx   eax, word [ecx + IA32_TSS._FS]
 | 
						|
    push    eax
 | 
						|
    movzx   eax, word [ecx + IA32_TSS._GS]
 | 
						|
    push    eax
 | 
						|
 | 
						|
;; UINT32  Eip;
 | 
						|
    push    dword [ecx + IA32_TSS.EIP]
 | 
						|
 | 
						|
;; UINT32  Gdtr[2], Idtr[2];
 | 
						|
    sub     esp, 8
 | 
						|
    sidt    [esp]
 | 
						|
    mov     eax, [esp + 2]
 | 
						|
    xchg    eax, [esp]
 | 
						|
    and     eax, 0xFFFF
 | 
						|
    mov     [esp+4], eax
 | 
						|
 | 
						|
    sub     esp, 8
 | 
						|
    sgdt    [esp]
 | 
						|
    mov     eax, [esp + 2]
 | 
						|
    xchg    eax, [esp]
 | 
						|
    and     eax, 0xFFFF
 | 
						|
    mov     [esp+4], eax
 | 
						|
 | 
						|
;; UINT32  Ldtr, Tr;
 | 
						|
    mov     eax, ebx    ; ebx still keeps selector of interrupted task
 | 
						|
    push    eax
 | 
						|
    movzx   eax, word [ecx + IA32_TSS.LDT]
 | 
						|
    push    eax
 | 
						|
 | 
						|
;; UINT32  EFlags;
 | 
						|
    push    dword [ecx + IA32_TSS.EFLAGS]
 | 
						|
 | 
						|
;; UINT32  Cr0, Cr1, Cr2, Cr3, Cr4;
 | 
						|
    mov     eax, cr4
 | 
						|
    push    eax             ; push cr4 firstly
 | 
						|
 | 
						|
    mov     edx, [ebp - 4]  ; cpuid.edx
 | 
						|
    test    edx, BIT24      ; Test for FXSAVE/FXRESTOR support
 | 
						|
    jz      .1
 | 
						|
    or      eax, BIT9       ; Set CR4.OSFXSR
 | 
						|
.1:
 | 
						|
    test    edx, BIT2       ; Test for Debugging Extensions support
 | 
						|
    jz      .2
 | 
						|
    or      eax, BIT3       ; Set CR4.DE
 | 
						|
.2:
 | 
						|
    mov     cr4, eax
 | 
						|
 | 
						|
    mov     eax, cr3
 | 
						|
    push    eax
 | 
						|
    mov     eax, cr2
 | 
						|
    push    eax
 | 
						|
    xor     eax, eax
 | 
						|
    push    eax
 | 
						|
    mov     eax, cr0
 | 
						|
    push    eax
 | 
						|
 | 
						|
;; UINT32  Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
 | 
						|
    mov     eax, dr7
 | 
						|
    push    eax
 | 
						|
    mov     eax, dr6
 | 
						|
    push    eax
 | 
						|
    mov     eax, dr3
 | 
						|
    push    eax
 | 
						|
    mov     eax, dr2
 | 
						|
    push    eax
 | 
						|
    mov     eax, dr1
 | 
						|
    push    eax
 | 
						|
    mov     eax, dr0
 | 
						|
    push    eax
 | 
						|
 | 
						|
;; FX_SAVE_STATE_IA32 FxSaveState;
 | 
						|
;; Clear TS bit in CR0 to avoid Device Not Available Exception (#NM)
 | 
						|
;; when executing fxsave/fxrstor instruction
 | 
						|
    test    edx, BIT24  ; Test for FXSAVE/FXRESTOR support.
 | 
						|
                        ; edx still contains result from CPUID above
 | 
						|
    jz      .3
 | 
						|
    clts
 | 
						|
    sub     esp, 512
 | 
						|
    mov     edi, esp
 | 
						|
    db      0xf, 0xae, 0x7 ;fxsave [edi]
 | 
						|
.3:
 | 
						|
 | 
						|
;; UINT32  ExceptionData;
 | 
						|
    push    dword [ebp + 8]
 | 
						|
 | 
						|
;; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
 | 
						|
    cld
 | 
						|
 | 
						|
;; call into exception handler
 | 
						|
    mov     esi, ecx            ; Keep TSS base to avoid overwrite
 | 
						|
    mov     eax, ASM_PFX(CommonExceptionHandler)
 | 
						|
 | 
						|
;; Prepare parameter and call
 | 
						|
    mov     edx, esp
 | 
						|
    push    edx                 ; EFI_SYSTEM_CONTEXT
 | 
						|
    push    dword [ebp + 4]     ; EFI_EXCEPTION_TYPE (vector number)
 | 
						|
 | 
						|
    ;
 | 
						|
    ; Call External Exception Handler
 | 
						|
    ;
 | 
						|
    call    eax
 | 
						|
    add     esp, 8              ; Restore stack before calling
 | 
						|
    mov     ecx, esi            ; Restore TSS base
 | 
						|
 | 
						|
;; UINT32  ExceptionData;
 | 
						|
    add     esp, 4
 | 
						|
 | 
						|
;; FX_SAVE_STATE_IA32 FxSaveState;
 | 
						|
    mov     edx, [ebp - 4]  ; cpuid.edx
 | 
						|
    test    edx, BIT24      ; Test for FXSAVE/FXRESTOR support
 | 
						|
    jz      .4
 | 
						|
    mov     esi, esp
 | 
						|
    db      0xf, 0xae, 0xe  ; fxrstor [esi]
 | 
						|
.4:
 | 
						|
    add     esp, 512
 | 
						|
 | 
						|
;; UINT32  Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
 | 
						|
;; Skip restoration of DRx registers to support debuggers
 | 
						|
;; that set breakpoints in interrupt/exception context
 | 
						|
    add     esp, 4 * 6
 | 
						|
 | 
						|
;; UINT32  Cr0, Cr1, Cr2, Cr3, Cr4;
 | 
						|
    pop     eax
 | 
						|
    mov     cr0, eax
 | 
						|
    add     esp, 4    ; not for Cr1
 | 
						|
    pop     eax
 | 
						|
    mov     cr2, eax
 | 
						|
    pop     eax
 | 
						|
    mov     dword [ecx + IA32_TSS._CR3], eax
 | 
						|
    pop     eax
 | 
						|
    mov     cr4, eax
 | 
						|
 | 
						|
;; UINT32  EFlags;
 | 
						|
    pop     dword [ecx + IA32_TSS.EFLAGS]
 | 
						|
    mov     ebx, dword [ecx + IA32_TSS.EFLAGS]
 | 
						|
    btr     ebx, 9      ; Do 'cli'
 | 
						|
    mov     dword [ecx + IA32_TSS.EFLAGS], ebx
 | 
						|
 | 
						|
;; UINT32  Ldtr, Tr;
 | 
						|
;; UINT32  Gdtr[2], Idtr[2];
 | 
						|
;; Best not let anyone mess with these particular registers...
 | 
						|
    add     esp, 24
 | 
						|
 | 
						|
;; UINT32  Eip;
 | 
						|
    pop     dword [ecx + IA32_TSS.EIP]
 | 
						|
 | 
						|
;; UINT32  Gs, Fs, Es, Ds, Cs, Ss;
 | 
						|
;; NOTE - modified segment registers could hang the debugger...  We
 | 
						|
;;        could attempt to insulate ourselves against this possibility,
 | 
						|
;;        but that poses risks as well.
 | 
						|
;;
 | 
						|
    pop     eax
 | 
						|
o16 mov     [ecx + IA32_TSS._GS], ax
 | 
						|
    pop     eax
 | 
						|
o16 mov     [ecx + IA32_TSS._FS], ax
 | 
						|
    pop     eax
 | 
						|
o16 mov     [ecx + IA32_TSS._ES], ax
 | 
						|
    pop     eax
 | 
						|
o16 mov     [ecx + IA32_TSS._DS], ax
 | 
						|
    pop     eax
 | 
						|
o16 mov     [ecx + IA32_TSS._CS], ax
 | 
						|
    pop     eax
 | 
						|
o16 mov     [ecx + IA32_TSS._SS], ax
 | 
						|
 | 
						|
;; UINT32  Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
 | 
						|
    pop     dword [ecx + IA32_TSS._EDI]
 | 
						|
    pop     dword [ecx + IA32_TSS._ESI]
 | 
						|
    add     esp, 4   ; not for ebp
 | 
						|
    add     esp, 4   ; not for esp
 | 
						|
    pop     dword [ecx + IA32_TSS._EBX]
 | 
						|
    pop     dword [ecx + IA32_TSS._EDX]
 | 
						|
    pop     dword [ecx + IA32_TSS._ECX]
 | 
						|
    pop     dword [ecx + IA32_TSS._EAX]
 | 
						|
 | 
						|
; Set single step DB# to allow debugger to able to go back to the EIP
 | 
						|
; where the exception is triggered.
 | 
						|
 | 
						|
;; Create return context for iretd in stub function
 | 
						|
    mov    eax, dword [ecx + IA32_TSS._ESP]      ; Get old stack pointer
 | 
						|
    mov    ebx, dword [ecx + IA32_TSS.EIP]
 | 
						|
    mov    [eax - 0xc], ebx                      ; create EIP in old stack
 | 
						|
    movzx  ebx, word [ecx + IA32_TSS._CS]
 | 
						|
    mov    [eax - 0x8], ebx                      ; create CS in old stack
 | 
						|
    mov    ebx, dword [ecx + IA32_TSS.EFLAGS]
 | 
						|
    bts    ebx, 8                                ; Set TF
 | 
						|
    mov    [eax - 0x4], ebx                      ; create eflags in old stack
 | 
						|
    sub    eax, 0xc                              ; minus 12 byte
 | 
						|
    mov    dword [ecx + IA32_TSS._ESP], eax      ; Set new stack pointer
 | 
						|
 | 
						|
;; Replace the EIP of interrupted task with stub function
 | 
						|
    mov    eax, ASM_PFX(SingleStepStubFunction)
 | 
						|
    mov    dword [ecx + IA32_TSS.EIP], eax
 | 
						|
 | 
						|
    mov     ecx, [ebp - 8]                       ; Get current TSS base
 | 
						|
    mov     eax, dword [ecx + IA32_TSS._ESP]     ; Return current stack top
 | 
						|
    mov     esp, ebp
 | 
						|
 | 
						|
    ret
 | 
						|
 | 
						|
global ASM_PFX(SingleStepStubFunction)
 | 
						|
ASM_PFX(SingleStepStubFunction):
 | 
						|
;
 | 
						|
; we need clean TS bit in CR0 to execute
 | 
						|
; x87 FPU/MMX/SSE/SSE2/SSE3/SSSE3/SSE4 instructions.
 | 
						|
;
 | 
						|
    clts
 | 
						|
    iretd
 | 
						|
 | 
						|
global ASM_PFX(AsmGetTssTemplateMap)
 | 
						|
ASM_PFX(AsmGetTssTemplateMap):
 | 
						|
    push    ebp                 ; C prolog
 | 
						|
    mov     ebp, esp
 | 
						|
    pushad
 | 
						|
 | 
						|
    mov ebx, dword [ebp + 0x8]
 | 
						|
    mov dword [ebx],       ASM_PFX(ExceptionTaskSwtichEntry0)
 | 
						|
    mov dword [ebx + 0x4], (AsmExceptionEntryEnd - AsmExceptionEntryBegin) / 32
 | 
						|
    mov dword [ebx + 0x8], 0
 | 
						|
 | 
						|
    popad
 | 
						|
    pop     ebp
 | 
						|
    ret
 | 
						|
 |