AsmFuncs.s revision 4fd606d1f5abe38e1f42c38de1d2e895166bd0f4
/// @file
/// Low level IPF routines used by the debug support driver
///
/// Copyright (c) 2006 - 2008, 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
///
/// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
/// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
///
///
#include "Common.i"
#include "Ds64Macros.i"
/////////////////////////////////////////////
//
// Name:
// InstructionCacheFlush
//
// Description:
// Flushes instruction cache for specified number of bytes
//
.align 32
{ .mii
}
{ .mii
nop.m 0
}
{ .mii
}
{ .mii
nop.m 0
}
{ .mfb
nop.f 0
nop.b 0
}
LoopBack: // $L143:
{ .mii
}
{ .mfb
nop.m 0
nop.f 0
//(p14) br.cond.dptk.few $L143#;;
}
{ .mmi
sync.i;;
srlz.i
nop.i 0;;
}
{ .mfb
nop.m 0
nop.f 0
}
/////////////////////////////////////////////
//
// 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:
//
//
//
// 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
//
// Next, copy the patch code into the IVT
// copy original bundle 0 from the external interrupt handler to the
// appropriate place in the reserved IVT interrupt slot
// Now relocate it there because it very likely had a branch instruction that
// that must now be fixed up.
// 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
// Last, copy in our replacement for the external interrupt IVT entry bundle 0
addl out1=EXT_INT_ENTRY_OFFSET, r2 // out1 = destination buffer - bundle 0 of External interrupt entry
/////////////////////////////////////////////
//
// Name:
// UnchainHandler
//
// Description:
// Unchains an interrupt handler
//
// Arguments:
//
// Returns:
//
// Notes:
//
//
// First copy original Ext Int bundle 0 back to it's proper home...
// Now, relocate it again...
// Last, restore the patch area
/////////////////////////////////////////////
//
// 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
//
srlz.i;; // Ensure sync has been observed
/////////////////////////////////////////////
//
// 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.
//
/////////////////////////////////////////////
//
// Name:
// RelocateSlot
//
// Description:
// Relocates an instruction bundle by updating any ip-relative branch instructions.
//
// Arguments:
// in0 - Instruction encoding (41-bits, right justified)
// in1 - IP address of previous location of bundle
// in2 - IP address of new location of bundle
//
// Returns:
// in0 - Instruction encoding (41-bits, right justified)
// in1 - 1 if successful otherwise 0
//
// Notes:
// This procedure is a leaf routine
//
// IP-relative counted branch (B2)
/////////////////////////////////////////////
//
// Name:
// IsSlotBranch
//
// Description:
// Determines if the given instruction is a branch instruction.
//
// Arguments:
// in0 - Instruction encoding (41-bits, right justified)
// in1 - Instruction slot number
// in2 - Bundle template
//
// Returns:
// in0 - 1 if branch or 0 if not branch
//
// Notes:
// This procedure is a leaf routine
//
// IsSlotBranch recognizes all branch instructions by looking at the provided template.
// The instruction encoding is only passed to this routine for future expansion.
//
/////////////////////////////////////////////
//
// Name:
// GetTemplate
//
// Description:
// Retrieves the instruction template for an instruction bundle
//
// Arguments:
// in0 - Runtime address of bundle
//
// Returns:
// in0 - Instruction template (5-bits, right-justified)
//
// Notes:
// This procedure is a leaf routine
//
/////////////////////////////////////////////
//
// Name:
// GetSlot
//
// Description:
// Gets the instruction encoding for an instruction slot and bundle
//
// Arguments:
// in0 - Runtime address of bundle
// in1 - Instruction slot (either 0, 1, or 2)
//
// Returns:
// in0 - Instruction encoding (41-bits, right justified)
//
// Notes:
// This procedure is a leaf routine
//
// Slot0 - [in0 + 0x8] Bits 45-5
// Slot1 - [in0 + 0x8] Bits 63-46 and [in0] Bits 22-0
// Slot2 - [in0] Bits 63-23
//
/////////////////////////////////////////////
//
// Name:
// SetSlot
//
// Description:
// Sets the instruction encoding for an instruction slot and bundle
//
// Arguments:
// in0 - Runtime address of bundle
// in1 - Instruction slot (either 0, 1, or 2)
// in2 - Instruction encoding (41-bits, right justified)
//
// Returns:
//
// Notes:
// This procedure is a leaf routine
//
;;
/////////////////////////////////////////////
//
// Name:
// GetIva
//
// Description:
// C callable function to obtain the current value of IVA
//
// Returns:
// Current value if IVA
/////////////////////////////////////////////
//
// Name:
// ProgramInterruptFlags
//
// Description:
//
// Returns:
// Previous state of psr.ic
//
srlz.d
/////////////////////////////////////////////
//
// Name:
// SpillContext
//
// Description:
// Saves system context to context record.
//
// Arguments:
// in0 = 512 byte aligned context record address
// in1 = original B0
// in2 = original ar.bsp
// in3 = original ar.bspstore
// in4 = original ar.rnat
// in5 = original ar.pfs
//
// Notes:
// loc0 - scratch
// loc1 - scratch
// loc2 - temporary application unat storage
// loc3 - temporary exception handler unat storage
// save control registers
// save debug registers
/////////////////////////////////////////////
//
// Name:
// FillContext
//
// Description:
// Restores register context from context record.
//
// Arguments:
// in0 = address of last element 512 byte aligned context record address
// in1 = modified B0
// in2 = modified ar.bsp
// in3 = modified ar.bspstore
// in4 = modified ar.rnat
// in5 = modified ar.pfs
//
// Notes:
// loc0 - scratch
// loc1 - scratch
// loc2 - temporary application unat storage
// loc3 - temporary exception handler unat storage
/////////////////////////////////////////////
//
// Name:
// HookHandler
//
// Description:
// Common branch target from hooked IVT entries. Runs in interrupt context.
// Responsible for saving and restoring context and calling common C
// handler. Banked registers running on bank 0 at entry.
//
// Arguments:
// All arguments are passed in banked registers:
// B0_REG = Original B0
// SCRATCH_REG1 = IVT entry index
//
// Returns:
// Returns via rfi
//
// Notes:
// loc0 - scratch
// loc1 - scratch
// loc2 - vector number / mask
// loc3 - 16 byte aligned context record address
// loc4 - temporary storage of last address in context record
flushrs;; // Synch RSE with backing store
cover;; // creates new frame, moves old
// CFM to IFS.
;;
// save banked registers to locals
srlz.d // explicit serialize required
// now fill in context record structure
// loc3 now contains the 512 byte aligned context record
// spill register context into context record
// original B0 in out1 already
// original ar.bsp in out2 already
// original ar.bspstore in out3 already
// At this point, the context has been saved to the context record and we're
// ready to call the C part of the handler...
// We've returned from the C call, so restore the context and either rfi
// back to interrupted thread, or chain into the SAL if this was an external interrupt
// Loadrs is necessary because the debugger may have changed some values in
// the backing store. The processor, however may not be aware that the
// stacked registers need to be reloaded from the backing store. Therefore,
// we explicitly cause the RSE to refresh the stacked register's contents
// from the backing store.
loadrs;; // invalidate register stack
bsw.0;; // switch banked registers back to bank 0
srlz.d;; // explicit serialize required
rfi;; // we're outa here.
/////////////////////////////////////////////
//
// Name:
// HookStub
//
// Description:
// HookStub will be copied from it's loaded location into the IVT when
// an IVT entry is hooked. The IVT entry does an indirect jump via B0 to
// HookHandler, which in turn calls into the default C handler, which calls
// the user-installed C handler. The calls return and HookHandler executes
// an rfi.
//
// Notes:
// Saves B0 to B0_REG
// Saves IVT index to SCRATCH_REG1 (immediate value is fixed up when code is copied
// to the IVT entry.
mov SCRATCH_REG1=0;;// immediate value is fixed up during install of handler to be the vector number
/////////////////////////////////////////////
// The following code is moved into IVT entry 14 (offset 3400) which is reserved
// in the Itanium architecture. The patch code is located at the end of the
// IVT entry.
// turn off any virtual translations
srlz.d
// interrupted from IA32
// context. If so, bail out
// and chain to SAL immediately
// we only want to take 1 out of 32 external interrupts to minimize the
// impact to system performance. Check our interrupt count and bail
// out if we're not up to 32
// ExternalInterruptCount
// and Chain to SAL
// immediately
// ExternalInterruptCount
// and branch to
// HookHandler
// fake-up an rfi to get RSE back to being coherent and insure psr has
// original contents when interrupt occured, then exit to SAL
// at this point:
// cr.ifs has been modified by previous "cover"
// SCRATCH_REG6 has original cr.ifs
rfi;; // rfi to next instruction
/////////////////////////////////////////////
// The following bundle is moved into IVT entry 14 (offset 0x3400) which is reserved
// in the Itanium architecture. This bundle will be the last bundle and will
// be located at offset 0x37F0 in the IVT.
{
.mib
nop.m 0
nop.i 0
}
/////////////////////////////////////////////
// The following bundle is moved into IVT entry 13 (offset 0x3000) which is the
// external interrupt. It branches to the patch code.
{
.mib
nop.m 0
nop.i 0
}