[HAL]: Initialize the i8259A PIC controllers in C, and add register structures and enumerations to document the bits. These were taken from ISA System Architecture 3rd Edition and EISA System Architecture 2nd Edition by Mindshare.

[HAL]: Add code to detect EISA systems with ELCR (Edge/Level Control Register). Since the current HAL does not support these, warn users about any level/shared interrupts, since they are likely to cause trouble.

svn path=/trunk/; revision=45180
This commit is contained in:
Sir Richard 2010-01-21 12:51:13 +00:00
parent ffdab4c2f5
commit 202f931c4e
5 changed files with 275 additions and 82 deletions

View file

@ -92,7 +92,7 @@ HalInitSystem(IN ULONG BootPhase,
}
/* Initialize the PICs */
HalpInitPICs();
HalpInitializePICs(TRUE);
/* Force initial PIC state */
KfRaiseIrql(KeGetCurrentIrql());

View file

@ -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:

View file

@ -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 <hal.h>
#define NDEBUG
#include <debug.h>
/* 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);
}

View file

@ -6,6 +6,7 @@
<include base="ntoskrnl">include</include>
<define name="_NTHAL_" />
<directory name="generic">
<file>pic.c</file>
<file>irq.S</file>
<file>processor.c</file>
<file>spinlock.c</file>

View file

@ -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);