mirror of
https://github.com/reactos/reactos.git
synced 2025-08-06 11:53:16 +00:00
645 lines
15 KiB
ArmAsm
645 lines
15 KiB
ArmAsm
/*
|
|
* FILE: hal/halx86/generic/irql.S
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PURPOSE: Software, System and Hardware IRQ Management
|
|
* PROGRAMMER: Alex Ionescu (alex@relsoft.net)
|
|
*/
|
|
|
|
/* INCLUDES ******************************************************************/
|
|
|
|
#include <asm.h>
|
|
#include <internal/i386/asmmacro.S>
|
|
.intel_syntax noprefix
|
|
|
|
.extern _Kei386EoiHelper@0
|
|
.extern _KiUnexpectedInterrupt
|
|
|
|
/* GLOBALS *******************************************************************/
|
|
|
|
PICInitTable:
|
|
|
|
/* Master PIC */
|
|
.short 0x20 /* Port */
|
|
.byte 0x11 /* Edge,, cascade, CAI 8, ICW4 */
|
|
.byte 0x40 /* Base */
|
|
.byte 4 /* IRQ 4 connected to slave */
|
|
.byte 1 /* Non buffered, not nested, 8086 */
|
|
|
|
/* Slave PIC */
|
|
.short 0xA0 /* Port */
|
|
.byte 0x11 /* Edge, cascade, CAI 8, ICW4 */
|
|
.byte 0x48 /* Base */
|
|
.byte 2 /* Slave ID: Slave 2 */
|
|
.byte 1 /* Non buffered, not nested, 8086 */
|
|
|
|
/* End of initialization table */
|
|
.short 0
|
|
|
|
.globl _KiI8259MaskTable
|
|
_KiI8259MaskTable:
|
|
.long 0 /* IRQL 0 */
|
|
.long 0 /* IRQL 1 */
|
|
.long 0 /* IRQL 2 */
|
|
.long 0 /* IRQL 3 */
|
|
.long 0xFF800000 /* IRQL 4 */
|
|
.long 0xFFC00000 /* IRQL 5 */
|
|
.long 0xFFE00000 /* IRQL 6 */
|
|
.long 0xFFF00000 /* IRQL 7 */
|
|
.long 0xFFF80000 /* IRQL 8 */
|
|
.long 0xFFFC0000 /* IRQL 9 */
|
|
.long 0xFFFE0000 /* IRQL 10 */
|
|
.long 0xFFFF0000 /* IRQL 11 */
|
|
.long 0xFFFF8000 /* IRQL 12 */
|
|
.long 0xFFFFC000 /* IRQL 13 */
|
|
.long 0xFFFFE000 /* IRQL 14 */
|
|
.long 0xFFFFF000 /* IRQL 15 */
|
|
.long 0xFFFFF800 /* IRQL 16 */
|
|
.long 0xFFFFFC00 /* IRQL 17 */
|
|
.long 0xFFFFFE00 /* IRQL 18 */
|
|
.long 0xFFFFFE00 /* IRQL 19 */
|
|
.long 0xFFFFFE80 /* IRQL 20 */
|
|
.long 0xFFFFFEC0 /* IRQL 21 */
|
|
.long 0xFFFFFEE0 /* IRQL 22 */
|
|
.long 0xFFFFFEF0 /* IRQL 23 */
|
|
.long 0xFFFFFEF8 /* IRQL 24 */
|
|
.long 0xFFFFFEF8 /* IRQL 25 */
|
|
.long 0xFFFFFEFA /* IRQL 26 */
|
|
.long 0xFFFFFFFA /* IRQL 27 */
|
|
.long 0xFFFFFFFB /* IRQL 28 */
|
|
.long 0xFFFFFFFB /* IRQL 29 */
|
|
.long 0xFFFFFFFB /* IRQL 30 */
|
|
.long 0xFFFFFFFB /* IRQL 31 */
|
|
|
|
HalpSysIntHandler:
|
|
.rept 8
|
|
.long GenericIRQ /* IRQ 0-7 */
|
|
.endr
|
|
.long IRQ7 /* IRQ 7 */
|
|
.rept 8
|
|
.long GenericIRQ /* IRQ 8-15 */
|
|
.endr
|
|
.long IRQ15 /* IRQ 15 */
|
|
.rept 20
|
|
.long GenericIRQ /* IRQ 16-35 */
|
|
.endr
|
|
|
|
SoftIntByteTable:
|
|
.byte PASSIVE_LEVEL /* IRR 0 */
|
|
.byte PASSIVE_LEVEL /* IRR 1 */
|
|
.byte APC_LEVEL /* IRR 2 */
|
|
.byte APC_LEVEL /* IRR 3 */
|
|
.byte DISPATCH_LEVEL /* IRR 4 */
|
|
.byte DISPATCH_LEVEL /* IRR 5 */
|
|
.byte DISPATCH_LEVEL /* IRR 6 */
|
|
.byte DISPATCH_LEVEL /* IRR 7 */
|
|
|
|
SoftIntHandlerTable:
|
|
.long _KiUnexpectedInterrupt /* PASSIVE_LEVEL */
|
|
.long _HalpApcInterrupt /* APC_LEVEL */
|
|
.long _HalpDispatchInterrupt /* DISPATCH_LEVEL */
|
|
|
|
SoftIntHandlerTable2:
|
|
.long _KiUnexpectedInterrupt /* PASSIVE_LEVEL */
|
|
.long _HalpApcInterrupt2ndEntry /* APC_LEVEL */
|
|
.long _HalpDispatchInterrupt2ndEntry /* DISPATCH_LEVEL */
|
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
.globl _HalpInitPICs@0
|
|
.func HalpInitPICs@0
|
|
_HalpInitPICs@0:
|
|
|
|
/* Save ESI and disable interrupts */
|
|
push esi
|
|
pushf
|
|
cli
|
|
|
|
/* Read the init table */
|
|
lea esi, PICInitTable
|
|
lodsw
|
|
|
|
InitLoop:
|
|
|
|
/* Put the port in EDX */
|
|
movzx edx, ax
|
|
|
|
/* Initialize the PIC, using a delay for each command */
|
|
outsb
|
|
jmp $+2
|
|
inc edx
|
|
outsb
|
|
jmp $+2
|
|
outsb
|
|
jmp $+2
|
|
outsb
|
|
jmp $+2
|
|
|
|
/* Mask all interrupts */
|
|
mov al, 0xFA // FIXME: Should be 0xFF
|
|
out dx, al
|
|
|
|
/* Check if we're done, otherwise initialize next PIC */
|
|
lodsw
|
|
cmp ax, 0
|
|
jnz InitLoop
|
|
|
|
/* Restore interrupts and return */
|
|
or dword ptr [esp], EFLAGS_INTERRUPT_MASK
|
|
popf
|
|
pop esi
|
|
ret
|
|
.endfunc
|
|
|
|
.globl @HalRequestSoftwareInterrupt@4
|
|
.func @HalRequestSoftwareInterrupt@4
|
|
_@HalRequestSoftwareInterrupt@4:
|
|
@HalRequestSoftwareInterrupt@4:
|
|
|
|
/* Get IRR mask */
|
|
mov eax, 1
|
|
shl eax, cl
|
|
|
|
/* Disable interrupts */
|
|
pushf
|
|
cli
|
|
|
|
/* Set IRR and get IRQL */
|
|
or [fs:KPCR_IRR], eax
|
|
mov cl, [fs:KPCR_IRQL]
|
|
|
|
/* Get software IRR mask */
|
|
mov eax, [fs:KPCR_IRR]
|
|
and eax, 3
|
|
|
|
/* Get highest pending software interrupt and check if it's higher */
|
|
xor edx, edx
|
|
mov dl, SoftIntByteTable[eax]
|
|
cmp dl, cl
|
|
jbe AfterCall
|
|
|
|
/* Call the pending interrupt */
|
|
jmp $
|
|
call SoftIntHandlerTable[edx*4]
|
|
|
|
AfterCall:
|
|
|
|
/* Retore interrupts and return */
|
|
popf
|
|
ret
|
|
.endfunc
|
|
|
|
.globl _HalDisableSystemInterrupt@8
|
|
.func HalDisableSystemInterrupt@8
|
|
_HalDisableSystemInterrupt@8:
|
|
|
|
/* Convert to vector */
|
|
movzx ecx, byte ptr [esp+4]
|
|
sub ecx, PRIMARY_VECTOR_BASE
|
|
|
|
/* Disable interrupts and set the new IDR */
|
|
mov edx, 1
|
|
shl edx, cl
|
|
cli
|
|
or [fs:KPCR_IDR], edx
|
|
|
|
/* Get the current mask */
|
|
xor eax, eax
|
|
in al, 0xA1
|
|
shl eax, 8
|
|
in al, 0x21
|
|
|
|
/* Mask off the interrupt and write the new mask */
|
|
or eax, edx
|
|
out 0x21, al
|
|
shr eax, 8
|
|
out 0xA1, al
|
|
|
|
/* Return with interrupts enabled */
|
|
in al, 0xA1
|
|
sti
|
|
ret 8
|
|
.endfunc
|
|
|
|
#if 0
|
|
.globl _HalEnableSystemInterrupt@12
|
|
.func HalEnableSystemInterrupt@12
|
|
_HalEnableSystemInterrupt@12:
|
|
|
|
/* Get the vector and validate it */
|
|
jmp $
|
|
movzx ecx, byte ptr [esp+4]
|
|
sub ecx, PRIMARY_VECTOR_BASE
|
|
jb Invalid
|
|
cmp ecx, CLOCK2_LEVEL
|
|
jnb Invalid
|
|
|
|
/* Get the current PCI Edge/Level control registers */
|
|
mov edx, 0x4D1
|
|
in al, dx
|
|
shl ax, 8
|
|
mov eax, 0x4D0
|
|
in al, dx
|
|
mov dx, 1
|
|
shl dx, cl
|
|
|
|
/* Check if this is a latched interrupt */
|
|
cmp dword ptr [esp+12], 0
|
|
jnz Latched
|
|
|
|
/* Use OR for edge interrupt */
|
|
or ax, dx
|
|
jmp AfterMask
|
|
Latched:
|
|
|
|
/* Mask it out for level interrupt */
|
|
not dx
|
|
and ax, dx
|
|
|
|
AfterMask:
|
|
|
|
/* Set the PCI Edge/Level control registers */
|
|
mov edx, 0x4D0
|
|
out dx, al
|
|
shr ax, 8
|
|
mov edx, 0x4D1
|
|
out dx, al
|
|
|
|
/* Calculate the new IDR */
|
|
mov eax, 1
|
|
shl eax, cl
|
|
not eax
|
|
cli
|
|
and [fs:KPCR_IDR], eax
|
|
|
|
/* Get the current IRQL and mask the IRQs in the PIC */
|
|
movzx eax, byte ptr [fs:KPCR_IRQL]
|
|
mov eax, _KiI8259MaskTable[eax*4]
|
|
or eax, [fs:KPCR_IDR]
|
|
out 0x21, al
|
|
shr eax, 8
|
|
out 0xA1, al
|
|
|
|
/* Enable interrupts and return TRUE */
|
|
sti
|
|
mov eax, 1
|
|
ret 12
|
|
|
|
Invalid:
|
|
|
|
/* Fail, invalid IRQ */
|
|
xor eax, eax
|
|
ret 12
|
|
.endfunc
|
|
#endif
|
|
|
|
.globl _HalBeginSystemInterrupt@12
|
|
.func HalBeginSystemInterrupt@12
|
|
_HalBeginSystemInterrupt@12:
|
|
|
|
/* Convert to vector and call the handler */
|
|
mov edx, [esp+8]
|
|
sub edx, PRIMARY_VECTOR_BASE
|
|
jmp HalpSysIntHandler[edx*4]
|
|
|
|
IRQ15:
|
|
/* This is IRQ 15, check if it's spurious */
|
|
mov al, 0xB
|
|
out 0xA0, al
|
|
in al, 0xA0
|
|
test al, 0x80
|
|
jnz GenericIRQ
|
|
|
|
/* Cascaded interrupt... dismiss it and return FALSE */
|
|
mov al, 0x62
|
|
out 0x20, al
|
|
mov eax, 0
|
|
ret 12
|
|
|
|
IRQ7:
|
|
/* This is IRQ 7, check if it's spurious */
|
|
mov al, 0xB
|
|
out 0x20, al
|
|
in al, 0x20
|
|
test al, 0x80
|
|
jnz GenericIRQ
|
|
|
|
/* It is, return FALSE */
|
|
mov eax, 0
|
|
ret 12
|
|
|
|
GenericIRQ:
|
|
/* Return the current IRQL */
|
|
mov eax, [esp+12]
|
|
movzx ecx, byte ptr [fs:KPCR_IRQL]
|
|
mov [eax], cl
|
|
|
|
/* Set the new IRQL */
|
|
movzx eax, byte ptr [esp+4]
|
|
mov [fs:KPCR_IRQL], al
|
|
|
|
/* Set IRQ mask in the PIC */
|
|
mov eax, _KiI8259MaskTable[eax*4]
|
|
or eax, [fs:KPCR_IDR]
|
|
out 0x21, al
|
|
shr eax, 8
|
|
out 0xA1, al
|
|
|
|
/* Check to which PIC the EOI was sent */
|
|
mov eax, edx
|
|
cmp eax, 8
|
|
jnb Pic1
|
|
|
|
/* Write mask to master PIC */
|
|
or al, 0x60
|
|
out 0x20, al
|
|
jmp DoneBegin
|
|
|
|
Pic1:
|
|
/* Write mask to slave PIC */
|
|
mov al, 0x20
|
|
out 0xA0, al
|
|
mov al, 0x62
|
|
out 0x20, al
|
|
|
|
DoneBegin:
|
|
/* Enable interrupts and return TRUE */
|
|
in al, 0x21
|
|
sti
|
|
mov eax, 1
|
|
ret 12
|
|
.endfunc
|
|
|
|
#if 0
|
|
.globl _HalEndSystemInterrupt@8
|
|
.func HalEndSystemInterrupt@8
|
|
_HalEndSystemInterrupt@8:
|
|
|
|
/* Get the IRQL and check if it's a software interrupt */
|
|
movzx ecx, byte ptr [esp+4]
|
|
cmp byte ptr [fs:KPCR_IRQL], DISPATCH_LEVEL
|
|
jbe SkipMask2
|
|
|
|
/* Hardware interrupt, mask the appropriate IRQs in the PIC */
|
|
mov eax, _KiI8259MaskTable[ecx*4]
|
|
or eax, [fs:KPCR_IDR]
|
|
out 0x21, al
|
|
shr eax, 8
|
|
out 0xA1, al
|
|
|
|
SkipMask2:
|
|
|
|
/* Set IRQL and check if there are pending software interrupts */
|
|
mov [fs:KPCR_IRQL], cl
|
|
mov eax, [fs:KPCR_IDR]
|
|
mov al, SoftIntByteTable[eax]
|
|
cmp al, cl
|
|
ja DoCall
|
|
ret 8
|
|
|
|
DoCall:
|
|
|
|
/* There are pending softwate interrupts, call their handlers */
|
|
add esp, 8
|
|
jmp SoftIntHandlerTable2[eax*4]
|
|
.endfunc
|
|
|
|
.globl @KfLowerIrql@4
|
|
.func @KfLowerIrql@4
|
|
_@KfLowerIrql@4:
|
|
@KfLowerIrql@4:
|
|
|
|
/* Save flags since we'll disable interrupts */
|
|
pushf
|
|
|
|
/* Disable interrupts and check if IRQL is below DISPATCH_LEVEL */
|
|
movzx ecx, cl
|
|
cmp byte ptr [fs:KPCR_IRQL], DISPATCH_LEVEL
|
|
cli
|
|
jbe SkipMask
|
|
|
|
/* Clear interrupt masks since there's a pending hardware interrupt */
|
|
mov eax, _KiI8259MaskTable[ecx*4]
|
|
or eax, [fs:KPCR_IDR]
|
|
out 0x21, al
|
|
shr eax, 8
|
|
out 0xA1, al
|
|
|
|
SkipMask:
|
|
|
|
/* Set the new IRQL and check if there's a pending software interrupt */
|
|
mov [fs:KPCR_IRQL], cl
|
|
mov eax, [fs:KPCR_IDR]
|
|
mov al, SoftIntByteTable[eax]
|
|
cmp al, cl
|
|
jbe AfterCall2
|
|
|
|
/* There is, call it */
|
|
call SoftIntHandlerTable[eax*4]
|
|
|
|
AfterCall2:
|
|
|
|
/* Restore interrupts and return */
|
|
popf
|
|
ret
|
|
.endfunc
|
|
#endif
|
|
|
|
.globl @KfRaiseIrql@4
|
|
.func @KfRaiseIrql@4
|
|
_@KfRaiseIrql@4:
|
|
@KfRaiseIrql@4:
|
|
|
|
/* Get the IRQL and check if it's Software level only */
|
|
xor eax, eax
|
|
mov al, [fs:KPCR_IRQL]
|
|
|
|
movzx ecx, cl
|
|
cmp cl, DISPATCH_LEVEL
|
|
jbe SetIrql
|
|
|
|
/* Save the current IRQL */
|
|
mov edx, eax
|
|
|
|
/* It's a hardware IRQL, so disable interrupts */
|
|
pushf
|
|
cli
|
|
|
|
/* Set the new IRQL */
|
|
mov [fs:KPCR_IRQL], cl
|
|
|
|
#if 0
|
|
/* Mask the interrupts in the PIC */
|
|
mov eax, _KiI8259MaskTable[ecx*4]
|
|
or eax, [fs:KPCR_IDR]
|
|
out 0x21, al
|
|
shr eax, 8
|
|
out 0xA1, al
|
|
#endif
|
|
|
|
/* Restore interrupts and return old IRQL */
|
|
popf
|
|
mov eax, edx
|
|
ret
|
|
|
|
SetIrql:
|
|
|
|
/* Set the IRQL and return */
|
|
mov [fs:KPCR_IRQL], cl
|
|
ret
|
|
.endfunc
|
|
|
|
.globl _KeGetCurrentIrql@0
|
|
.func KeGetCurrentIrql@0
|
|
_KeGetCurrentIrql@0:
|
|
|
|
/* Return the IRQL */
|
|
movzx eax, word ptr [fs:KPCR_IRQL]
|
|
ret
|
|
.endfunc
|
|
|
|
.globl _KeRaiseIrqlToDpcLevel@0
|
|
.func KeRaiseIrqlToDpcLevel@0
|
|
_KeRaiseIrqlToDpcLevel@0:
|
|
|
|
/* Get the current IRQL */
|
|
xor eax, eax
|
|
mov al, [fs:KPCR_IRQL]
|
|
|
|
/* Set DISPATCH_LEVEL */
|
|
mov byte ptr [fs:KPCR_IRQL], DISPATCH_LEVEL
|
|
ret
|
|
.endfunc
|
|
|
|
.globl _KeRaiseIrqlToSynchLevel@0
|
|
.func KeRaiseIrqlToSynchLevel@0
|
|
_KeRaiseIrqlToSynchLevel@0:
|
|
|
|
/* Disable interrupts */
|
|
pushf
|
|
cli
|
|
|
|
/* Mask out interrupts */
|
|
mov eax, _KiI8259MaskTable + DISPATCH_LEVEL * 2
|
|
or eax, [fs:KPCR_IDR]
|
|
out 0x21, al
|
|
shr eax, 8
|
|
out 0xA1, al
|
|
|
|
/* Return the old IRQL, enable interrupts and set to DISPATCH */
|
|
mov al, [fs:KPCR_IRQL]
|
|
mov byte ptr [fs:KPCR_IRQL], DISPATCH_LEVEL
|
|
popf
|
|
ret
|
|
.endfunc
|
|
|
|
.globl _HalpApcInterrupt
|
|
.func HalpApcInterrupt
|
|
_HalpApcInterrupt:
|
|
|
|
/* Create fake interrupt stack */
|
|
pop eax
|
|
pushf
|
|
push cs
|
|
push eax
|
|
|
|
/* Enter interrupt */
|
|
INT_PROLOG(hapc)
|
|
.endfunc
|
|
|
|
.globl _HalpApcInterrupt2ndEntry
|
|
.func HalpApcInterrupt2ndEntry
|
|
_HalpApcInterrupt2ndEntry:
|
|
|
|
/* Save current IRQL and set to APC level */
|
|
push [fs:KPCR_IRQL]
|
|
mov byte ptr [fs:KPCR_IRQL], APC_LEVEL
|
|
and dword ptr [fs:KPCR_IRR], ~(1 << APC_LEVEL)
|
|
|
|
/* Enable interrupts and check if we came from User/V86 mode */
|
|
sti
|
|
mov eax, [ebp+KTRAP_FRAME_CS]
|
|
and eax, MODE_MASK
|
|
test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
|
|
jz DeliverApc
|
|
|
|
/* Set user mode delivery */
|
|
or eax, UserMode
|
|
|
|
DeliverApc:
|
|
|
|
/* Deliver the APCs */
|
|
push ebp
|
|
push 0
|
|
push eax
|
|
call _KiDeliverApc@12
|
|
|
|
/* Disable interrupts and end it */
|
|
cli
|
|
call _HalpEndSoftwareInterrupt@4
|
|
jmp _Kei386EoiHelper@0
|
|
.endfunc
|
|
|
|
.globl _HalpDispatchInterrupt
|
|
.func HalpDispatchInterrupt
|
|
_HalpDispatchInterrupt:
|
|
|
|
/* Create fake interrupt stack */
|
|
pop eax
|
|
pushf
|
|
push cs
|
|
push eax
|
|
|
|
/* Enter interrupt */
|
|
INT_PROLOG(hapc)
|
|
.endfunc
|
|
|
|
.globl _HalpDispatchInterrupt2ndEntry
|
|
.func HalpDispatchInterrupt2ndEntry
|
|
_HalpDispatchInterrupt2ndEntry:
|
|
|
|
/* Save current IRQL and set to DPC level */
|
|
push [fs:KPCR_IRQL]
|
|
mov byte ptr [fs:KPCR_IRQL], DISPATCH_LEVEL
|
|
and dword ptr [fs:KPCR_IRR], ~(1 << DISPATCH_LEVEL)
|
|
|
|
/* Enable interrupts and let the kernel handle this */
|
|
sti
|
|
call _KiDispatchInterrupt@0
|
|
|
|
/* Disable interrupts and end it */
|
|
cli
|
|
call _HalpEndSoftwareInterrupt@4
|
|
jmp _Kei386EoiHelper@0
|
|
.endfunc
|
|
|
|
.globl _HalpEndSoftwareInterrupt@4
|
|
.func HalpEndSoftwareInterrupt@4
|
|
_HalpEndSoftwareInterrupt@4:
|
|
|
|
/* Get the IRQL and check if we're in the software region */
|
|
movzx ecx, byte ptr [esp+4]
|
|
cmp byte ptr [fs:KPCR_IRQL], DISPATCH_LEVEL
|
|
jbe SoftwareInt
|
|
|
|
/* Set the right mask in the PIC for the hardware IRQ */
|
|
mov eax, _KiI8259MaskTable[ecx*4]
|
|
or eax, [fs:KPCR_IDR]
|
|
out 0x21, al
|
|
shr eax, 8
|
|
out 0xA1, al
|
|
|
|
SoftwareInt:
|
|
/* Check if there are pending software interrupts */
|
|
mov [fs:KPCR_IRQL], cl
|
|
mov eax, [fs:KPCR_IDR]
|
|
mov al, SoftIntByteTable[eax]
|
|
cmp al, cl
|
|
ja DoCall2
|
|
ret 4
|
|
|
|
DoCall2:
|
|
|
|
/* There are pending softwate interrupts, call their handlers */
|
|
add esp, 8
|
|
jmp SoftIntHandlerTable2[eax*4]
|
|
.endfunc
|