284 lines
6.8 KiB
NASM
284 lines
6.8 KiB
NASM
title "Software Interrupts"
|
|
;++
|
|
;
|
|
;Copyright (c) 1992, 1993, 1994 Corollary Inc
|
|
;
|
|
;Module Name:
|
|
;
|
|
; cbuscbc.asm
|
|
;
|
|
;Abstract:
|
|
;
|
|
; This module implements the Corollary Cbus2 HAL routines to deal
|
|
; with the Corollary CBC distributed interrupt controller chip.
|
|
;
|
|
; This includes the_sending_ of software and IPI interrupts in Windows NT.
|
|
; The receipt of these interrupts is handled elsewhere.
|
|
;
|
|
; Note: The routines in this module are jmp'ed to directly from
|
|
; their common Hal counterparts.
|
|
;
|
|
;Author:
|
|
;
|
|
; Landy Wang (landy@corollary.com) 26-Mar-1992
|
|
;
|
|
;Environment:
|
|
;
|
|
; Kernel Mode
|
|
;
|
|
;Revision History:
|
|
;
|
|
;--
|
|
|
|
|
|
.386p
|
|
.xlist
|
|
include hal386.inc
|
|
include callconv.inc ; calling convention macros
|
|
include i386\kimacro.inc
|
|
include cbus.inc
|
|
|
|
;
|
|
; Some definitions needed for accessing the Corollary CBC...
|
|
;
|
|
|
|
INTS_ENABLED equ 200 ; X86 EFLAGS bit definition
|
|
|
|
.list
|
|
|
|
_TEXT SEGMENT DWORD PUBLIC 'CODE'
|
|
ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
|
|
|
|
;++
|
|
;
|
|
; VOID
|
|
; Cbus2RequestSoftwareInterrupt (
|
|
; IN KIRQL RequestIrql
|
|
; )
|
|
;
|
|
; Routine Description:
|
|
;
|
|
; This routine is used to issue a software interrupt to the
|
|
; calling processor. Since this is all done in hardware, the
|
|
; code to implement this is trivial. Our hardware supports
|
|
; sending the interrupt to lowest-in-group processors, which
|
|
; would be useful for a good number of DPCs, for example, but
|
|
; the kernel doesn't currently tell us which kinds of software
|
|
; interrupts need to go to the caller versus which can go to
|
|
; any processor.
|
|
;
|
|
; Arguments:
|
|
;
|
|
; (esp+4) = RequestIrql - Supplies the request IRQL value
|
|
;
|
|
; Return Value:
|
|
;
|
|
; None.
|
|
;
|
|
;--
|
|
|
|
;
|
|
; equates for accessing arguments
|
|
;
|
|
|
|
KsiRequestIrql equ byte ptr [esp+4]
|
|
|
|
cPublicProc _Cbus2RequestSoftwareInterrupt ,1
|
|
|
|
xor ecx, ecx ; (faster than movzx)
|
|
mov cl, KsiRequestIrql ; to get the irql
|
|
|
|
mov eax, [_Cbus2IrqlToCbus2Addr+4*ecx] ; get h/w CSR offset
|
|
ifdef CBC_REV1
|
|
pushfd
|
|
cli
|
|
add eax, PCR[PcHal.PcrCSR] ; get h/w CSR base
|
|
|
|
mov dword ptr [eax], 1 ; send the interrupt
|
|
popfd
|
|
else
|
|
mov dword ptr [eax], 1 ; send the interrupt
|
|
endif
|
|
|
|
stdRET _Cbus2RequestSoftwareInterrupt
|
|
stdENDP _Cbus2RequestSoftwareInterrupt
|
|
|
|
page ,132
|
|
subttl "Cbus2RequestIpi"
|
|
;++
|
|
;
|
|
; VOID
|
|
; Cbus2RequestIpi(
|
|
; IN ULONG Mask
|
|
; );
|
|
;
|
|
; Routine Description:
|
|
;
|
|
; Requests an interprocessor interrupt.
|
|
;
|
|
; This is generally not an easy thing in Cbus2 hardware...
|
|
;
|
|
; a) Interrupting everyone incl yourself: EASY IN HARDWARE
|
|
;
|
|
; b) Interrupting everyone but yourself: DIFFICULT IN HARDWARE,
|
|
; MADE EASY BY SOFTWARE
|
|
;
|
|
; c) Interrupting a random processor subset: DIFFICULT IN HARDWARE,
|
|
; NOT EASY FOR SOFTWARE EITHER,
|
|
; RESULTS IN LOOPING BELOW
|
|
;
|
|
;
|
|
; To deal with case b), a set of MAX_CBUS_ELEMENTS interrupts have
|
|
; been allocated for IPI vectors. Each processor participates in ALL of them
|
|
; EXCEPT one. So for any processor to issue a global broadcast to all
|
|
; the others, he just sends the IPI vector which he isn't participating in.
|
|
;
|
|
; To support case c) using the case b) model would result in too many
|
|
; vectors being allocated, so instead we loop here in software to do it.
|
|
;
|
|
; Arguments:
|
|
;
|
|
; Mask - Mask of processors to be interrupted
|
|
;
|
|
; Return Value:
|
|
;
|
|
; None.
|
|
;
|
|
;--
|
|
|
|
cPublicProc _Cbus2RequestIpi ,1
|
|
mov edx, [esp+4] ; get requested recipients
|
|
|
|
cmp [_Cbus2EnableBroadcast], 1
|
|
jne short somesubset
|
|
|
|
cmp edx, PCR[PcHal.PcrAllOthers] ; broadcast to everyone else?
|
|
jne short somesubset ; no, some subset of processors
|
|
|
|
mov edx, PCR[PcHal.PcrBroadcast] ; get h/w addr of all others
|
|
mov dword ptr [edx], 1 ; interrupt them all
|
|
|
|
stdRET _Cbus2RequestIpi
|
|
|
|
;
|
|
; somewhat unwieldy to structure the code this way, but
|
|
; it avoids the expensive bsr/bsf. to avoid a 64K array
|
|
; of processor numbers, do it in two separate passes,
|
|
; first do processors 0 through 7, and then processors 8
|
|
; through 0xF.
|
|
;
|
|
|
|
align 4
|
|
somesubset:
|
|
|
|
or dl, dl ; any processors 0..7 ?
|
|
jz highcpus ; no, check processors 8..F
|
|
|
|
align 4
|
|
@@:
|
|
movzx ecx, dl ; set up working copy
|
|
mov cl, _HalpFindFirstSetRight[ecx] ; get processor number
|
|
|
|
mov eax, 1
|
|
shl eax, cl
|
|
xor edx, eax ; clear bit in requested mask
|
|
|
|
; get correct IPI address
|
|
mov ecx, dword ptr [_Cbus2SendIPI + ecx * 4]
|
|
|
|
mov dword ptr [ecx], 1 ; send this processor the IPI
|
|
|
|
or dl, dl ; any more processors 0..7 ?
|
|
jnz short @b ; get next 0..7 processor
|
|
|
|
align 4
|
|
highcpus:
|
|
or dh, dh ; any processors 8..F?
|
|
jz alldone ; no, all done
|
|
shr edx, 8 ; check high processors in dl
|
|
|
|
align 4
|
|
@@:
|
|
movzx ecx, dl ; set up working copy
|
|
mov cl, _HalpFindFirstSetRight[ecx] ; get (processor number - 8)
|
|
|
|
mov eax, 1
|
|
shl eax, cl
|
|
xor edx, eax ; clear bit in requested mask
|
|
|
|
add ecx, 8 ; in second set of processors
|
|
|
|
; get correct IPI address
|
|
mov ecx, [_Cbus2SendIPI + ecx * 4 ]
|
|
|
|
mov dword ptr [ecx], 1 ; send this processor the IPI
|
|
|
|
or dl, dl ; any more processors 0..7 ?
|
|
jnz short @b ; get next 0..7 processor
|
|
|
|
align 4
|
|
alldone:
|
|
|
|
stdRET _Cbus2RequestIpi
|
|
stdENDP _Cbus2RequestIpi
|
|
|
|
;
|
|
; ULONG
|
|
; Cbus2ReadCSR(
|
|
; ULONG CsrAddress
|
|
; )
|
|
;
|
|
; Routine Description:
|
|
;
|
|
; Read the specified register in the CSR space. This routine is
|
|
; coded in assembly because the register must be read/written 32
|
|
; bits at a time, and we don't want the compiler "optimizing" our
|
|
; accesses into byte-enabled operations which the hardware won't
|
|
; understand.
|
|
;
|
|
; Arguments:
|
|
; (esp+4) = Address of the CSR register
|
|
;
|
|
; Returns:
|
|
; Value of the register.
|
|
;
|
|
;--
|
|
cPublicProc _Cbus2ReadCSR ,1
|
|
mov ecx, [esp + 4] ; CSR register address
|
|
mov eax, dword ptr [ecx] ; return CSR register contents
|
|
stdRET _Cbus2ReadCSR
|
|
stdENDP _Cbus2ReadCSR
|
|
|
|
;++
|
|
;
|
|
; VOID
|
|
; Cbus2WriteCSR(
|
|
; ULONG CsrAddress
|
|
; )
|
|
;
|
|
; Routine Description:
|
|
;
|
|
; Write the specified register in the CSR space. This routine is
|
|
; coded in assembly because the register must be read/written 32
|
|
; bits at a time, and we don't want the compiler "optimizing" our
|
|
; accesses into byte-enabled operations which the hardware won't
|
|
; understand.
|
|
;
|
|
; Arguments:
|
|
; (esp+4) = Address of the CSR register
|
|
; (esp+8) = Contents to write to the specified register
|
|
;
|
|
;--
|
|
cPublicProc _Cbus2WriteCSR ,2
|
|
|
|
mov ecx, [esp + 4] ; CSR register address
|
|
mov eax, [esp + 8] ; new contents
|
|
mov [ecx], eax ; set the new value
|
|
|
|
stdRET _Cbus2WriteCSR
|
|
|
|
stdENDP _Cbus2WriteCSR
|
|
|
|
_TEXT ENDS
|
|
END
|