mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
295 lines
7.1 KiB
295 lines
7.1 KiB
/*++
|
|
|
|
Copyright (c) 1991-1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
xxinitnt.c
|
|
|
|
Abstract:
|
|
|
|
|
|
This module implements the interrupt initialization for a MIPS R3000
|
|
or R4000 system.
|
|
|
|
Author:
|
|
|
|
David N. Cutler (davec) 26-Apr-1991
|
|
|
|
Environment:
|
|
|
|
Kernel mode only.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "halp.h"
|
|
|
|
//
|
|
// Define forward referenced prototypes.
|
|
//
|
|
|
|
VOID
|
|
HalpCountInterrupt (
|
|
VOID
|
|
);
|
|
|
|
//
|
|
// Put all code for HAL initialization in the INIT section. It will be
|
|
// deallocated by memory management when phase 1 initialization is
|
|
// completed.
|
|
//
|
|
|
|
#if defined(ALLOC_PRAGMA)
|
|
|
|
#pragma alloc_text(INIT, HalpInitializeInterrupts)
|
|
#pragma alloc_text(INIT, HalpCountInterrupt)
|
|
|
|
#endif
|
|
|
|
//
|
|
// Define global data for builtin device interrupt enables.
|
|
//
|
|
|
|
USHORT HalpBuiltinInterruptEnable;
|
|
|
|
//
|
|
// Define the IRQL mask and level mapping table.
|
|
//
|
|
// These tables are transfered to the PCR and determine the priority of
|
|
// interrupts.
|
|
//
|
|
// N.B. The two software interrupt levels MUST be the lowest levels.
|
|
//
|
|
|
|
UCHAR HalpIrqlMask[] = {4, 5, 6, 6, 7, 7, 7, 7, // 0000 - 0111 high 4-bits
|
|
8, 8, 8, 8, 8, 8, 8, 8, // 1000 - 1111 high 4-bits
|
|
0, 1, 2, 2, 3, 3, 3, 3, // 0000 - 0111 low 4-bits
|
|
4, 4, 4, 4, 4, 4, 4, 4}; // 1000 - 1111 low 4-bits
|
|
|
|
UCHAR HalpIrqlTable[] = {0xff, // IRQL 0
|
|
0xfe, // IRQL 1
|
|
0xfc, // IRQL 2
|
|
0xf8, // IRQL 3
|
|
0xf0, // IRQL 4
|
|
0xe0, // IRQL 5
|
|
0xc0, // IRQL 6
|
|
0x80, // IRQL 7
|
|
0x00}; // IRQL 8
|
|
|
|
VOID
|
|
HalpCountInterrupt (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function serves as the count/compare interrupt service routine
|
|
early in the system initialization. Its only function is to field
|
|
and acknowledge count/compare interrupts during the system boot process.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// Acknowledge the count/compare interrupt.
|
|
//
|
|
|
|
HalpWriteCompareRegisterAndClear(DEFAULT_PROFILE_COUNT);
|
|
return;
|
|
}
|
|
|
|
BOOLEAN
|
|
HalpInitializeInterrupts (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function initializes interrupts for a Jazz or Duo MIPS system.
|
|
|
|
N.B. This function is only called during phase 0 initialization.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
A value of TRUE is returned if the initialization is successfully
|
|
completed. Otherwise a value of FALSE is returned.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
USHORT DataShort;
|
|
ULONG DataLong;
|
|
ULONG Index;
|
|
PKPRCB Prcb;
|
|
|
|
//
|
|
// Get the address of the processor control block for the current
|
|
// processor.
|
|
//
|
|
|
|
Prcb = PCR->Prcb;
|
|
|
|
//
|
|
// Initialize the IRQL translation tables in the PCR. These tables are
|
|
// used by the interrupt dispatcher to determine the new IRQL and the
|
|
// mask value that is to be loaded into the PSR. They are also used by
|
|
// the routines that raise and lower IRQL to load a new mask value into
|
|
// the PSR.
|
|
//
|
|
|
|
for (Index = 0; Index < sizeof(HalpIrqlMask); Index += 1) {
|
|
PCR->IrqlMask[Index] = HalpIrqlMask[Index];
|
|
}
|
|
|
|
for (Index = 0; Index < sizeof(HalpIrqlTable); Index += 1) {
|
|
PCR->IrqlTable[Index] = HalpIrqlTable[Index];
|
|
}
|
|
|
|
//
|
|
// Clear interprocessor, timer, EISA, local device, and DMA interrupt
|
|
// enables.
|
|
//
|
|
|
|
#if defined(_DUO_)
|
|
|
|
WRITE_REGISTER_ULONG(&((PDMA_REGISTERS)DMA_VIRTUAL_BASE)->InterruptEnable.Long,
|
|
0);
|
|
|
|
#endif
|
|
|
|
//
|
|
// If processor 0 is being initialized, then clear all builtin device
|
|
// interrupt enables.
|
|
//
|
|
|
|
if (Prcb->Number == 0) {
|
|
HalpBuiltinInterruptEnable = 0;
|
|
}
|
|
|
|
//
|
|
// Disable individual device interrupts and make sure no device interrupts
|
|
// are pending.
|
|
//
|
|
|
|
WRITE_REGISTER_USHORT(&((PINTERRUPT_REGISTERS)INTERRUPT_VIRTUAL_BASE)->Enable,
|
|
0);
|
|
|
|
#if defined(_DUO_)
|
|
|
|
do {
|
|
DataLong = READ_REGISTER_ULONG(&((PDMA_REGISTERS)DMA_VIRTUAL_BASE)->LocalInterruptAcknowledge.Long) & 0x3ff;
|
|
} while (DataLong != 0);
|
|
|
|
//
|
|
// If processor 0 is being initialized, then enable device interrupts.
|
|
//
|
|
|
|
if (Prcb->Number == 0) {
|
|
DataLong = READ_REGISTER_ULONG(&((PDMA_REGISTERS)DMA_VIRTUAL_BASE)->InterruptEnable.Long);
|
|
DataLong |= ENABLE_DEVICE_INTERRUPTS;
|
|
WRITE_REGISTER_ULONG(&((PDMA_REGISTERS)DMA_VIRTUAL_BASE)->InterruptEnable.Long,
|
|
DataLong);
|
|
}
|
|
|
|
#endif
|
|
|
|
#if defined(_JAZZ_)
|
|
|
|
do {
|
|
DataShort = READ_REGISTER_USHORT(&((PINTERRUPT_REGISTERS)INTERRUPT_VIRTUAL_BASE)->Source) & 0x3ff;
|
|
} while (DataShort != 0);
|
|
|
|
#endif
|
|
|
|
//
|
|
// If processor 0 is being initialized, then connect the interval timer
|
|
// interrupt to the stall interrupt routine so the stall execution count
|
|
// can be computed during phase 1 initialization. Otherwise, connect the
|
|
// interval timer interrupt to the appropriate interrupt service routine
|
|
// and set stall execution count from the computation made on processor
|
|
// 0.
|
|
//
|
|
|
|
if (Prcb->Number == 0) {
|
|
PCR->InterruptRoutine[CLOCK2_LEVEL] = HalpStallInterrupt;
|
|
|
|
} else {
|
|
PCR->InterruptRoutine[CLOCK2_LEVEL] = HalpClockInterrupt1;
|
|
PCR->StallScaleFactor = HalpStallScaleFactor;
|
|
}
|
|
|
|
//
|
|
// Initialize the interval timer to interrupt at the specified interval.
|
|
//
|
|
|
|
WRITE_REGISTER_ULONG(&DMA_CONTROL->InterruptInterval.Long, CLOCK_INTERVAL);
|
|
|
|
//
|
|
// Enable the interval timer interrupt on the current processor.
|
|
//
|
|
|
|
#if defined(_DUO_)
|
|
|
|
DataLong = READ_REGISTER_ULONG(&((PDMA_REGISTERS)DMA_VIRTUAL_BASE)->InterruptEnable.Long);
|
|
DataLong |= ENABLE_TIMER_INTERRUPTS;
|
|
WRITE_REGISTER_ULONG(&((PDMA_REGISTERS)DMA_VIRTUAL_BASE)->InterruptEnable.Long,
|
|
DataLong);
|
|
|
|
#endif
|
|
|
|
//
|
|
// If processor 0 is being initialized, then connect the count/compare
|
|
// interrupt to the count interrupt routine to handle early count/compare
|
|
// interrupts during phase 1 initialization. Otherwise, connect the
|
|
// count\comapre interrupt to the appropriate interrupt service routine.
|
|
//
|
|
|
|
if (Prcb->Number == 0) {
|
|
PCR->InterruptRoutine[PROFILE_LEVEL] = HalpCountInterrupt;
|
|
|
|
} else {
|
|
PCR->InterruptRoutine[PROFILE_LEVEL] = HalpProfileInterrupt;
|
|
}
|
|
|
|
//
|
|
// Connect the interprocessor interrupt service routine and enable
|
|
// interprocessor interrupts.
|
|
//
|
|
|
|
#if defined(_DUO_)
|
|
|
|
PCR->InterruptRoutine[IPI_LEVEL] = HalpIpiInterrupt;
|
|
DataLong = READ_REGISTER_ULONG(&((PDMA_REGISTERS)DMA_VIRTUAL_BASE)->InterruptEnable.Long);
|
|
DataLong |= ENABLE_IP_INTERRUPTS;
|
|
WRITE_REGISTER_ULONG(&((PDMA_REGISTERS)DMA_VIRTUAL_BASE)->InterruptEnable.Long,
|
|
DataLong);
|
|
|
|
#endif
|
|
|
|
//
|
|
// Reserve the local device interrupt vector for exclusive use by the HAL.
|
|
//
|
|
|
|
PCR->ReservedVectors |= ((1 << DEVICE_LEVEL) | (1 << EISA_DEVICE_LEVEL));
|
|
return TRUE;
|
|
}
|