diff --git a/reactos/hal/halx86/generic/halinit.c b/reactos/hal/halx86/generic/halinit.c index 27077d678c3..1fb157fa0b7 100644 --- a/reactos/hal/halx86/generic/halinit.c +++ b/reactos/hal/halx86/generic/halinit.c @@ -92,7 +92,7 @@ HalInitSystem(IN ULONG BootPhase, } /* Initialize the PICs */ - HalpInitPICs(); + HalpInitializePICs(TRUE); /* Force initial PIC state */ KfRaiseIrql(KeGetCurrentIrql()); diff --git a/reactos/hal/halx86/generic/irq.S b/reactos/hal/halx86/generic/irq.S index 2b4e70f1062..84ab80f62b0 100644 --- a/reactos/hal/halx86/generic/irq.S +++ b/reactos/hal/halx86/generic/irq.S @@ -16,25 +16,6 @@ /* GLOBALS *******************************************************************/ -PICInitTable: - - /* Master PIC */ - .short 0x20 /* Port */ - .byte 0x11 /* Edge, cascade, CAI 8, ICW4 */ - .byte PRIMARY_VECTOR_BASE /* 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 PRIMARY_VECTOR_BASE + 8 /* Base */ - .byte 2 /* Slave ID: Slave 2 */ - .byte 1 /* Non buffered, not nested, 8086 */ - - /* End of initialization table */ - .short 0 - KiI8259MaskTable: .long 0 /* IRQL 0 */ .long 0 /* IRQL 1 */ @@ -193,66 +174,6 @@ NothingHardware: ret .endfunc -.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, 0xFF - out dx, al - - /* Check if we're done, otherwise initialize next PIC */ - lodsw - cmp ax, 0 - jnz InitLoop - - /* Read EISA Edge/Level Register */ - mov edx, 0x4D1 - in al, dx - mov ah, al - dec edx - in al, dx - - /* Clear reserved bits and see if there's anything there */ - and eax, 0xDEF8 - cmp eax, 0xDEF8 - jz NoEisa - - /* FIXME */ - //UNHANDLED_PATH - -/* Restore interrupts and return */ -NoEisa: - popf - pop esi - ret -.endfunc - .globl @HalClearSoftwareInterrupt@4 .func @HalClearSoftwareInterrupt@4, @HalClearSoftwareInterrupt@4 @HalClearSoftwareInterrupt@4: diff --git a/reactos/hal/halx86/generic/pic.c b/reactos/hal/halx86/generic/pic.c new file mode 100644 index 00000000000..0785f5ac134 --- /dev/null +++ b/reactos/hal/halx86/generic/pic.c @@ -0,0 +1,116 @@ +/* + * PROJECT: ReactOS HAL + * LICENSE: BSD - See COPYING.ARM in the top level directory + * FILE: hal/halx86/generic/pic.c + * PURPOSE: HAL PIC Management and Control Code + * PROGRAMMERS: ReactOS Portable Systems Group + */ + +/* INCLUDES *******************************************************************/ + +#include +#define NDEBUG +#include + +/* GLOBALS ********************************************************************/ + +USHORT HalpEisaELCR; + +/* FUNCTIONS ******************************************************************/ + +VOID +NTAPI +HalpInitializePICs(IN BOOLEAN EnableInterrupts) +{ + ULONG EFlags; + I8259_ICW1 Icw1; + I8259_ICW2 Icw2; + I8259_ICW3 Icw3; + I8259_ICW4 Icw4; + EISA_ELCR Elcr; + ULONG i, j; + + /* Save EFlags and disable interrupts */ + EFlags = __readeflags(); + _disable(); + + /* Initialize ICW1 for master, interval 8, edge-triggered mode with ICW4 */ + Icw1.NeedIcw4 = TRUE; + Icw1.OperatingMode = Cascade; + Icw1.Interval = Interval8; + Icw1.Init = TRUE; + Icw1.InterruptVectorAddress = 0; /* This is only used in MCS80/85 mode */ + __outbyte(PIC1_CONTROL_PORT, Icw1.Bits); + + /* Set interrupt vector base */ + Icw2.Bits = PRIMARY_VECTOR_BASE; + __outbyte(PIC1_DATA_PORT, Icw2.Bits); + + /* Connect slave to IRQ 2 */ + Icw3.Bits = 0; + Icw3.SlaveIrq2 = TRUE; + __outbyte(PIC1_DATA_PORT, Icw3.Bits); + + /* Enable 8086 mode, non-automatic EOI, non-buffered mode, non special fully nested mode */ + Icw4.Reserved = 0; + Icw4.SystemMode = New8086Mode; + Icw4.EoiMode = NormalEoi; + Icw4.BufferedMode = NonBuffered; + Icw4.SpecialFullyNestedMode = FALSE; + __outbyte(PIC1_DATA_PORT, Icw4.Bits); + + /* Mask all interrupts */ + __outbyte(PIC1_DATA_PORT, 0xFF); + + /* Initialize ICW1 for master, interval 8, edge-triggered mode with ICW4 */ + Icw1.NeedIcw4 = TRUE; + Icw1.OperatingMode = Cascade; + Icw1.Interval = Interval8; + Icw1.Init = TRUE; + Icw1.InterruptVectorAddress = 0; /* This is only used in MCS80/85 mode */ + __outbyte(PIC2_CONTROL_PORT, Icw1.Bits); + + /* Set interrupt vector base */ + Icw2.Bits = PRIMARY_VECTOR_BASE + 8; + __outbyte(PIC2_DATA_PORT, Icw2.Bits); + + /* Slave ID */ + Icw3.Bits = 0; + Icw3.SlaveId = 2; + __outbyte(PIC2_DATA_PORT, Icw3.Bits); + + /* Enable 8086 mode, non-automatic EOI, non-buffered mode, non special fully nested mode */ + Icw4.Reserved = 0; + Icw4.SystemMode = New8086Mode; + Icw4.EoiMode = NormalEoi; + Icw4.BufferedMode = NonBuffered; + Icw4.SpecialFullyNestedMode = FALSE; + __outbyte(PIC2_DATA_PORT, Icw4.Bits); + + /* Mask all interrupts */ + __outbyte(PIC2_DATA_PORT, 0xFF); + + /* Read EISA Edge/Level Register for master and slave */ + Elcr.Bits = (__inbyte(EISA_ELCR_SLAVE) << 8) | __inbyte(EISA_ELCR_MASTER); + + /* IRQs 0, 1, 2, 8, and 13 are system-reserved and must be edge */ + if (!(Elcr.Master.Irq0Level) && !(Elcr.Master.Irq1Level) && !(Elcr.Master.Irq2Level) && + !(Elcr.Slave.Irq8Level) && !(Elcr.Slave.Irq13Level)) + { + /* ELCR is as it's supposed to be, save it */ + HalpEisaELCR = Elcr.Bits; + DPRINT1("HAL Detected EISA Interrupt Controller (ELCR: %lx)\n", HalpEisaELCR); + + /* Scan for level interrupts */ + for (i = 1, j = 0; j < 16; i <<= 1, j++) + { + /* Warn the user ReactOS does not (and has never) supported this */ + if (HalpEisaELCR & i) DPRINT1("WARNING: IRQ %d is SHARED and LEVEL-SENSITIVE. This is unsupported!\n", j); + } + } + + /* Restore interrupt state */ + if (EnableInterrupts) EFlags |= EFLAGS_INTERRUPT_MASK; + __writeeflags(EFlags); +} + diff --git a/reactos/hal/halx86/hal_generic_up.rbuild b/reactos/hal/halx86/hal_generic_up.rbuild index 11fb20e4a18..609dfe01682 100644 --- a/reactos/hal/halx86/hal_generic_up.rbuild +++ b/reactos/hal/halx86/hal_generic_up.rbuild @@ -6,6 +6,7 @@ include + pic.c irq.S processor.c spinlock.c diff --git a/reactos/hal/halx86/include/halp.h b/reactos/hal/halx86/include/halp.h index 6fe0daab24d..1b456bd647d 100644 --- a/reactos/hal/halx86/include/halp.h +++ b/reactos/hal/halx86/include/halp.h @@ -127,6 +127,161 @@ typedef union _SYSTEM_CONTROL_PORT_B_REGISTER UCHAR Bits; } SYSTEM_CONTROL_PORT_B_REGISTER, *PSYSTEM_CONTROL_PORT_B_REGISTER; +// +// See ISA System Architecture 3rd Edition (Tom Shanley, Don Anderson, John Swindle) +// P. 396, 397 +// +// These ports are controlled by the i8259 Programmable Interrupt Controller (PIC) +// +#define PIC1_CONTROL_PORT 0x20 +#define PIC1_DATA_PORT 0x21 +#define PIC2_CONTROL_PORT 0xA0 +#define PIC2_DATA_PORT 0xA1 + +// +// Definitions for ICW/OCW Bits +// +typedef enum _I8259_ICW1_OPERATING_MODE +{ + Cascade, + Single +} I8259_ICW1_OPERATING_MODE; + +typedef enum _I8259_ICW1_INTERRUPT_MODE +{ + EdgeTriggered, + LevelTriggered +} I8259_ICW1_INTERRUPT_MODE; + +typedef enum _I8259_ICW1_INTERVAL +{ + Interval8, + Interval4 +} I8259_ICW1_INTERVAL; + +typedef enum _I8259_ICW4_SYSTEM_MODE +{ + Mcs8085Mode, + New8086Mode +} I8259_ICW4_SYSTEM_MODE; + +typedef enum _I8259_ICW4_EOI_MODE +{ + NormalEoi, + AutomaticEoi +} I8259_ICW4_EOI_MODE; + +typedef enum _I8259_ICW4_BUFFERED_MODE +{ + NonBuffered, + NonBuffered2, + BufferedSlave, + BufferedMaster +} I8259_ICW4_BUFFERED_MODE; + +// +// Definitions for ICW Registers +// +typedef union _I8259_ICW1 +{ + struct + { + UCHAR NeedIcw4:1; + I8259_ICW1_OPERATING_MODE OperatingMode:1; + I8259_ICW1_INTERVAL Interval:1; + I8259_ICW1_INTERRUPT_MODE InterruptMode:1; + UCHAR Init:1; + UCHAR InterruptVectorAddress:3; + }; + UCHAR Bits; +} I8259_ICW1, *PI8259_ICW1; + +typedef union _I8259_ICW2 +{ + struct + { + UCHAR Sbz:3; + UCHAR InterruptVector:5; + }; + UCHAR Bits; +} I8259_ICW2, *PI8259_ICW2; + +typedef union _I8259_ICW3 +{ + union + { + struct + { + UCHAR SlaveIrq0:1; + UCHAR SlaveIrq1:1; + UCHAR SlaveIrq2:1; + UCHAR SlaveIrq3:1; + UCHAR SlaveIrq4:1; + UCHAR SlaveIrq5:1; + UCHAR SlaveIrq6:1; + UCHAR SlaveIrq7:1; + }; + struct + { + UCHAR SlaveId:3; + UCHAR Reserved:5; + }; + }; + UCHAR Bits; +} I8259_ICW3, *PI8259_ICW3; + +typedef union _I8259_ICW4 +{ + struct + { + I8259_ICW4_SYSTEM_MODE SystemMode:1; + I8259_ICW4_EOI_MODE EoiMode:1; + I8259_ICW4_BUFFERED_MODE BufferedMode:2; + UCHAR SpecialFullyNestedMode:1; + UCHAR Reserved:3; + }; + UCHAR Bits; +} I8259_ICW4, *PI8259_ICW4; + +// +// See EISA System Architecture 2nd Edition (Tom Shanley, Don Anderson, John Swindle) +// P. 34, 35 +// +// These ports are controlled by the i8259A Programmable Interrupt Controller (PIC) +// +#define EISA_ELCR_MASTER 0x4D0 +#define EISA_ELCR_SLAVE 0x4D1 + +typedef union _EISA_ELCR +{ + struct + { + struct + { + UCHAR Irq0Level:1; + UCHAR Irq1Level:1; + UCHAR Irq2Level:1; + UCHAR Irq3Level:1; + UCHAR Irq4Level:1; + UCHAR Irq5Level:1; + UCHAR Irq6Level:1; + UCHAR Irq7Level:1; + } Master; + struct + { + UCHAR Irq8Level:1; + UCHAR Irq9Level:1; + UCHAR Irq10Level:1; + UCHAR Irq11Level:1; + UCHAR Irq12Level:1; + UCHAR Irq13Level:1; + UCHAR Irq14Level:1; + UCHAR Irq15Level:1; + } Slave; + }; + USHORT Bits; +} EISA_ELCR, *PEISA_ELCR; + // // Mm PTE/PDE to Hal PTE/PDE // @@ -176,8 +331,8 @@ HalpEnableInterruptHandler(IN UCHAR Flags, IN PVOID Handler, IN KINTERRUPT_MODE Mode); -/* irql.c */ -VOID NTAPI HalpInitPICs(VOID); +/* pic.c */ +VOID NTAPI HalpInitializePICs(IN BOOLEAN EnableInterrupts); /* udelay.c */ VOID NTAPI HalpInitializeClock(VOID);