summaryrefslogtreecommitdiffstats
path: root/private/ntos/nthals/halncr/i386/ncrirql.asm
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/nthals/halncr/i386/ncrirql.asm
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to 'private/ntos/nthals/halncr/i386/ncrirql.asm')
-rw-r--r--private/ntos/nthals/halncr/i386/ncrirql.asm1223
1 files changed, 1223 insertions, 0 deletions
diff --git a/private/ntos/nthals/halncr/i386/ncrirql.asm b/private/ntos/nthals/halncr/i386/ncrirql.asm
new file mode 100644
index 000000000..c30cdf910
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ncrirql.asm
@@ -0,0 +1,1223 @@
+ title "Irql Processing"
+;++
+;
+; Copyright (c) 1992 NCR Corporation
+;
+; Module Name:
+;
+; ncrirql.asm
+;
+; Abstract:
+;
+; This module implements the code necessary to raise and lower i386
+; Irql and dispatch software interrupts with the 8259 PIC.
+;
+; Author:
+;
+; Richard Barton (o-richb) 24-Jan-1992
+;
+; Environment:
+;
+; Kernel mode only.
+;
+; Revision History:
+;
+;--
+
+.486p
+ .xlist
+include hal386.inc
+include callconv.inc ; calling convention macros
+include i386\ix8259.inc
+include i386\kimacro.inc
+include i386\ncr.inc
+include mac386.inc
+ .list
+
+
+ EXTRNP _KeBugCheck,1,IMPORT
+ EXTRNP _KeSetEventBoostPriority, 2, IMPORT
+ EXTRNP _KeWaitForSingleObject,5, IMPORT
+
+ extrn _HalpApcInterrupt:NEAR
+ extrn _HalpDispatchInterrupt:NEAR
+ extrn _KiUnexpectedInterrupt:NEAR
+ extrn _NCREmulateClockTick:NEAR
+ extrn _HalpBusType:DWORD
+
+ifdef NT_UP
+ LOCK_ADD equ add
+ LOCK_DEC equ dec
+else
+ LOCK_ADD equ lock add
+ LOCK_DEC equ lock dec
+endif
+;
+; Initialization control words equates for the PICs
+;
+
+ICW1_ICW4_NEEDED equ 01H
+ICW1_CASCADE equ 00H
+ICW1_INTERVAL8 equ 00H
+ICW1_LEVEL_TRIG equ 08H
+ICW1_EDGE_TRIG equ 00H
+ICW1_ICW equ 10H
+
+ICW4_8086_MODE equ 001H
+ICW4_NORM_EOI equ 000H
+ICW4_NON_BUF_MODE equ 000H
+ICW4_SPEC_FULLY_NESTED equ 010H
+ICW4_NOT_SPEC_FULLY_NESTED equ 000H
+
+OCW2_NON_SPECIFIC_EOI equ 020H
+OCW2_SPECIFIC_EOI equ 060H
+OCW2_SET_PRIORITY equ 0c0H
+
+PIC_SLAVE_IRQ equ 2
+PIC1_BASE equ 30H
+PIC2_BASE equ 38H
+
+;
+; Interrupt flag bit maks for EFLAGS
+;
+
+EFLAGS_IF equ 200H
+EFLAGS_SHIFT equ 9
+
+
+_DATA SEGMENT DWORD PUBLIC 'DATA'
+
+;
+; PICsInitializationString - Master PIC initialization command string
+;
+
+
+PICsInitializationString dw PIC1_PORT0
+
+;
+; Master PIC initialization command
+;
+
+ db ICW1_ICW + ICW1_LEVEL_TRIG + ICW1_INTERVAL8 +\
+ ICW1_CASCADE + ICW1_ICW4_NEEDED
+ db PIC1_BASE
+ db 1 SHL PIC_SLAVE_IRQ
+ db ICW4_NOT_SPEC_FULLY_NESTED + \
+ ICW4_NON_BUF_MODE + \
+ ICW4_NORM_EOI + \
+ ICW4_8086_MODE
+;
+; Slave PIC initialization command strings
+;
+
+ dw PIC2_PORT0
+ db ICW1_ICW + ICW1_LEVEL_TRIG + ICW1_INTERVAL8 +\
+ ICW1_CASCADE + ICW1_ICW4_NEEDED
+ db PIC2_BASE
+ db PIC_SLAVE_IRQ
+ db ICW4_NOT_SPEC_FULLY_NESTED + \
+ ICW4_NON_BUF_MODE + \
+ ICW4_NORM_EOI + \
+ ICW4_8086_MODE
+ dw 0 ; end of string
+
+ align 4
+ public KiI8259MaskTable
+KiI8259MaskTable label dword
+ dd 00000000000000000000000000000000B ; irql 0 low
+ dd 00000000000000000000000000000000B ; irql 1 apc
+ dd 00000000000000000000000000000000B ; irql 2 dpc
+ dd 00000000000000000000000000000000B ; irql 3 .
+ dd 11111111100000000000000000000000B ; irql 4 .
+ dd 11111111110000000000000000000000B ; irql 5 .
+ dd 11111111111000000000000000000000B ; irql 6 .
+ dd 11111111111100000000000000000000B ; irql 7 .
+ dd 11111111111110000000000000000000B ; irql 8 .
+ dd 11111111111111000000000000000000B ; irql 9 .
+ dd 11111111111111100000000000000000B ; irql 10 .
+ dd 11111111111111110000000000000000B ; irql 11 .\
+ dd 11111111111111111000000000000000B ; irql 12 . irql
+ dd 11111111111111111100000000000000B ; irql 13 . device
+ dd 11111111111111111110000000000000B ; irql 14 . range
+ dd 11111111111111111111000000000000B ; irql 15 ./
+ dd 11111111111111111111100000000000B ; irql 16 .
+ dd 11111111111111111111110000000000B ; irql 17 .
+ dd 11111111111111111111111000000000B ; irql 18 .
+ dd 11111111111111111111111000000000B ; irql 19 .
+ dd 11111111111111111111111010000000B ; irql 20 .
+ dd 11111111111111111111111011000000B ; irql 21 .
+ dd 11111111111111111111111011100000B ; irql 22 .
+ dd 11111111111111111111111011110000B ; irql 23 .
+ dd 11111111111111111111111011111000B ; irql 24 .
+ dd 11111111111111111111111011111000B ; irql 25 .
+ dd 11111111111111111111111011111010B ; irql 26 .
+ dd 11111111111111111111111111111110B ; irql 27 profile/clock
+; ^ bubug- change to a 0 (see below)
+ dd 11111111111111111111111111111110B ; irql 28 clock
+ dd 11111111111111111111111111111111B ; irql 29 ipi
+ dd 11111111111111111111111111111111B ; irql 30 power
+ dd 11111111111111111111111111111111B ; irql 31 high
+; | | |
+; | | +- NT IPI vector &
+; | | clock interrupt
+; | | multiplexed here.
+; | | raised to ipi level
+; | |
+; | +--- CPI Clock broadcasts
+; | here. raise to clock
+; | level.
+; |
+; +--- RTC for NT Profile vector
+; raised to profile level
+
+;
+; Warning - I moved the CPI Clock to below profile for now.
+;
+
+
+;
+; This table is used to mask all pending interrupts below a given Irql
+; out of the IRR
+;
+ align 4
+
+FindHigherIrqlMask label dword
+ dd 11111111111111111111111111111111B ; irql 0
+ dd 11111111111111111111111111111100B ; irql 1 (APC)
+ dd 11111111111111111111111111111000B ; irql 2 (DISPATCH)
+ dd 11111111111111111111111111110000B ; irql 3
+ dd 00000111111111111111111111110000B ; irql 4
+ dd 00000011111111111111111111110000B ; irql 5
+ dd 00000001111111111111111111110000B ; irql 6
+ dd 00000000111111111111111111110000B ; irql 7
+ dd 00000000011111111111111111110000B ; irql 8
+ dd 00000000001111111111111111110000B ; irql 9
+ dd 00000000000111111111111111110000B ; irql 10
+ dd 00000000000011111111111111110000B ; irql 11
+ dd 00000000000001111111111111110000B ; irql 12
+ dd 00000000000000111111111111110000B ; irql 13
+ dd 00000000000000011111111111110000B ; irql 14
+ dd 00000000000000001111111111110000B ; irql 15
+ dd 00000000000000000111111111110000B ; irql 16
+ dd 00000000000000000011111111110000B ; irql 17
+ dd 00000000000000000001111111110000B ; irql 18
+ dd 00000000000000000001111111110000B ; irql 19
+ dd 00000000000000000001011111110000B ; irql 20
+ dd 00000000000000000001001111110000B ; irql 20
+ dd 00000000000000000001000111110000B ; irql 22
+ dd 00000000000000000001000011110000B ; irql 23
+ dd 00000000000000000001000001110000B ; irql 24
+ dd 00000000000000000001000001110000B ; irql 25
+ dd 00000000000000000001000001010000B ; irql 26
+ dd 00000000000000000000000000010000B ; irql 27 profile/clock
+; ^ Warning - change to a 1 (see above)
+ dd 00000000000000000000000000000000B ; irql 28 clock
+ dd 00000000000000000000000000000000B ; irql 29 ipi
+ dd 00000000000000000000000000000000B ; irql 30 power
+ dd 00000000000000000000000000000000B ; irql 31 high
+; | | |
+; | | +- We only emulate clock
+; | | interrupts here, not IPIs.
+; | | So this is set to clock
+; | | level
+; | |
+; | +--- CPI Clock broadcasts
+; | here. raise to clock
+; | level
+; |
+; +--- RTC for NT Profile vector
+; raised to profile level
+
+ align 4
+;
+; The following tables define the addresses of software interrupt routers
+;
+
+;
+; Use this table if there is NO machine state frame on stack already
+;
+
+ public SWInterruptHandlerTable
+SWInterruptHandlerTable label dword
+ dd offset FLAT:_KiUnexpectedInterrupt ; irql 0
+ dd offset FLAT:_HalpApcInterrupt ; irql 1
+ dd offset FLAT:_HalpDispatchInterrupt ; irql 2
+ dd offset FLAT:_KiUnexpectedInterrupt ; irql 3
+ dd offset FLAT:_NCREmulateClockTick ; 8259 irq#0
+ dd offset FLAT:HalpHardwareInterrupt01 ; 8259 irq#1
+ dd offset FLAT:HalpHardwareInterrupt02 ; 8259 irq#2
+ dd offset FLAT:HalpHardwareInterrupt03 ; 8259 irq#3
+ dd offset FLAT:HalpHardwareInterrupt04 ; 8259 irq#4
+ dd offset FLAT:HalpHardwareInterrupt05 ; 8259 irq#5
+ dd offset FLAT:HalpHardwareInterrupt06 ; 8259 irq#6
+ dd offset FLAT:HalpHardwareInterrupt07 ; 8259 irq#7
+ dd offset FLAT:HalpHardwareInterrupt08 ; 8259 irq#8
+ dd offset FLAT:HalpHardwareInterrupt09 ; 8259 irq#9
+ dd offset FLAT:HalpHardwareInterrupt10 ; 8259 irq#10
+ dd offset FLAT:HalpHardwareInterrupt11 ; 8259 irq#11
+ dd offset FLAT:HalpHardwareInterrupt12 ; 8259 irq#12
+ dd offset FLAT:HalpHardwareInterrupt13 ; 8259 irq#13
+ dd offset FLAT:HalpHardwareInterrupt14 ; 8259 irq#14
+ dd offset FLAT:HalpHardwareInterrupt15 ; 8259 irq#15
+
+;
+; The following table picks up the highest pending software irq level
+; from software irr
+;
+
+ public SWInterruptLookUpTable
+SWInterruptLookUpTable label byte
+ db 0 ; SWIRR=0, so highest pending SW irql= 0
+ db 0 ; SWIRR=1, so highest pending SW irql= 0
+ db 1 ; SWIRR=2, so highest pending SW irql= 1
+ db 1 ; SWIRR=3, so highest pending SW irql= 1
+ db 2 ; SWIRR=4, so highest pending SW irql= 2
+ db 2 ; SWIRR=5, so highest pending SW irql= 2
+ db 2 ; SWIRR=6, so highest pending SW irql= 2
+ db 2 ; SWIRR=7, so highest pending SW irql= 2
+ db 3 ; SWIRR=8, so highest pending SW irql= 3
+ db 3 ; SWIRR=9, so highest pending SW irql= 3
+ db 3 ; SWIRR=A, so highest pending SW irql= 3
+ db 3 ; SWIRR=B, so highest pending SW irql= 3
+ db 3 ; SWIRR=C, so highest pending SW irql= 3
+ db 3 ; SWIRR=D, so highest pending SW irql= 3
+ db 3 ; SWIRR=E, so highest pending SW irql= 3
+ db 3 ; SWIRR=F, so highest pending SW irql= 3
+
+ db 4 ; SWIRR=10, so highest pending SW irql= 4
+ db 4 ; SWIRR=11, so highest pending SW irql= 4
+ db 4 ; SWIRR=12, so highest pending SW irql= 4
+ db 4 ; SWIRR=13, so highest pending SW irql= 4
+ db 4 ; SWIRR=14, so highest pending SW irql= 4
+ db 4 ; SWIRR=15, so highest pending SW irql= 4
+ db 4 ; SWIRR=16, so highest pending SW irql= 4
+ db 4 ; SWIRR=17, so highest pending SW irql= 4
+ db 4 ; SWIRR=18, so highest pending SW irql= 4
+ db 4 ; SWIRR=19, so highest pending SW irql= 4
+ db 4 ; SWIRR=1A, so highest pending SW irql= 4
+ db 4 ; SWIRR=1B, so highest pending SW irql= 4
+ db 4 ; SWIRR=1C, so highest pending SW irql= 4
+ db 4 ; SWIRR=1D, so highest pending SW irql= 4
+ db 4 ; SWIRR=1E, so highest pending SW irql= 4
+ db 4 ; SWIRR=1F, so highest pending SW irql= 4
+
+
+
+; public SWInterruptLookUpTable, FindFirstSetBit
+;FindFirstSetBit label byte
+; db 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
+; db 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
+; db 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
+; db 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
+; db 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
+; db 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
+; db 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
+; db 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
+; db 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
+; db 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
+; db 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
+; db 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
+; db 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
+; db 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
+; db 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
+; db 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
+;
+;
+; public AcquireBufferPosition, SpinLockRecord
+;
+;AcquireBufferPosition dd 0
+;SpinLockRecord dd 4096 dup (0)
+
+
+ifdef IRQL_METRICS
+
+ public HalRaiseIrqlCount
+ public HalLowerIrqlCount
+ public HalQuickLowerIrqlCount
+ public HalApcSoftwareIntCount
+ public HalDpcSoftwareIntCount
+ public HalHardwareIntCount
+ public HalPostponedIntCount
+ public Hal8259MaskCount
+
+HalRaiseIrqlCount dd 0
+HalLowerIrqlCount dd 0
+HalQuickLowerIrqlCount dd 0
+HalApcSoftwareIntCount dd 0
+HalDpcSoftwareIntCount dd 0
+HalHardwareIntCount dd 0
+HalPostponedIntCount dd 0
+Hal8259MaskCount dd 0
+
+endif
+_DATA ENDS
+
+ page ,132
+ subttl "Raise Irql"
+
+_TEXT SEGMENT PARA PUBLIC 'CODE'
+ ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:FLAT, FS:NOTHING, GS:NOTHING
+;++
+;
+; KIRQL
+; FASTCALL
+; KfRaiseIrql (
+; IN KIRQL NewIrql
+; )
+;
+; Routine Description:
+;
+; This routine is used to raise IRQL to the specified value.
+; Also, a mask will be used to mask off all the lower lever 8259
+; interrupts.
+;
+; Arguments:
+;
+; (cl) = NewIrql - the new irql to be raised to
+;
+; Return Value:
+;
+; OldIrql
+;
+;--
+
+cPublicFastCall KfRaiseIrql ,1
+cPublicFpo 0,0
+ mov al, PCR[PcIrql] ; get current irql
+ mov PCR[PcIrql], cl
+
+ifdef IRQL_METRICS
+ lock inc HalRaiseIrqlCount
+endif
+if DBG
+ cmp al, cl ; old > new?
+ ja short Kri99 ; yes, go bugcheck
+
+ fstRET KfRaiseIrql
+
+cPublicFpo 2,2
+Kri99:
+ push eax ; put new irql where we can find it
+ push ecx ; put old irql where we can find it
+ mov byte ptr PCR[PcIrql],0 ; avoid recursive error
+ stdCall _KeBugCheck, <IRQL_NOT_GREATER_OR_EQUAL> ; never return
+endif
+ fstRET KfRaiseIrql
+
+fstENDP KfRaiseIrql
+
+
+;++
+;
+; KIRQL
+; KeRaiseIrqlToDpcLevel (
+; )
+;
+; Routine Description:
+;
+; This routine is used to raise IRQL to DPC level.
+;
+; Arguments:
+;
+; Return Value:
+;
+; OldIrql - the addr of a variable which old irql should be stored
+;
+;--
+
+cPublicProc _KeRaiseIrqlToDpcLevel,0
+cPublicFpo 0, 0
+
+ mov al, PCR[PcIrql] ; (al) = Old Irql
+ mov byte ptr PCR[PcIrql], DISPATCH_LEVEL ; set new irql
+
+ifdef IRQL_METRICS
+ inc HalRaiseIrqlCount
+endif
+if DBG
+ cmp al, DISPATCH_LEVEL ; old > new?
+ ja short Krid99 ; yes, go bugcheck
+
+ stdRET _KeRaiseIrqlToDpcLevel
+
+cPublicFpo 0,1
+Krid99: movzx eax, al
+ push eax ; put old irql where we can find it
+ stdCall _KeBugCheck, <IRQL_NOT_GREATER_OR_EQUAL> ; never return
+endif
+ stdRET _KeRaiseIrqlToDpcLevel
+
+stdENDP _KeRaiseIrqlToDpcLevel
+
+
+;++
+;
+; KIRQL
+; KeRaiseIrqlToSynchLevel (
+; )
+;
+; Routine Description:
+;
+; This routine is used to raise IRQL to SYNC level.
+;
+; Arguments:
+;
+; Return Value:
+;
+; OldIrql - the addr of a variable which old irql should be stored
+;
+;--
+
+cPublicProc _KeRaiseIrqlToSynchLevel,0
+cPublicFpo 0, 0
+
+ mov al, PCR[PcIrql] ; (al) = Old Irql
+ mov byte ptr PCR[PcIrql], SYNCH_LEVEL ; set new irql
+
+ifdef IRQL_METRICS
+ inc HalRaiseIrqlCount
+endif
+if DBG
+ cmp al, SYNCH_LEVEL ; old > new?
+ ja short Kris99 ; yes, go bugcheck
+
+ stdRET _KeRaiseIrqlToSynchLevel
+
+cPublicFpo 0,1
+Kris99: movzx eax, al
+ push eax ; put old irql where we can find it
+ stdCall _KeBugCheck, <IRQL_NOT_GREATER_OR_EQUAL> ; never return
+endif
+ stdRET _KeRaiseIrqlToSynchLevel
+
+stdENDP _KeRaiseIrqlToSynchLevel
+
+ page ,132
+ subttl "Lower irql"
+
+;++
+;
+; VOID
+; FASTCALL
+; KfLowerIrql (
+; IN KIRQL NewIrql
+; )
+;
+; Routine Description:
+;
+; This routine is used to lower IRQL to the specified value.
+; The IRQL and PIRQL will be updated accordingly. Also, this
+; routine checks to see if any software interrupt should be
+; generated. The following condition will cause software
+; interrupt to be simulated:
+; any software interrupt which has higher priority than
+; current IRQL's is pending.
+;
+; NOTE: This routine simulates software interrupt as long as
+; any pending SW interrupt level is higher than the current
+; IRQL, even when interrupts are disabled.
+;
+; On a UP system, HalEndSystenInterrupt is treated as a
+; LowerIrql.
+;
+; Arguments:
+;
+; (cl) = NewIrql - the new irql to be set.
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+cPublicFastCall KfLowerIrql ,1
+cPublicFpo 0,1
+ pushfd ; save caller's eflags
+ movzx ecx, cl ; (ecx) = NewIrql
+
+ifdef IRQL_METRICS
+ lock inc HalLowerIrqlCount
+endif
+
+if DBG
+ cmp cl,PCR[PcIrql]
+ ja KliBug
+endif
+ cli
+ mov edx, PCR[PcIRR]
+ and edx, FindHigherIrqlMask[ecx*4] ; (edx) is the bitmask of
+ ; pending interrupts we need to
+ ; dispatch now.
+ jz KliSWInterruptsDone
+
+cPublicFpo 0,1
+ push ecx ; Save NewIrql
+
+KliDoSWInterrupt:
+ bsr ecx, edx ; find highest priority interrupt.
+ ; (ecx) is bit position
+;
+; lower to irql level we are emulating
+;
+ mov PCR[PcIrql], ecx
+ cmp ecx, PCR[PcHal.PcrMyPICsIrql]
+ jae short Kli50
+
+ mov PCR[PcHal.PcrMyPICsIrql], ecx
+ mov eax, KiI8259MaskTable[ecx*4]
+ or eax, PCR[PcIDR]
+ SET_IRQ_MASK
+
+Kli50:
+ mov eax, 1
+ shl eax, cl
+ xor PCR[PcIRR], eax ; clear bit in IRR
+
+ call SWInterruptHandlerTable[ecx*4]
+
+;
+; When the trap handler returns, we will end up here
+;
+
+ mov ecx, [esp] ; Restore NewIrql
+ mov edx, PCR[PcIRR]
+ and edx, FindHigherIrqlMask[ecx*4] ; (edx) is the bitmask of
+ jnz KliDoSWInterrupt ; get next pending interrupt
+
+ add esp, 4
+cPublicFpo 0,0
+
+KliSWInterruptsDone:
+ mov PCR[PcIrql], ecx ; save NewIrql
+ cmp ecx, PCR[PcHal.PcrMyPICsIrql]
+ jb KliLowerPICMasks ; really lower the masks
+ popfd
+ fstRET KfLowerIrql
+
+KliLowerPICMasks:
+;
+; really lower each PICs mask
+;
+ mov PCR[PcHal.PcrMyPICsIrql], ecx
+ mov eax, KiI8259MaskTable[ecx*4]
+ or eax, PCR[PcIDR]
+ SET_IRQ_MASK
+
+ popfd
+ fstRET KfLowerIrql
+
+if DBG
+cPublicFpo 1,3
+KliBug:
+ push ecx ; new irql for debugging
+ push PCR[PcIrql] ; old irql for debugging
+ mov byte ptr PCR[PcIrql],HIGH_LEVEL ; avoid recursive error
+ stdCall _KeBugCheck, <IRQL_NOT_LESS_OR_EQUAL> ; never return
+endif
+fstENDP KfLowerIrql
+
+cPublicProc _HalpEndSoftwareInterrupt,1
+cPublicFpo 1,0
+ mov ecx, [esp+4]
+ fstCall KfLowerIrql
+ stdRet _HalpEndSoftwareInterrupt
+stdENDP _HalpEndSoftwareInterrupt
+
+ page ,132
+ subttl "Get current irql"
+;++
+;
+; KIRQL
+; KeGetCurrentIrql (VOID)
+;
+; Routine Description:
+;
+; This routine returns to current IRQL.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; The current IRQL.
+;
+;--
+
+cPublicProc _KeGetCurrentIrql ,0
+cPublicFpo 0,0
+ xor eax,eax
+ mov al, byte ptr PCR[PcIrql] ; Current irql is in the PCR
+ stdRET _KeGetCurrentIrql
+stdENDP _KeGetCurrentIrql
+
+;++
+;
+; KIRQL
+; FASTCALL
+; KfAcquireSpinLock (
+; IN PKSPIN_LOCK SpinLock
+; )
+;
+; Routine Description:
+;
+; This function raises to DISPATCH_LEVEL and then acquires a the
+; kernel spin lock.
+;
+; Arguments:
+;
+; (ecx) = SpinLock - Supplies a pointer to an kernel spin lock.
+;
+; Return Value:
+;
+; OldIrql
+;
+;--
+
+cPublicFastCall KfAcquireSpinLock,1
+cPublicFpo 0,0
+
+ mov al, PCR[PcIrql] ; (al) = Old Irql
+ mov byte ptr PCR[PcIrql], DISPATCH_LEVEL ; set new irql
+if DBG
+ cmp al, DISPATCH_LEVEL ; old > new?
+ ja short asl99 ; yes, go bugcheck
+endif
+ifdef IRQL_METRICS
+ inc HalRaiseIrqlCount
+endif
+
+sl10: ACQUIRE_SPINLOCK ecx,<short sl20>
+ fstRET KfAcquireSpinLock
+
+ public KfAcquireSpinLockSpinning
+KfAcquireSpinLockSpinning: ; label for profiling
+
+align 4
+sl20: SPIN_ON_SPINLOCK ecx,<short sl10>
+
+if DBG
+cPublicFpo 2, 1
+asl99:
+ push eax ; put old irql where we can find it
+ stdCall _KeBugCheck, <IRQL_NOT_GREATER_OR_EQUAL> ; never return
+endif
+ fstRET KfAcquireSpinLock
+fstENDP KfAcquireSpinLock
+
+ PAGE
+ SUBTTL "Acquire Synch Kernel Spin Lock"
+;++
+;
+; KIRQL
+; FASTCALL
+; KeAcquireSpinLockRaiseToSynch (
+; IN PKSPIN_LOCK SpinLock
+; )
+;
+; Routine Description:
+;
+; This function acquires the SpinLock at SYNCH_LEVEL. The function
+; is optmized for hoter locks (the lock is tested before acquired,
+; any spin should occur at OldIrql)
+;
+; Arguments:
+;
+; (ecx) = SpinLock - Supplies a pointer to an kernel spin lock.
+;
+; Return Value:
+;
+; OldIrql - pointer to place old irql
+;
+;--
+
+align 16
+cPublicFastCall KeAcquireSpinLockRaiseToSynch,1
+cPublicFpo 0,0
+
+;
+; Disable interrupts
+;
+
+sls10: cli
+
+;
+; Try to obtain spinlock. Use non-lock operation first
+;
+ TEST_SPINLOCK ecx,<short sls20>
+ ACQUIRE_SPINLOCK ecx,<short sls20>
+
+
+;
+; Got the lock, raise to SYNCH_LEVEL
+;
+
+ mov ecx, SYNCH_LEVEL
+ fstCall KfRaiseIrql ; (al) = OldIrql
+
+;
+; Enable interrupts and return
+;
+
+ sti
+ fstRET KeAcquireSpinLockRaiseToSynch
+
+
+;
+; Lock is owned, spin till it looks free, then go get it again.
+;
+
+sls20: sti
+ SPIN_ON_SPINLOCK ecx,sls10
+
+fstENDP KeAcquireSpinLockRaiseToSynch
+
+
+
+;++
+;
+; VOID
+; FASTCALL
+; KfReleaseSpinLock (
+; IN PKSPIN_LOCK SpinLock,
+; IN KIRQL NewIrql
+; )
+;
+; Routine Description:
+;
+; This function releases a kernel spin lock and lowers to the new irql
+;
+; In a UP hal spinlock serialization is accomplished by raising the
+; IRQL to DISPATCH_LEVEL. The SpinLock is not used.
+;
+; Arguments:
+;
+; (ecx) = SpinLock - Supplies a pointer to an executive spin lock.
+; (dl) = NewIrql - New irql value to set
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+align 16
+cPublicFastCall KfReleaseSpinLock ,2
+cPublicFpo 0,0
+
+ RELEASE_SPINLOCK ecx ; release it
+
+ mov ecx, edx ; (ecx) = NewIrql
+ jmp @KfLowerIrql@4
+
+fstENDP KfReleaseSpinLock
+
+;++
+;
+; VOID
+; FASTCALL
+; ExAcquireFastMutex (
+; IN PFAST_MUTEX FastMutex
+; )
+;
+; Routine description:
+;
+; This function acquire ownership of the FastMutex
+;
+; Arguments:
+;
+; (ecx) = FastMutex - Supplies a pointer to the fast mutex
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+cPublicFastCall ExAcquireFastMutex,1
+cPublicFpo 0,1
+
+ push ecx ; Push FAST_MUTEX addr
+ mov ecx, APC_LEVEL
+ fstCall KfRaiseIrql
+
+ pop ecx ; (ecx) = Fast Mutex
+
+cPublicFpo 0,0
+ LOCK_DEC dword ptr [ecx].FmCount ; Get count
+ jz short afm_ret ; The owner? Yes, Done
+
+ inc dword ptr [ecx].FmContention
+
+cPublicFpo 0,1
+ push ecx
+ push eax
+ add ecx, FmEvent ; Wait on Event
+ stdCall _KeWaitForSingleObject,<ecx,WrExecutive,0,0,0>
+ pop eax
+ pop ecx
+
+cPublicFpo 0,0
+afm_ret:
+ mov byte ptr [ecx].FmOldIrql, al
+ fstRet ExAcquireFastMutex
+
+fstENDP ExAcquireFastMutex
+
+;++
+;
+; BOOLEAN
+; FASTCALL
+; ExTryToAcquireFastMutex (
+; IN PFAST_MUTEX FastMutex
+; )
+;
+; Routine description:
+;
+; This function acquire ownership of the FastMutex
+;
+; Arguments:
+;
+; (ecx) = FastMutex - Supplies a pointer to the fast mutex
+;
+; Return Value:
+;
+; Returns TRUE if the FAST_MUTEX was acquired; otherwise false
+;
+;--
+
+cPublicFastCall ExTryToAcquireFastMutex,1
+cPublicFpo 0,0
+
+;
+; Try to acquire
+;
+ cmp dword ptr [ecx].FmCount, 1 ; Busy?
+ jne short tam25 ; Yes, abort
+
+cPublicFpo 0,1
+ push ecx ; Push FAST_MUTEX
+ mov ecx, APC_LEVEL
+ fstCall KfRaiseIrql ; (al) = OldIrql
+
+ mov ecx, [esp] ; Restore FAST_MUTEX
+ mov [esp], eax ; Save OldIrql
+
+ mov eax, 1 ; Value to compare against
+ mov edx, 0 ; Value to set
+ lock cmpxchg dword ptr [ecx].FmCount, edx ; Attempt to acquire
+ jnz short tam20 ; got it?
+
+cPublicFpo 0,0
+ pop edx ; (edx) = OldIrql
+ mov eax, 1 ; return TRUE
+ mov byte ptr [ecx].FmOldIrql, dl ; Store OldIrql
+ fstRet ExTryToAcquireFastMutex
+
+tam20: pop ecx ; (ecx) = OldIrql
+ fstCall KfLowerIrql ; restore OldIrql
+tam25: xor eax, eax ; return FALSE
+ fstRet ExTryToAcquireFastMutex ; all done
+
+fstENDP ExTryToAcquireFastMutex
+
+
+;++
+;
+; VOID
+; FASTCALL
+; ExReleaseFastMutex (
+; IN PFAST_MUTEX FastMutex
+; )
+;
+; Routine description:
+;
+; This function releases ownership of the FastMutex
+;
+; Arguments:
+;
+; (ecx) FastMutex - Supplies a pointer to the fast mutex
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+cPublicFastCall ExReleaseFastMutex,1
+
+cPublicFpo 0,0
+ mov al, byte ptr [ecx].FmOldIrql ; (cl) = OldIrql
+
+ LOCK_ADD dword ptr [ecx].FmCount, 1 ; Remove our count
+ xchg ecx, eax ; (cl) = OldIrql
+ js short rfm05 ; if < 0, set event
+ jnz @KfLowerIrql@4 ; if != 0, don't set event
+
+rfm05: add eax, FmEvent
+ push ecx
+ stdCall _KeSetEventBoostPriority, <eax, 0>
+ pop ecx
+ jmp @KfLowerIrql@4
+
+
+fstENDP ExReleaseFastMutex
+
+
+;++
+;
+; VOID
+; HalpDisableAllInterrupts (VOID)
+;
+; Routine Description:
+;
+; This routine is called during a system crash. The hal needs all
+; interrupts disabled.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; None - all interrupts are masked off
+;
+;--
+
+cPublicProc _HalpDisableAllInterrupts,0
+cPublicFpo 0,0
+
+ ;
+ ; Mask interrupts off at PIC
+ ; (raising to high_level does not work on lazy irql implementation)
+ ;
+ mov eax, KiI8259MaskTable[HIGH_LEVEL*4]; get pic masks for the new irql
+ or eax, PCR[PcIDR] ; mask irqs which are disabled
+ SET_IRQ_MASK ; set 8259 masks
+
+ mov byte ptr PCR[PcIrql], HIGH_LEVEL ; set new irql
+
+ stdRET _HalpDisableAllInterrupts
+
+stdENDP _HalpDisableAllInterrupts
+
+
+
+ page ,132
+ subttl "Postponed Hardware Interrupt Dispatcher"
+;++
+;
+; VOID
+; HalpHardwareInterruptNN (
+; VOID
+; );
+;
+; Routine Description:
+;
+; These routines branch through the IDT to simulate the appropriate
+; hardware interrupt. They use the "INT nn" instruction to do this.
+;
+; Arguments:
+;
+; None.
+;
+; Returns:
+;
+; None.
+;
+; Environment:
+;
+; IRET frame is on the stack
+;
+;--
+cPublicProc _HalpHardwareInterruptTable
+cPublicFpo 0,0
+
+ public HalpHardwareInterrupt00
+HalpHardwareInterrupt00 label byte
+ifdef IRQL_METRICS
+ lock inc HalHardwareIntCount
+endif
+ int PRIMARY_VECTOR_BASE + 0
+ ret
+
+ public HalpHardwareInterrupt01
+HalpHardwareInterrupt01 label byte
+ifdef IRQL_METRICS
+ lock inc HalHardwareIntCount
+endif
+ int PRIMARY_VECTOR_BASE + 1
+ ret
+
+ public HalpHardwareInterrupt02
+HalpHardwareInterrupt02 label byte
+ifdef IRQL_METRICS
+ lock inc HalHardwareIntCount
+endif
+ int PRIMARY_VECTOR_BASE + 2
+ ret
+
+ public HalpHardwareInterrupt03
+HalpHardwareInterrupt03 label byte
+ifdef IRQL_METRICS
+ lock inc HalHardwareIntCount
+endif
+ int PRIMARY_VECTOR_BASE + 3
+ ret
+
+ public HalpHardwareInterrupt04
+HalpHardwareInterrupt04 label byte
+ifdef IRQL_METRICS
+ lock inc HalHardwareIntCount
+endif
+ int PRIMARY_VECTOR_BASE + 4
+ ret
+
+ public HalpHardwareInterrupt05
+HalpHardwareInterrupt05 label byte
+ifdef IRQL_METRICS
+ lock inc HalHardwareIntCount
+endif
+ int PRIMARY_VECTOR_BASE + 5
+ ret
+
+ public HalpHardwareInterrupt06
+HalpHardwareInterrupt06 label byte
+ifdef IRQL_METRICS
+ lock inc HalHardwareIntCount
+endif
+ int PRIMARY_VECTOR_BASE + 6
+ ret
+
+ public HalpHardwareInterrupt07
+HalpHardwareInterrupt07 label byte
+ifdef IRQL_METRICS
+ lock inc HalHardwareIntCount
+endif
+ int PRIMARY_VECTOR_BASE + 7
+ ret
+
+ public HalpHardwareInterrupt08
+HalpHardwareInterrupt08 label byte
+ifdef IRQL_METRICS
+ lock inc HalHardwareIntCount
+endif
+ int PRIMARY_VECTOR_BASE + 8
+ ret
+
+ public HalpHardwareInterrupt09
+HalpHardwareInterrupt09 label byte
+ifdef IRQL_METRICS
+ lock inc HalHardwareIntCount
+endif
+ int PRIMARY_VECTOR_BASE + 9
+ ret
+
+ public HalpHardwareInterrupt10
+HalpHardwareInterrupt10 label byte
+ifdef IRQL_METRICS
+ lock inc HalHardwareIntCount
+endif
+ int PRIMARY_VECTOR_BASE + 10
+ ret
+
+ public HalpHardwareInterrupt11
+HalpHardwareInterrupt11 label byte
+ifdef IRQL_METRICS
+ lock inc HalHardwareIntCount
+endif
+ int PRIMARY_VECTOR_BASE + 11
+ ret
+
+ public HalpHardwareInterrupt12
+HalpHardwareInterrupt12 label byte
+ifdef IRQL_METRICS
+ lock inc HalHardwareIntCount
+endif
+ int PRIMARY_VECTOR_BASE + 12
+ ret
+
+ public HalpHardwareInterrupt13
+HalpHardwareInterrupt13 label byte
+ifdef IRQL_METRICS
+ lock inc HalHardwareIntCount
+endif
+ int PRIMARY_VECTOR_BASE + 13
+ ret
+
+ public HalpHardwareInterrupt14
+HalpHardwareInterrupt14 label byte
+ifdef IRQL_METRICS
+ lock inc HalHardwareIntCount
+endif
+ int PRIMARY_VECTOR_BASE + 14
+ ret
+
+ public HalpHardwareInterrupt15
+HalpHardwareInterrupt15 label byte
+ifdef IRQL_METRICS
+ lock inc HalHardwareIntCount
+endif
+ int PRIMARY_VECTOR_BASE + 15
+ ret
+stdENDP _HalpHardwareInterruptTable
+
+ page ,132
+ subttl "Interrupt Controller Chip Initialization"
+;++
+;
+; VOID
+; HalpInitializePICs (
+; )
+;
+; Routine Description:
+;
+; This routine sends the 8259 PIC initialization commands and
+; masks all the interrupts on 8259s.
+;
+; Arguments:
+;
+; None
+;
+; Return Value:
+;
+; None.
+;
+;--
+cPublicProc _HalpInitializePICs ,0
+
+ push esi ; save caller's esi
+ cli ; disable interrupt
+ lea esi, PICsInitializationString
+ lodsw ; (AX) = PIC port 0 address
+Hip10: movzx edx, ax
+ outsb ; output ICW1
+ IODelay
+ inc edx ; (DX) = PIC port 1 address
+ outsb ; output ICW2
+ IODelay
+ outsb ; output ICW3
+ IODelay
+ outsb ; output ICW4
+ IODelay
+ mov al, 0FFH ; mask all 8259 irqs
+ out dx,al ; write mask to PIC
+ lodsw
+ cmp ax, 0 ; end of init string?
+ jne short Hip10 ; go init next PIC
+
+ mov al, OCW3_READ_ISR ; tell 8259 we want to read ISR
+ out PIC1_PORT0, al
+
+ mov al, OCW3_READ_ISR ; tell 8259 we want to read ISR
+ out PIC2_PORT0, al
+
+ pop esi ; restore caller's esi
+ sti ; enable interrupt
+ stdRET _HalpInitializePICs
+stdENDP _HalpInitializePICs
+
+
+_TEXT ends
+
+ end