452 lines
13 KiB
ArmAsm
452 lines
13 KiB
ArmAsm
|
// TITLE("Interprocessor Interrupt support routines")
|
|||
|
//++
|
|||
|
//
|
|||
|
// Copyright (c) 1993 Microsoft Corporation
|
|||
|
//
|
|||
|
// Module Name:
|
|||
|
//
|
|||
|
// x4mpipi.s
|
|||
|
//
|
|||
|
// Abstract:
|
|||
|
//
|
|||
|
// This module implements the MIPS specific functions required to
|
|||
|
// support multiprocessor systems.
|
|||
|
//
|
|||
|
// Author:
|
|||
|
//
|
|||
|
// David N. Cutler (davec) 22-Apr-1993
|
|||
|
//
|
|||
|
// Environment:
|
|||
|
//
|
|||
|
// Kernel mode only.
|
|||
|
//
|
|||
|
// Revision History:
|
|||
|
//
|
|||
|
//--
|
|||
|
|
|||
|
#include "ksmips.h"
|
|||
|
|
|||
|
SBTTL("Interprocess Interrupt Processing")
|
|||
|
//++
|
|||
|
//
|
|||
|
// VOID
|
|||
|
// KeIpiInterrupt (
|
|||
|
// IN PKTRAP_FRAME TrapFrame
|
|||
|
// );
|
|||
|
//
|
|||
|
// Routine Description:
|
|||
|
//
|
|||
|
// This routine is entered as the result of an interprocessor interrupt.
|
|||
|
// It's function is to process all interprocess immediate and packet
|
|||
|
// requests.
|
|||
|
//
|
|||
|
// Arguments:
|
|||
|
//
|
|||
|
// TrapFrame (s8) - Supplies a pointer to a trap frame.
|
|||
|
//
|
|||
|
// Return Value:
|
|||
|
//
|
|||
|
// None.
|
|||
|
//
|
|||
|
//--
|
|||
|
|
|||
|
NESTED_ENTRY(KeIpiInterrupt, ExceptionFrameLength, zero)
|
|||
|
|
|||
|
subu sp,sp,ExceptionFrameLength // allocate exception frame
|
|||
|
sw ra,ExIntRa(sp) // save return address
|
|||
|
|
|||
|
PROLOGUE_END
|
|||
|
|
|||
|
//
|
|||
|
// Process all interprocessor requests.
|
|||
|
//
|
|||
|
|
|||
|
jal KiIpiProcessRequests // process requests
|
|||
|
andi v1,v0,IPI_FREEZE // check if freeze is requested
|
|||
|
beq zero,v1,10f // if eq, no freeze requested
|
|||
|
|
|||
|
//
|
|||
|
// Save the floating state.
|
|||
|
//
|
|||
|
|
|||
|
SAVE_VOLATILE_FLOAT_STATE // save volatile floating state
|
|||
|
|
|||
|
sdc1 f20,ExFltF20(sp) // save floating registers f20 - f31
|
|||
|
sdc1 f22,ExFltF22(sp) //
|
|||
|
sdc1 f24,ExFltF24(sp) //
|
|||
|
sdc1 f26,ExFltF26(sp) //
|
|||
|
sdc1 f28,ExFltF28(sp) //
|
|||
|
sdc1 f30,ExFltF30(sp) //
|
|||
|
|
|||
|
//
|
|||
|
// Freeze the execution of the current processor.
|
|||
|
//
|
|||
|
|
|||
|
move a0,s8 // set address of trap frame
|
|||
|
move a1,sp // set address of exception frame
|
|||
|
jal KiFreezeTargetExecution // freeze current processor execution
|
|||
|
|
|||
|
//
|
|||
|
// Restore the volatile floating state.
|
|||
|
//
|
|||
|
|
|||
|
RESTORE_VOLATILE_FLOAT_STATE // restore volatile floating state
|
|||
|
|
|||
|
ldc1 f20,ExFltF20(sp) // restore floating registers f20 - f31
|
|||
|
ldc1 f22,ExFltF22(sp) //
|
|||
|
ldc1 f24,ExFltF24(sp) //
|
|||
|
ldc1 f26,ExFltF26(sp) //
|
|||
|
ldc1 f28,ExFltF28(sp) //
|
|||
|
ldc1 f30,ExFltF30(sp) //
|
|||
|
|
|||
|
10: lw ra,ExIntRa(sp) // restore return address
|
|||
|
addu sp,sp,ExceptionFrameLength // deallocate exception frame
|
|||
|
j ra // return
|
|||
|
|
|||
|
.end KeIpiInterrupt
|
|||
|
|
|||
|
SBTTL("Processor Request")
|
|||
|
//++
|
|||
|
//
|
|||
|
// ULONG
|
|||
|
// KiIpiProcessRequests (
|
|||
|
// VOID
|
|||
|
// );
|
|||
|
//
|
|||
|
// Routine Description:
|
|||
|
//
|
|||
|
// This routine processes interprocessor requests and returns a summary
|
|||
|
// of the requests that were processed.
|
|||
|
//
|
|||
|
// Arguments:
|
|||
|
//
|
|||
|
// None.
|
|||
|
//
|
|||
|
// Return Value:
|
|||
|
//
|
|||
|
// The request summary is returned as the function value.
|
|||
|
//
|
|||
|
//--
|
|||
|
|
|||
|
.struct 0
|
|||
|
.space 4 * 4 // argument save area
|
|||
|
PrS0: .space 4 // saved integer register s0
|
|||
|
PrS1: .space 4 // saved integer register s1
|
|||
|
.space 4 // fill
|
|||
|
PrRa: .space 4 // saved return address
|
|||
|
PrFrameLength: // frame length
|
|||
|
|
|||
|
NESTED_ENTRY(KiIpiProcessRequests, PrFrameLength, zero)
|
|||
|
|
|||
|
subu sp,sp,PrFrameLength // allocate exception frame
|
|||
|
sw s0,PrS0(sp) // save integer register s0
|
|||
|
|
|||
|
#if NT_INST
|
|||
|
|
|||
|
sw s1,PrS1(sp) // save integer register s1
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
sw ra,PrRa(sp) // save return address
|
|||
|
|
|||
|
PROLOGUE_END
|
|||
|
|
|||
|
//
|
|||
|
// Read request summary and write a zero result interlocked.
|
|||
|
//
|
|||
|
|
|||
|
lw t0,KiPcr + PcPrcb(zero) // get current processor block address
|
|||
|
10: lld t1,PbRequestSummary(t0) // get request summary and entry address
|
|||
|
move t2,zero // set zero value for store
|
|||
|
scd t2,PbRequestSummary(t0) // zero request summary
|
|||
|
beq zero,t2,10b // if eq, store conditional failed
|
|||
|
dsra a0,t1,32 // shift entry address to low 32-bits
|
|||
|
move s0,t1 // copy request summary
|
|||
|
|
|||
|
//
|
|||
|
// Check for Packet ready.
|
|||
|
//
|
|||
|
// If a packet is ready, then get the address of the requested function
|
|||
|
// and call the function passing the address of the packet address as a
|
|||
|
// parameter.
|
|||
|
//
|
|||
|
|
|||
|
and t1,s0,IPI_PACKET_READY // check for packet ready
|
|||
|
beq zero,t1,20f // if eq, packet not ready
|
|||
|
lw t2,PbWorkerRoutine(a0) // get address of worker function
|
|||
|
lw a1,PbCurrentPacket(a0) // get request parameters
|
|||
|
lw a2,PbCurrentPacket + 4(a0) //
|
|||
|
lw a3,PbCurrentPacket + 8(a0) //
|
|||
|
jal t2 // call work routine
|
|||
|
|
|||
|
#if NT_INST
|
|||
|
|
|||
|
lw s1,PbIpiCounts(t0) // get interrupt count structure
|
|||
|
lw t1,IcPacket(s1) // increment number of packet requests
|
|||
|
addu t1,t1,1 //
|
|||
|
sw t1,IcPacket(s1) //
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// Check for APC interrupt request.
|
|||
|
//
|
|||
|
// If an APC interrupt is requested, then request a software interrupt at
|
|||
|
// APC level on the current processor.
|
|||
|
//
|
|||
|
|
|||
|
20: and t1,s0,IPI_APC // check for APC interrupt request
|
|||
|
beq zero,t1,25f // if eq, no APC interrupt requested
|
|||
|
|
|||
|
DISABLE_INTERRUPTS(t0) // disable interrupts
|
|||
|
|
|||
|
.set noreorder
|
|||
|
.set noat
|
|||
|
mfc0 t1,cause // get exception cause register
|
|||
|
or t1,t1,APC_INTERRUPT // set dispatch interrupt request
|
|||
|
mtc0 t1,cause // set exception cause register
|
|||
|
.set at
|
|||
|
.set reorder
|
|||
|
|
|||
|
ENABLE_INTERRUPTS(t0) // enable interrupts
|
|||
|
|
|||
|
#if NT_INST
|
|||
|
|
|||
|
lw t1,IcAPC(s1) // increment number of APC requests
|
|||
|
addu t1,t1,1 //
|
|||
|
sw t1,IcAPC(s1) //
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// Check for DPC interrupt request.
|
|||
|
//
|
|||
|
// If an DPC interrupt is requested, then request a software interrupt at
|
|||
|
// DPC level on the current processor.
|
|||
|
//
|
|||
|
|
|||
|
25: and t1,s0,IPI_DPC // check for DPC interrupt request
|
|||
|
beq zero,t1,30f // if eq, no DPC interrupt requested
|
|||
|
|
|||
|
DISABLE_INTERRUPTS(t0) // disable interrupts
|
|||
|
|
|||
|
.set noreorder
|
|||
|
.set noat
|
|||
|
mfc0 t1,cause // get exception cause register
|
|||
|
or t1,t1,DISPATCH_INTERRUPT // set dispatch interrupt request
|
|||
|
mtc0 t1,cause // set exception cause register
|
|||
|
.set at
|
|||
|
.set reorder
|
|||
|
|
|||
|
ENABLE_INTERRUPTS(t0) // enable interrupts
|
|||
|
|
|||
|
#if NT_INST
|
|||
|
|
|||
|
lw t1,IcDPC(s1) // increment number of DPC requests
|
|||
|
addu t1,t1,1 //
|
|||
|
sw t1,IcDPC(s1) //
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// Set function return value, restores registers, and return.
|
|||
|
//
|
|||
|
|
|||
|
30: move v0,s0 // set funtion return value
|
|||
|
lw s0,PrS0(sp) // restore integer register s0
|
|||
|
|
|||
|
#if NT_INST
|
|||
|
|
|||
|
and t1,v0,IPI_FREEZE // check if freeze requested
|
|||
|
beq zero,t1,40f // if eq, no freeze request
|
|||
|
lw t1,IcFreeze(s1) // increment number of freeze requests
|
|||
|
addu t1,t1,1 //
|
|||
|
sw t1,IcFreeze(s1) //
|
|||
|
40: lw s1,PrS1(sp) // restore integer register s1
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
lw ra,PrRa(sp) // restore return address
|
|||
|
addu sp,sp,PrFrameLength // deallocate stack frame
|
|||
|
j ra // return
|
|||
|
|
|||
|
.end KiIpiProcessRequests
|
|||
|
|
|||
|
SBTTL("Send Interprocess Request")
|
|||
|
//++
|
|||
|
//
|
|||
|
// VOID
|
|||
|
// KiIpiSend (
|
|||
|
// IN KAFINITY TargetProcessors,
|
|||
|
// IN KIPI_REQUEST IpiRequest
|
|||
|
// );
|
|||
|
//
|
|||
|
// Routine Description:
|
|||
|
//
|
|||
|
// This routine requests the specified operation on the target set of
|
|||
|
// processors.
|
|||
|
//
|
|||
|
// Arguments:
|
|||
|
//
|
|||
|
// TargetProcessors (a0) - Supplies the set of processors on which the
|
|||
|
// specified operation is to be executed.
|
|||
|
//
|
|||
|
// IpiRequest (a1) - Supplies the request operation mask.
|
|||
|
//
|
|||
|
// Return Value:
|
|||
|
//
|
|||
|
// None.
|
|||
|
//
|
|||
|
//--
|
|||
|
|
|||
|
LEAF_ENTRY(KiIpiSend)
|
|||
|
|
|||
|
#if !defined(NT_UP)
|
|||
|
|
|||
|
move v0,a0 // copy target processor set
|
|||
|
la v1,KiProcessorBlock // get processor block array address
|
|||
|
|
|||
|
//
|
|||
|
// Loop through the target processors and send the request to the specified
|
|||
|
// recipients.
|
|||
|
//
|
|||
|
|
|||
|
10: and t1,v0,1 // check if target bit set
|
|||
|
srl v0,v0,1 // shift out target processor
|
|||
|
beq zero,t1,30f // if eq, target not specified
|
|||
|
lw t1,0(v1) // get target processor block address
|
|||
|
20: lld t3,PbRequestSummary(t1) // get request summary of target
|
|||
|
or t3,t3,a1 // merge current request with summary
|
|||
|
scd t3,PbRequestSummary(t1) // store request summary and entry address
|
|||
|
beq zero,t3,20b // if eq, store conditional failed
|
|||
|
30: add v1,v1,4 // advance to next array element
|
|||
|
bne zero,v0,10b // if ne, more targets requested
|
|||
|
lw t0,__imp_HalRequestIpi // request IPI interrupt on targets
|
|||
|
j t0 //
|
|||
|
#else
|
|||
|
|
|||
|
j ra // return
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
.end KiIpiSend
|
|||
|
|
|||
|
SBTTL("Send Interprocess Request Packet")
|
|||
|
//++
|
|||
|
//
|
|||
|
// VOID
|
|||
|
// KiIpiSendPacket (
|
|||
|
// IN KAFINITY TargetProcessors,
|
|||
|
// IN PKIPI_WORKER WorkerFunction,
|
|||
|
// IN PVOID Parameter1,
|
|||
|
// IN PVOID Parameter2,
|
|||
|
// IN PVOID Parameter3
|
|||
|
// );
|
|||
|
//
|
|||
|
// Routine Description:
|
|||
|
//
|
|||
|
// This routine executes the specified worker function on the specified
|
|||
|
// set of processors.
|
|||
|
//
|
|||
|
// Arguments:
|
|||
|
//
|
|||
|
// TargetProcessors (a0) - Supplies the set of processors on which the
|
|||
|
// specified operation is to be executed.
|
|||
|
//
|
|||
|
// WorkerFunction (a1) - Supplies the address of the worker function.
|
|||
|
//
|
|||
|
// Parameter1 - Parameter3 (a2, a3, 4 * 4(sp)) - Supplies worker
|
|||
|
// function specific parameters.
|
|||
|
//
|
|||
|
// Return Value:
|
|||
|
//
|
|||
|
// None.
|
|||
|
//
|
|||
|
//--
|
|||
|
|
|||
|
LEAF_ENTRY(KiIpiSendPacket)
|
|||
|
|
|||
|
#if !defined(NT_UP)
|
|||
|
|
|||
|
lw t0,KiPcr + PcPrcb(zero) // get current processor block address
|
|||
|
move v0,a0 // copy target processor set
|
|||
|
la v1,KiProcessorBlock // get processor block array address
|
|||
|
|
|||
|
//
|
|||
|
// Store function address and parameters in the packet area of the PRCB on
|
|||
|
// the current processor.
|
|||
|
//
|
|||
|
|
|||
|
lw t9,4 * 4(sp) // get parameter3 value
|
|||
|
sw a0,PbTargetSet(t0) // set target processor set
|
|||
|
sw a1,PbWorkerRoutine(t0) // set worker function address
|
|||
|
sw a2,PbCurrentPacket(t0) // store worker function parameters
|
|||
|
sw a3,PbCurrentPacket + 4(t0) //
|
|||
|
sw t9,PbCurrentPacket + 8(t0) //
|
|||
|
|
|||
|
//
|
|||
|
// Loop through the target processors and send the packet to the specified
|
|||
|
// recipients.
|
|||
|
//
|
|||
|
|
|||
|
10: and t1,v0,1 // check if target bit set
|
|||
|
srl v0,v0,1 // shift out target processor
|
|||
|
beq zero,t1,30f // if eq, target not specified
|
|||
|
lw t1,0(v1) // get target processor block address
|
|||
|
dsll t3,t0,32 // shift entry address to upper 32-bits
|
|||
|
or t3,t3,IPI_PACKET_READY // set packet ready in lower 32-bits
|
|||
|
20: lld t4,PbRequestSummary(t1) // get request summary of target
|
|||
|
and t5,t4,IPI_PACKET_READY // check if target packet busy
|
|||
|
or t4,t4,t3 // set entry address in request summary
|
|||
|
bne zero,t5,20b // if ne, target packet busy
|
|||
|
scd t4,PbRequestSummary(t1) // store request summary and entry address
|
|||
|
beq zero,t4,20b // if eq, store conditional failed
|
|||
|
30: addu v1,v1,4 // advance to get array element
|
|||
|
bne zero,v0,10b // if ne, more targets requested
|
|||
|
lw t0,__imp_HalRequestIpi // request IPI interrupt on targets
|
|||
|
j t0 //
|
|||
|
|
|||
|
#else
|
|||
|
|
|||
|
j ra // return
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
.end KiIpiSendPacket
|
|||
|
|
|||
|
SBTTL("Signal Packet Done")
|
|||
|
//++
|
|||
|
//
|
|||
|
// VOID
|
|||
|
// KeIpiSignalPacketDone (
|
|||
|
// IN PVOID SignalDone
|
|||
|
// );
|
|||
|
//
|
|||
|
// Routine Description:
|
|||
|
//
|
|||
|
// This routine signals that a processor has completed a packet by
|
|||
|
// clearing the calling processor's set member of the requesting
|
|||
|
// processor's packet.
|
|||
|
//
|
|||
|
// Arguments:
|
|||
|
//
|
|||
|
// SignalDone (a0) - Supplies a pointer to the processor block of the
|
|||
|
// sending processor.
|
|||
|
//
|
|||
|
// Return Value:
|
|||
|
//
|
|||
|
// None.
|
|||
|
//
|
|||
|
//--
|
|||
|
|
|||
|
LEAF_ENTRY(KiIpiSignalPacketDone)
|
|||
|
|
|||
|
lw a1,KiPcr + PcNotMember(zero) // get processor set member
|
|||
|
10: ll a2,PbTargetSet(a0) // get request target set
|
|||
|
and a2,a2,a1 // clear processor set member
|
|||
|
sc a2,PbTargetSet(a0) // store target set
|
|||
|
beq zero,a2,10b // if eq, store conditional failed
|
|||
|
j ra // return
|
|||
|
|
|||
|
.end KiIpiSignalPacketDone
|