2020-09-30 17:12:29 +02:00

956 lines
25 KiB
NASM

title "Interprocessor Interrupt"
;++
;
; Copyright (c) 1991 Microsoft Corporation
; Copyright (c) 1993 Sequent Computer Systems, Inc.
;
; Module Name:
;
; w3ipi.asm
;
; Abstract:
;
; Provides the HAL support for Interprocessor Interrupts and
; the initial processor initialization.
;
; Author:
;
; Phil Hochstetler (phil@sequent.com) 3-30-93
;
; Revision History:
;
;--
.386p
.xlist
;
; Include WinServer 3000 detection code
;
include i386\w3detect.asm
;
; Normal includes
;
include ks386.inc
include i386\kimacro.inc
include callconv.inc ; calling convention macros
include i386\apic.inc
include i386\w3.inc
;
; Import/Export
;
EXTRNP _KiCoprocessorError,0,IMPORT
EXTRNP _KeRaiseIrql,2
EXTRNP Kei386EoiHelper,0,IMPORT
EXTRNP _HalBeginSystemInterrupt,3
EXTRNP _HalEndSystemInterrupt,2
EXTRNP _KiIpiServiceRoutine,2,IMPORT
EXTRNP _HalEnableSystemInterrupt,3
EXTRNP _HalDisplayString,1
EXTRNP _HalEnableSystemInterrupt,3
EXTRNP _HalDisableSystemInterrupt,2
EXTRNP _HalpInitializeLocalUnit,0
EXTRNP _DbgBreakPoint,0,IMPORT
EXTRNP _HalpMapPhysicalMemoryWriteThrough,2
EXTRNP _HalpMySlotAddr,0
EXTRNP _HalpResetLocalUnits,0
extrn _HalpDefaultInterruptAffinity:DWORD
extrn _HalpActiveProcessors:DWORD
extrn _HalpLocalUnitBase:DWORD
extrn _HalpIOunitBase:DWORD
extrn _HalpIOunitTwoBase:DWORD
extrn _HalpELCRImage:WORD
extrn _HalpMASKED:WORD
_DATA SEGMENT DWORD PUBLIC 'DATA'
HALBadVaddr db 'HAL: No Virtual Address available to map the APIC', CR, LF, 0
HALMisMatch db 'HAL: This HAL only runs on a WinServer 3000.', CR, LF
db ' Please replace the hal.dll with the correct hal', CR, LF
db ' System is HALTING.', 0
ALIGN dword
public _HalpProcessorPCR
_HalpProcessorPCR dd 8 dup (0) ; PCR pointer for each processor
_DATA ENDS
page ,132
subttl "Initialize Processor"
_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 KeRaiseIrql/LowerIrq's must be available once this function
; returns. (IPI's are only used once two or more processors are
; available)
;
; . Save EISA Slot Address in PCR.
; . Save Processor Number in PCR.
; . Set initial StallScaleFactor
; . Set bit in global data structures for each new processor
; . if (P0)
; . determine if the system is a WS3000,
; . if (!WS3000) Halt;
; . Enable IPI's on CPU.
;
;Arguments:
;
; Number - Logical processor number of calling processor
;
;Return Value:
;
; None.
;
;--
cPublicProc _HalInitializeProcessor ,1
cPublicFpo 1, 0
mov dword ptr PCR[PcStallScaleFactor], INITIAL_STALL_COUNT
stdCall _HalpMySlotAddr
mov PCR[PcHal.ProcSlotAddr], ax ; Save processor slot
mov eax, [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
lock bts _HalpDefaultInterruptAffinity, eax ; update globals for each
lock bts _HalpActiveProcessors, eax ; online processor
test eax, eax
jnz ipi_10
; Only Boot Processor executes from here to label ipi_10
sub esp, 4
stdCall _DetectWS3000 <esp>
add esp, 4
test eax, eax
jz ipi_notW3
; Initialize PICs and IDT for PICs
mov ax, 0FFFFh
SET_8259_MASK
stdCall _HalInitPicInterruptHandlers
; call HAL memory manager to get a virtual address mapping for the
; APIC(s); virtual addresses are saved in global variables for indirect
; addressing later. This assumes that the page tables are built
; for P0 in Phase 0 are valid for P1.
stdCall _HalpMapPhysicalMemoryWriteThrough <LU_BASE_ADDRESS,1>
test eax, eax
jz NoHalVaddr
mov _HalpLocalUnitBase, eax
stdCall _HalpMapPhysicalMemoryWriteThrough <IO_BASE_ADDRESS,1>
test eax, eax
jz NoHalVaddr
mov _HalpIOunitBase, eax
stdCall _HalpMapPhysicalMemoryWriteThrough <IO_BASE_ADDRESS+020000h,1>
test eax, eax
jz NoHalVaddr
mov _HalpIOunitTwoBase, eax
; Reset all other local units to keep them from accepting any
; interrupts until their processor is out of reset. This is a
; problem because starting with Beta 2, not all processors may
; be brought up during install and the WS3000 BIOS enables the
; APICs even though the corresponding processor is held in reset.
; This would not be a bug if setting the FCR to put the processor
; into reset also put the APIC into reset, or if the APIC reset output
; was wired to the processor and used to reset it instead of the FCR.
stdCall _HalpResetLocalUnits
ipi_10:
; For P0-Pn, disable the IO unit so it can't suprise us.
; We have to do this on each CPU on the WS3000 since each CPU can
; only address the IO unit on its local APIC. Each CPU IO unit
; has the same address.
mov edx, _HalpIOunitTwoBase ; get base address of IO unit
mov ecx, IO_REDIR_00_LOW
mov eax, INTERRUPT_MASKED
ipi_15:
mov [edx+IO_REGISTER_SELECT], ecx ; write mask to redir entry
mov [edx+IO_REGISTER_WINDOW], eax
add ecx, 2 ; increment to next redir entry
cmp ecx, IO_REDIR_00_LOW + 32 ; go for 16 entries
jb ipi_15 ; more to go
;
; initialize the APIC local unit for this Processor
;
stdCall _HalpInitializeLocalUnit
stdRET _HalInitializeProcessor
NoHalVaddr:
stdCall _HalDisplayString, <offset HALBadVaddr>
hlt
ipi_notW3:
stdCall _HalDisplayString, <offset HALMisMatch>
hlt
stdENDP _HalInitializeProcessor
;++
;
; VOID
; HalInitPicInterruptHandlers(
; );
;
;Routine Description:
;
; initialize the EISA IDT entries for the WinServer 3000.
; This includes installing spurious interrupt handlers for:
;
; PIC1 spurious interrupt vector (EISA_IRQ7_VECTOR)
; PIC2 spurious interrupt vector (EISA_IRQ15_VECTOR)
;
; and handlers for
;
; CLOCK on PIC1 Vector (EISA_IRQ0_VECTOR)
; KEYBOARD on PIC1 Vector (EISA_IRQ1_VECTOR)
; FLOPPY on PIC1 Vector (EISA_IRQ6_VECTOR)
; RTC on PIC2 Vector (EISA_IRQ8_VECTOR)
; MOUSE on PIC2 Vector (EISA_IRQ12_VECTOR)
; DMA on PIC2 Vector (EISA_IRQ13_VECTOR)
; IDE on PIC2 Vector (EISA_IRQ14_VECTOR)
;
; The 82357 ISP on the WinServer 3000 platform does not route the
; clock and DMA interrupts externally. And the Keyboard, Floppy, Rtc,
; Mouse, and Ide are not available to the APIC by design. Instead, we
; must get these interrupts from the integrated PIC (master and
; slave, actually), whose interrupt output drives INTIN<13> of the 82489DX
; APIC. This APIC interrupt input is programmed for ExtINT (external
; interrupt) mode, which causes the integrated PIC to generate the
; interrupt vector instead of the APIC.
;
; Since we want to route all system interrupts through the APIC to take
; advantage of its prioritization mechanism, we install our own interrupt
; handlers for the Clock, Keyboard, Floppy, RTC, , Mouse, DMA, and
; IDE interrupts from the PIC, then redispatch the interrupts through the
; APIC.
;
; Spurious interrupt handlers for the integrated PICs are required because
; the devices can still generate spurious interrupts.
;
;Arguments:
;
; None.
;
;Return Value:
;
; None.
;
;--
cPublicProc _HalInitPicInterruptHandlers ,0
IDTEntry EISA_PIC1_SPURIOUS_VECTOR, EisaPic1SpuriousService
IDTEntry EISA_PIC2_SPURIOUS_VECTOR, EisaPic2SpuriousService
IDTEntry EISA_CLOCK_VECTOR, EisaClockService
IDTEntry EISA_KBD_VECTOR, EisaKbdService
IDTEntry EISA_FLOPPY_VECTOR, EisaFloppyService
IDTEntry EISA_RTC_VECTOR, EisaRTCService
IDTEntry EISA_DMA_VECTOR, EisaDmaService
IDTEntry EISA_MOUSE_VECTOR, EisaMouseService
IDTEntry EISA_IDE_VECTOR, EisaIDEService
stdRET _HalInitPicInterruptHandlers
stdENDP _HalInitPicInterruptHandlers
;++
;
; VOID
; ApicSpuriousService(
; );
;
;Routine Description:
;
; A place for spurious interrupts to end up.
;
;--
cPublicProc ApicSpuriousService ,0
iretd
stdENDP ApicSpuriousService
;++
;
; VOID
; EisaPic1SpuriousService(
; );
;
;Routine Description:
;
; A place for spurious EISA PIC one interrupts to end up.
;
;--
cPublicProc EisaPic1SpuriousService,0
iretd
stdENDP EisaPic1SpuriousService
;++
;
; VOID
; EisaPic2SpuriousService(
; );
;
;Routine Description:
;
; A place for spurious EISA PIC two interrupts to end up.
;
;--
cPublicProc EisaPic2SpuriousService,0
iretd
stdENDP EisaPic2SpuriousService
;++
;
; VOID
; EisaClockService(
; );
;
;Routine Description:
;
; This handler receives interrupts from the EISA PIC and reissues them via
; a vector at the proper priority level. This is needed on the WinServer
; 3000 because we use the PIC interrupts as EXTINT for the 8254 Clock,
; Keyboard, Floppy, RTC, Mouse, DMA, and IDE. Since EXTINT interrupts are
; received outside of the APIC priority structure we use the APIC ICR
; to generate interrupts to the proper handler at the proper priority.
;
; The EXTINT interrupts are programmed via the CCS APIC IO Unit's
; redirection table. They are directed to Processor zero only.
;
;--
IPI_CLOCK_ALL equ (DELIVER_FIXED OR ICR_ALL_INCL_SELF OR APIC_CLOCK_VECTOR)
ENTER_DR_ASSIST H99_a, H99_t
cPublicProc EisaClockService,0
;
; Save machine state in trap frame
;
ENTER_INTERRUPT H99_a, H99_t ; (esp) - base of trap frame
;
; Just IPI All Processors ( this is done from P0 )
;
mov al, OCW2_SPECIFIC_EOI OR (EISA_CLOCK_VECTOR - PIC0_BASE_VECTOR)
; specific eoi
out PIC1_PORT0, al ; dismiss the interrupt
;
; Make sure the ICR is available
;
mov ecx, _HalpLocalUnitBase ; load base address of CCS
; local unit
@@:
test [ecx+LU_INT_CMD_LOW], DELIVERY_PENDING
jnz @b
;
; Write the Clock IPI Command to the Memory Mapped Register
;
mov [ecx+LU_INT_CMD_LOW], IPI_CLOCK_ALL
SPURIOUS_INTERRUPT_EXIT ; exit interrupt without eoi
stdENDP EisaClockService
;++
;
; VOID
; EisaKbdService(
; );
;
;Routine Description:
;
; This handler receives interrupts from the EISA PIC and reissues them via
; a vector at the proper priority level. This is needed on the WinServer
; 3000 because we use the PIC interrupts as EXTINT for the 8254 Clock,
; Keyboard, Floppy, RTC, Mouse, DMA, and IDE. Since EXTINT interrupts are
; received outside of the APIC priority structure we use the APIC ICR
; to generate interrupts to the proper handler at the proper priority.
;
; The EXTINT interrupts are programmed via the CCS APIC IO Unit's
; redirection table. They are directed to Processor zero only.
;
;--
IPI_KBD_ALL equ (DELIVER_LOW_PRIORITY OR LOGICAL_DESTINATION OR ICR_ALL_INCL_SELF OR APIC_KBD_VECTOR)
ENTER_DR_ASSIST H98_a, H98_t
cPublicProc EisaKbdService ,0
;
; Save machine state in trap frame
;
ENTER_INTERRUPT H98_a, H98_t ; (esp) - base of trap frame
mov al, OCW2_SPECIFIC_EOI OR (EISA_KBD_VECTOR - PIC0_BASE_VECTOR)
; specific eoi
out PIC1_PORT0, al ; dismiss the interrupt
;
; Make sure the ICR is available
;
mov ecx, _HalpLocalUnitBase ; load base address of CCS
; local unit
@@:
test [ecx+LU_INT_CMD_LOW],DELIVERY_PENDING
jnz @b
;
; Write the KEYBOARD IPI Command to the Memory Mapped Register
;
mov [ecx+LU_INT_CMD_LOW], IPI_KBD_ALL
SPURIOUS_INTERRUPT_EXIT ; exit interrupt without eoi
stdENDP EisaKbdService
;++
;
; VOID
; EisaFloppyService(
; );
;
;Routine Description:
;
; This handler receives interrupts from the EISA PIC and reissues them via
; a vector at the proper priority level. This is needed on the WinServer
; 3000 because we use the PIC interrupts as EXTINT for the 8254 Clock,
; Keyboard, Floppy, RTC, Mouse, DMA, and IDE. Since EXTINT interrupts are
; received outside of the APIC priority structure we use the APIC ICR
; to generate interrupts to the proper handler at the proper priority.
;
; The EXTINT interrupts are programmed via the CCS APIC IO Unit's
; redirection table. They are directed to Processor zero only.
;
;--
IPI_FLOPPY_ALL equ (DELIVER_LOW_PRIORITY OR LOGICAL_DESTINATION OR ICR_ALL_INCL_SELF OR APIC_FLOPPY_VECTOR)
ENTER_DR_ASSIST H97_a, H97_t
cPublicProc EisaFloppyService ,0
;
; Save machine state in trap frame
;
ENTER_INTERRUPT H97_a, H97_t ; (esp) - base of trap frame
mov al, OCW2_SPECIFIC_EOI OR (EISA_FLOPPY_VECTOR - PIC0_BASE_VECTOR)
; specific eoi
out PIC1_PORT0, al ; dismiss the interrupt
;
; Make sure the ICR is available
;
mov ecx, _HalpLocalUnitBase ; load base address of CCS
; local unit
@@:
test [ecx+LU_INT_CMD_LOW],DELIVERY_PENDING
jnz @b
;
; Write the FLOPPY IPI Command to the Memory Mapped Register
;
mov [ecx+LU_INT_CMD_LOW], IPI_FLOPPY_ALL
SPURIOUS_INTERRUPT_EXIT ; exit interrupt without eoi
stdENDP EisaFloppyService
;++
;
; VOID
; EisaRTCService(
; );
;
;Routine Description:
;
; This handler receives interrupts from the EISA PIC and reissues them via
; a vector at the proper priority level. This is needed on the WinServer
; 3000 because we use the PIC interrupts as EXTINT for the 8254 Clock,
; Keyboard, Floppy, RTC, Mouse, DMA, and IDE. Since EXTINT interrupts are
; received outside of the APIC priority structure we use the APIC ICR
; to generate interrupts to the proper handler at the proper priority.
;
; The EXTINT interrupts are programmed via the CCS APIC IO Unit's
; redirection table. They are directed to Processor zero only.
;
;--
IPI_RTC_ALL equ (DELIVER_LOW_PRIORITY OR LOGICAL_DESTINATION OR ICR_ALL_INCL_SELF OR APIC_RTC_VECTOR)
ENTER_DR_ASSIST H96_a, H96_t
cPublicProc EisaRTCService ,0
;
; Save machine state in trap frame
;
ENTER_INTERRUPT H96_a, H96_t ; (esp) - base of trap frame
mov al, OCW2_NON_SPECIFIC_EOI ; send non specific eoi to slave
out PIC2_PORT0, al
mov al, OCW2_SPECIFIC_EOI OR (EISA_IRQ2_VECTOR - PIC0_BASE_VECTOR)
; specific eoi to master for pic2 eoi
out PIC1_PORT0, al ; send irq2 specific eoi to master
;
; Make sure the ICR is available
;
mov ecx, _HalpLocalUnitBase ; load base address of CCS
; local unit
@@:
test [ecx+LU_INT_CMD_LOW],DELIVERY_PENDING
jnz @b
;
; Write the RTC IPI Command to the Memory Mapped Register
;
mov [ecx+LU_INT_CMD_LOW], IPI_RTC_ALL
SPURIOUS_INTERRUPT_EXIT ; exit interrupt without eoi
stdENDP EisaRTCService
;++
;
; VOID
; EisaDmaService(
; );
;
;Routine Description:
;
; This handler receives interrupts from the EISA PIC and reissues them via
; a vector at the proper priority level. This is needed on the WinServer
; 3000 because we use the PIC interrupts as EXTINT for the 8254 Clock,
; Keyboard, Floppy, RTC, Mouse, DMA, and IDE. Since EXTINT interrupts are
; received outside of the APIC priority structure we use the APIC ICR
; to generate interrupts to the proper handler at the proper priority.
;
; The EXTINT interrupts are programmed via the CCS APIC IO Unit's
; redirection table. They are directed to Processor zero only.
;
;--
IPI_DMA_ALL equ (DELIVER_LOW_PRIORITY OR LOGICAL_DESTINATION OR ICR_ALL_INCL_SELF OR APIC_DMA_VECTOR)
ENTER_DR_ASSIST H95_a, H95_t
cPublicProc EisaDmaService ,0
;
; Save machine state in trap frame
;
ENTER_INTERRUPT H95_a, H95_t ; (esp) - base of trap frame
mov al, OCW2_NON_SPECIFIC_EOI ; send non specific eoi to slave
out PIC2_PORT0, al
mov al, OCW2_SPECIFIC_EOI OR (EISA_IRQ2_VECTOR - PIC0_BASE_VECTOR)
; specific eoi to master for pic2 eoi
out PIC1_PORT0, al ; send irq2 specific eoi to master
;
; Make sure the ICR is available
;
mov ecx, _HalpLocalUnitBase ; load base address of CCS
; local unit
@@:
test [ecx+LU_INT_CMD_LOW],DELIVERY_PENDING
jnz @b
;
; Write the DMA IPI Command to the Memory Mapped Register
;
mov [ecx+LU_INT_CMD_LOW], IPI_DMA_ALL
SPURIOUS_INTERRUPT_EXIT ; exit interrupt without eoi
stdENDP EisaDmaService
;++
;
; VOID
; EisaMouseService(
; );
;
;Routine Description:
;
; This handler receives interrupts from the EISA PIC and reissues them via
; a vector at the proper priority level. This is needed on the WinServer
; 3000 because we use the PIC interrupts as EXTINT for the 8254 Clock,
; Keyboard, Floppy, RTC, DMA, Mouse, and IDE. Since EXTINT interrupts are
; received outside of the APIC priority structure we use the APIC ICR
; to generate interrupts to the proper handler at the proper priority.
;
; The EXTINT interrupts are programmed via the CCS APIC IO Unit's
; redirection table. They are directed to Processor zero only.
;
;--
IPI_MOUSE_ALL equ (DELIVER_LOW_PRIORITY OR LOGICAL_DESTINATION OR ICR_ALL_INCL_SELF OR APIC_MOUSE_VECTOR)
ENTER_DR_ASSIST H94_a, H94_t
cPublicProc EisaMouseService ,0
;
; Save machine state in trap frame
;
ENTER_INTERRUPT H94_a, H94_t ; (esp) - base of trap frame
mov al, OCW2_NON_SPECIFIC_EOI ; send non specific eoi to slave
out PIC2_PORT0, al
mov al, OCW2_SPECIFIC_EOI OR (EISA_IRQ2_VECTOR - PIC0_BASE_VECTOR)
; specific eoi to master for pic2 eoi
out PIC1_PORT0, al ; send irq2 specific eoi to master
;
; Make sure the ICR is available
;
mov ecx, _HalpLocalUnitBase ; load base address of CCS
; local unit
@@:
test [ecx+LU_INT_CMD_LOW],DELIVERY_PENDING
jnz @b
;
; Write the MOUSE IPI Command to the Memory Mapped Register
;
mov [ecx+LU_INT_CMD_LOW], IPI_MOUSE_ALL
SPURIOUS_INTERRUPT_EXIT ; exit interrupt without eoi
stdENDP EisaMouseService
;++
;
; VOID
; EisaIDEService(
; );
;
;Routine Description:
;
; This handler receives interrupts from the EISA PIC and reissues them via
; a vector at the proper priority level. This is needed on the WinServer
; 3000 because we use the PIC interrupts as EXTINT for the 8254 Clock,
; Keyboard, Floppy, RTC, Mouse, DMA, and IDE. Since EXTINT interrupts are
; received outside of the APIC priority structure we use the APIC ICR
; to generate interrupts to the proper handler at the proper priority.
;
; The EXTINT interrupts are programmed via the CCS APIC IO Unit's
; redirection table. They are directed to Processor zero only.
;
;--
ENTER_DR_ASSIST H93_a, H93_t
cPublicProc EisaIDEService ,0
;
; Save machine state in trap frame
;
ENTER_INTERRUPT H93_a, H93_t ; (esp) - base of trap frame
mov ebx, (DELIVER_LOW_PRIORITY OR LOGICAL_DESTINATION OR ICR_ALL_INCL_SELF OR APIC_IDE_VECTOR)
test _HalpELCRImage, (1 SHL (EISA_IDE_VECTOR - PIC0_BASE_VECTOR))
jz short @f
; If a level PIC interrupt, mask the interrupt at the PIC until
; the APIC interrupt HalEndSystemInterrupt unmasks it.
; We also only send it to ourselves since it needs to mess with the
; pic in the end of interrupt code.
lock or _HalpMASKED, (1 SHL (EISA_IDE_VECTOR - PIC0_BASE_VECTOR))
in al, PIC2_PORT1
or al, (1 SHL (EISA_IDE_VECTOR - PIC1_BASE_VECTOR))
out PIC2_PORT1, al
mov ebx, (DELIVER_LOW_PRIORITY OR LOGICAL_DESTINATION OR ICR_SELF OR APIC_IDE_VECTOR)
@@:
mov al, OCW2_NON_SPECIFIC_EOI ; send non specific eoi to slave
out PIC2_PORT0, al
mov al, OCW2_SPECIFIC_EOI OR (EISA_IRQ2_VECTOR - PIC0_BASE_VECTOR)
; specific eoi to master for pic2 eoi
out PIC1_PORT0, al ; send irq2 specific eoi to master
;
; Make sure the ICR is available
;
mov ecx, _HalpLocalUnitBase ; load base address of CCS
; local unit
@@: test [ecx+LU_INT_CMD_LOW],DELIVERY_PENDING
jnz @b
;
; Write the IDE IPI Command to the Memory Mapped Register
;
mov [ecx+LU_INT_CMD_LOW], ebx
SPURIOUS_INTERRUPT_EXIT ; exit interrupt without eoi
stdENDP EisaIDEService
;++
;
; VOID
; HalRequestIpi(
; IN KAFFINITY 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, dword ptr [esp+4] ; (eax) = Processor bitmask
mov ecx, _HalpLocalUnitBase ; load base address of local unit
DISABLE_INTERRUPTS_AT_CPU
if DBG
or eax, eax ; must ipi somebody
jz short ipibad
movzx edx, byte ptr PCR[PcHal.PcrNumber] ; Get Processor Number
bt eax, edx ; cannot ipi yourself
jc short ipibad
endif
;
; 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 APIC ID this IS true
;
;
; Make sure the ICR is available
;
@@:
test [ecx+LU_INT_CMD_LOW],DELIVERY_PENDING
jnz @b
;
; Set the destination address, (eax) = Processor bitmask
;
mov [ecx+LU_INT_CMD_HIGH], eax
;
; Now issue the command by writing to the Memory Mapped Register
;
mov [ecx+LU_INT_CMD_LOW], APIC_IPI
RESTORE_INTERRUPTS_AT_CPU
stdRET _HalRequestIpi
if DBG
ipibad:
RESTORE_INTERRUPTS_AT_CPU
stdCall _DbgBreakPoint
stdRET _HalRequestIpi
endif
stdENDP _HalRequestIpi
;++
;
; VOID
; HalIntProcessorAPIC(
; IN ULONG Mask,
; IN ULONG ICRCommand
; );
;
;Routine Description:
;
; Requests an interprocessor interrupt
;
;Arguments:
;
; Mask - Supplies a mask of the processors to be interrupted
;
; ICRCommand - ICR Command to use
;
;Return Value:
;
; None.
;
;--
cPublicProc _HalIntProcessorAPIC ,2
mov edx, dword ptr [esp+4] ; (edx) = Processor bitmask
mov eax, dword ptr [esp+8] ; (eax) = ICR Command
mov ecx, _HalpLocalUnitBase ; load base address of local unit
;
; Make sure the ICR is available
;
pushfd ; save interrupt mode
cli ; disable interrupt
@@:
test [ecx+LU_INT_CMD_LOW],DELIVERY_PENDING
jnz @b
; (edx) = Processor bitmask
; (eax) = ICR Command
mov [ecx+LU_INT_CMD_HIGH], edx
;
; Now issue the command by writing the ICR Command to the Memory Mapped Register
;
mov [ecx+LU_INT_CMD_LOW], eax
popfd
stdRET _HalIntProcessorAPIC
stdENDP _HalIntProcessorAPIC
page ,132
subttl "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>
; Pass Null ExceptionFrame
; Pass TrapFrame to Ipi service rtn
;
stdCall _KiIpiServiceRoutine, <ebp,0>
;
; Do interrupt exit processing
;
INTERRUPT_EXIT ; will return to caller
stdENDP _HalpIpiHandler
_TEXT ENDS
END