445 lines
9.4 KiB
C
445 lines
9.4 KiB
C
//
|
||
// No Check-in Source Code.
|
||
//
|
||
// Do not make this code available to non-Microsoft personnel
|
||
// without Intel's express permission
|
||
//
|
||
/**
|
||
*** Copyright (C) 1996-97 Intel Corporation. All rights reserved.
|
||
***
|
||
*** The information and source code contained herein is the exclusive
|
||
*** property of Intel Corporation and may not be disclosed, examined
|
||
*** or reproduced in whole or in part without explicit written authorization
|
||
*** from the company.
|
||
**/
|
||
|
||
/*++
|
||
|
||
Copyright (c) 1995 Intel Corporation
|
||
|
||
Module Name:
|
||
|
||
simsxint.c
|
||
|
||
Abstract:
|
||
|
||
This module implements the routines to manage the
|
||
system interrupt and IRQL.
|
||
|
||
Author:
|
||
|
||
William K. Cheung (wcheung) 14-Apr-1995
|
||
|
||
Environment:
|
||
|
||
Kernel mode
|
||
|
||
Revision History:
|
||
|
||
|
||
--*/
|
||
|
||
#include "halp.h"
|
||
|
||
|
||
PULONGLONG HalEOITable[256];
|
||
|
||
|
||
VOID
|
||
HalpInitEOITable(
|
||
VOID
|
||
)
|
||
{
|
||
USHORT Index;
|
||
|
||
for (Index=0; Index < 256; Index++) {
|
||
HalEOITable[Index] = 0;
|
||
}
|
||
}
|
||
|
||
VOID
|
||
HalpInitializeInterrupts (
|
||
VOID
|
||
)
|
||
{
|
||
ULONG Index;
|
||
ULONG InterruptVector;
|
||
|
||
//
|
||
// Interrupt routine table initialization in KiInitializeKernel.
|
||
//
|
||
|
||
//
|
||
// interval timer interrupt; 10ms by default
|
||
//
|
||
|
||
InterruptVector = CLOCK_LEVEL << VECTOR_IRQL_SHIFT;
|
||
PCR->InterruptRoutine[InterruptVector] = (PKINTERRUPT_ROUTINE)HalpClockInterrupt;
|
||
|
||
SscConnectInterrupt(SSC_CLOCK_TIMER_INTERRUPT, InterruptVector);
|
||
SscSetPeriodicInterruptInterval(
|
||
SSC_CLOCK_TIMER_INTERRUPT,
|
||
DEFAULT_CLOCK_INTERVAL * 100
|
||
);
|
||
|
||
//
|
||
// profile timer interrupt; turned off initially
|
||
//
|
||
|
||
InterruptVector = PROFILE_LEVEL << VECTOR_IRQL_SHIFT;
|
||
PCR->InterruptRoutine[InterruptVector] = (PKINTERRUPT_ROUTINE)HalpProfileInterrupt;
|
||
|
||
SscConnectInterrupt(SSC_PROFILE_TIMER_INTERRUPT, InterruptVector);
|
||
SscSetPeriodicInterruptInterval (SSC_PROFILE_TIMER_INTERRUPT, 0);
|
||
|
||
//
|
||
// s/w interrupts; corresponding ISRs provided by kernel.
|
||
//
|
||
|
||
SscConnectInterrupt (SSC_APC_INTERRUPT, APC_VECTOR);
|
||
SscConnectInterrupt (SSC_DPC_INTERRUPT, DISPATCH_VECTOR);
|
||
}
|
||
|
||
BOOLEAN
|
||
HalEnableSystemInterrupt (
|
||
IN ULONG Vector,
|
||
IN KIRQL Irql,
|
||
IN KINTERRUPT_MODE InterruptMode
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine enables the specified system interrupt.
|
||
|
||
N.B. This routine assumes that the caller has provided any required
|
||
synchronization to enable a system interrupt.
|
||
|
||
Arguments:
|
||
|
||
Vector - Supplies the vector of the system interrupt that is enabled.
|
||
|
||
Irql - Supplies the IRQL of the interrupting source.
|
||
|
||
InterruptMode - Supplies the mode of the interrupt; LevelSensitive or
|
||
Latched.
|
||
|
||
Return Value:
|
||
|
||
TRUE if the system interrupt was enabled
|
||
|
||
--*/
|
||
|
||
{
|
||
KIRQL OldIrql;
|
||
BOOLEAN Result = TRUE;
|
||
|
||
//
|
||
// Raise IRQL to the highest level.
|
||
//
|
||
|
||
KeRaiseIrql (HIGH_LEVEL, &OldIrql);
|
||
|
||
switch (Irql) {
|
||
|
||
case DISK_IRQL:
|
||
SscConnectInterrupt (SSC_DISK_INTERRUPT, Vector);
|
||
break;
|
||
|
||
case MOUSE_IRQL:
|
||
SscConnectInterrupt (SSC_MOUSE_INTERRUPT, Vector);
|
||
break;
|
||
|
||
case KEYBOARD_IRQL:
|
||
SscConnectInterrupt (SSC_KEYBOARD_INTERRUPT, Vector);
|
||
break;
|
||
|
||
case SERIAL_IRQL:
|
||
SscConnectInterrupt (SSC_SERIAL_INTERRUPT, Vector);
|
||
break;
|
||
|
||
default:
|
||
//
|
||
// Invalid Device Interrupt Source; only three devices
|
||
// defined in the Gambit platform.
|
||
//
|
||
Result = FALSE;
|
||
DbgPrint("HalEnableSystemInterrupt: Invalid Device Interrupt Source");
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Restore the original IRQL
|
||
//
|
||
|
||
KeLowerIrql (OldIrql);
|
||
|
||
return (Result);
|
||
}
|
||
|
||
VOID
|
||
HalDisableSystemInterrupt (
|
||
IN ULONG Vector,
|
||
IN KIRQL Irql
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine disables the specified system interrupt.
|
||
|
||
In the simulation environment, this function does nothing and returns.
|
||
|
||
N.B. This routine assumes that the caller has provided any required
|
||
synchronization to disable a system interrupt.
|
||
|
||
Arguments:
|
||
|
||
Vector - Supplies the vector of the system interrupt that is disabled.
|
||
|
||
Irql - Supplies the IRQL of the interrupting source.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
return;
|
||
}
|
||
|
||
ULONG
|
||
HalGetInterruptVector(
|
||
IN INTERFACE_TYPE InterfaceType,
|
||
IN ULONG BusNumber,
|
||
IN ULONG BusInterruptLevel,
|
||
IN ULONG BusInterruptVector,
|
||
OUT PKIRQL Irql,
|
||
OUT PKAFFINITY Affinity
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function returns the system interrupt vector and IRQL level
|
||
corresponding to the specified bus interrupt level and/or vector. The
|
||
system interrupt vector and IRQL are suitable for use in a subsequent call
|
||
to KeInitializeInterrupt.
|
||
|
||
In the simulation environment, just return the parameters passed in
|
||
from the caller - the device driver.
|
||
|
||
Arguments:
|
||
|
||
InterfaceType - Supplies the type of bus which the vector is for.
|
||
|
||
BusNumber - Supplies the bus number for the device.
|
||
|
||
BusInterruptLevel - Supplies the bus specific interrupt level.
|
||
|
||
BusInterruptVector - Supplies the bus specific interrupt vector.
|
||
|
||
Irql - Returns the system request priority.
|
||
|
||
Affinity - Returns the affinity for the requested vector
|
||
|
||
Return Value:
|
||
|
||
Returns the system interrupt vector corresponding to the specified device.
|
||
|
||
--*/
|
||
|
||
{
|
||
//
|
||
// Just return the passed parameters.
|
||
//
|
||
|
||
*Irql = (KIRQL) BusInterruptLevel;
|
||
*Affinity = 1;
|
||
return( BusInterruptLevel << VECTOR_IRQL_SHIFT );
|
||
|
||
}
|
||
|
||
BOOLEAN
|
||
HalBeginSystemInterrupt(
|
||
IN KIRQL Irql,
|
||
IN CCHAR Vector,
|
||
OUT PKIRQL OldIrql
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine raises the IRQL to the level of the specified
|
||
interrupt vector. It is called by the hardware interrupt
|
||
handler before any other interrupt service routine code is
|
||
executed. The CPU interrupt flag is set on exit.
|
||
|
||
Arguments:
|
||
|
||
Irql - Supplies the IRQL to raise to
|
||
|
||
Vector - Supplies the vector of the interrupt to be
|
||
dismissed
|
||
|
||
OldIrql- Location to return OldIrql
|
||
|
||
Return Value:
|
||
|
||
TRUE - Interrupt successfully dismissed and Irql raised.
|
||
This routine cannot fail.
|
||
|
||
--*/
|
||
|
||
{
|
||
return (TRUE);
|
||
}
|
||
|
||
VOID
|
||
HalEndSystemInterrupt (
|
||
IN KIRQL NewIrql,
|
||
IN ULONG Vector
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is used to lower IRQL to the specified value.
|
||
The IRQL and PIRQL will be updated accordingly.
|
||
|
||
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.
|
||
|
||
Arguments:
|
||
|
||
NewIrql - the new irql to be set.
|
||
|
||
Vector - Vector number of the interrupt
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
return;
|
||
}
|
||
|
||
|
||
//
|
||
// Almost all of the last 4MB of virtual memory address range are available
|
||
// to the HAL to map physical memory. The kernel may use some of these
|
||
// PTEs for special purposes.
|
||
//
|
||
//
|
||
// The kernel now uses one PTE in this
|
||
// area to map the area from which interrupt messages are to be retrieved.
|
||
//
|
||
|
||
|
||
#define HAL_VA_START 0xffd00000
|
||
|
||
PVOID HalpHeapStart=(PVOID)(KADDRESS_BASE+HAL_VA_START);
|
||
|
||
|
||
PVOID
|
||
HalMapPhysicalMemory(
|
||
IN PHYSICAL_ADDRESS PhysicalAddress,
|
||
IN ULONG NumberPages
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine maps physical memory into the area of virtual memory
|
||
reserved for the HAL. It does this by directly inserting the PTE
|
||
into the Page Table which the OS Loader has provided.
|
||
|
||
N.B. This routine does *NOT* update the MemoryDescriptorList. The
|
||
caller is responsible for either removing the appropriate
|
||
physical memory from the list, or creating a new descriptor to
|
||
describe it.
|
||
|
||
Arguments:
|
||
|
||
PhysicalAddress - Supplies the physical address of the start of the
|
||
area of physical memory to be mapped.
|
||
|
||
NumberPages - Supplies the number of pages contained in the area of
|
||
physical memory to be mapped.
|
||
|
||
Return Value:
|
||
|
||
PVOID - Virtual address at which the requested block of physical memory
|
||
was mapped
|
||
|
||
NULL - The requested block of physical memory could not be mapped.
|
||
|
||
--*/
|
||
|
||
{
|
||
PHARDWARE_PTE PTE;
|
||
ULONG PagesMapped;
|
||
PVOID VirtualAddress;
|
||
|
||
//
|
||
// The OS Loader sets up hyperspace for us, so we know that the Page
|
||
// Tables are magically mapped starting at V.A. 0xC0000000.
|
||
//
|
||
|
||
PagesMapped = 0;
|
||
while (PagesMapped < NumberPages) {
|
||
//
|
||
// Look for enough consecutive free ptes to honor mapping
|
||
//
|
||
|
||
PagesMapped = 0;
|
||
VirtualAddress = HalpHeapStart;
|
||
|
||
while (PagesMapped < NumberPages) {
|
||
PTE=MiGetPteAddress(VirtualAddress);
|
||
if (*(PULONGLONG)PTE != 0) {
|
||
|
||
//
|
||
// Pte is not free, skip up to the next pte and start over
|
||
//
|
||
|
||
HalpHeapStart = (PVOID) ((ULONG_PTR)VirtualAddress + PAGE_SIZE);
|
||
break;
|
||
}
|
||
VirtualAddress = (PVOID) ((ULONG_PTR)VirtualAddress + PAGE_SIZE);
|
||
PagesMapped++;
|
||
}
|
||
|
||
}
|
||
|
||
PagesMapped = 0;
|
||
VirtualAddress = (PVOID) ((ULONG_PTR) HalpHeapStart | BYTE_OFFSET (PhysicalAddress.QuadPart));
|
||
while (PagesMapped < NumberPages) {
|
||
PTE=MiGetPteAddress(HalpHeapStart);
|
||
|
||
PTE->PageFrameNumber = (PhysicalAddress.QuadPart >> PAGE_SHIFT);
|
||
PTE->Valid = 1;
|
||
PTE->Write = 1;
|
||
|
||
// TBD PTE->MemAttribute = 0;
|
||
|
||
PhysicalAddress.QuadPart = PhysicalAddress.QuadPart + PAGE_SIZE;
|
||
HalpHeapStart = (PVOID)((ULONG_PTR)HalpHeapStart + PAGE_SIZE);
|
||
|
||
++PagesMapped;
|
||
}
|
||
|
||
return(VirtualAddress);
|
||
}
|
||
|