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.
1556 lines
34 KiB
1556 lines
34 KiB
|
|
/*++
|
|
|
|
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 ([email protected])
|
|
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
|
|
|
|
#define VideoBiosFirstPage 0x60
|
|
#define VideoBiosLastPage 0x67
|
|
|
|
VOID
|
|
HalpInitReservedPages(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
HalpRegisterKdSupportFunctions(
|
|
IN PLOADER_PARAMETER_BLOCK LoaderBlock
|
|
);
|
|
|
|
extern ADDRESS_USAGE HalpDefaultPcIoSpace;
|
|
extern ULONGLONG HalpITCFrequency;
|
|
extern ULONGLONG HalpProcessorFrequency;
|
|
extern ULONG HalpOsBootRendezVector;
|
|
|
|
ULONG HalpBusType;
|
|
|
|
ULONGLONG PhysicalIOBase;
|
|
|
|
static short HalpOwnDisplay = TRUE;
|
|
|
|
PULONGLONG InterruptBlock;
|
|
|
|
extern KEVENT HalpNewAdapter;
|
|
|
|
extern ULONGLONG HalpPhysPalProcPointer;
|
|
extern ULONGLONG HalpPhysSalProcPointer;
|
|
extern ULONGLONG HalpPhysSalProcGlobalPointer;
|
|
|
|
extern ULONG HalpPlatformPropertiesEfiFlags;
|
|
|
|
BOOLEAN HalpVideoBiosPresent;
|
|
|
|
//
|
|
// 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 & ((KAFFINITY)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 = HalpReadITC();
|
|
|
|
LimitITC = CurrentITC + (ULONGLONG) (HalpITCTicksPer100ns * 10 * MicroSeconds);
|
|
|
|
while (LimitITC > CurrentITC) {
|
|
|
|
KeYieldProcessor();
|
|
CurrentITC = HalpReadITC();
|
|
}
|
|
|
|
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.
|
|
|
|
--*/
|
|
|
|
|
|
{
|
|
|
|
//
|
|
// If this is the BSP then prepare the HAL to make physical mode firmware
|
|
// calls on this processor. This duplicates some of what is later done
|
|
// by HalpAllocateProcessorPhysicalCallStacks on the APs in order to
|
|
// facilitate physical mode calls on the BSP before EFI initialization.
|
|
//
|
|
|
|
if (Number == 0) {
|
|
ULONG Length;
|
|
PVOID Block;
|
|
|
|
Length = HALP_FW_MEMORY_STACK_SIZE + HALP_FW_BACKING_STORE_SIZE;
|
|
|
|
//
|
|
// Allocate sufficient stack and backing store for calls to
|
|
// the firmware.
|
|
//
|
|
|
|
Block = HalpAllocPhysicalMemory(LoaderBlock,
|
|
MAXIMUM_PHYSICAL_ADDRESS,
|
|
Length >> PAGE_SHIFT,
|
|
FALSE);
|
|
if (Block == NULL) {
|
|
HalDebugPrint((HAL_ERROR, "HAL_INIT: can't allocate stack space "
|
|
"for physical mode firmware calls.\n"));
|
|
|
|
} else {
|
|
|
|
//
|
|
// Store a pointer to the firmware stacks in the PCR.
|
|
//
|
|
|
|
PCR->HalReserved[PROCESSOR_PHYSICAL_FW_STACK_INDEX] =
|
|
(ULONGLONG) Block;
|
|
|
|
//
|
|
// Load the physical addresses of SAL_PROC and the SAL GP.
|
|
//
|
|
|
|
HalpPhysSalProcPointer = LoaderBlock->u.Ia64.Sal.PhysicalAddress;
|
|
HalpPhysSalProcGlobalPointer
|
|
= LoaderBlock->u.Ia64.SalGP.PhysicalAddress;
|
|
|
|
//
|
|
// Load the physical address of PAL_PROC.
|
|
//
|
|
|
|
HalpPhysPalProcPointer = LoaderBlock->u.Ia64.Pal.PhysicalAddress;
|
|
}
|
|
}
|
|
|
|
//
|
|
// 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();
|
|
|
|
|
|
PCR->StallScaleFactor = 0;
|
|
|
|
//
|
|
// Save my processor ID in PCR
|
|
//
|
|
|
|
PCR->HalReserved[PROCESSOR_ID_INDEX] = HalpReadLID() >> 16;
|
|
|
|
if (Number == 0) {
|
|
|
|
HalpInitCacheInfo(LoaderBlock->u.Ia64.ProcessorConfigInfo.CacheFlushStride);
|
|
|
|
//
|
|
// 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;
|
|
|
|
//
|
|
// Initialize HAL global PlatformProperties EFI flags with loader value.
|
|
//
|
|
|
|
HalpPlatformPropertiesEfiFlags = LoaderBlock->u.Ia64.EfiMemMapParam.InitialPlatformPropertiesEfiFlags;
|
|
|
|
//
|
|
// 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);
|
|
}
|
|
}
|
|
|
|
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;
|
|
HalAllocateMapRegisters = HalpAllocateMapRegisters;
|
|
|
|
#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);
|
|
HalpInitInterruptTables();
|
|
|
|
//
|
|
// Initialize CMOS
|
|
//
|
|
|
|
HalpInitializeCmos();
|
|
|
|
//
|
|
// Initialize per processor EOI table
|
|
//
|
|
|
|
HalpInitEOITable();
|
|
HalpInitPlatformInterrupts();
|
|
|
|
//
|
|
// 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.
|
|
//
|
|
|
|
HalpSetupProfilingPhase0( LoaderBlock );
|
|
|
|
//
|
|
// Interrupts should be safe now.
|
|
//
|
|
|
|
if (EnableInterrupts) {
|
|
HalpEnableInterrupts();
|
|
}
|
|
|
|
//
|
|
// Initialize event for serialization of new dma adapter events
|
|
//
|
|
|
|
KeInitializeEvent(&HalpNewAdapter, SynchronizationEvent, TRUE);
|
|
|
|
//
|
|
// Fill in the PAL TR_INFO structure so Mm can build PTEs for
|
|
// the PAL during phase 0 initialization.
|
|
//
|
|
|
|
HalpInitializePalTrInfo(LoaderBlock);
|
|
|
|
//
|
|
// 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" ));
|
|
|
|
if (HalpVideoBiosPresent) {
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
if ((Descriptor->BasePage <= VideoBiosFirstPage) &&
|
|
(Descriptor->BasePage + Descriptor->PageCount) > VideoBiosLastPage) {
|
|
HalpVideoBiosPresent = TRUE;
|
|
HalDebugPrint(( HAL_INFO, "HAL: Video BIOS present\n" ));
|
|
|
|
if (NoMemoryAbove4Gb == FALSE) {
|
|
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 = 1uI64 << 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
|
|
|
|
if (!NT_SUCCESS(HalpEfiInitialization(LoaderBlock))) {
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Set initial feature bits
|
|
//
|
|
|
|
HalpFeatureBits = HalpGetFeatureBits();
|
|
|
|
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);
|
|
|
|
//
|
|
// Initialize per-processor profiling
|
|
//
|
|
// Requires HalpITCTicksPer100ns initialized.
|
|
|
|
HalpInitializeProfiling( pPCR->Number );
|
|
|
|
HalpMCAEnable();
|
|
HalpCMCEnable();
|
|
HalpCPEEnable();
|
|
|
|
} else {
|
|
|
|
//
|
|
// Initialize per processor EOI table
|
|
//
|
|
HalpInitEOITable();
|
|
HalpInitPlatformInterrupts();
|
|
|
|
//
|
|
// Initialization needed only on non BSP processors
|
|
//
|
|
if ( !HalpInitSalPalNonBsp() ) {
|
|
return FALSE;
|
|
}
|
|
|
|
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 |= 1uI64 << 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 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 ;
|
|
}
|
|
|
|
|