diff options
author | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
---|---|---|
committer | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
commit | e611b132f9b8abe35b362e5870b74bce94a1e58e (patch) | |
tree | a5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/nthals/halncr/i386/ncrirql.asm | |
download | NT4.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.asm | 1223 |
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 |