title "Interprocessor Interrupt"
;++
;
;Copyright (c) 1991 Microsoft Corporation
;Copyright (c) 1992 Intel Corporation
;All rights reserved
;
;INTEL CORPORATION PROPRIETARY INFORMATION
;
;This software is supplied to Microsoft under the terms
;of a license agreement with Intel Corporation and may not be
;copied nor disclosed except in accordance with the terms
;of that agreement.
;
;
;Module Name:
;
; mpipi.asm
;
;Abstract:
;
; PC+MP IPI code.
; Provides the HAL support for Interprocessor Interrupts and Processor
; initialization for PC+MP Systems
;
;Author:
;
; Ken Reneris (kenr) 13-Jan-1992
;
;Revision History:
;
; Ron Mosgrove (Intel) Aug 1993
; Modified for PC+MP Systems
;--
.386p
.xlist
;
; Normal includes
;
include hal386.inc
include i386\kimacro.inc
include mac386.inc
include i386\apic.inc
include callconv.inc ; calling convention macros
include i386\pcmp_nt.inc
EXTRNP Kei386EoiHelper,0,IMPORT
EXTRNP _HalBeginSystemInterrupt,3
EXTRNP _HalEndSystemInterrupt,2
EXTRNP _KiIpiServiceRoutine,2,IMPORT
EXTRNP _HalDisplayString,1
EXTRNP HalpAcquireHighLevelLock,1,,FASTCALL
EXTRNP HalpReleaseHighLevelLock,2,,FASTCALL
EXTRNP _DetectMPS,1
EXTRNP _HalpInitializeLocalUnit,0
EXTRNP _HalpResetThisProcessor,0
if DBG OR DEBUGGING
EXTRNP _DbgBreakPoint,0,IMPORT
endif
extrn _HalpDefaultInterruptAffinity:DWORD
extrn _HalpActiveProcessors:DWORD
extrn _HalpGlobal8259Mask:WORD
extrn _HalpPICINTToVector:BYTE
extrn _rgzBadHal:BYTE
I386_80387_BUSY_PORT equ 0f0h
_DATA SEGMENT DWORD PUBLIC 'DATA'
ALIGN dword
public _HalpProcessorPCR
_HalpProcessorPCR dd MAXIMUM_PROCESSORS dup (?) ; PCR pointer for each processor
;
; The following symbols are used by the Local Apic Error handler.
;
LogApicErrors equ 1
if LogApicErrors
public _HalpLocalApicErrorLock
public _HalpLocalApicErrorCount
public _HalpApicErrorLog
APIC_ERROR_LOG_SIZE equ 128 ; Must be 2^n see usage below
ALIGN dword
_HalpApicErrorLog dw APIC_ERROR_LOG_SIZE dup(0)
_HalpLocalApicErrorLock dd 0
_HalpLocalApicErrorCount dd 0
;
; Bit:
;
; 0 - Send checksum error
; 1 - Recieve checksum error
; 2 - Send accept error
; 3 - Receive accept error
; 4 - reserved
; 5 - Send illegal vector
; 6 - Receive illegal vector
; 7 - illegal register address
; 8-31 - reserved
;
endif ; LogApicErrors
public HalpBroadcastLock, HalpBroadcastTargets
public HalpBroadcastFunction, HalpBroadcastContext
HalpBroadcastLock dd 0
HalpBroadcastFunction dd 0
HalpBroadcastContext dd 0
HalpBroadcastTargets dd 0
ALIGN dword
;
; The _PicExtintIntiHandlers and the _PicNopIntiHandlers tables are
; used by the enable and disable system interrupt routines to determine
; the EXTINT interrupt handler to install.
;
public _PicExtintIntiHandlers
_PicExtintIntiHandlers label dword
dd PicInterruptHandlerInti0 ; Inti 0 - PIC 1
dd PicInterruptHandlerInti1 ; Inti 1 - PIC 1
dd PicInterruptHandlerInti2 ; Inti 2 - PIC 1
dd PicInterruptHandlerInti3 ; Inti 3 - PIC 1
dd PicInterruptHandlerInti4 ; Inti 4 - PIC 1
dd PicInterruptHandlerInti5 ; Inti 5 - PIC 1
dd PicInterruptHandlerInti6 ; Inti 6 - PIC 1
dd PicInterruptHandlerInti7 ; Inti 7 - PIC 1
dd PicInterruptHandlerInti8 ; Inti 8 - PIC 2
dd PicInterruptHandlerInti9 ; Inti 9 - PIC 2
dd PicInterruptHandlerIntiA ; Inti 10 - PIC 2
dd PicInterruptHandlerIntiB ; Inti 11 - PIC 2
dd PicInterruptHandlerIntiC ; Inti 12 - PIC 2
dd PicInterruptHandlerIntiD ; Inti 13 - PIC 2
dd PicInterruptHandlerIntiE ; Inti 14 - PIC 2
dd PicInterruptHandlerIntiF ; Inti 15 - PIC 2
public _PicNopIntiHandlers
_PicNopIntiHandlers label dword
dd PicNopHandlerInti0 ; Inti 0 - PIC 1
dd PicNopHandlerInti1 ; Inti 1 - PIC 1
dd PicNopHandlerInti2 ; Inti 2 - PIC 1
dd PicNopHandlerInti3 ; Inti 3 - PIC 1
dd PicNopHandlerInti4 ; Inti 4 - PIC 1
dd PicNopHandlerInti5 ; Inti 5 - PIC 1
dd PicNopHandlerInti6 ; Inti 6 - PIC 1
dd PicNopHandlerInti7 ; Inti 7 - PIC 1
dd CommonPic2NopHandler ; Inti 8 - PIC 2
dd CommonPic2NopHandler ; Inti 9 - PIC 2
dd CommonPic2NopHandler ; Inti 10 - PIC 2
dd CommonPic2NopHandler ; Inti 11 - PIC 2
dd CommonPic2NopHandler ; Inti 12 - PIC 2
dd PicNopHandlerIntiD ; Inti 13 - PIC 2
dd CommonPic2NopHandler ; Inti 14 - PIC 2
dd CommonPic2NopHandler ; Inti 15 - PIC 2
_DATA ends
page ,132
subttl "Post InterProcessor Interrupt"
_TEXT SEGMENT DWORD PUBLIC 'CODE'
ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
;++
;
; VOID
; HalInitializeProcessor(
; ULONG Number
; );
;
;Routine Description:
;
; Initialize hal pcr values for current processor (if any)
; (called shortly after processor reaches kernel, before
; HalInitSystem if P0)
;
; IPI's and KeReadir/LowerIrq's must be available once this function
; returns. (IPI's are only used once two or more processors are
; available)
;
; . Enable IPI interrupt (makes sense for P1, P2, ...).
; . Save Processor Number in PCR.
; . if (P0)
; . determine if the system is a PC+MP,
; . if not a PC+MP System Halt;
; . Enable IPI's on CPU.
;
;Arguments:
;
; Number - Logical processor number of calling processor
;
;Return Value:
;
; None.
;
;--
cPublicProc _HalInitializeProcessor ,1
mov PCR[PcIDR], 0FFFFFFFFH ; mark all INTs as disabled
movzx eax, byte ptr [esp+4]
mov PCR[PcHal.PcrNumber], al ; Save processor # in PCR
mov ecx, PCR[PcSelfPcr] ; Flat address of this PCR
mov _HalpProcessorPCR[eax*4], ecx ; Save it away
mov dword ptr PCR[PcStallScaleFactor], INITIAL_STALL_COUNT
;
; set bit in interrupt affinity mask for this processor
;
lock bts _HalpDefaultInterruptAffinity, eax
lock bts _HalpActiveProcessors, eax
;
; Most of the following code is only needed on P0
;
or eax, eax
jnz PnInitCode ; Not P0 skip a lot
; Run on P0 only
;
; Determine if the system we are on is an PC+MP
;
; DetectMPS has a parameter we don't currently use. It's a boolean
; which is set to TRUE if the system we're on is a MP system. Remember,
; we could have a UP PC+MP system.
;
; The DetectMPS routine also allocates Virtual Addresses for all of
; the APIC's in the system (it needs to access the devices anyway so ...)
;
sub esp, 4
stdCall _DetectMPS <esp> ; Are we running on an PC+MP
add esp,4
cmp eax, 0 ; Yes (nonZero) or
je NotPcMp ; No (Zero)
; stdCall _HalDisplayString, <offset HalSignonString>
mov ax, 0FFFFH ; mask all PIC interrupts
mov _HalpGlobal8259Mask, ax ; save the mask
SET_8259_MASK
;
; Other P0 initialization would go here
;
jmp CommonInitCode
PnInitCode:
;
; Pn initialization goes here
;
CommonInitCode:
stdCall _HalInitApicInterruptHandlers
;
; initialize the APIC local unit for this Processor
;
stdCall _HalpInitializeLocalUnit
stdRET _HalInitializeProcessor
NotPcMp:
stdCall _HalDisplayString, <offset _rgzBadHal>
hlt
stdENDP _HalInitializeProcessor
D_INT032 EQU 8E00h ; access word for 386 ring 0 interrupt gate
;++
;
; VOID
; HalInitApicInterruptHandlers(
; );
;
;Routine Description:
;
; This routine installs the interrupt vector in the IDT for the APIC
; spurious interrupt.
;
;Arguments:
;
; None.
;
;Return Value:
;
; None.
;
;--
cPublicProc _HalInitApicInterruptHandlers ,0
enter 8,0 ; setup ebp, reserve 8 bytes of stack
sidt fword ptr [ebp-8] ; get IDT address
mov edx, [ebp-6] ; (edx)->IDT
mov ecx, PIC1_SPURIOUS_VECTOR ; Spurious Vector
mov eax, offset FLAT:PicSpuriousService37
mov word ptr [edx+8*ecx], ax ; Lower half of handler addr
mov word ptr [edx+8*ecx+2], KGDT_R0_CODE ; set up selector
mov word ptr [edx+8*ecx+4], D_INT032 ; 386 interrupt gate
shr eax, 16 ; (ax)=higher half of handler addr
mov word ptr [edx+8*ecx+6], ax
mov ecx, APIC_SPURIOUS_VECTOR ; Apic Spurious Vector
mov eax, offset FLAT:_HalpApicSpuriousService
mov word ptr [edx+8*ecx], ax ; Lower half of handler addr
mov word ptr [edx+8*ecx+2], KGDT_R0_CODE ; set up selector
mov word ptr [edx+8*ecx+4], D_INT032 ; 386 interrupt gate
shr eax, 16 ; (ax)=higher half of handler addr
mov word ptr [edx+8*ecx+6], ax
leave
stdRET _HalInitApicInterruptHandlers
stdENDP _HalInitApicInterruptHandlers
cPublicProc PicSpuriousService37 ,0
iretd
stdENDP PicSpuriousService37
;++
;
; VOID
; HalpApicRebootService(
; );
;
;Routine Description:
;
; This is the ISR that handles Reboot events
;
;--
ENTER_DR_ASSIST HReboot_a, HReboot_t
cPublicProc _HalpApicRebootService ,0
ENTER_INTERRUPT HReboot_a, HReboot_t ; (ebp) -> Trap frame
mov eax, APIC_REBOOT_VECTOR
mov ecx, dword ptr APIC[LU_TPR] ; get the old TPR
push ecx ; save it
mov dword ptr APIC[LU_TPR], eax ; set the TPR
APICFIX edx
;
; EOI the local APIC, warm reset does not reset the 82489 APIC
; so if we don't EOI here we'll never see an interrupt after
; the reboot.
;
mov dword ptr APIC[LU_EOI], 0 ; send EOI to APIC local unit
stdCall _HalpResetThisProcessor
;
; We should never get here, but just in case someone is stepping
; through this
;
pop eax
mov dword ptr APIC[LU_TPR], eax ; reset the TPR
APICFIX edx
;
; Do interrupt exit processing without EOI
;
SPURIOUS_INTERRUPT_EXIT
stdENDP _HalpApicRebootService
;++
;
; VOID
; HalpGenericCallService(
; );
;
; Routine Description:
; This is the ISR that handles the GenericCall interrupt
;
;--
ENTER_DR_ASSIST HGeneric_a, HGeneric_t
cPublicProc _HalpBroadcastCallService ,0
ENTER_INTERRUPT HGeneric_a, HGeneric_t ; (ebp) -> Trap frame
;
; (esp) - base of trap frame
;
; dismiss interrupt and raise Irql
;
push APIC_GENERIC_VECTOR
sub esp, 4 ; allocate space to save OldIrql
stdCall _HalBeginSystemInterrupt, <CLOCK2_LEVEL-1,APIC_GENERIC_VECTOR,esp>
call _HalpPollForBroadcast
INTERRUPT_EXIT ; lower irql to old value, iret
stdENDP _HalpBroadcastCallService
;++
;
; VOID
; HalpGenericCall(
; IN VOID (*WorkerFunction)(VOID),
; IN ULONG Context,
; IN KAFFINITY TargetProcessors
; );
;
; Routine Description:
; Causes the WorkerFunction to be called on the specified target
; processors. The WorkerFunction is called at CLOCK2_LEVEL-1
; (Must be below IPI_LEVEL in order to prevent system deadlocks).
;
; Enviroment:
; Must be called with interrupts enabled.
; Must be called with IRQL = CLOCK2_LEVEL-1
;--
cPublicProc _HalpGenericCall,3
cPublicFpo 3, 0
GENERIC_IPI equ (DELIVER_FIXED OR LOGICAL_DESTINATION OR ICR_USE_DEST_FIELD OR APIC_GENERIC_VECTOR)
@@: call _HalpPollForBroadcast
test HalpBroadcastLock, 1 ; Is broadcast busy?
jnz short @b ; Yes, wait
lock bts HalpBroadcastLock, 0 ; Try to get lock
jc short @b ; didn't get it, loop
hgc30: mov ecx, [esp+4]
mov edx, [esp+8]
mov eax, [esp+12]
mov HalpBroadcastFunction, ecx
mov HalpBroadcastContext, edx
mov HalpBroadcastTargets, eax
or eax, eax ; (eax) = Targets
jz short gc90
shl eax, DESTINATION_SHIFT
cli
STALL_WHILE_APIC_BUSY
;
; Set the destination address, (eax) = Processor bitmask
;
mov dword ptr APIC[LU_INT_CMD_HIGH], eax
APICFIX edx
;
; Now issue the command by writing to the Memory Mapped Register
;
mov dword ptr APIC[LU_INT_CMD_LOW], GENERIC_IPI
;
; Why do we need to wait again???
;
STALL_WHILE_APIC_BUSY
sti
;
; Wait for all processors to call broadcast function
;
@@: call _HalpPollForBroadcast
cmp HalpBroadcastTargets, 0
jnz short @b
gc90: mov HalpBroadcastLock, 0 ; Release BroadcastLock
stdRET _HalpGenericCall
stdENDP _HalpGenericCall
;++
;
; VOID
; _HalpPollForBroadcast (
; VOID
; );
;
; Routine Description:
;
; IRQL = CLOCK2_LEVEL-1
;--
cPublicProc _HalpPollForBroadcast, 0
cPublicFpo 0, 0
mov eax, PCR[PcSetMember]
test HalpBroadcastTargets, eax
jz short pb90
mov ecx, HalpBroadcastFunction ; Pickup broadcast function
push HalpBroadcastContext
not eax ; Remove our bit from destionations
lock and HalpBroadcastTargets, eax
call ecx
pb90: stdRET _HalpPollForBroadcast
stdENDP _HalpPollForBroadcast
;++
;
; ULONG
; FASTCALL
; HalpWaitForPending (
; ULONG Count (ecx)
; PULONG LuICR (edx)
; );
;
; Routine Description:
;
; Waits for DELIVERY_PENDING to clear and returns remaining iteration count
;--
cPublicFastCall HalpWaitForPending, 2
cPublicFpo 0, 0
wfp10: test dword ptr [edx], DELIVERY_PENDING
jz short wfp20
dec ecx
jnz short wfp10
wfp20: mov eax, ecx
fstRet HalpWaitForPending
fstENDP HalpWaitForPending
;++
;
; VOID
; HalpLocalApicErrorService(
; );
;
;Routine Description:
;
; This routine fields Local APIC error Events
;
;--
ENTER_DR_ASSIST HApicErr_a, HApicErr_t
cPublicProc _HalpLocalApicErrorService ,0
;
; Save machine state in trap frame
;
ENTER_INTERRUPT HApicErr_a, HApicErr_t ; (ebp) -> Trap frame
if LogApicErrors
lea ecx, _HalpLocalApicErrorLock
fstCall HalpAcquireHighLevelLock
push eax
mov eax, _HalpLocalApicErrorCount
inc _HalpLocalApicErrorCount
lea ecx, _HalpApicErrorLog
and eax, APIC_ERROR_LOG_SIZE-1
shl eax, 1
add ecx, eax
endif ; LogApicErrors
mov dword ptr APIC[LU_EOI], 0 ; local unit EOI
APICFIX eax
;
; The Apic EDS (Rev 4.0) says you have to write before you read
; this doesn't work. The write clears the status bits.
; But P6 works as according to the EDS!
;
mov eax, PCR[PcPrcb]
cmp byte ptr [eax].PbCpuType, 6
jc short lae10
mov dword ptr APIC[LU_ERROR_STATUS], 0
lae10:
mov eax, dword ptr APIC[LU_ERROR_STATUS] ; read error status
; Find out what kind of error it is and update the appropriate count.
if LogApicErrors
; out 80h, al
mov byte ptr [ecx], al
inc ecx
mov al, byte ptr PCR[PcHal.PcrNumber]
mov byte ptr [ecx], al
lea ecx, _HalpLocalApicErrorLock
pop edx
fstCall HalpReleaseHighLevelLock
endif ; LogApicErrors
SPURIOUS_INTERRUPT_EXIT ; exit interrupt without eoi
stdENDP _HalpLocalApicErrorService
;++
;
; VOID
; HalRequestIpi(
; IN ULONG Mask
; );
;
;Routine Description:
;
; Requests an interprocessor interrupt
;
;Arguments:
;
; Mask - Supplies a mask of the processors to be interrupted
;
;Return Value:
;
; None.
;
;--
APIC_IPI equ (DELIVER_FIXED OR LOGICAL_DESTINATION OR ICR_USE_DEST_FIELD OR APIC_IPI_VECTOR)
cPublicProc _HalRequestIpi ,1
cPublicFpo 1, 0
mov eax, [esp+4] ; (eax) = Processor bitmask
shl eax, DESTINATION_SHIFT
;
; With an APIC we'll IPI everyone needed at the same time.
; This assumes that:
; (mask passed in) == (APIC logical destination mask) Since we've programmed
; the APIC Local Units to use the Processor ID as the Logical ID's this IS true
;
pushfd ; save interrupt mode
cli ; disable interrupt
STALL_WHILE_APIC_BUSY
;
; Set the destination address, (eax) = Processor bitmask
;
mov dword ptr APIC[LU_INT_CMD_HIGH], eax
APICFIX edx
;
; Now issue the command by writing to the Memory Mapped Register
;
mov dword ptr APIC[LU_INT_CMD_LOW], APIC_IPI
;
; Wait for the delivery to happen
; KenR why is there a wait here????
;
STALL_WHILE_APIC_BUSY
popfd
stdRET _HalRequestIpi
stdENDP _HalRequestIpi
page ,132
subttl "PC+MP IPI Interrupt Handler"
;++
;
; VOID
; HalpIpiHandler (
; );
;
; Routine Description:
;
; This routine is entered as the result of an interrupt generated by inter
; processor communication.
;
; Arguments:
;
; None.
;
; Return Value:
;
; None.
;
;--
ENTER_DR_ASSIST Hipi_a, Hipi_t
cPublicProc _HalpIpiHandler ,0
;
; Save machine state in trap frame
;
ENTER_INTERRUPT Hipi_a, Hipi_t ; (ebp) -> Trap frame
;
; Save previous IRQL
;
push APIC_IPI_VECTOR ; Vector
sub esp, 4 ; space for OldIrql
;
; We now dismiss the interprocessor interrupt and call its handler
;
stdCall _HalBeginSystemInterrupt,<IPI_LEVEL,APIC_IPI_VECTOR,esp>
stdCall _KiIpiServiceRoutine, <ebp,0>
;
; Do interrupt exit processing
;
INTERRUPT_EXIT ; will return to caller
stdENDP _HalpIpiHandler
;++
;
; VOID
; HalpApicSpuriousService(
; );
;
;Routine Description:
;
; A place for spurious interrupts to end up.
;
;--
cPublicProc _HalpApicSpuriousService,0
iretd
stdENDP _HalpApicSpuriousService
;++
;
; VOID
; _PicInterruptHandlerIntiXX(
; );
;
;Routine Description:
;
; These handlers receive interrupts from the PIC and reissues them via
; a vector at the proper priority level. This is used to provide a symetric
; interrupt distribution on a non symetric system.
;
; The PIC interrupts will normally only be received (in the PC+MP Hal) via an
; interrupt input from on either the IO Unit or the Local unit which has been
; programed as EXTINT. EXTINT interrupts are received outside of the APIC
; priority structure (the PIC provides the vector). We use the APIC ICR to
; generate interrupts to the proper handler at the proper priority.
;
; The EXTINT interrupts are directed to a single processor, currently P0.
; There is no good reason why they can't be directed to another processor.
;
; Since one processor must absorb the overhead of redistributing PIC interrupts
; the interrupt handling on a system using EXTINT interrupts is not symetric.
;
;--
ENTER_DR_ASSIST Hcpic_a, Hcpic_t
cPublicProc PicHandler ,0
PicInterruptHandlerInti0:
push 0
jmp short CommonPicHandler
PicInterruptHandlerInti1:
push 1
jmp short CommonPicHandler
PicInterruptHandlerInti2:
push 2
jmp short CommonPicHandler
PicInterruptHandlerInti3:
push 3
jmp short CommonPicHandler
PicInterruptHandlerInti4:
push 4
jmp short CommonPicHandler
PicInterruptHandlerInti5:
push 5
jmp short CommonPicHandler
PicInterruptHandlerInti6:
push 6
jmp short CommonPicHandler
PicInterruptHandlerInti7:
;
; Check to see if this is a spurious interrupt
;
push eax
mov al, OCW3_READ_ISR ; tell 8259 we want to read ISR
out PIC1_PORT0, al
IODelay ; delay
in al, PIC1_PORT0 ; (al) = content of PIC 1 ISR
test al, 10000000B ; Is In-Service register set?
pop eax
jz short pic7_spurious ;
push 7
jmp short CommonPicHandler
picf_spurious:
mov al, OCW2_SPECIFIC_EOI OR SlavePicInti ; specific eoi to master for pic2 eoi
out PIC1_PORT0, al
pop eax
pic7_spurious:
iretd ; ignore PIC
PicInterruptHandlerInti8:
push 8
jmp short CommonPicHandler
PicInterruptHandlerInti9:
push 9
jmp short CommonPicHandler
PicInterruptHandlerIntiA:
push 10
jmp short CommonPicHandler
PicInterruptHandlerIntiB:
push 11
jmp short CommonPicHandler
PicInterruptHandlerIntiC:
push 12
jmp short CommonPicHandler
PicInterruptHandlerIntiD:
push 13
push eax
xor eax, eax
out I386_80387_BUSY_PORT, al
pop eax
jmp short CommonPicHandler
PicInterruptHandlerIntiE:
push 14
jmp short CommonPicHandler
PicInterruptHandlerIntiF:
push eax
mov al, OCW3_READ_ISR ; tell 8259 we want to read ISR
out PIC2_PORT0, al
IODelay ; delay
in al, PIC2_PORT0 ; (al) = content of PIC 1 ISR
test al, 10000000B ; Is In-Service register set?
jz short picf_spurious ; Go eoi PIC1 & Ignore PIC2
pop eax
push 15
jmp short CommonPicHandler
CommonPicHandler:
ENTER_INTERRUPT Hcpic_a, Hcpic_t,PassDwordParm ; (ebp) -> Trap frame
;
; Need to determine if we have a level interrupt and if so don't EOI it
; It should be EOI'd by end system interrupt
;
cmp bl, 8 ; Pic or Slave Pic
jae short cph20
mov al, bl
or al, OCW2_SPECIFIC_EOI ; specific eoi
out PIC1_PORT0, al ; dismiss the interrupt
jmp short cph30
cph20:
mov al, OCW2_NON_SPECIFIC_EOI ; send non specific eoi to slave
out PIC2_PORT0, al
mov al, OCW2_SPECIFIC_EOI OR SlavePicInti ; specific eoi to master for pic2 eoi
out PIC1_PORT0, al ; send irq2 specific eoi to master
cph30:
mov al, _HalpPICINTToVector[ebx] ; Get vector for PIC interrupt
or al, al ; Is vector known?
jz short cph90 ; No, don't dispatch it
;
; Now gain exclusive access to the ICR
;
STALL_WHILE_APIC_BUSY
cmp bl, 8
je short HandleClockInti
;
; Write the IPI Command to the Memory Mapped Register
;
mov dword ptr APIC[LU_INT_CMD_HIGH], DESTINATION_ALL_CPUS
APICFIX edx
mov dword ptr APIC[LU_INT_CMD_LOW], eax
jmp short cph90
HandleClockInti:
;
; Write the IPI Command to the Memory Mapped Register
;
mov dword ptr APIC[LU_INT_CMD_LOW], (DELIVER_FIXED OR ICR_SELF OR APIC_CLOCK_VECTOR)
cph90: APICFIX edx
SPURIOUS_INTERRUPT_EXIT ; exit interrupt without eoi
stdENDP PicHandler
;++
;
; VOID
; _PicXXNopHandler(
; );
;
;Routine Description:
;
; These handlers are designed to be installed on a system to field any PIC
; interrupts when there are not supposed to be any delivered.
;
; In the Debug case this routine increments an error count EOI's the PIC and
; returns. Normally the increment is not performed.
;--
cPublicProc PicNopHandler ,0
PicNopHandlerInti0:
push eax ; Save Scratch Registers
mov al, 0
jmp short CommonPic1NopHandler
PicNopHandlerInti1:
push eax ; Save Scratch Registers
mov al, 1
jmp short CommonPic1NopHandler
PicNopHandlerInti2:
push eax ; Save Scratch Registers
mov al, 2
jmp short CommonPic1NopHandler
PicNopHandlerInti3:
push eax ; Save Scratch Registers
mov al, 3
jmp short CommonPic1NopHandler
PicNopHandlerInti4:
push eax ; Save Scratch Registers
mov al, 4
jmp short CommonPic1NopHandler
PicNopHandlerInti5:
push eax ; Save Scratch Registers
mov al, 5
jmp short CommonPic1NopHandler
PicNopHandlerInti6:
push eax ; Save Scratch Registers
mov al, 6
jmp short CommonPic1NopHandler
PicNopHandlerInti7:
push eax ; Save Scratch Registers
mov al, 7
CommonPic1NopHandler:
;
; Need to determine if we have a level interrupt and if so don't EOI it
; It should be EOI'd by end system interrupt
;
or al, OCW2_SPECIFIC_EOI ; specific eoi
out PIC1_PORT0, al ; dismiss the interrupt
pop eax ; Restore Scratch registers
iretd
PicNopHandlerIntiD:
push eax
xor eax, eax
out I386_80387_BUSY_PORT, al
pop eax
CommonPic2NopHandler:
push eax
;
; Need to determine if we have a level interrupt and if so don't EOI it
; It should be EOI'd by end system interrupt
;
mov al, OCW2_NON_SPECIFIC_EOI ; send non specific eoi to slave
out PIC2_PORT0, al
mov al, OCW2_SPECIFIC_EOI OR SlavePicInti ; specific eoi to master for pic2 eoi
out PIC1_PORT0, al ; send irq2 specific eoi to master
pop eax
iretd
stdENDP PicNopHandler
_TEXT ENDS
END