Implement APIC timer initialization and calibration
This commit is contained in:
@@ -179,6 +179,10 @@
|
|||||||
#define COMPORT_REG_MSR 0x06 /* Modem Status Register */
|
#define COMPORT_REG_MSR 0x06 /* Modem Status Register */
|
||||||
#define COMPORT_REG_SR 0x07 /* Scratch Register */
|
#define COMPORT_REG_SR 0x07 /* Scratch Register */
|
||||||
|
|
||||||
|
/* Minimum and maximum profile intervals */
|
||||||
|
#define MIN_PROFILE_INTERVAL 1000
|
||||||
|
#define MAX_PROFILE_INTERVAL 10000000
|
||||||
|
|
||||||
|
|
||||||
/* C/C++ specific code */
|
/* C/C++ specific code */
|
||||||
#ifndef __XTOS_ASSEMBLER__
|
#ifndef __XTOS_ASSEMBLER__
|
||||||
|
|||||||
@@ -137,6 +137,37 @@ typedef enum _KPROCESS_STATE
|
|||||||
ProcessOutSwap
|
ProcessOutSwap
|
||||||
} KPROCESS_STATE, *PKPROCESS_STATE;
|
} KPROCESS_STATE, *PKPROCESS_STATE;
|
||||||
|
|
||||||
|
/* Kernel profiling sources */
|
||||||
|
typedef enum _KPROFILE_SOURCE
|
||||||
|
{
|
||||||
|
ProfileTime,
|
||||||
|
ProfileAlignmentFixup,
|
||||||
|
ProfileTotalIssues,
|
||||||
|
ProfilePipelineDry,
|
||||||
|
ProfileLoadInstructions,
|
||||||
|
ProfilePipelineFrozen,
|
||||||
|
ProfileBranchInstructions,
|
||||||
|
ProfileTotalNonissues,
|
||||||
|
ProfileDcacheMisses,
|
||||||
|
ProfileIcacheMisses,
|
||||||
|
ProfileCacheMisses,
|
||||||
|
ProfileBranchMispredictions,
|
||||||
|
ProfileStoreInstructions,
|
||||||
|
ProfileFpInstructions,
|
||||||
|
ProfileIntegerInstructions,
|
||||||
|
Profile2Issue,
|
||||||
|
Profile3Issue,
|
||||||
|
Profile4Issue,
|
||||||
|
ProfileSpecialInstructions,
|
||||||
|
ProfileTotalCycles,
|
||||||
|
ProfileIcacheIssues,
|
||||||
|
ProfileDcacheAccesses,
|
||||||
|
ProfileMemoryBarrierCycles,
|
||||||
|
ProfileLoadLinkedIssues,
|
||||||
|
ProfileXtKernel,
|
||||||
|
ProfileMaximum
|
||||||
|
} KPROFILE_SOURCE, *PKPROFILE_SOURCE;
|
||||||
|
|
||||||
/* Thread state */
|
/* Thread state */
|
||||||
typedef enum _KTHREAD_STATE
|
typedef enum _KTHREAD_STATE
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ typedef enum _KDPC_IMPORTANCE KDPC_IMPORTANCE, *PKDPC_IMPORTANCE;
|
|||||||
typedef enum _KEVENT_TYPE KEVENT_TYPE, *PKEVENT_TYPE;
|
typedef enum _KEVENT_TYPE KEVENT_TYPE, *PKEVENT_TYPE;
|
||||||
typedef enum _KOBJECTS KOBJECTS, *PKOBJECTS;
|
typedef enum _KOBJECTS KOBJECTS, *PKOBJECTS;
|
||||||
typedef enum _KPROCESS_STATE KPROCESS_STATE, *PKPROCESS_STATE;
|
typedef enum _KPROCESS_STATE KPROCESS_STATE, *PKPROCESS_STATE;
|
||||||
|
typedef enum _KPROFILE_SOURCE KPROFILE_SOURCE, *PKPROFILE_SOURCE;
|
||||||
typedef enum _KTHREAD_STATE KTHREAD_STATE, *PKTHREAD_STATE;
|
typedef enum _KTHREAD_STATE KTHREAD_STATE, *PKTHREAD_STATE;
|
||||||
typedef enum _KTIMER_TYPE KTIMER_TYPE, *PKTIMER_TYPE;
|
typedef enum _KTIMER_TYPE KTIMER_TYPE, *PKTIMER_TYPE;
|
||||||
typedef enum _KUBSAN_DATA_TYPE KUBSAN_DATA_TYPE, *PKUBSAN_DATA_TYPE;
|
typedef enum _KUBSAN_DATA_TYPE KUBSAN_DATA_TYPE, *PKUBSAN_DATA_TYPE;
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ list(APPEND XTOSKRNL_SOURCE
|
|||||||
${XTOSKRNL_SOURCE_DIR}/hl/${ARCH}/ioport.cc
|
${XTOSKRNL_SOURCE_DIR}/hl/${ARCH}/ioport.cc
|
||||||
${XTOSKRNL_SOURCE_DIR}/hl/${ARCH}/irq.cc
|
${XTOSKRNL_SOURCE_DIR}/hl/${ARCH}/irq.cc
|
||||||
${XTOSKRNL_SOURCE_DIR}/hl/${ARCH}/runlevel.cc
|
${XTOSKRNL_SOURCE_DIR}/hl/${ARCH}/runlevel.cc
|
||||||
|
${XTOSKRNL_SOURCE_DIR}/hl/${ARCH}/timer.cc
|
||||||
${XTOSKRNL_SOURCE_DIR}/hl/acpi.cc
|
${XTOSKRNL_SOURCE_DIR}/hl/acpi.cc
|
||||||
${XTOSKRNL_SOURCE_DIR}/hl/cport.cc
|
${XTOSKRNL_SOURCE_DIR}/hl/cport.cc
|
||||||
${XTOSKRNL_SOURCE_DIR}/hl/data.cc
|
${XTOSKRNL_SOURCE_DIR}/hl/data.cc
|
||||||
|
|||||||
13
xtoskrnl/hl/amd64/timer.cc
Normal file
13
xtoskrnl/hl/amd64/timer.cc
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
/**
|
||||||
|
* PROJECT: ExectOS
|
||||||
|
* COPYRIGHT: See COPYING.md in the top level directory
|
||||||
|
* FILE: xtoskrnl/hl/amd64/timer.cc
|
||||||
|
* DESCRIPTION: APIC Timer for AMD64 support
|
||||||
|
* DEVELOPERS: Aiken Harris <harraiken91@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <xtos.hh>
|
||||||
|
|
||||||
|
|
||||||
|
/* Include common Timer interface */
|
||||||
|
#include ARCH_COMMON(timer.cc)
|
||||||
13
xtoskrnl/hl/i686/timer.cc
Normal file
13
xtoskrnl/hl/i686/timer.cc
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
/**
|
||||||
|
* PROJECT: ExectOS
|
||||||
|
* COPYRIGHT: See COPYING.md in the top level directory
|
||||||
|
* FILE: xtoskrnl/hl/i686/timer.cc
|
||||||
|
* DESCRIPTION: APIC Timer for i686 support
|
||||||
|
* DEVELOPERS: Aiken Harris <harraiken91@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <xtos.hh>
|
||||||
|
|
||||||
|
|
||||||
|
/* Include common Timer interface */
|
||||||
|
#include ARCH_COMMON(timer.cc)
|
||||||
350
xtoskrnl/hl/x86/timer.cc
Normal file
350
xtoskrnl/hl/x86/timer.cc
Normal file
@@ -0,0 +1,350 @@
|
|||||||
|
/**
|
||||||
|
* PROJECT: ExectOS
|
||||||
|
* COPYRIGHT: See COPYING.md in the top level directory
|
||||||
|
* FILE: xtoskrnl/hl/x86/timer.cc
|
||||||
|
* DESCRIPTION: APIC Timer support for x86 (i686/AMD64) support
|
||||||
|
* DEVELOPERS: Aiken Harris <harraiken91@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <xtos.hh>
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calibrates the Local APIC timer frequency.
|
||||||
|
*
|
||||||
|
* @return This routine returns a status code.
|
||||||
|
*
|
||||||
|
* @since XT 1.0
|
||||||
|
*/
|
||||||
|
XTAPI
|
||||||
|
XTSTATUS
|
||||||
|
HL::Timer::CalibrateApicTimer()
|
||||||
|
{
|
||||||
|
ULONG CurrentCount, Frequency, InitialCount;
|
||||||
|
XTSTATUS Status;
|
||||||
|
|
||||||
|
/* Get APIC timer frequency from the Core Crystal Clock */
|
||||||
|
Status = GetApicTimerFrequency(&Frequency);
|
||||||
|
if(Status != STATUS_SUCCESS || !Frequency)
|
||||||
|
{
|
||||||
|
/* CCC unavailable, fallback to PIT calibration */
|
||||||
|
InitialCount = 0xFFFFFFFF;
|
||||||
|
|
||||||
|
/* Load the initial count into the APIC Timer and begin the countdown */
|
||||||
|
HL::Pic::WriteApicRegister(APIC_TICR, InitialCount);
|
||||||
|
|
||||||
|
/* Wait for 10ms */
|
||||||
|
StallExecution(10000);
|
||||||
|
|
||||||
|
/* Read current tick count from APIC timer and clear APIC timer */
|
||||||
|
CurrentCount = HL::Pic::ReadApicRegister(APIC_TCCR);
|
||||||
|
HL::Pic::WriteApicRegister(APIC_TICR, 0);
|
||||||
|
|
||||||
|
/* Calculate APIC timer frequency based on ticks passed */
|
||||||
|
Frequency = (InitialCount - CurrentCount) * 100;
|
||||||
|
|
||||||
|
/* Verify APIC timer frequency */
|
||||||
|
if(Frequency == 0)
|
||||||
|
{
|
||||||
|
/* Unable to calibrate APIC timer, return error */
|
||||||
|
return STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Save APIC timer frequency */
|
||||||
|
TimerFrequency = Frequency;
|
||||||
|
|
||||||
|
/* Print APIC timer frequency and return success */
|
||||||
|
DebugPrint(L"APIC Timer calibrated: %u Ticks/s\n", TimerFrequency);
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the APIC timer frequency from the Core Crystal Clock.
|
||||||
|
*
|
||||||
|
* @param Frequency
|
||||||
|
* Supplies a pointer to a variable that will receive the nominal APIC timer frequency in Hz.
|
||||||
|
*
|
||||||
|
* @return This routine returns a status code.
|
||||||
|
*
|
||||||
|
* @since XT 1.0
|
||||||
|
*/
|
||||||
|
XTAPI
|
||||||
|
XTSTATUS
|
||||||
|
HL::Timer::GetApicTimerFrequency(OUT PULONG Frequency)
|
||||||
|
{
|
||||||
|
CPUID_REGISTERS CpuRegisters;
|
||||||
|
|
||||||
|
/* Verify input parameter */
|
||||||
|
if(!Frequency)
|
||||||
|
{
|
||||||
|
/* Invalid parameter passed */
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize output parameter to 0 */
|
||||||
|
*Frequency = 0;
|
||||||
|
|
||||||
|
/* Get maximum supported standard CPUID leaf */
|
||||||
|
CpuRegisters.Leaf = 0;
|
||||||
|
CpuRegisters.SubLeaf = 0;
|
||||||
|
CpuRegisters.Eax = 0;
|
||||||
|
CpuRegisters.Ebx = 0;
|
||||||
|
CpuRegisters.Ecx = 0;
|
||||||
|
CpuRegisters.Edx = 0;
|
||||||
|
AR::CpuFunc::CpuId(&CpuRegisters);
|
||||||
|
|
||||||
|
/* Check if leaf 0x15 is supported by the CPU */
|
||||||
|
if(CpuRegisters.Eax < 0x15)
|
||||||
|
{
|
||||||
|
/* Processor is too old, return error */
|
||||||
|
return STATUS_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Query Time Stamp Counter and Core Crystal Clock information */
|
||||||
|
CpuRegisters.Leaf = 0x15;
|
||||||
|
CpuRegisters.SubLeaf = 0;
|
||||||
|
CpuRegisters.Eax = 0;
|
||||||
|
CpuRegisters.Ebx = 0;
|
||||||
|
CpuRegisters.Ecx = 0;
|
||||||
|
CpuRegisters.Edx = 0;
|
||||||
|
AR::CpuFunc::CpuId(&CpuRegisters);
|
||||||
|
|
||||||
|
/* Check if the leaf is properly enumerated */
|
||||||
|
if(CpuRegisters.Eax == 0 || CpuRegisters.Ebx == 0)
|
||||||
|
{
|
||||||
|
/* Intel SDM: EAX or EBX is 0, the leaf is not properly enumerated, return error */
|
||||||
|
return STATUS_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if ECX contains the nominal frequency of the core crystal clock */
|
||||||
|
if(CpuRegisters.Ecx == 0)
|
||||||
|
{
|
||||||
|
/* Hardware did not provide the exact frequency, return error */
|
||||||
|
return STATUS_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Save the base frequency for the APIC Timer and return success */
|
||||||
|
*Frequency = CpuRegisters.Ecx;
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes and calibrates the Local APIC Timer.
|
||||||
|
*
|
||||||
|
* @return This routine does not return any value.
|
||||||
|
*
|
||||||
|
* @since XT 1.0
|
||||||
|
*/
|
||||||
|
XTAPI
|
||||||
|
VOID
|
||||||
|
HL::Timer::InitializeApicTimer(VOID)
|
||||||
|
{
|
||||||
|
XTSTATUS Status;
|
||||||
|
|
||||||
|
/* Set APIC timer to divide by 1 */
|
||||||
|
HL::Pic::WriteApicRegister(APIC_TDCR, TIMER_DivideBy1);
|
||||||
|
|
||||||
|
/* Calibrate the APIC timer */
|
||||||
|
Status = CalibrateApicTimer();
|
||||||
|
if(Status != STATUS_SUCCESS)
|
||||||
|
{
|
||||||
|
/* System cannot operate without a calibrated system timer, raise kernel panic */
|
||||||
|
KE::Crash::Panic(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the default system profile interval */
|
||||||
|
HL::Timer::SetProfileInterval(1000);
|
||||||
|
|
||||||
|
/* Program the APIC timer for periodic mode */
|
||||||
|
StopProfileInterrupt(ProfileXtKernel);
|
||||||
|
|
||||||
|
// StartProfileInterrupt(ProfileXtKernel);
|
||||||
|
// AR::CpuFunc::SetInterruptFlag();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stalls the CPU execution for a specified duration (maximum 3 seconds) using the legacy PIT timer.
|
||||||
|
*
|
||||||
|
* @param MicroSeconds
|
||||||
|
* Specifies the number of microseconds to stall execution.
|
||||||
|
*
|
||||||
|
* @return This routine does not return any value.
|
||||||
|
*
|
||||||
|
* @since XT 1.0
|
||||||
|
*/
|
||||||
|
XTAPI
|
||||||
|
VOID
|
||||||
|
HL::Timer::PitStallExecution(IN ULONG MicroSeconds)
|
||||||
|
{
|
||||||
|
USHORT CurrentCount, PreviousCount;
|
||||||
|
ULONG TargetTicks, TickCounter;
|
||||||
|
|
||||||
|
/* Validate input parameter */
|
||||||
|
if(MicroSeconds == 0)
|
||||||
|
{
|
||||||
|
/* Nothing to do */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if(MicroSeconds > 3000000)
|
||||||
|
{
|
||||||
|
/* Cap execution stall to 3 seconds */
|
||||||
|
MicroSeconds = 3000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert us to PIT ticks and initialize tick counter */
|
||||||
|
TargetTicks = (MicroSeconds * 1193) / 1000;
|
||||||
|
TickCounter = 0;
|
||||||
|
|
||||||
|
/* Configure PIT Channel 0: Read/Write LSB then MSB, Mode 0 (Interrupt on Terminal Count) */
|
||||||
|
HL::IoPort::WritePort8(PIT_COMMAND_PORT, 0x30);
|
||||||
|
|
||||||
|
/* Initialize the PIT counter with the maximum possible value (0xFFFF) */
|
||||||
|
HL::IoPort::WritePort8(PIT_DATA_PORT0, 0xFF);
|
||||||
|
HL::IoPort::WritePort8(PIT_DATA_PORT0, 0xFF);
|
||||||
|
|
||||||
|
/* Latch and read the initial counter value */
|
||||||
|
HL::IoPort::WritePort8(PIT_COMMAND_PORT, 0x00);
|
||||||
|
PreviousCount = HL::IoPort::ReadPort8(PIT_DATA_PORT0);
|
||||||
|
PreviousCount |= (HL::IoPort::ReadPort8(PIT_DATA_PORT0) << 8);
|
||||||
|
|
||||||
|
/* Poll the PIT */
|
||||||
|
while(TickCounter < TargetTicks)
|
||||||
|
{
|
||||||
|
/* Latch the current counter value without stopping the timer */
|
||||||
|
HL::IoPort::WritePort8(PIT_COMMAND_PORT, 0x00);
|
||||||
|
CurrentCount = HL::IoPort::ReadPort8(PIT_DATA_PORT0);
|
||||||
|
CurrentCount |= (HL::IoPort::ReadPort8(PIT_DATA_PORT0) << 8);
|
||||||
|
|
||||||
|
/* Calculate elapsed ticks since the last read */
|
||||||
|
TickCounter += (PreviousCount - CurrentCount) & 0xFFFF;
|
||||||
|
|
||||||
|
/* Update the tracking variable */
|
||||||
|
PreviousCount = CurrentCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the profile interrupt interval. The interval may be bounded by hardware capabilities.
|
||||||
|
*
|
||||||
|
* @param Interval
|
||||||
|
* Supplies the requested profile interval in 100-nanosecond units.
|
||||||
|
*
|
||||||
|
* @return This routine returns the actual profile interval that was set.
|
||||||
|
*
|
||||||
|
* @since XT 1.0
|
||||||
|
*/
|
||||||
|
XTAPI
|
||||||
|
ULONG_PTR
|
||||||
|
HL::Timer::SetProfileInterval(IN ULONG_PTR Interval)
|
||||||
|
{
|
||||||
|
/* Validate and bound the requested profile interval against hardware limits */
|
||||||
|
if(Interval < MIN_PROFILE_INTERVAL)
|
||||||
|
{
|
||||||
|
/* Enforce the minimum profile interval limit */
|
||||||
|
Interval = MIN_PROFILE_INTERVAL;
|
||||||
|
}
|
||||||
|
else if(Interval > MAX_PROFILE_INTERVAL)
|
||||||
|
{
|
||||||
|
/* Enforce the maximum profile interval limit */
|
||||||
|
Interval = MAX_PROFILE_INTERVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Calculate the number of APIC timer ticks required for the requested interval */
|
||||||
|
ProfilingInterval = (TimerFrequency / 10000) * (Interval / 1000);
|
||||||
|
|
||||||
|
/* Update the APIC Timer Initial Count Register (TICR) to apply the new interval immediately */
|
||||||
|
HL::Pic::WriteApicRegister(APIC_TICR, ProfilingInterval);
|
||||||
|
|
||||||
|
/* Return the actual interval */
|
||||||
|
return Interval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stalls the CPU execution for a specified duration.
|
||||||
|
*
|
||||||
|
* @param MicroSeconds
|
||||||
|
* Supplies the number of microseconds to stall execution.
|
||||||
|
*
|
||||||
|
* @return This routine does not return any value.
|
||||||
|
*
|
||||||
|
* @since XT 1.0
|
||||||
|
*/
|
||||||
|
XTAPI
|
||||||
|
VOID
|
||||||
|
HL::Timer::StallExecution(IN ULONG MicroSeconds)
|
||||||
|
{
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
|
||||||
|
/* ACPI PM Timer not supported, fall back to PIT */
|
||||||
|
PitStallExecution(MicroSeconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables the profile interrupt for the specified profile source.
|
||||||
|
*
|
||||||
|
* @param ProfileSource
|
||||||
|
* Supplies the source of the profile interrupt to start.
|
||||||
|
*
|
||||||
|
* @return This routine does not return any value.
|
||||||
|
*
|
||||||
|
* @since XT 1.0
|
||||||
|
*/
|
||||||
|
XTAPI
|
||||||
|
VOID
|
||||||
|
HL::Timer::StartProfileInterrupt(IN KPROFILE_SOURCE ProfileSource)
|
||||||
|
{
|
||||||
|
APIC_LVT_REGISTER LvtRegister;
|
||||||
|
|
||||||
|
/* Handle only ProfileTime and ProfileXtKernel */
|
||||||
|
if(ProfileSource != ProfileTime && ProfileSource != ProfileXtKernel)
|
||||||
|
{
|
||||||
|
/* Invalid profile source, do nothing */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the interval */
|
||||||
|
HL::Pic::WriteApicRegister(APIC_TICR, ProfilingInterval);
|
||||||
|
|
||||||
|
/* Unmask interrupt */
|
||||||
|
LvtRegister.Long = 0;
|
||||||
|
LvtRegister.Mask = 0;
|
||||||
|
LvtRegister.DeliveryMode = APIC_DM_FIXED;
|
||||||
|
LvtRegister.TimerMode = 1;
|
||||||
|
LvtRegister.TriggerMode = APIC_TGM_EDGE;
|
||||||
|
LvtRegister.Vector = APIC_VECTOR_PROFILE;
|
||||||
|
HL::Pic::WriteApicRegister(APIC_TMRLVTR, LvtRegister.Long);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disables the profile interrupt for the specified profile source.
|
||||||
|
*
|
||||||
|
* @param ProfileSource
|
||||||
|
* Supplies the source of the profile interrupt to stop.
|
||||||
|
*
|
||||||
|
* @return This routine does not return any value.
|
||||||
|
*
|
||||||
|
* @since XT 1.0
|
||||||
|
*/
|
||||||
|
XTAPI
|
||||||
|
VOID
|
||||||
|
HL::Timer::StopProfileInterrupt(IN KPROFILE_SOURCE ProfileSource)
|
||||||
|
{
|
||||||
|
APIC_LVT_REGISTER LvtRegister;
|
||||||
|
|
||||||
|
/* Handle only ProfileTime and ProfileXtKernel */
|
||||||
|
if(ProfileSource != ProfileTime && ProfileSource != ProfileXtKernel)
|
||||||
|
{
|
||||||
|
/* Invalid profile source, do nothing */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mask interrupt */
|
||||||
|
LvtRegister.Long = 0;
|
||||||
|
LvtRegister.Mask = 1;
|
||||||
|
LvtRegister.DeliveryMode = APIC_DM_FIXED;
|
||||||
|
LvtRegister.TimerMode = 1;
|
||||||
|
LvtRegister.TriggerMode = APIC_TGM_EDGE;
|
||||||
|
LvtRegister.Vector = APIC_VECTOR_PROFILE;
|
||||||
|
HL::Pic::WriteApicRegister(APIC_TMRLVTR, LvtRegister.Long);
|
||||||
|
}
|
||||||
@@ -21,6 +21,7 @@
|
|||||||
#include <hl/irq.hh>
|
#include <hl/irq.hh>
|
||||||
#include <hl/pic.hh>
|
#include <hl/pic.hh>
|
||||||
#include <hl/runlevel.hh>
|
#include <hl/runlevel.hh>
|
||||||
|
#include <hl/timer.hh>
|
||||||
|
|
||||||
|
|
||||||
#endif /* __XTOSKRNL_HL_HH */
|
#endif /* __XTOSKRNL_HL_HH */
|
||||||
|
|||||||
38
xtoskrnl/includes/hl/timer.hh
Normal file
38
xtoskrnl/includes/hl/timer.hh
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
/**
|
||||||
|
* PROJECT: ExectOS
|
||||||
|
* COPYRIGHT: See COPYING.md in the top level directory
|
||||||
|
* FILE: xtoskrnl/includes/hl/timer.hh
|
||||||
|
* DESCRIPTION: ACPI Timer support
|
||||||
|
* DEVELOPERS: Aiken Harris <harraiken91@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __XTOSKRNL_HL_TIMER_HH
|
||||||
|
#define __XTOSKRNL_HL_TIMER_HH
|
||||||
|
|
||||||
|
#include <xtos.hh>
|
||||||
|
|
||||||
|
|
||||||
|
/* Hardware Layer */
|
||||||
|
namespace HL
|
||||||
|
{
|
||||||
|
class Timer
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
STATIC ULONG ProfilingInterval;
|
||||||
|
STATIC ULONG TimerFrequency;
|
||||||
|
|
||||||
|
public:
|
||||||
|
STATIC XTAPI VOID InitializeApicTimer(VOID);
|
||||||
|
STATIC XTAPI ULONG_PTR SetProfileInterval(IN ULONG_PTR Interval);
|
||||||
|
STATIC XTAPI VOID StartProfileInterrupt(IN KPROFILE_SOURCE ProfileSource);
|
||||||
|
STATIC XTAPI VOID StopProfileInterrupt(IN KPROFILE_SOURCE ProfileSource);
|
||||||
|
|
||||||
|
private:
|
||||||
|
STATIC XTAPI XTSTATUS CalibrateApicTimer();
|
||||||
|
STATIC XTAPI XTSTATUS GetApicTimerFrequency(OUT PULONG Frequency);
|
||||||
|
STATIC XTAPI VOID PitStallExecution(IN ULONG Us);
|
||||||
|
STATIC XTAPI VOID StallExecution(IN ULONG MicroSeconds);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __XTOSKRNL_HL_TIMER_HH */
|
||||||
Reference in New Issue
Block a user