Signed-off-by: rsun3 Reviewed-by: jyao1 git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@11670 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			408 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
			
		
		
	
	
			408 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
| #/**@file
 | |
| # Low leve IA32 specific debug support functions.
 | |
| #
 | |
| # Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
 | |
| # This program and the accompanying materials
 | |
| # are licensed and made available under the terms and conditions of the BSD License
 | |
| # which accompanies this distribution.  The full text of the license may be found at
 | |
| # http://opensource.org/licenses/bsd-license.php
 | |
| #
 | |
| # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | |
| # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | |
| #
 | |
| #**/
 | |
| 
 | |
| ASM_GLOBAL ASM_PFX(OrigVector)
 | |
| ASM_GLOBAL ASM_PFX(InterruptEntryStub)
 | |
| ASM_GLOBAL ASM_PFX(StubSize)
 | |
| ASM_GLOBAL ASM_PFX(CommonIdtEntry)
 | |
| ASM_GLOBAL ASM_PFX(FxStorSupport)
 | |
| 
 | |
| ASM_PFX(StubSize):       .long   ASM_PFX(InterruptEntryStubEnd) - ASM_PFX(InterruptEntryStub)
 | |
| ASM_PFX(AppEsp):         .long   0x11111111 # ?
 | |
| ASM_PFX(DebugEsp):       .long   0x22222222 # ?
 | |
| ASM_PFX(ExtraPush):      .long   0x33333333 # ?
 | |
| ASM_PFX(ExceptData):     .long   0x44444444 # ?
 | |
| ASM_PFX(Eflags):         .long   0x55555555 # ?
 | |
| ASM_PFX(OrigVector):     .long   0x66666666 # ?
 | |
| 
 | |
| #------------------------------------------------------------------------------
 | |
| # BOOLEAN
 | |
| # FxStorSupport (
 | |
| #   void
 | |
| #   )
 | |
| #
 | |
| # Abstract: Returns TRUE if FxStor instructions are supported
 | |
| #
 | |
| ASM_GLOBAL ASM_PFX(FxStorSupport)
 | |
| ASM_PFX(FxStorSupport):
 | |
| #
 | |
| # cpuid corrupts ebx which must be preserved per the C calling convention
 | |
| #
 | |
|         push   %ebx
 | |
|         mov    $0x1,%eax
 | |
|         cpuid
 | |
|         mov    %edx,%eax
 | |
|         and    $0x1000000,%eax
 | |
|         shr    $0x18,%eax
 | |
|         pop    %ebx
 | |
|         ret
 | |
| #------------------------------------------------------------------------------
 | |
| # void
 | |
| # Vect2Desc (
 | |
| #   DESCRIPTOR * DestDesc,
 | |
| #   void (*Vector) (void)
 | |
| #   )
 | |
| #
 | |
| # Abstract: Encodes an IDT descriptor with the given physical address
 | |
| #
 | |
| 
 | |
| ASM_GLOBAL ASM_PFX(Vect2Desc)
 | |
| ASM_PFX(Vect2Desc):
 | |
|         push   %ebp
 | |
|         mov    %esp,%ebp
 | |
|         mov    0xc(%ebp),%eax
 | |
|         mov    0x8(%ebp),%ecx
 | |
|         mov    %ax,(%ecx)
 | |
|         movw   $0x20,0x2(%ecx)
 | |
|         movw   $0x8e00,0x4(%ecx)
 | |
|         shr    $0x10,%eax
 | |
|         mov    %ax,0x6(%ecx)
 | |
|         leave
 | |
|         ret
 | |
| 
 | |
| ASM_GLOBAL ASM_PFX(InterruptEntryStub)
 | |
| ASM_PFX(InterruptEntryStub):
 | |
|         mov    %esp,0x0                    # save stack top
 | |
|         mov    $0x0,%esp                   # switch to debugger stack
 | |
|         push   $0x0                        # push vector number - will be modified before installed
 | |
|         jmp    ASM_PFX(CommonIdtEntry)     # jump CommonIdtEntry
 | |
| ASM_GLOBAL ASM_PFX(InterruptEntryStubEnd)
 | |
| ASM_PFX(InterruptEntryStubEnd):
 | |
| 
 | |
| #------------------------------------------------------------------------------
 | |
| # CommonIdtEntry
 | |
| #
 | |
| # Abstract: This code is not a function, but is the common part for all IDT
 | |
| #               vectors.
 | |
| #
 | |
| ASM_GLOBAL ASM_PFX(CommonIdtEntry)
 | |
| ASM_PFX(CommonIdtEntry):
 | |
| ##
 | |
| ## At this point, the stub has saved the current application stack esp into AppEsp
 | |
| ## and switched stacks to the debug stack, where it pushed the vector number
 | |
| ##
 | |
| ## The application stack looks like this:
 | |
| ##
 | |
| ##              ...
 | |
| ##              (last application stack entry)
 | |
| ##              eflags from interrupted task
 | |
| ##              CS from interrupted task
 | |
| ##              EIP from interrupted task
 | |
| ##              Error code <-------------------- Only present for some exeption types
 | |
| ##
 | |
| ##
 | |
| 
 | |
| 
 | |
| ## The stub switched us to the debug stack and pushed the interrupt number.
 | |
| ##
 | |
| ## Next, construct the context record.  It will be build on the debug stack by
 | |
| ## pushing the registers in the correct order so as to create the context structure
 | |
| ## on the debug stack.  The context record must be built from the end back to the
 | |
| ## beginning because the stack grows down...
 | |
| #
 | |
| ## For reference, the context record looks like this:
 | |
| ##
 | |
| ## typedef
 | |
| ## struct {
 | |
| ##   UINT32             ExceptionData;
 | |
| ##   FX_SAVE_STATE_IA32 FxSaveState;
 | |
| ##   UINT32             Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
 | |
| ##   UINT32             Cr0, Cr2, Cr3, Cr4;
 | |
| ##   UINT32             EFlags;
 | |
| ##   UINT32             Ldtr, Tr;
 | |
| ##   UINT32             Gdtr[2], Idtr[2];
 | |
| ##   UINT32             Eip;
 | |
| ##   UINT32             Gs, Fs, Es, Ds, Cs, Ss;
 | |
| ##   UINT32             Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
 | |
| ## } SYSTEM_CONTEXT_IA32;  // 32 bit system context record
 | |
| 
 | |
| ## UINT32  Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
 | |
|         pusha
 | |
| ## Save interrupt state eflags register...
 | |
|         pushf
 | |
|         pop    %eax
 | |
| ## We need to determine if any extra data was pushed by the exception, and if so, save it
 | |
| ## To do this, we check the exception number pushed by the stub, and cache the
 | |
| ## result in a variable since we'll need this again.
 | |
|         mov    %eax,0x0
 | |
|         cmpl   $0x8,0x0
 | |
|         jne    ASM_PFX(CommonIdtEntry+0x20)
 | |
|         movl   $0x1,0x0
 | |
|         jmp    ASM_PFX(CommonIdtEntry+0xa8)
 | |
|         cmpl   $0xa,0x0
 | |
|         jne    ASM_PFX(CommonIdtEntry+0x35)
 | |
|         movl   $0x1,0x0
 | |
|         jmp    ASM_PFX(CommonIdtEntry+0xa8)
 | |
|         cmpl   $0xb,0x0
 | |
|         jne    ASM_PFX(CommonIdtEntry+0x4a)
 | |
|         movl   $0x1,0x0
 | |
|         jmp    ASM_PFX(CommonIdtEntry+0xa8)
 | |
|         cmpl   $0xc,0x0
 | |
|         jne    ASM_PFX(CommonIdtEntry+0x5f)
 | |
|         movl   $0x1,0x0
 | |
|         jmp    ASM_PFX(CommonIdtEntry+0xa8)
 | |
|         cmpl   $0xd,0x0
 | |
|         jne    ASM_PFX(CommonIdtEntry+0x74)
 | |
|         movl   $0x1,0x0
 | |
|         jmp    ASM_PFX(CommonIdtEntry+0xa8)
 | |
|         cmpl   $0xe,0x0
 | |
|         jne    ASM_PFX(CommonIdtEntry+0x89)
 | |
|         movl   $0x1,0x0
 | |
|         jmp    ASM_PFX(CommonIdtEntry+0xa8)
 | |
|         cmpl   $0x11,0x0
 | |
|         jne    ASM_PFX(CommonIdtEntry+0x9e)
 | |
|         movl   $0x1,0x0
 | |
|         jmp    ASM_PFX(CommonIdtEntry+0xa8)
 | |
|         movl   $0x0,0x0
 | |
| ## If there's some extra data, save it also, and modify the saved AppEsp to effectively
 | |
| ## pop this value off the application's stack.
 | |
| 
 | |
|         cmpl   $0x1,0x0
 | |
|         jne    ASM_PFX(CommonIdtEntry+0xc8)
 | |
|         mov    0x0,%eax
 | |
|         mov    (%eax),%ebx
 | |
|         mov    %ebx,0x0
 | |
|         add    $0x4,%eax
 | |
|         mov    %eax,0x0
 | |
|         jmp    ASM_PFX(CommonIdtEntry+0xd2)
 | |
|         movl   $0x0,0x0
 | |
| ## The "pushad" above pushed the debug stack esp.  Since what we're actually doing
 | |
| ## is building the context record on the debug stack, we need to save the pushed
 | |
| ## debug ESP, and replace it with the application's last stack entry...
 | |
|         mov    0xc(%esp),%eax
 | |
|         mov    %eax,0x0
 | |
|         mov    0x0,%eax
 | |
|         add    $0xc,%eax
 | |
|         # application stack has eflags, cs, & eip, so
 | |
|         # last actual application stack entry is
 | |
|         # 12 bytes into the application stack.
 | |
|         mov    %eax,0xc(%esp)
 | |
| ## continue building context record
 | |
| ## UINT32  Gs, Fs, Es, Ds, Cs, Ss;  insure high 16 bits of each is zero
 | |
|         mov    %ss,%eax
 | |
|         push   %eax
 | |
|         
 | |
|         # CS from application is one entry back in application stack
 | |
|         mov    0x0,%eax
 | |
|         movzwl 0x4(%eax),%eax
 | |
|         push   %eax
 | |
|         mov    %ds,%eax
 | |
|         push   %eax
 | |
|         mov    %es,%eax
 | |
|         push   %eax
 | |
|         mov    %fs,%eax
 | |
|         push   %eax
 | |
|         mov    %gs,%eax
 | |
|         push   %eax
 | |
| 
 | |
| ## UINT32  Eip;
 | |
|         # Eip from application is on top of application stack
 | |
|         mov    0x0,%eax
 | |
|         pushl  (%eax)
 | |
| 
 | |
| ## UINT32  Gdtr[2], Idtr[2];
 | |
|         push   $0x0
 | |
|         push   $0x0
 | |
|         sidtl  (%esp)
 | |
|         push   $0x0
 | |
|         push   $0x0
 | |
|         sgdtl  (%esp)
 | |
| 
 | |
| ## UINT32  Ldtr, Tr;
 | |
|         xor    %eax,%eax
 | |
|         str    %eax
 | |
|         push   %eax
 | |
|         sldt   %eax
 | |
|         push   %eax
 | |
| 
 | |
| ## UINT32  EFlags;
 | |
| ## Eflags from application is two entries back in application stack
 | |
|         mov    0x0,%eax
 | |
|         pushl  0x8(%eax)
 | |
| 
 | |
| ## UINT32  Cr0, Cr1, Cr2, Cr3, Cr4;
 | |
| ## insure FXSAVE/FXRSTOR is enabled in CR4...
 | |
| ## ... while we're at it, make sure DE is also enabled...
 | |
|         mov    %cr4,%eax
 | |
|         or     $0x208,%eax
 | |
|         mov    %eax,%cr4
 | |
|         push   %eax
 | |
|         mov    %cr3,%eax
 | |
|         push   %eax
 | |
|         mov    %cr2,%eax
 | |
|         push   %eax
 | |
|         push   $0x0
 | |
|         mov    %cr0,%eax
 | |
|         push   %eax
 | |
| 
 | |
| ## UINT32  Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
 | |
|         mov    %db7,%eax
 | |
|         push   %eax
 | |
| 
 | |
| ## clear Dr7 while executing debugger itself
 | |
|         xor    %eax,%eax
 | |
|         mov    %eax,%db7
 | |
|         mov    %db6,%eax
 | |
|         push   %eax
 | |
| 
 | |
| ## insure all status bits in dr6 are clear...
 | |
|         xor    %eax,%eax
 | |
|         mov    %eax,%db6
 | |
|         mov    %db3,%eax
 | |
|         push   %eax
 | |
|         mov    %db2,%eax
 | |
|         push   %eax
 | |
|         mov    %db1,%eax
 | |
|         push   %eax
 | |
|         mov    %db0,%eax
 | |
|         push   %eax
 | |
| 
 | |
| ## FX_SAVE_STATE_IA32 FxSaveState;
 | |
|         sub    $0x200,%esp
 | |
|         mov    %esp,%edi
 | |
|         # IMPORTANT!! The debug stack has been carefully constructed to
 | |
|         # insure that esp and edi are 16 byte aligned when we get here.
 | |
|         # They MUST be.  If they are not, a GP fault will occur.
 | |
|         fxsave (%edi)
 | |
| 
 | |
| ## UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
 | |
|         cld
 | |
|                 
 | |
| ## UINT32  ExceptionData;
 | |
|         mov    0x0,%eax
 | |
|         push   %eax
 | |
| 
 | |
| # call to C code which will in turn call registered handler
 | |
| # pass in the vector number
 | |
|         mov    %esp,%eax
 | |
|         push   %eax
 | |
|         mov    0x0,%eax
 | |
|         push   %eax
 | |
|         call   ASM_PFX(CommonIdtEntry+0x184)
 | |
|         add    $0x8,%esp
 | |
| 
 | |
| # restore context...
 | |
| ## UINT32  ExceptionData;
 | |
|         add    $0x4,%esp
 | |
| 
 | |
| ## FX_SAVE_STATE_IA32 FxSaveState;
 | |
|         mov    %esp,%esi
 | |
|         fxrstor (%esi)
 | |
|         add    $0x200,%esp
 | |
| 
 | |
| ## UINT32  Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
 | |
|         pop    %eax
 | |
|         mov    %eax,%db0
 | |
|         pop    %eax
 | |
|         mov    %eax,%db1
 | |
|         pop    %eax
 | |
|         mov    %eax,%db2
 | |
|         pop    %eax
 | |
|         mov    %eax,%db3
 | |
| 
 | |
| ## skip restore of dr6.  We cleared dr6 during the context save.
 | |
|         add    $0x4,%esp
 | |
|         pop    %eax
 | |
|         mov    %eax,%db7
 | |
| 
 | |
| ## UINT32  Cr0, Cr1, Cr2, Cr3, Cr4;
 | |
|         pop    %eax
 | |
|         mov    %eax,%cr0
 | |
|         add    $0x4,%esp
 | |
|         pop    %eax
 | |
|         mov    %eax,%cr2
 | |
|         pop    %eax
 | |
|         mov    %eax,%cr3
 | |
|         pop    %eax
 | |
|         mov    %eax,%cr4
 | |
| 
 | |
| ## UINT32  EFlags;
 | |
|         mov    0x0,%eax
 | |
|         popl   0x8(%eax)
 | |
| 
 | |
| ## UINT32  Ldtr, Tr;
 | |
| ## UINT32  Gdtr[2], Idtr[2];
 | |
| ## Best not let anyone mess with these particular registers...
 | |
|         add    $0x18,%esp
 | |
| 
 | |
| ## UINT32  Eip;
 | |
|         popl   (%eax)
 | |
| 
 | |
| ## UINT32  SegGs, SegFs, SegEs, SegDs, SegCs, SegSs;
 | |
| ## NOTE - modified segment registers could hang the debugger...  We
 | |
| ##        could attempt to insulate ourselves against this possibility,
 | |
| ##        but that poses risks as well.
 | |
| ##
 | |
| 
 | |
|         pop    %gs
 | |
|         pop    %fs
 | |
|         pop    %es
 | |
|         pop    %ds
 | |
|         popl   0x4(%eax)
 | |
|         pop    %ss
 | |
|         mov    0xc(%esp),%ebx
 | |
| 
 | |
| ## The next stuff to restore is the general purpose registers that were pushed
 | |
| ## using the "pushad" instruction.
 | |
| ##
 | |
| ## The value of ESP as stored in the context record is the application ESP
 | |
| ## including the 3 entries on the application stack caused by the exception
 | |
| ## itself. It may have been modified by the debug agent, so we need to
 | |
| ## determine if we need to relocate the application stack.
 | |
| 
 | |
|         mov    0x0,%eax          # move the potentially modified AppEsp into ebx
 | |
|         add    $0xc,%eax
 | |
|         cmp    %eax,%ebx
 | |
|         je     ASM_PFX(CommonIdtEntry+0x202)
 | |
|         mov    0x0,%eax
 | |
|         mov    (%eax),%ecx       # EIP
 | |
|         mov    %ecx,(%ebx)
 | |
|         mov    0x4(%eax),%ecx    # CS
 | |
|         mov    %ecx,0x4(%ebx)
 | |
|         mov    0x8(%eax),%ecx    # EFLAGS
 | |
|         mov    %ecx,0x8(%ebx)
 | |
| 	
 | |
|         mov    %ebx,%eax         # modify the saved AppEsp to the new AppEsp
 | |
|         mov    %eax,0x0
 | |
|         mov    0x0,%eax          # restore the DebugEsp on the debug stack
 | |
| 	                               # so our "popad" will not cause a stack switch
 | |
|         mov    %eax,0xc(%esp)    
 | |
|         cmpl   $0x68,0x0
 | |
|         jne    PhonyIretd+0xd
 | |
| ## Restore eflags so when we chain, the flags will be exactly as if we were never here.
 | |
| ## We gin up the stack to do an iretd so we can get ALL the flags.
 | |
|         mov    0x0,%eax
 | |
|         mov    0x8(%eax),%ebx
 | |
|         and    $0xfffffcff,%ebx  # special handling for IF and TF
 | |
|         push   %ebx
 | |
|         push   %cs
 | |
|         push   $0x0
 | |
|         iret
 | |
| 
 | |
| PhonyIretd:
 | |
| ## UINT32  Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
 | |
|         popa
 | |
| 
 | |
| ## Switch back to application stack
 | |
|         mov    0x0,%esp
 | |
|         jmp    *0x0
 | |
| ## Jump to original handler
 | |
| ## UINT32  Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
 | |
|         popa
 | |
| ## Switch back to application stack
 | |
|         mov    0x0,%esp
 | |
| 
 | |
| ## We're outa here...
 | |
|         iret
 |