asmfuncs.s

来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· S 代码 · 共 1,390 行 · 第 1/4 页

S
1,390
字号
//++
// Copyright (c) 2004, Intel Corporation                                                         
// All rights reserved. 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.             
// 
// Module Name:
//
//  AsmFuncs.s
//
// Abstract:
//
//  Low level IPF routines used by the debug support driver
//
// Revision History:
//
//--


#include "common.i"
#include "Ds64Macros.i"

.global PatchSaveBuffer
.global IpfContextBuf
.global CommonHandler
.global ExternalInterruptCount


/////////////////////////////////////////////
//
//  Name:
//      InstructionCacheFlush
//
//  Description:
//      Flushes instruction cache for specified number of bytes
//
        .global InstructionCacheFlush
        .proc   InstructionCacheFlush
        .align 32
InstructionCacheFlush::
 {      .mii
        alloc   r3=2, 0, 0, 0
        cmp4.leu p0,p6=32, r33;;
        (p6)    mov r33=32;;
 }
 {      .mii
        nop.m    0
        zxt4    r29=r33;;
        dep.z   r30=r29, 0, 5;;
 }
 {      .mii
        cmp4.eq p0,p7=r0, r30
        shr.u   r28=r29, 5;;
        (p7)    adds    r28=1, r28;;
 }
 {      .mii
        nop.m    0
        shl r27=r28, 5;;
        zxt4    r26=r27;;
 }
 {      .mfb
        add r31=r26, r32
        nop.f    0
        nop.b    0
 }
LoopBack:   // $L143:
 {      .mii
        fc   r32
        adds    r32=32, r32;;
        cmp.ltu p14,p15=r32, r31
 }
 {      .mfb
        nop.m    0
        nop.f    0
        //(p14) br.cond.dptk.few $L143#;;
        (p14)   br.cond.dptk.few LoopBack;;
 }
 {      .mmi
        sync.i;;
        srlz.i
        nop.i   0;;
 }
 {      .mfb
        nop.m    0
        nop.f    0
        br.ret.sptk.few b0;;
 }
        .endp   InstructionCacheFlush


/////////////////////////////////////////////
//
//  Name:
//      ChainHandler
//
//  Description:
//      Chains an interrupt handler
//
//      The purpose of this function is to enable chaining of the external interrupt.
//      Since there's no clean SAL abstraction for doing this, we must do it
//      surreptitiously.
//
//      The reserved IVT entry at offset 0x3400 is coopted for use by this handler.
//      According to Itanium architecture, it is reserved.  Strictly speaking, this is
//      not safe, as we're cheating and violating the Itanium architecture.  However,
//      as long as we're the only ones cheating, we should be OK.  Without hooks in
//      the SAL to enable IVT management, there aren't many good options.
//
//      The strategy is to replace the first bundle of the external interrupt handler
//      with our own that will branch into a piece of code we've supplied and located
//      in the reserved IVT entry.  Only the first bundle of the external interrupt
//      IVT entry is modified.
//
//      The original bundle is moved and relocated to space
//      allocated within the reserved IVT entry.  The next bundle following is
//      is generated to go a hard coded branch back to the second bundle of the
//      external interrupt IVT entry just in case the first bundle had no branch.
//
//      Our new code will execute our handler, and then fall through to the
//      original bundle after restoring all context appropriately.
//
//      The following is a representation of what the IVT memory map looks like with
//      our chained handler installed:
//
//
//                                                 
//                                                 
//                           
//      This IVT entry is      Failsafe bundle     
//      reserved by the         
//      Itanium architecture   Original bundle 0   
//      and is used for         
//      for locating our                           
//      handler and the                            
//      original bundle        Patch code...       
//      zero of the ext                            
//      interrupt handler                          
//                              
//      RSVD    (3400)         Unused              
//                           
//                                                 
//                                                 
//                                                 
//                                                 
//                                                 
//                                                 
//                                                 
//                                                 
//                                                 
//                                                 
//                              
//      EXT_INT (3000)         Bundle 0               Bundle zero - This one is
//                                modified, all other bundles
//                                                       in the EXT_INT entry are
//                                                       untouched.
//
//
//       Arguments:
//
//       Returns:
//
//       Notes:
//
//
        .global ChainHandler
        .proc ChainHandler
ChainHandler:

        NESTED_SETUP( 0,2+3,3,0 )

        mov         r8=1                           // r8 = success
        mov         r2=cr.iva;;
//
// NOTE: There's a potential hazard here in that we're simply stealing a bunch of
// bundles (memory) from the IVT and assuming there's no catastrophic side effect.
//
// First, save IVT area we're taking over with the patch so we can restore it later
//
        addl        out0=PATCH_ENTRY_OFFSET, r2    // out0 = source buffer
        movl        out1=PatchSaveBuffer           // out1 = destination buffer
        mov         out2=0x40;;                    // out2 = number of bundles to copy... save entire IDT entry
        br.call.sptk.few    b0 = CopyBundles

// Next, copy the patch code into the IVT
        movl        out0=PatchCode                 // out0 = source buffer of patch code
        addl        out1=PATCH_OFFSET, r2          // out1 = destination buffer - in IVT
        mov         out2=NUM_PATCH_BUNDLES;;       // out2 = number of bundles to copy
        br.call.sptk.few    b0 = CopyBundles


// copy original bundle 0 from the external interrupt handler to the
// appropriate place in the reserved IVT interrupt slot
        addl        out0=EXT_INT_ENTRY_OFFSET, r2  // out0 = source buffer
        addl        out1=RELOCATED_EXT_INT, r2     // out1 = destination buffer - in reserved IVT
        mov         out2=1;;                       // out2 = copy 1 bundle
        br.call.sptk.few    b0 = CopyBundles

// Now relocate it there because it very likely had a branch instruction that
// that must now be fixed up.
        addl        out0=RELOCATED_EXT_INT, r2     // out0 = new runtime address of bundle - in reserved IVT
        addl        out1=EXT_INT_ENTRY_OFFSET, r2;;// out1 = IP address of previous location
        mov         out2=out0;;                    // out2 = IP address of new location
        br.call.sptk.few    b0 = RelocateBundle

// Now copy into the failsafe branch into the next bundle just in case
// the original ext int bundle 0 bundle did not contain a branch instruction
        movl        out0=FailsafeBranch            // out0 = source buffer
        addl        out1=FAILSAFE_BRANCH_OFFSET, r2  // out1 = destination buffer - in reserved IVT
        mov         out2=1;;                       // out2 = copy 1 bundle
        br.call.sptk.few    b0 = CopyBundles

// Last, copy in our replacement for the external interrupt IVT entry bundle 0
        movl        out0=PatchCodeNewBun0          // out0 = source buffer - our replacement bundle 0
        addl        out1=EXT_INT_ENTRY_OFFSET, r2  // out1 = destination buffer - bundle 0 of External interrupt entry
        mov         out2=1;;                       // out2 = copy 1 bundle
        br.call.sptk.few    b0 = CopyBundles

ChainHandlerDone:
        NESTED_RETURN

        .endp ChainHandler


/////////////////////////////////////////////
//
//  Name:
//      UnchainHandler
//
//  Description:
//      Unchains an interrupt handler
//
//  Arguments:
//
//  Returns:
//
//  Notes:
//
//
        .global UnchainHandler
        .proc UnchainHandler

UnchainHandler:

        NESTED_SETUP( 0,2+3,3,0 )

        mov         r8=1                        // r8 = success
        mov         r2=cr.iva;;                 // r2 = interrupt vector address

// First copy original Ext Int bundle 0 back to it's proper home...
        addl        out0=RELOCATED_EXT_INT, r2     // out0 = source - in reserved IVT
        addl        out1=EXT_INT_ENTRY_OFFSET, r2  // out1 = destination buffer - first bundle of Ext Int entry
        mov         out2=1;;                       // out2 = copy 1 bundle
        br.call.sptk.few    b0 = CopyBundles

// Now, relocate it again...
        addl        out0=EXT_INT_ENTRY_OFFSET, r2  // out1 = New runtime address
        addl        out1=RELOCATED_EXT_INT, r2;;   // out0 = IP address of previous location
        mov         out2=out0;;                    // out2 = IP address of new location
        br.call.sptk.few    b0 = RelocateBundle

// Last, restore the patch area
        movl        out0=PatchSaveBuffer           // out0 = source buffer
        addl        out1=PATCH_ENTRY_OFFSET, r2    // out1 = destination buffer
        mov         out2=0x40;;                    // out2 = number of bundles to copy... save entire IDT entry
        br.call.sptk.few    b0 = CopyBundles

UnchainHandlerDone:
        NESTED_RETURN

        .endp UnchainHandler


/////////////////////////////////////////////
//
//  Name:
//      CopyBundles
//
//  Description:
//      Copies instruction bundles - flushes icache as necessary
//
//  Arguments:
//      in0 - Bundle source
//      in1 - Bundle destination
//      in2 - Bundle count
//
//  Returns:
//
//  Notes:
//      This procedure is a leaf routine
//
        .proc   CopyBundles

CopyBundles:

        NESTED_SETUP(3,2+1,0,0)

        shl         in2=in2, 1;;                // in2 = count of 8 byte blocks to copy

CopyBundlesLoop:

        cmp.eq      p14, p15 = 0, in2;;         // Check if done
(p14)   br.sptk.few CopyBundlesDone;;

        ld8         loc2=[in0], 0x8;;           // loc2 = source bytes
        st8         [in1]=loc2;;                // [in1] = destination bytes
        fc          in1;;                       // Flush instruction cache
        sync.i;;                                // Ensure local and remote data/inst caches in sync
        srlz.i;;                                // Ensure sync has been observed
        add         in1=0x8, in1;;              // in1 = next destination
        add         in2=-1, in2;;               // in2 = decrement 8 bytes blocks to copy
        br.sptk.few CopyBundlesLoop;;

CopyBundlesDone:
        NESTED_RETURN

        .endp   CopyBundles


/////////////////////////////////////////////
//
//  Name:
//      RelocateBundle
//
//  Description:
//      Relocates an instruction bundle by updating any ip-relative branch instructions.
//
//  Arguments:
//      in0 - Runtime address of bundle
//      in1 - IP address of previous location of bundle
//      in2 - IP address of new location of bundle
//
//  Returns:
//      in0 - 1 if successful or 0 if unsuccessful
//
//  Notes:
//      This routine examines all slots in the given bundle that are destined for the
//      branch execution unit.  If any of these slots contain an IP-relative branch
//      namely instructions B1, B2, B3, or B6, the slot is fixed-up with a new relative
//      address.  Errors can occur if a branch cannot be reached.
//
        .proc   RelocateBundle

RelocateBundle:

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?