1485 lines
29 KiB
C
1485 lines
29 KiB
C
|
||
/*++
|
||
|
||
Copyright (c) 1995 Intel Corporation
|
||
|
||
Module Name:
|
||
|
||
i64krnl.c
|
||
|
||
Abstract:
|
||
|
||
This module implements the kernel support routines for the HAL DLL.
|
||
|
||
Author:
|
||
|
||
Bernard Lint
|
||
M. Jayakumar (Muthurajan.Jayakumar@intel.com)
|
||
14-Apr-1995
|
||
|
||
Environment:
|
||
|
||
Kernel mode
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "halp.h"
|
||
#include "i64fw.h"
|
||
#include "check.h"
|
||
#include "osmca.h"
|
||
#include "iosapic.h"
|
||
#include "string.h"
|
||
#include "stdlib.h"
|
||
#include "stdio.h"
|
||
|
||
#define GreaterThan4GB 0x100000000
|
||
|
||
VOID
|
||
HalpInitReservedPages(
|
||
VOID
|
||
);
|
||
|
||
VOID
|
||
HalpRegisterKdSupportFunctions(
|
||
IN PLOADER_PARAMETER_BLOCK LoaderBlock
|
||
);
|
||
|
||
extern ADDRESS_USAGE HalpDefaultPcIoSpace;
|
||
extern ULONGLONG HalpITCFrequency;
|
||
extern ULONGLONG HalpProcessorFrequency;
|
||
extern ULONG HalpOsBootRendezVector;
|
||
|
||
WCHAR HalHardwareIdString[] = L"acpi";
|
||
ULONG HalpBusType;
|
||
|
||
ULONGLONG PhysicalIOBase;
|
||
|
||
static short HalpOwnDisplay = TRUE;
|
||
|
||
PKPROCESSOR_STATE HalpProcessorState;
|
||
|
||
PULONGLONG InterruptBlock;
|
||
|
||
extern KEVENT HalpNewAdapter;
|
||
|
||
ULONG HalPxbTcap;
|
||
|
||
//
|
||
// When Accessing IO SAPIC, HalpIoSapicLock is acquired and released
|
||
//
|
||
|
||
KSPIN_LOCK HalpIoSapicLock;
|
||
|
||
PHYSICAL_ADDRESS INTERRUPT_BLOCK_ADDRESS = { 0x0FEE00000 };
|
||
|
||
//
|
||
// Thierry - 10/01/2000 - Do NOT check the HALP_FIX_KD_HALIA64_MASK related
|
||
// code and data in the tree.
|
||
//
|
||
// This is to allow us to enable HAL_INFO level or other desired mask.
|
||
// The current debugger does not allow this and it should.
|
||
//
|
||
|
||
// #define HALP_FIX_KD_HALIA64_MASK 1
|
||
|
||
ULONG HalpFixKdHalia64Mask = 0;
|
||
|
||
|
||
VOID
|
||
HalpInitializeInterruptBlock (
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Map Interrupt Block used for IPI. The size of the IPI area is 1MB.
|
||
|
||
Arguements:
|
||
|
||
None
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
|
||
{
|
||
InterruptBlock = (PULONGLONG) HalpMapPhysicalMemory (
|
||
INTERRUPT_BLOCK_ADDRESS,
|
||
256,
|
||
MmNonCached);
|
||
return;
|
||
}
|
||
|
||
VOID
|
||
HalpCalibrateTB (
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function calibrates the time base by determining the frequency
|
||
that the ITC is running at to determine the interval value for a
|
||
100 ns time increment (used by clock and profile).
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
*/
|
||
|
||
{
|
||
return;
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
HalpFlushTLB (
|
||
VOID
|
||
)
|
||
{
|
||
return;
|
||
}
|
||
|
||
|
||
|
||
BOOLEAN
|
||
HalAllProcessorsStarted (
|
||
VOID
|
||
)
|
||
|
||
/**++
|
||
|
||
Routine Description:
|
||
|
||
This function returns TRUE if all the processors in the system started
|
||
successfully.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
Returns TRUE.
|
||
--**/
|
||
|
||
{
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
VOID
|
||
HalpIpiInterruptHandler(
|
||
IN PKINTERRUPT_ROUTINE Interrupt,
|
||
IN PKTRAP_FRAME TrapFrame
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is entered as the result of an interrupt generated by inter
|
||
processor communication.
|
||
|
||
Arguments:
|
||
|
||
Interrupt - Interrupt object address
|
||
|
||
TrapFrame - Trap frame address
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
|
||
KeIpiInterrupt(TrapFrame);
|
||
|
||
return;
|
||
|
||
}
|
||
|
||
|
||
VOID
|
||
HalpSendIPI(
|
||
IN USHORT ProcessorID,
|
||
IN ULONGLONG Data
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function sends IPI to the processor specified.
|
||
|
||
Arguements:
|
||
|
||
ProcessorID - Supplies the ID of processor to IPI.
|
||
|
||
Data - The formatted Data ready to ship it as IPI.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
|
||
PULONGLONG Address;
|
||
ULONG tmp1;
|
||
KIRQL OldIrql;
|
||
|
||
tmp1 = ProcessorID << IPI_ID_SHIFT;
|
||
|
||
Address = (PULONGLONG)((UINT_PTR)(InterruptBlock) + tmp1);
|
||
|
||
*(volatile ULONGLONG *)Address = Data;
|
||
|
||
return;
|
||
|
||
}
|
||
|
||
NTSTATUS
|
||
HalpSendCrossPartitionIpi(
|
||
IN USHORT ProcessorID,
|
||
IN UCHAR HardwareVector
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function sends a cross partition IPI to the processor
|
||
specified. The caller must know that this processor is in another
|
||
partition and the hardware vector previously reserved for
|
||
receiving cross partition IPIs.
|
||
|
||
Arguements:
|
||
|
||
ProcessorID - Supplies the ID of processor to IPI.
|
||
|
||
HardwareVector - Hardware Vector on remote processor that will
|
||
receive the interrupt.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
{
|
||
ULONGLONG Data;
|
||
|
||
if (HardwareVector < 16) {
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
Data = HardwareVector | DELIVER_FIXED;
|
||
HalpSendIPI(ProcessorID, Data);
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
VOID
|
||
HalpOSRendez (
|
||
IN USHORT ProcessorID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function does IPI to start the next processor.
|
||
|
||
Arguements:
|
||
|
||
PhysicalNumber - Supplies the physical number of processor to IPI.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
HalpSendIPI ( ProcessorID, HalpOsBootRendezVector);
|
||
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. If a value of
|
||
TRUE is returned, then the logical processor number is stored
|
||
in the processor control block specified by the loader block.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG count;
|
||
ULONGLONG EntryPoint;
|
||
ULONG ProcNumber = ((PKPRCB)LoaderBlock->Prcb)->Number;
|
||
SAL_PAL_RETURN_VALUES SalReturn;
|
||
SAL_STATUS salStatus;
|
||
NTSTATUS ntStatus;
|
||
USHORT TargetProcessorID;
|
||
|
||
if (HalpAcpiNumProcessors() <= ProcNumber) {
|
||
return (FALSE);
|
||
}
|
||
|
||
//
|
||
// Boot OS rendezvous entry point
|
||
//
|
||
|
||
EntryPoint = ProcessorState->ContextFrame.StIIP;
|
||
salStatus = HalpSalCall(SAL_SET_VECTORS,
|
||
2 /* Boot rendz */,
|
||
(ULONGLONG)(MmGetPhysicalAddress((PUCHAR)EntryPoint).QuadPart),
|
||
0,
|
||
0,
|
||
0,
|
||
0,
|
||
0,
|
||
&SalReturn);
|
||
|
||
if (salStatus != 0) {
|
||
HalDebugPrint(( HAL_ERROR, "HAL: HalStartNextProcessor - Cannot register OS rendezvous with SAL for processor %d\n",
|
||
ProcNumber ));
|
||
return (FALSE);
|
||
}
|
||
|
||
//
|
||
// For ia64, we will assume that the processor is ready and not started
|
||
//
|
||
|
||
//
|
||
// Start the next processor, if Processor ID not self
|
||
//
|
||
|
||
|
||
ntStatus = HalpGetApicIdByProcessorNumber((UCHAR)ProcNumber, &TargetProcessorID);
|
||
|
||
if (!NT_SUCCESS(ntStatus)) {
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
HalpOSRendez(TargetProcessorID);
|
||
|
||
count = 0;
|
||
|
||
while (*((volatile ULONG_PTR *)&LoaderBlock->Prcb) != 0 && (count < RENDEZ_TIME_OUT)) {
|
||
KeStallExecutionProcessor (1000); // 1000000
|
||
count++;
|
||
} // end while (count < RENDEZ_TIMEOUT)
|
||
|
||
if (LoaderBlock->Prcb != 0) {
|
||
return (FALSE);
|
||
} else {
|
||
return (TRUE);
|
||
}
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
HalRequestIpi (
|
||
IN KAFFINITY Mask
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function does nothing on a uni-processor platform.
|
||
|
||
Arguments:
|
||
|
||
Mask - A mask that specifies the target processor(s) to which an
|
||
IPI is to be sent.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
USHORT LogicalCpu;
|
||
USHORT ProcessorID;
|
||
|
||
//
|
||
// Make sure we don't try and IPI processors that we don't believe are
|
||
// started
|
||
//
|
||
|
||
Mask &= HalpActiveProcessors;
|
||
|
||
//
|
||
// Scan the processor set and request an interprocessor interrupt on
|
||
// each of the specified targets.
|
||
//
|
||
|
||
for (LogicalCpu = 0; LogicalCpu < HalpMpInfo.ProcessorCount; LogicalCpu++) {
|
||
|
||
if ((Mask & (1 << HalpProcessorInfo[LogicalCpu].NtProcessorNumber)) != 0) {
|
||
|
||
ProcessorID = HalpProcessorInfo[LogicalCpu].LocalApicID;
|
||
|
||
//
|
||
// Request interprocessor interrupt on target physicalCpu.
|
||
//
|
||
|
||
HalpSendIPI(ProcessorID, IPI_VECTOR);
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
VOID
|
||
HalProcessorIdle (
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function calls the TAL function to halt the processor.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
|
||
{
|
||
_enable();
|
||
}
|
||
|
||
#if !defined(NO_LEGACY_DRIVERS)
|
||
|
||
|
||
BOOLEAN
|
||
HalMakeBeep (
|
||
IN ULONG Frequency
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function calls SSC function SscMakeBeep() to make a beep sound
|
||
when the specified frequency has a non-zero value.
|
||
|
||
Arguments:
|
||
|
||
Frequency - the frequency of the sound to be made.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
if (Frequency > 0) {
|
||
|
||
SscMakeBeep(Frequency);
|
||
}
|
||
return TRUE;
|
||
}
|
||
|
||
#endif // NO_LEGACY_DRIVERS
|
||
|
||
|
||
VOID
|
||
KeStallExecutionProcessor (
|
||
IN ULONG MicroSeconds
|
||
)
|
||
|
||
/**
|
||
Routine Description:
|
||
|
||
This function stalls the processor.
|
||
|
||
Arguments:
|
||
|
||
MicroSeconds - Number of microseconds to stall the processor.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
**/
|
||
|
||
{
|
||
ULONGLONG CurrentITC;
|
||
ULONGLONG LimitITC;
|
||
|
||
CurrentITC = __getReg(CV_IA64_ApITC);
|
||
|
||
#ifndef DISABLE_ITC_WORKAROUND
|
||
while ((CurrentITC & 0xFFFFFFFF) == 0xFFFFFFFF) {
|
||
CurrentITC = __getReg(CV_IA64_ApITC);
|
||
}
|
||
#endif
|
||
|
||
LimitITC = CurrentITC + (ULONGLONG) (HalpITCTicksPer100ns * 10 * MicroSeconds);
|
||
|
||
while (LimitITC > CurrentITC) {
|
||
CurrentITC = __getReg(CV_IA64_ApITC);
|
||
|
||
#ifndef DISABLE_ITC_WORKAROUND
|
||
while ((CurrentITC & 0xFFFFFFFF) == 0xFFFFFFFF) {
|
||
CurrentITC = __getReg(CV_IA64_ApITC);
|
||
}
|
||
#endif
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
VOID HalpInitLINT(VOID);
|
||
|
||
|
||
VOID
|
||
HalInitializeProcessor (
|
||
ULONG Number,
|
||
PLOADER_PARAMETER_BLOCK LoaderBlock
|
||
)
|
||
|
||
/*++
|
||
|
||
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.
|
||
|
||
--*/
|
||
|
||
|
||
{
|
||
extern ULONG HalpDefaultInterruptAffinity;
|
||
|
||
//
|
||
// Add this processor to the interrupt affinity mask
|
||
//
|
||
|
||
HalpDefaultInterruptAffinity |= 1<<Number;
|
||
|
||
//
|
||
// Turn off LINT0 LINT1 (disable 8259)
|
||
//
|
||
|
||
// __setReg(CV_IA64_SaLRR0, 0x10000);
|
||
// __setReg(CV_IA64_SaLRR1, 0x10000);
|
||
//
|
||
|
||
HalpInitLINT();
|
||
__dsrlz();
|
||
|
||
|
||
//
|
||
// No need to Initialize the virtual address mapping for IO port space
|
||
// since loader/MM do that
|
||
//
|
||
|
||
PhysicalIOBase = LoaderBlock->u.Ia64.DtrInfo[DTR_IO_PORT_INDEX].PhysicalAddress;
|
||
|
||
PCR->StallScaleFactor = 0;
|
||
|
||
//
|
||
// Save my processor ID in PCR
|
||
//
|
||
|
||
PCR->HalReserved[PROCESSOR_ID_INDEX] = HalpReadLID() >> 16;
|
||
|
||
//
|
||
// This next call has nothing to do with processor init.
|
||
// But this is the only function in the HAL that gets
|
||
// called before KdInit.
|
||
//
|
||
|
||
HalpRegisterKdSupportFunctions(LoaderBlock);
|
||
|
||
//
|
||
// Update node tables
|
||
//
|
||
|
||
HalpAddNodeNumber(Number);
|
||
|
||
return;
|
||
}
|
||
|
||
VOID
|
||
HalpRegisterInternalInterrupts(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function reserves the known HAL IA64 resources usage and
|
||
registers the IDT vectors usage.
|
||
|
||
Arguements:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
ULONG i;
|
||
|
||
//
|
||
// Make sure all vectors 00-2f, c0-ff are reserved
|
||
// 00-0E Passive Reserved by Intel
|
||
// 0F SAPIC Spurious Interrupt Vector Reserved
|
||
// 10-1F APC priority level Reserved
|
||
// 20-2F DPC priority level Reserved
|
||
// c0-ff clock, ipi, synch, high
|
||
// these are reserved in HalpGetSystemInterruptVector()
|
||
// Do not report to IoReportHalResourceUsage()
|
||
//
|
||
|
||
for(i=0; i < PRIMARY_VECTOR_BASE; i++) {
|
||
if (!(HalpIDTUsage[i].Flags & IDTOwned)) {
|
||
HalpIDTUsage[i].Flags = 0;
|
||
HalpIDTUsage[i].BusReleativeVector = (UCHAR) i;
|
||
}
|
||
}
|
||
|
||
|
||
//
|
||
// Make sure all the interrupts in the SYNCH IRQL range are
|
||
// also reserved.
|
||
//
|
||
|
||
for(i= SYNCH_VECTOR; i < (SYNCH_VECTOR+16); i++) {
|
||
if (!(HalpIDTUsage[i].Flags & IDTOwned)) {
|
||
HalpIDTUsage[i].Flags = 0;
|
||
HalpIDTUsage[i].BusReleativeVector = (UCHAR) i;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Make sure all the interrupts in the IPI IRQL range are also
|
||
// reserved.
|
||
//
|
||
|
||
for(i= IPI_VECTOR; i < (IPI_VECTOR+16); i++) {
|
||
if (!(HalpIDTUsage[i].Flags & IDTOwned)) {
|
||
HalpIDTUsage[i].Flags = 0;
|
||
HalpIDTUsage[i].BusReleativeVector = (UCHAR) i;
|
||
}
|
||
}
|
||
|
||
|
||
//
|
||
// Make sure all the interrupts in the CLOCK IRQL range are also
|
||
// reserved.
|
||
//
|
||
|
||
for(i= CLOCK_VECTOR; i < (CLOCK_VECTOR+16); i++) {
|
||
if (!(HalpIDTUsage[i].Flags & IDTOwned)) {
|
||
HalpIDTUsage[i].Flags = 0;
|
||
HalpIDTUsage[i].BusReleativeVector = (UCHAR) i;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Make sure all interrupts in the PROFILE IRQL range also are
|
||
// reserved.
|
||
//
|
||
|
||
for(i= PROFILE_VECTOR; i < (PROFILE_VECTOR+16); i++) {
|
||
if (!(HalpIDTUsage[i].Flags & IDTOwned)) {
|
||
HalpIDTUsage[i].Flags = 0;
|
||
HalpIDTUsage[i].BusReleativeVector = (UCHAR) i;
|
||
}
|
||
}
|
||
|
||
HalpRegisterVector (
|
||
0,
|
||
SAPIC_SPURIOUS_VECTOR,
|
||
SAPIC_SPURIOUS_VECTOR,
|
||
SAPIC_SPURIOUS_LEVEL
|
||
);
|
||
|
||
HalpRegisterVector (
|
||
0,
|
||
(APC_LEVEL << VECTOR_IRQL_SHIFT),
|
||
(APC_LEVEL << VECTOR_IRQL_SHIFT),
|
||
APC_LEVEL
|
||
);
|
||
|
||
HalpRegisterVector (
|
||
0,
|
||
(DPC_LEVEL << VECTOR_IRQL_SHIFT),
|
||
(DPC_LEVEL << VECTOR_IRQL_SHIFT),
|
||
DPC_LEVEL
|
||
);
|
||
|
||
HalpRegisterVector (
|
||
0,
|
||
MC_RZ_VECTOR,
|
||
MC_RZ_VECTOR,
|
||
HIGH_LEVEL
|
||
);
|
||
|
||
HalpRegisterVector (
|
||
0,
|
||
MC_WKUP_VECTOR,
|
||
MC_WKUP_VECTOR,
|
||
HIGH_LEVEL
|
||
);
|
||
|
||
//
|
||
// Note that it is possible that HAL_CMC_PRESENT is not set.
|
||
// With the current implementation, we always register the CMC vector.
|
||
//
|
||
|
||
HalpRegisterVector (
|
||
0,
|
||
CMCI_VECTOR,
|
||
CMCI_VECTOR,
|
||
CMCI_LEVEL
|
||
);
|
||
|
||
//
|
||
// Note that it is possible that HAL_CPE_PRESENT is not set.
|
||
// With the current implementation, we always register the CPE vector.
|
||
//
|
||
|
||
HalpRegisterVector (
|
||
0,
|
||
CPEI_VECTOR,
|
||
CPEI_VECTOR,
|
||
CPEI_LEVEL
|
||
);
|
||
|
||
HalpRegisterVector (
|
||
0,
|
||
SYNCH_VECTOR,
|
||
SYNCH_VECTOR,
|
||
SYNCH_LEVEL
|
||
);
|
||
|
||
HalpRegisterVector (
|
||
0,
|
||
IPI_VECTOR,
|
||
IPI_VECTOR,
|
||
IPI_LEVEL
|
||
);
|
||
|
||
|
||
HalpRegisterVector (
|
||
0,
|
||
CLOCK_VECTOR,
|
||
CLOCK_VECTOR,
|
||
CLOCK_LEVEL
|
||
);
|
||
|
||
HalpRegisterVector (
|
||
0,
|
||
PROFILE_VECTOR,
|
||
PROFILE_VECTOR,
|
||
PROFILE_LEVEL
|
||
);
|
||
|
||
HalpRegisterVector (
|
||
0,
|
||
PERF_VECTOR,
|
||
PERF_VECTOR,
|
||
PROFILE_LEVEL
|
||
);
|
||
|
||
return;
|
||
|
||
} // HalpRegisterInternalInterrupts()
|
||
|
||
|
||
VOID
|
||
HalpPerfInterrupt (
|
||
IN PKINTERRUPT_ROUTINE Interrupt,
|
||
IN PKTRAP_FRAME TrapFrame
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguements:
|
||
|
||
|
||
Return Parameters:
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
// Thierry: This interrupt handler could be used to implement instructions
|
||
// tracing based on the overflow interrupts generated by PMU events
|
||
// like "retired instructions" or "taken branches".
|
||
// This would provide very valuable inputs for hardware performance simulators.
|
||
//
|
||
// XXTF - not implemented yet...
|
||
return;
|
||
|
||
} // HalpPerfInterrupt()
|
||
|
||
|
||
|
||
#if defined(HALP_FIX_KD_HALIA64_MASK)
|
||
#if DBG
|
||
|
||
VOID
|
||
HalpSetKdHalia64Mask(
|
||
ULONG Mask
|
||
)
|
||
//
|
||
// Mask == 0 should return without modifying Kd_HALIA64_Mask.
|
||
//
|
||
{
|
||
NTSTATUS status;
|
||
ULONG level, levelMasked;
|
||
int shift;
|
||
|
||
if ( Mask == (ULONG)-1 ) {
|
||
status = DbgSetDebugFilterState( DPFLTR_HALIA64_ID, -1, TRUE );
|
||
if ( !NT_SUCCESS(status) ) {
|
||
HalDebugPrint(( HAL_ERROR,
|
||
"HAL!HalInitSystem: failed to set Kd_HALIA64_Mask to maximum debug spew... 0x%lx\n",
|
||
status ));
|
||
}
|
||
return;
|
||
}
|
||
|
||
level = levelMasked = Mask & HALIA64_DPFLTR_MAXMASK;
|
||
shift = 0;
|
||
while( level ) {
|
||
level &= 0x1;
|
||
if ( level ) {
|
||
status = DbgSetDebugFilterState( DPFLTR_HALIA64_ID, shift, TRUE );
|
||
if ( !NT_SUCCESS(status) ) {
|
||
HalDebugPrint(( HAL_ERROR,
|
||
"HAL!HalInitSystem: failed to set Kd_HALIA64_Mask to 0x%lx... 0x%lx\n",
|
||
shift,
|
||
status ));
|
||
break;
|
||
}
|
||
}
|
||
shift = shift + 1;
|
||
level = levelMasked >> shift;
|
||
}
|
||
|
||
return;
|
||
|
||
} // HalpSetKdHalia64Mask()
|
||
|
||
#else // !DBG
|
||
|
||
#define HalpSetKdHalia64Mask()
|
||
|
||
#endif // !DBG
|
||
#endif // HALP_FIX_KD_HALIA64_MASK
|
||
|
||
|
||
|
||
BOOLEAN
|
||
HalInitSystem (
|
||
IN ULONG Phase,
|
||
IN PLOADER_PARAMETER_BLOCK LoaderBlock
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function initializes the Hardware Architecture Layer (HAL) for an
|
||
ia64 system.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
A value of TRUE is returned is the initialization was successfully
|
||
complete. Otherwise a value of FALSE is returned.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PMEMORY_ALLOCATION_DESCRIPTOR Descriptor;
|
||
PLIST_ENTRY NextMd;
|
||
PKPRCB pPRCB;
|
||
volatile KPCR * const pPCR = KeGetPcr();
|
||
BOOLEAN Found;
|
||
|
||
ULONGLONG ITCFrequencyQueried;
|
||
ULONGLONG ProcessorFrequencyQueried;
|
||
|
||
ULONG RTCInti;
|
||
|
||
KIRQL OldIrql;
|
||
NTSTATUS status;
|
||
|
||
//
|
||
// This is for testing RTC clock
|
||
//
|
||
|
||
TIME_FIELDS CurrentTimeFields;
|
||
|
||
pPRCB = KeGetCurrentPrcb();
|
||
|
||
if (Phase == 0) {
|
||
|
||
extern VOID DetectAcpiMP();
|
||
BOOLEAN IsMP;
|
||
BOOLEAN EnableInterrupts;
|
||
|
||
//
|
||
// Phase 0 initialization only called by P0
|
||
//
|
||
|
||
HalpBusType = LoaderBlock->u.Ia64.MachineType & 0x00ff;
|
||
HalpGetParameters (LoaderBlock);
|
||
|
||
//
|
||
// Disable Interrupts before messing around with the APIC etc.
|
||
//
|
||
|
||
EnableInterrupts = HalpDisableInterrupts();
|
||
|
||
DetectAcpiMP(&IsMP, LoaderBlock);
|
||
|
||
HalpSetupAcpiPhase0(LoaderBlock);
|
||
|
||
//
|
||
// Verify Prcb version and build flags conform to
|
||
// this image
|
||
//
|
||
|
||
if (pPRCB->MajorVersion != PRCB_MAJOR_VERSION) {
|
||
KeBugCheckEx (
|
||
MISMATCHED_HAL,
|
||
1,
|
||
pPRCB->MajorVersion,
|
||
PRCB_MAJOR_VERSION,
|
||
0
|
||
);
|
||
}
|
||
|
||
KeInitializeSpinLock(&HalpIoSapicLock);
|
||
|
||
//
|
||
// Fill in handlers for APIs which this hal supports
|
||
//
|
||
|
||
HalQuerySystemInformation = HaliQuerySystemInformation;
|
||
HalSetSystemInformation = HaliSetSystemInformation;
|
||
HalInitPnpDriver = HaliInitPnpDriver;
|
||
|
||
//
|
||
// HalGetDmaAdapter was commented in previous version
|
||
// also. HalInitPowerManagement, HalLocateHiberRanges and
|
||
// HalGetInterruptTranslator are added in the latest version
|
||
// of Microsoft source code.
|
||
//
|
||
|
||
HalGetDmaAdapter = HaliGetDmaAdapter;
|
||
HalHaltSystem = HaliHaltSystem;
|
||
HalResetDisplay = HalpBiosDisplayReset;
|
||
|
||
#if !defined( HAL_SP )
|
||
HalGetInterruptTranslator = HalacpiGetInterruptTranslator;
|
||
#endif // HAL_SP
|
||
|
||
#if DBG
|
||
//
|
||
// Switch from HalDisplayString to DbgPrint.
|
||
//
|
||
|
||
HalpUseDbgPrint++;
|
||
#endif // DBG
|
||
|
||
#if !defined( HAL_SP ) && !(MCA)
|
||
HalInitPowerManagement = HaliInitPowerManagement;
|
||
HalLocateHiberRanges = HaliLocateHiberRanges;
|
||
#endif// HAL_SP and MCA
|
||
|
||
//
|
||
// Register PC style IO space used by hal
|
||
//
|
||
|
||
HalpRegisterAddressUsage (&HalpDefaultPcIoSpace);
|
||
HalpInitIntiInfo ();
|
||
|
||
//
|
||
// Initialize CMOS
|
||
//
|
||
|
||
HalpInitializeCmos();
|
||
|
||
//
|
||
// Initialize per processor EOI table
|
||
//
|
||
|
||
HalpInitEOITable();
|
||
|
||
//
|
||
// Initialize the clock for the processor that keeps
|
||
// the system time. This uses a stub ISR until Phase 1
|
||
//
|
||
|
||
// Initialize Clock interrupts, profile , APC and DPC interrupts,
|
||
|
||
HalpInitializeClock();
|
||
HalpRegisterInternalInterrupts();
|
||
HalpInitializeInterrupts();
|
||
|
||
//
|
||
// Initialize initial processor and NT profiling state
|
||
// that should be initialized at Phase 0 and
|
||
// do not require to wait for Phase 1.
|
||
//
|
||
|
||
HalpSetInitialProfileState();
|
||
|
||
//
|
||
// Interrupts should be safe now.
|
||
//
|
||
|
||
if (EnableInterrupts) {
|
||
HalpEnableInterrupts();
|
||
}
|
||
|
||
//
|
||
// Initialize event for serialization of new dma adapter events
|
||
//
|
||
|
||
KeInitializeEvent(&HalpNewAdapter, SynchronizationEvent, TRUE);
|
||
|
||
//
|
||
// Determine if there is physical memory above 4 GB.
|
||
//
|
||
|
||
HalDebugPrint(( HAL_INFO, "HAL: Determine if there is memory above 4 Gb\n" ));
|
||
NoMemoryAbove4Gb = TRUE;
|
||
|
||
NextMd = LoaderBlock->MemoryDescriptorListHead.Flink;
|
||
|
||
while (NextMd != &LoaderBlock->MemoryDescriptorListHead) {
|
||
Descriptor = CONTAINING_RECORD(
|
||
NextMd,
|
||
MEMORY_ALLOCATION_DESCRIPTOR,
|
||
ListEntry
|
||
);
|
||
|
||
if (Descriptor->MemoryType != LoaderFirmwarePermanent &&
|
||
Descriptor->MemoryType != LoaderSpecialMemory) {
|
||
//
|
||
// Test for 4 GB:
|
||
//
|
||
if ((Descriptor->BasePage + Descriptor->PageCount) > (GreaterThan4GB >> PAGE_SHIFT)) {
|
||
NoMemoryAbove4Gb = FALSE;
|
||
HalDebugPrint(( HAL_INFO, "HAL: Memory is present above 4Gb\n" ));
|
||
break;
|
||
}
|
||
}
|
||
|
||
NextMd = Descriptor->ListEntry.Flink;
|
||
}
|
||
|
||
//
|
||
// Determine the size needed for map buffers. If this system has
|
||
// memory that requires more than 32 bits to access, then allocate
|
||
// a large chunk; otherwise, allocate a small chunk.
|
||
//
|
||
|
||
if (NoMemoryAbove4Gb) {
|
||
|
||
//
|
||
// Allocate a small set of map buffers. They are only need for
|
||
// devices which do not function.
|
||
//
|
||
|
||
HalpMapBufferSize = INITIAL_MAP_BUFFER_SMALL_SIZE;
|
||
HalDebugPrint(( HAL_INFO, "HAL: No memory beyond 4Gb\n" ));
|
||
|
||
} else {
|
||
|
||
//
|
||
// Allocate a larger set of map buffers. These are used for
|
||
// 32 bit devices to reach memory above 4gb.
|
||
//
|
||
|
||
HalpMapBufferSize = INITIAL_MAP_BUFFER_LARGE_SIZE;
|
||
HalDebugPrint(( HAL_INFO, "HAL: Map Buffers for 32 bit devices to reach memory above 4Gb\n" ));
|
||
|
||
}
|
||
|
||
//
|
||
// Allocate map buffers for the adapter objects
|
||
//
|
||
|
||
HalpMapBufferPhysicalAddress.QuadPart = (ULONGLONG)
|
||
HalpAllocPhysicalMemory(LoaderBlock,
|
||
MAXIMUM_PHYSICAL_ADDRESS,
|
||
HalpMapBufferSize >> PAGE_SHIFT,
|
||
TRUE);
|
||
|
||
HalpMapBufferPhysicalAddress.HighPart = 0;
|
||
|
||
|
||
if (!HalpMapBufferPhysicalAddress.LowPart) {
|
||
|
||
//
|
||
// There was not a satisfactory block. Clear the allocation.
|
||
//
|
||
|
||
HalpMapBufferSize = 0;
|
||
}
|
||
|
||
//
|
||
// Set the processor active in the HAL private active processor mask.
|
||
//
|
||
// For the BSP processor, the specific bit is set at the end of HalInitSystem(Phase0).
|
||
|
||
HalpActiveProcessors = 1 << pPRCB->Number;
|
||
|
||
} else {
|
||
|
||
//
|
||
// Phase 1 initialization
|
||
//
|
||
|
||
if ( pPCR->Number == 0) {
|
||
|
||
//
|
||
// Back-pocket some PTEs for DMA during low mem
|
||
//
|
||
HalpInitReservedPages();
|
||
|
||
#if defined(HALP_FIX_KD_HALIA64_MASK)
|
||
#if DBG
|
||
|
||
HalpSetKdHalia64Mask( HalpFixKdHalia64Mask );
|
||
|
||
#endif // DBG
|
||
#endif // HALP_FIX_KD_HALIA64_MASK
|
||
|
||
HalpEfiInitialization(LoaderBlock);
|
||
|
||
HalpInitIoMemoryBase();
|
||
HalpInitializeX86Int10Call();
|
||
HalpInitializeInterruptBlock();
|
||
|
||
//
|
||
// Map the APICs so that MM will allow us to access them in the
|
||
// debugger.
|
||
//
|
||
|
||
HalpInitApicDebugMappings();
|
||
|
||
//
|
||
// Initialize MCA,INIT parameters and pre-allocate Event records for BSP processor.
|
||
//
|
||
|
||
if ( !HalpInitializeOSMCA( pPCR->Number ) ) {
|
||
return FALSE;
|
||
}
|
||
|
||
HalpInitNonBusHandler();
|
||
|
||
//
|
||
// Raise IRQL to the highest level, set the new clock interrupt
|
||
// parameters, lower IRQl, and return the new time increment value.
|
||
//
|
||
|
||
status = HalpQueryFrequency( &ITCFrequencyQueried,
|
||
&ProcessorFrequencyQueried);
|
||
|
||
KeRaiseIrql(HIGH_LEVEL, &OldIrql);
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
HalpITCFrequency = ITCFrequencyQueried;
|
||
HalpProcessorFrequency = ProcessorFrequencyQueried;
|
||
}
|
||
|
||
HalpSetInitialClockRate();
|
||
|
||
KeLowerIrql(OldIrql);
|
||
|
||
//
|
||
// Set initial feature bits
|
||
//
|
||
|
||
HalpFeatureBits = HalpGetFeatureBits();
|
||
|
||
//
|
||
// Initialize per-processor profiling
|
||
//
|
||
// Requires HalpITCTicksPer100ns initialized.
|
||
|
||
HalpInitializeProfiling( pPCR->Number );
|
||
|
||
HalpMCAEnable();
|
||
HalpCMCEnable();
|
||
HalpCPEEnable();
|
||
|
||
} else {
|
||
|
||
//
|
||
// Initialize per processor EOI table
|
||
//
|
||
|
||
HalpInitEOITable();
|
||
|
||
//
|
||
// Initialization needed only on non BSP processors
|
||
//
|
||
|
||
HalpInitSalPalNonBsp();
|
||
HalpInitializeClockPn();
|
||
|
||
//
|
||
// Allocate MCA, INIT stacks on non BSP processors
|
||
//
|
||
|
||
if ( !HalpAllocateMceStacks( pPCR->Number) ) {
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// Pre-allocate MCA,INIT records on non BSP processors
|
||
//
|
||
|
||
if ( !HalpPreAllocateMceRecords( pPCR->Number) ) {
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// Reduce feature bits to be a subset
|
||
//
|
||
|
||
HalpFeatureBits &= HalpGetFeatureBits();
|
||
|
||
HalpInitializeInterrupts();
|
||
|
||
//
|
||
// Initialize per-processor profiling
|
||
//
|
||
|
||
HalpInitializeProfiling( pPCR->Number );
|
||
|
||
HalpMCAEnable();
|
||
HalpCMCEnable();
|
||
|
||
//
|
||
// Set the processor active in the HAL private active processor mask.
|
||
//
|
||
// For non-BSP processors, the specific bit is set at the end of HalInitSystem(Phase1).
|
||
|
||
HalpActiveProcessors |= 1 << pPRCB->Number;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
VOID
|
||
HalChangeColorPage (
|
||
IN PVOID NewColor,
|
||
IN PVOID OldColor,
|
||
IN ULONG PageFrame
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function changes the color of a page if the old and new colors
|
||
do not match.
|
||
|
||
Arguments:
|
||
|
||
NewColor - Supplies the page aligned virtual address of the
|
||
new color of the page to change.
|
||
|
||
OldColor - Supplies the page aligned virtual address of the
|
||
old color of the page to change.
|
||
|
||
pageFrame - Supplies the page frame number of the page that
|
||
is changed.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
return;
|
||
}
|
||
|
||
//****************************************************************
|
||
// T. Kjos Added stuff after this line as part of initial
|
||
// APIC, PCMP removal.
|
||
|
||
// From mpsproc.c
|
||
ULONG HalpDontStartProcessors = 0;
|
||
|
||
//
|
||
// Since IA-64 does not support lowest priority interrupts set
|
||
// processors per cluster to 1 so that we staically assign interrupts
|
||
// in round robin to the processors.
|
||
//
|
||
|
||
UCHAR HalpMaxProcsPerCluster = 1;
|
||
|
||
// From pmmphal.c:
|
||
BOOLEAN HalpStaticIntAffinity = FALSE;
|
||
|
||
extern UCHAR HalpSzInterruptAffinity[];
|
||
extern UCHAR HalpSzOneCpu[];
|
||
extern ULONG HalpDontStartProcessors;
|
||
extern UCHAR HalpSzPciLock[];
|
||
extern UCHAR HalpSzBreak[];
|
||
extern UCHAR HalpSzForceClusterMode[];
|
||
|
||
VOID
|
||
HalpGetParameters (
|
||
IN PLOADER_PARAMETER_BLOCK LoaderBlock
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This gets any parameters from the boot.ini invocation line.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
PCHAR Options;
|
||
PCHAR p;
|
||
|
||
if (LoaderBlock != NULL && LoaderBlock->LoadOptions != NULL) {
|
||
|
||
Options = LoaderBlock->LoadOptions;
|
||
|
||
//
|
||
// Has the user set the debug flag?
|
||
//
|
||
//
|
||
// Has the user requested a particular number of CPU's?
|
||
//
|
||
|
||
if (strstr(Options, HalpSzOneCpu)) {
|
||
HalpDontStartProcessors++;
|
||
}
|
||
|
||
//
|
||
// Check if user wants device ints to go to highest numbered processor
|
||
//
|
||
|
||
if (strstr(Options, HalpSzInterruptAffinity)) {
|
||
HalpStaticIntAffinity = TRUE;
|
||
}
|
||
|
||
//
|
||
// Has the user asked for an initial BreakPoint?
|
||
//
|
||
|
||
if (strstr(Options, HalpSzBreak)) {
|
||
DbgBreakPoint();
|
||
}
|
||
|
||
//
|
||
// Used to define the size of a node = MaxProcsPerCluster
|
||
// 0 implies one node for the whole machine
|
||
//
|
||
p = strstr(Options, HalpSzForceClusterMode);
|
||
if (p) {
|
||
// skip to value
|
||
while (*p && *p != ' ' && (*p < '0' || *p > '9')) {
|
||
p++;
|
||
}
|
||
HalpMaxProcsPerCluster = (UCHAR)atoi(p);
|
||
}
|
||
}
|
||
|
||
return ;
|
||
}
|
||
|
||
|