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.
606 lines
14 KiB
606 lines
14 KiB
/*++
|
|
|
|
Copyright (c) 1991 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
xxinithl.c
|
|
|
|
Abstract:
|
|
|
|
|
|
This module implements the initialization of the system dependent
|
|
functions that define the Hardware Architecture Layer (HAL) for an
|
|
Alpha machine
|
|
|
|
Author:
|
|
|
|
David N. Cutler (davec) 25-Apr-1991
|
|
Miche Baker-Harvey (miche) 18-May-1992
|
|
|
|
Environment:
|
|
|
|
Kernel mode only.
|
|
|
|
Revision History:
|
|
|
|
28-Jul-1992 Jeff McLeman (mcleman)
|
|
Add code to allocate a mapping buffer for buffered DMA
|
|
|
|
14-Jul-1992 Jeff McLeman (mcleman)
|
|
Add call to HalpCachePcrValues, which will call the PALcode to
|
|
cache values of the PCR that need fast access.
|
|
|
|
10-Jul-1992 Jeff McLeman (mcleman)
|
|
Remove reference to initializing the fixed TB entries, since Alpha
|
|
does not have fixed TB entries.
|
|
|
|
--*/
|
|
|
|
#include "halp.h"
|
|
#include "eisa.h"
|
|
#include "jxisa.h"
|
|
#include "jnsnrtc.h"
|
|
|
|
ULONG HalpBusType = MACHINE_TYPE_EISA;
|
|
ULONG HalpMapBufferSize;
|
|
PHYSICAL_ADDRESS HalpMapBufferPhysicalAddress;
|
|
|
|
typedef
|
|
BOOLEAN
|
|
KBUS_ERROR_ROUTINE (
|
|
IN struct _EXCEPTION_RECORD *ExceptionRecord,
|
|
IN struct _KEXCEPTION_FRAME *ExceptionFrame,
|
|
IN struct _KTRAP_FRAME *TrapFrame
|
|
);
|
|
|
|
KBUS_ERROR_ROUTINE HalMachineCheck;
|
|
|
|
//
|
|
// HalpClockFrequency is the processor cycle counter frequency in units
|
|
// of cycles per second (Hertz). It is a large number (e.g., 125,000,000)
|
|
// but will still fit in a ULONG.
|
|
//
|
|
// HalpClockMegaHertz is the processor cycle counter frequency in units
|
|
// of megahertz. It is a small number (e.g., 125) and is also the number
|
|
// of cycles per microsecond. The assumption here is that clock rates will
|
|
// always be an integral number of megahertz.
|
|
//
|
|
// Having the frequency available in both units avoids multiplications, or
|
|
// especially divisions in time critical code.
|
|
//
|
|
|
|
ULONG HalpClockFrequency;
|
|
ULONG HalpClockMegaHertz;
|
|
|
|
//
|
|
// Use the square wave mode of the PIT to measure the processor
|
|
// speed. The timer has a frequency of 1.193MHz. We want a
|
|
// square wave with a period of 50ms so we must initialize the
|
|
// pit with a count of:
|
|
// 50ms*1.193MHz = 59650 cycles
|
|
//
|
|
|
|
#define TIMER_REF_VALUE 59650
|
|
|
|
ULONG
|
|
HalpQuerySystemFrequency(
|
|
ULONG SampleTime
|
|
);
|
|
|
|
BOOLEAN
|
|
HalInitSystem (
|
|
IN ULONG Phase,
|
|
IN PLOADER_PARAMETER_BLOCK LoaderBlock
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function initializes the Hardware Architecture Layer (HAL) for an
|
|
Alpha system.
|
|
|
|
Arguments:
|
|
|
|
Phase - Supplies the initialization phase (zero or one).
|
|
|
|
LoaderBlock - Supplies a pointer to a loader parameter block.
|
|
|
|
Return Value:
|
|
|
|
A value of TRUE is returned is the initialization was successfully
|
|
complete. Otherwise a value of FALSE is returend.
|
|
|
|
--*/
|
|
|
|
{
|
|
PKPRCB Prcb;
|
|
|
|
if (Phase == 0) {
|
|
|
|
//
|
|
// Phase 0 initialization.
|
|
//
|
|
|
|
//
|
|
// Set the time increment value.
|
|
//
|
|
|
|
HalpCurrentTimeIncrement = MAXIMUM_INCREMENT;
|
|
HalpNextTimeIncrement = MAXIMUM_INCREMENT;
|
|
HalpNextRateSelect = 0;
|
|
KeSetTimeIncrement( MAXIMUM_INCREMENT, MINIMUM_INCREMENT );
|
|
|
|
HalpMapIoSpace();
|
|
HalpInitializeInterrupts();
|
|
HalpCreateDmaStructures();
|
|
HalpInitializeDisplay(LoaderBlock);
|
|
HalpCachePcrValues();
|
|
|
|
//
|
|
// Fill in handlers for APIs which this HAL supports
|
|
//
|
|
|
|
HalQuerySystemInformation = HaliQuerySystemInformation;
|
|
HalSetSystemInformation = HaliSetSystemInformation;
|
|
|
|
//
|
|
// Establish the machine check handler for in the PCR.
|
|
//
|
|
|
|
PCR->MachineCheckError = HalMachineCheck;
|
|
|
|
//
|
|
// Verify Prcb major version number, and build options are
|
|
// all conforming to this binary image
|
|
//
|
|
|
|
Prcb = KeGetCurrentPrcb();
|
|
#if DBG
|
|
if (!(Prcb->BuildType & PRCB_BUILD_DEBUG)) {
|
|
// This checked hal requires a checked kernel
|
|
KeBugCheckEx (MISMATCHED_HAL, 2, Prcb->BuildType, PRCB_BUILD_DEBUG, 0);
|
|
}
|
|
#else
|
|
if (Prcb->BuildType & PRCB_BUILD_DEBUG) {
|
|
// This free hal requires a free kernel
|
|
KeBugCheckEx (MISMATCHED_HAL, 2, Prcb->BuildType, 0, 0);
|
|
}
|
|
#endif
|
|
#ifndef NT_UP
|
|
if (Prcb->BuildType & PRCB_BUILD_UNIPROCESSOR) {
|
|
// This MP hal requires an MP kernel
|
|
KeBugCheckEx (MISMATCHED_HAL, 2, Prcb->BuildType, 0, 0);
|
|
}
|
|
#endif
|
|
if (Prcb->MajorVersion != PRCB_MAJOR_VERSION) {
|
|
KeBugCheckEx (MISMATCHED_HAL,
|
|
1, Prcb->MajorVersion, PRCB_MAJOR_VERSION, 0);
|
|
}
|
|
|
|
//
|
|
// Now alocate a mapping buffer for buffered DMA.
|
|
//
|
|
|
|
LessThan16Mb = FALSE;
|
|
|
|
HalpMapBufferSize = INITIAL_MAP_BUFFER_LARGE_SIZE;
|
|
HalpMapBufferPhysicalAddress.LowPart =
|
|
HalpAllocPhysicalMemory (LoaderBlock, MAXIMUM_ISA_PHYSICAL_ADDRESS,
|
|
HalpMapBufferSize >> PAGE_SHIFT, TRUE);
|
|
HalpMapBufferPhysicalAddress.HighPart = 0;
|
|
|
|
if (!HalpMapBufferPhysicalAddress.LowPart) {
|
|
HalpMapBufferSize = 0;
|
|
}
|
|
|
|
//
|
|
// Setup special memory AFTER we've allocated our COMMON BUFFER!
|
|
//
|
|
|
|
HalpInitializeSpecialMemory( LoaderBlock );
|
|
|
|
return TRUE;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Phase 1 initialization.
|
|
//
|
|
|
|
HalpCalibrateStall();
|
|
|
|
//
|
|
// Initialize the existing bus handlers.
|
|
//
|
|
|
|
HalpRegisterInternalBusHandlers();
|
|
|
|
//
|
|
// Allocate pool for evnironment variable support
|
|
//
|
|
|
|
if (HalpEnvironmentInitialize() != 0) {
|
|
HalDisplayString(" No pool available for Environment Variables\n");
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
HalInitializeProcessor (
|
|
IN ULONG Number
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called early in the initialization of the kernel
|
|
to perform platform dependent initialization for each processor
|
|
before the HAL Is fully functional.
|
|
|
|
N.B. When this routine is called, the PCR is present but is not
|
|
fully initialized.
|
|
|
|
Arguments:
|
|
|
|
Number - Supplies the number of the processor to initialize.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
return;
|
|
}
|
|
|
|
BOOLEAN
|
|
HalStartNextProcessor (
|
|
IN PLOADER_PARAMETER_BLOCK LoaderBlock,
|
|
IN PKPROCESSOR_STATE ProcessorState
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called to start the next processor.
|
|
|
|
Arguments:
|
|
|
|
LoaderBlock - Supplies a pointer to the loader parameter block.
|
|
|
|
ProcessorState - Supplies a pointer to the processor state to be
|
|
used to start the processor.
|
|
|
|
Return Value:
|
|
|
|
If a processor is successfully started, then a value of TRUE is
|
|
returned. Otherwise a value of FALSE is returned.
|
|
|
|
--*/
|
|
|
|
{
|
|
return FALSE;
|
|
}
|
|
VOID
|
|
HalpVerifyPrcbVersion ()
|
|
{
|
|
|
|
}
|
|
|
|
|
|
ULONG
|
|
HalpQuerySystemFrequency(
|
|
ULONG SampleTime
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns the speed at which the system is running in hertz.
|
|
The system frequency is calculated by counting the number of processor
|
|
cycles that occur during 500ms, using the Programmable Interval Timer
|
|
(PIT) as the reference time. The PIT is used to generate a square
|
|
wave with a 50ms Period. We use the Speaker counter since we can
|
|
enable and disable the count from software. The output of the
|
|
speaker is obtained from the SIO NmiStatus register.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
The system frequency in Hertz.
|
|
|
|
--*/
|
|
{
|
|
TIMER_CONTROL TimerControlSetup;
|
|
TIMER_CONTROL TimerControlReadStatus;
|
|
TIMER_STATUS TimerStatus;
|
|
NMI_STATUS NmiStatus;
|
|
PEISA_CONTROL controlBase;
|
|
ULONGLONG Count1;
|
|
ULONGLONG Count2;
|
|
ULONG NumberOfIntervals;
|
|
ULONG SquareWaveState = 0;
|
|
|
|
// mdbfix - move this into eisa.h one day
|
|
#define SB_READ_STATUS_ONLY 2
|
|
|
|
controlBase = HalpEisaControlBase;
|
|
|
|
//
|
|
// Disable the speaker counter.
|
|
//
|
|
|
|
*((PUCHAR) &NmiStatus) = READ_PORT_UCHAR(&controlBase->NmiStatus);
|
|
|
|
NmiStatus.SpeakerGate = 0;
|
|
NmiStatus.SpeakerData = 0;
|
|
|
|
// these are MBZ when writing to NMIMISC
|
|
NmiStatus.RefreshToggle = 0;
|
|
NmiStatus.SpeakerTimer = 0;
|
|
NmiStatus.IochkNmi = 0;
|
|
|
|
WRITE_PORT_UCHAR(&controlBase->NmiStatus, *((PUCHAR) &NmiStatus));
|
|
|
|
//
|
|
// Number of Square Wave transitions to count.
|
|
// at 50ms period, count the number of 25ms
|
|
// square wave transitions for a sample reference
|
|
// time to against which we measure processor cycle count.
|
|
//
|
|
|
|
NumberOfIntervals = (SampleTime/50) * 2;
|
|
|
|
//
|
|
// Set the timer for counter 0 in binary mode, square wave output
|
|
//
|
|
|
|
TimerControlSetup.BcdMode = 0;
|
|
TimerControlSetup.Mode = TM_SQUARE_WAVE;
|
|
TimerControlSetup.SelectByte = SB_LSB_THEN_MSB;
|
|
TimerControlSetup.SelectCounter = SELECT_COUNTER_2;
|
|
|
|
//
|
|
// Set the counter for a latched read of the status.
|
|
// We will poll the PIT for the state of the square
|
|
// wave output.
|
|
//
|
|
|
|
TimerControlReadStatus.BcdMode = 0;
|
|
TimerControlReadStatus.Mode = (1 << SELECT_COUNTER_2);
|
|
TimerControlReadStatus.SelectByte = SB_READ_STATUS_ONLY;
|
|
TimerControlReadStatus.SelectCounter = SELECT_READ_BACK;
|
|
|
|
|
|
//
|
|
// Write the count value LSB and MSB for a 50ms clock period
|
|
//
|
|
|
|
WRITE_PORT_UCHAR( &controlBase->CommandMode1,
|
|
*(PUCHAR)&TimerControlSetup );
|
|
|
|
WRITE_PORT_UCHAR( &controlBase->SpeakerTone,
|
|
TIMER_REF_VALUE & 0xff );
|
|
|
|
WRITE_PORT_UCHAR( &controlBase->SpeakerTone,
|
|
(TIMER_REF_VALUE >> 8) & 0xff );
|
|
|
|
//
|
|
// Enable the speaker counter but disable the SPKR output signal.
|
|
//
|
|
|
|
*((PUCHAR) &NmiStatus) = READ_PORT_UCHAR(&controlBase->NmiStatus);
|
|
|
|
NmiStatus.SpeakerGate = 1;
|
|
NmiStatus.SpeakerData = 0;
|
|
|
|
// these are MBZ when writing to NMIMISC
|
|
NmiStatus.RefreshToggle = 0;
|
|
NmiStatus.SpeakerTimer = 0;
|
|
NmiStatus.IochkNmi = 0;
|
|
|
|
WRITE_PORT_UCHAR(&controlBase->NmiStatus, *((PUCHAR) &NmiStatus));
|
|
|
|
//
|
|
// Synchronize with the counter before taking the first
|
|
// sample of the Processor Cycle Count (PCC). Since we
|
|
// are using the Square Wave Mode, wait until the next
|
|
// state change and then observe half a cycle before
|
|
// sampling.
|
|
//
|
|
|
|
//
|
|
// observe the low transition of the square wave output.
|
|
//
|
|
do {
|
|
|
|
*((PUCHAR) &NmiStatus) = READ_PORT_UCHAR(&controlBase->NmiStatus);
|
|
|
|
} while (NmiStatus.SpeakerTimer != SquareWaveState);
|
|
|
|
SquareWaveState ^= 1;
|
|
|
|
//
|
|
// observe the next transition of the square wave output and then
|
|
// take the first cycle counter sample.
|
|
//
|
|
do {
|
|
|
|
*((PUCHAR) &NmiStatus) = READ_PORT_UCHAR(&controlBase->NmiStatus);
|
|
|
|
} while (NmiStatus.SpeakerTimer != SquareWaveState);
|
|
|
|
Count1 = __RCC();
|
|
|
|
//
|
|
// Wait for the 500ms time period to pass and then take the
|
|
// second sample of the PCC. For a 50ms period, we have to
|
|
// observe eight wave transitions (25ms each).
|
|
//
|
|
|
|
do {
|
|
|
|
SquareWaveState ^= 1;
|
|
|
|
//
|
|
// wait for wave transition
|
|
//
|
|
do {
|
|
|
|
*((PUCHAR) &NmiStatus) = READ_PORT_UCHAR(&controlBase->NmiStatus);
|
|
|
|
} while (NmiStatus.SpeakerTimer != SquareWaveState);
|
|
|
|
} while (--NumberOfIntervals);
|
|
|
|
Count2 = __RCC();
|
|
|
|
//
|
|
// Disable the speaker counter.
|
|
//
|
|
|
|
*((PUCHAR) &NmiStatus) = READ_PORT_UCHAR(&controlBase->NmiStatus);
|
|
|
|
NmiStatus.SpeakerGate = 0;
|
|
NmiStatus.SpeakerData = 0;
|
|
|
|
WRITE_PORT_UCHAR(&controlBase->NmiStatus, *((PUCHAR) &NmiStatus));
|
|
|
|
//
|
|
// Calculate the Hz by the number of processor cycles
|
|
// elapsed during 1s.
|
|
//
|
|
// Hz = PCC/SampleTime * 1000ms/s
|
|
// = PCC * (1000/SampleTime)
|
|
//
|
|
|
|
// did the counter wrap? if so add 2^32
|
|
if (Count1 > Count2) {
|
|
|
|
Count2 += (ULONGLONG)(1 << 32);
|
|
|
|
}
|
|
|
|
return ((Count2 - Count1)*(((ULONG)1000)/SampleTime));
|
|
}
|
|
|
|
|
|
VOID
|
|
HalpInitializeProcessorParameters(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine initalize the performance counter parameters
|
|
HalpClockFrequency and HalpClockMegaHertz based on the
|
|
estimated CPU speed. A 1s reference time is used for
|
|
the estimation.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
|
|
HalpClockFrequency = HalpQuerySystemFrequency(1000);
|
|
HalpClockMegaHertz = (HalpClockFrequency + 500000)/ 1000000;
|
|
|
|
}
|
|
|
|
#if 0
|
|
VOID
|
|
HalpGatherProcessorParameterStats(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine gathers statistics on the method for
|
|
estimating the system frequency.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG Index;
|
|
ULONG Hertz[32];
|
|
ULONGLONG Mean = 0;
|
|
ULONGLONG Variance = 0;
|
|
ULONGLONG TempHertz;
|
|
|
|
//
|
|
// take 32 samples of estimated CPU speed,
|
|
// calculating the mean in the process.
|
|
//
|
|
DbgPrint("Sample\tFrequency\tMegaHertz\n\n");
|
|
|
|
for (Index = 0; Index < 32; Index++) {
|
|
Hertz[Index] = HalpQuerySystemFrequency(500);
|
|
Mean += Hertz[Index];
|
|
|
|
DbgPrint(
|
|
"%d\t%d\t%d\n",
|
|
Index,
|
|
Hertz[Index],
|
|
(ULONG)((Hertz[Index] + 500000)/1000000)
|
|
);
|
|
|
|
}
|
|
|
|
//
|
|
// calculate the mean
|
|
//
|
|
|
|
Mean /= 32;
|
|
|
|
//
|
|
// calculate the variance
|
|
//
|
|
for (Index = 0; Index < 32; Index++) {
|
|
TempHertz = (Mean > Hertz[Index])?
|
|
(Mean - Hertz[Index]) : (Hertz[Index] - Mean);
|
|
TempHertz = TempHertz*TempHertz;
|
|
Variance += TempHertz;
|
|
}
|
|
|
|
Variance /= 32;
|
|
|
|
DbgPrint("\nResults\n\n");
|
|
DbgPrint(
|
|
"Mean = %d\nVariance = %d\nMegaHertz (derived) = %d\n",
|
|
Mean,
|
|
Variance,
|
|
(Mean + 500000)/ 1000000
|
|
);
|
|
|
|
}
|
|
#endif
|
|
|