Ver código fonte

Added support for the ARM Generic Timer.

This change adds the HL hardware module for the ARM Generic Timer. This is
a 64-bit non-periodic, absolute timer. For now, it only exposes the GT's
virtual timer. Future changes could add support for the secure/non-secure
physical timer and the hypervisor mode timer.
Chris Stevens 8 anos atrás
pai
commit
09de0e09b4

+ 73 - 0
include/minoca/fw/acpitabs.h

@@ -34,6 +34,7 @@ Author:
 #define DSDT_SIGNATURE 0x54445344 // 'DSDT'
 #define SSDT_SIGNATURE 0x54445353 // 'SSDT'
 #define DBG2_SIGNATURE 0x32474244 // 'DBG2'
+#define GTDT_SIGNATURE 0x54445447 // 'GTDT'
 
 #define ACPI_20_RSDP_REVISION 0x02
 #define ACPI_30_RSDT_REVISION 0x01
@@ -752,6 +753,26 @@ typedef enum _MADT_ENTRY_TYPE {
 #define ACPI_OSC_INTEL_PSTATE_COLLABORATIVE (1 << 12)
 #define ACPI_OSC_INTEL_HARDWARE_DUTY_CYCLING (1 << 13)
 
+//
+// Define the generic timer global flags.
+//
+
+#define GTDT_GLOBAL_FLAG_MEMORY_MAPPED_BLOCK_PRESENT 0x00000001
+#define GTDT_GLOBAL_FLAG_INTERRUPT_MODE_MASK         0x00000002
+#define GTDT_GLOBAL_FLAG_INTERRUPT_MODE_EDGE         0x00000002
+#define GTDT_GLOBAL_FLAG_INTERRUPT_MODE_LEVEL        0x00000000
+
+//
+// Define the generic timer flags.
+//
+
+#define GTDT_TIMER_FLAG_INTERRUPT_MODE_MASK            0x00000001
+#define GTDT_TIMER_FLAG_INTERRUPT_MODE_EDGE            0x00000001
+#define GTDT_TIMER_FLAG_INTERRUPT_MODE_LEVEL           0x00000000
+#define GTDT_TIMER_FLAG_INTERRUPT_POLARITY_MASK        0x00000002
+#define GTDT_TIMER_FLAG_INTERRUPT_POLARITY_ACTIVE_LOW  0x00000002
+#define GTDT_TIMER_FLAG_INTERRUPT_POLARITY_ACTIVE_HIGH 0x00000000
+
 //
 // ------------------------------------------------------ Data Type Definitions
 //
@@ -1585,6 +1606,58 @@ typedef struct _DEBUG_PORT_16550_OEM_DATA {
     ULONG Flags;
 } PACKED DEBUG_PORT_16550_OEM_DATA, *PDEBUG_PORT_16550_OEM_DATA;
 
+/*++
+
+Structure Description:
+
+    This structure defines the system's Generic Timer information.
+
+Members:
+
+    Header - Stores the table header, including the signature, 'GTDT'.
+
+    CounterBlockAddress - Stores the physical address of the counter block.
+
+    GlobalFlags - Stores a bitmask of global GTDT flags. See GTDT_GLOBAL_FLAG_*
+        for definitions.
+
+    SecurePl1Gsi - Stores the optional GSI of the secure PL1 physical timer.
+        Stores 0 if not provided.
+
+    SecurePl1Flags - Stores a bitmask of timer flags. See GTDT_TIMER_FLAG_* for
+        definitions.
+
+    NonSecurePl1Gsi - Stores the GSI of the non-secure PL1 physical timer.
+
+    NonSecurePl1Flags - Stores a bitmask of timer flags. See GTDT_TIMER_FLAG_*
+        for definitions.
+
+    VirtualTimerGsi - Stores the GSI of the virtual timer.
+
+    VirtualTimerFlags - Stores a bitmask of timer flags. See GTDT_TIMER_FLAG_*
+        for definitions.
+
+    NonSecurePl2Gsi - Stores the GSI of the non-secure PL2 physical timer.
+
+    NonSecurePl2Flags - Stores a bitmask of timer flags. See GTDT_TIMER_FLAG_*
+        for definitions.
+
+--*/
+
+typedef struct _GTDT {
+    DESCRIPTION_HEADER Header;
+    ULONGLONG CounterBlockAddress;
+    ULONG GlobalFlags;
+    ULONG SecurePl1Gsi;
+    ULONG SecurePl1Flags;
+    ULONG NonSecurePl1Gsi;
+    ULONG NonSecurePl1Flags;
+    ULONG VirtualTimerGsi;
+    ULONG VirtualTimerFlags;
+    ULONG NonSecurePl2Gsi;
+    ULONG NonSecurePl2Flags;
+} PACKED GTDT, *PGTDT;
+
 //
 // -------------------------------------------------------------------- Globals
 //

+ 6 - 4
include/minoca/kernel/arm.h

@@ -367,15 +367,17 @@ Author:
 // Define processor features bits.
 //
 
-#define CPUID_PROCESSOR1_SECURITY_EXTENSION_MASK 0x000000F0
-#define CPUID_PROCESSOR1_SECURITY_EXTENSION_UNSUPPORTED 0
+#define CPUID_PROCESSOR1_SECURITY_EXTENSION_MASK        0x000000F0
+#define CPUID_PROCESSOR1_SECURITY_EXTENSION_UNSUPPORTED 0x00000000
+#define CPUID_PROCESSOR1_GENERIC_TIMER_MASK             0x000F0000
+#define CPUID_PROCESSOR1_GENERIC_TIMER_UNSUPPORTED      0x00000000
 
 //
 // Define bits in the ARMv7 Cache Type Register (CTR).
 //
 
-#define ARMV7_CACHE_TYPE_DATA_CACHE_SIZE_MASK 0x000F0000
-#define ARMV7_CACHE_TYPE_DATA_CACHE_SIZE_SHIFT 16
+#define ARMV7_CACHE_TYPE_DATA_CACHE_SIZE_MASK        0x000F0000
+#define ARMV7_CACHE_TYPE_DATA_CACHE_SIZE_SHIFT       16
 #define ARMV7_CACHE_TYPE_INSTRUCTION_CACHE_SIZE_MASK 0x0000000F
 #define ARMV7_CACHE_TYPE_INSTRUCTION_CACHE_TYPE_MASK 0x0000C000
 

+ 2 - 0
kernel/hl/Makefile

@@ -61,6 +61,8 @@ ARMV7_OBJS = armv7/am335int.o \
              armv7/cycsupc.o  \
              armv7/gic.o      \
              armv7/gicid.o    \
+             armv7/gt.o       \
+             armv7/gta.o      \
              armv7/omapintr.o \
              armv7/omap3pwr.o \
              armv7/omap3tmr.o \

+ 7 - 1
kernel/hl/armv7/archtimr.c

@@ -89,6 +89,11 @@ HlpRk32TimerModuleEntry (
     VOID
     );
 
+VOID
+HlpGtModuleEntry (
+    VOID
+    );
+
 //
 // -------------------------------------------------------------------- Globals
 //
@@ -112,7 +117,8 @@ PHARDWARE_MODULE_ENTRY HlBuiltinTimerModules[] = {
     HlpOmap4TimerModuleEntry,
     HlpAm335TimerModuleEntry,
     HlpBcm2709TimerModuleEntry,
-    HlpRk32TimerModuleEntry
+    HlpRk32TimerModuleEntry,
+    HlpGtModuleEntry
 };
 
 //

+ 405 - 0
kernel/hl/armv7/gt.c

@@ -0,0 +1,405 @@
+/*++
+
+Copyright (c) 2016 Minoca Corp. All Rights Reserved
+
+Module Name:
+
+    gt.c
+
+Abstract:
+
+    This module implements timer support for the ARM Generic Timer.
+
+Author:
+
+    Chris Stevens 23-May-2016
+
+Environment:
+
+    Kernel
+
+--*/
+
+//
+// ------------------------------------------------------------------- Includes
+//
+
+//
+// Include kernel.h, but be cautious about which APIs are used. Most of the
+// system depends on the hardware modules. Limit use to HL, RTL and AR routines.
+//
+
+#include <minoca/kernel/kernel.h>
+#include <minoca/kernel/arm.h>
+
+//
+// ---------------------------------------------------------------- Definitions
+//
+
+//
+// Define the GT allocation tag.
+//
+
+#define GT_ALLOCATION_TAG 0x524D5447 //'RMTG'
+
+//
+// Define the bits for a generic timer control register.
+//
+
+#define GT_CONTROL_INTERRUPT_STATUS_ASSERTED 0x00000004
+#define GT_CONTROL_INTERRUPT_MASKED          0x00000002
+#define GT_CONTROL_TIMER_ENABLE              0x00000001
+
+//
+// --------------------------------------------------------------------- Macros
+//
+
+//
+// ----------------------------------------------- Internal Function Prototypes
+//
+
+KSTATUS
+HlpGtInitialize (
+    PVOID Context
+    );
+
+ULONGLONG
+HlpGtRead (
+    PVOID Context
+    );
+
+KSTATUS
+HlpGtArm (
+    PVOID Context,
+    TIMER_MODE Mode,
+    ULONGLONG TickCount
+    );
+
+VOID
+HlpGtDisarm (
+    PVOID Context
+    );
+
+VOID
+HlpGtAcknowledgeInterrupt (
+    PVOID Context
+    );
+
+ULONG
+HlpGtGetFrequency (
+    VOID
+    );
+
+VOID
+HlpGtSetVirtualTimerControl (
+    ULONG Control
+    );
+
+ULONGLONG
+HlpGtGetVirtualCount (
+    VOID
+    );
+
+VOID
+HlpGtSetVirtualTimerCompare (
+    ULONGLONG CompareValue
+    );
+
+//
+// ------------------------------------------------------ Data Type Definitions
+//
+
+//
+// -------------------------------------------------------------------- Globals
+//
+
+//
+// ------------------------------------------------------------------ Functions
+//
+
+VOID
+HlpGtModuleEntry (
+    VOID
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is the entry point for the Integrator/CP timer hardware module.
+    Its role is to detect and report the prescense of an Integrator/CP timer.
+
+Arguments:
+
+    None.
+
+Return Value:
+
+    None.
+
+--*/
+
+{
+
+    ARM_CPUID Cpuid;
+    ULONG Flags;
+    ULONG Frequency;
+    TIMER_DESCRIPTION Gt;
+    PGTDT GtdtTable;
+    KSTATUS Status;
+
+    //
+    // Determine if the ARM Generic Timer is supported based on the processor
+    // features.
+    //
+
+    ArCpuid(&Cpuid);
+    if ((Cpuid.ProcessorFeatures[1] & CPUID_PROCESSOR1_GENERIC_TIMER_MASK) ==
+        CPUID_PROCESSOR1_GENERIC_TIMER_UNSUPPORTED) {
+
+        goto GtModuleEntryEnd;
+    }
+
+    //
+    // Attempt to find an GTDT. If one exists, then the GT is present.
+    //
+
+    GtdtTable = HlGetAcpiTable(GTDT_SIGNATURE, NULL);
+    if (GtdtTable == NULL) {
+        goto GtModuleEntryEnd;
+    }
+
+    RtlZeroMemory(&Gt, sizeof(TIMER_DESCRIPTION));
+    Gt.TableVersion = TIMER_DESCRIPTION_VERSION;
+    Gt.FunctionTable.Initialize = HlpGtInitialize;
+    Gt.FunctionTable.ReadCounter = HlpGtRead;
+    Gt.FunctionTable.Arm = HlpGtArm;
+    Gt.FunctionTable.Disarm = HlpGtDisarm;
+    Gt.FunctionTable.AcknowledgeInterrupt = HlpGtAcknowledgeInterrupt;
+
+    //
+    // Get the frequency from the Generic Timer frequency register. The
+    // firmware should have programmed this correctly.
+    //
+
+    Frequency = HlpGtGetFrequency();
+
+    //
+    // Only use the virtual timer. This could potentially allow for this module
+    // to run on top of a hypervisor. Since this timer uses a compare register
+    // to trigger interrupts, mark it as absolute and one-shot.
+    //
+
+    Gt.Features = TIMER_FEATURE_ABSOLUTE |
+                  TIMER_FEATURE_ONE_SHOT |
+                  TIMER_FEATURE_READABLE |
+                  TIMER_FEATURE_PER_PROCESSOR;
+
+    Gt.CounterBitWidth = 64;
+    Gt.CounterFrequency = Frequency;
+    Gt.Interrupt.Line.Type = InterruptLineControllerSpecified;
+    Gt.Interrupt.Line.U.Local.Controller = 0;
+    Gt.Interrupt.Line.U.Local.Line = GtdtTable->VirtualTimerGsi;
+    Flags = GtdtTable->VirtualTimerFlags;
+    if ((Flags & GTDT_TIMER_FLAG_INTERRUPT_MODE_EDGE) != 0) {
+        Gt.Interrupt.TriggerMode = InterruptModeEdge;
+
+    } else {
+        Gt.Interrupt.TriggerMode = InterruptModeLevel;
+    }
+
+    if ((Flags & GTDT_TIMER_FLAG_INTERRUPT_POLARITY_ACTIVE_LOW) != 0) {
+        Gt.Interrupt.ActiveLevel = InterruptActiveLow;
+
+    } else {
+        Gt.Interrupt.ActiveLevel = InterruptActiveHigh;
+    }
+
+    Status = HlRegisterHardware(HardwareModuleTimer, &Gt);
+    if (!KSUCCESS(Status)) {
+        goto GtModuleEntryEnd;
+    }
+
+GtModuleEntryEnd:
+    return;
+}
+
+//
+// --------------------------------------------------------- Internal Functions
+//
+
+KSTATUS
+HlpGtInitialize (
+    PVOID Context
+    )
+
+/*++
+
+Routine Description:
+
+    This routine initializes an ARM Generic Timer.
+
+Arguments:
+
+    Context - Supplies the pointer to the timer's context, provided by the
+        hardware module upon initialization.
+
+Return Value:
+
+    Status code.
+
+--*/
+
+{
+
+    //
+    // The timer is already running, just make sure interrupts are off.
+    //
+
+    HlpGtSetVirtualTimerControl(0);
+    return STATUS_SUCCESS;
+}
+
+ULONGLONG
+HlpGtRead (
+    PVOID Context
+    )
+
+/*++
+
+Routine Description:
+
+    This routine returns the hardware counter's raw value.
+
+Arguments:
+
+    Context - Supplies the pointer to the timer's context.
+
+Return Value:
+
+    Returns the timer's current count.
+
+--*/
+
+{
+
+    return HlpGtGetVirtualCount();
+}
+
+KSTATUS
+HlpGtArm (
+    PVOID Context,
+    TIMER_MODE Mode,
+    ULONGLONG TickCount
+    )
+
+/*++
+
+Routine Description:
+
+    This routine arms the timer to fire an interrupt after the specified number
+    of ticks.
+
+Arguments:
+
+    Context - Supplies the pointer to the timer's context, provided by the
+        hardware module upon initialization.
+
+    Mode - Supplies the mode to arm the timer in (periodic or one-shot). The
+        system will never request a mode not supported by the timer's feature
+        bits.
+
+    TickCount - Supplies the number of timer ticks from now for the timer to
+        fire in. In absolute mode, this supplies the time in timer ticks at
+        which to fire an interrupt.
+
+Return Value:
+
+    STATUS_SUCCESS always.
+
+--*/
+
+{
+
+    if (Mode == TimerModePeriodic) {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    //
+    // The tick count is relative in one shot mode, but the GT can only be
+    // armed with an absolute time. Add the current time.
+    //
+
+    if (Mode == TimerModeOneShot) {
+        TickCount += HlpGtGetVirtualCount();
+    }
+
+    HlpGtSetVirtualTimerCompare(TickCount);
+    HlpGtSetVirtualTimerControl(GT_CONTROL_TIMER_ENABLE);
+    return STATUS_SUCCESS;
+}
+
+VOID
+HlpGtDisarm (
+    PVOID Context
+    )
+
+/*++
+
+Routine Description:
+
+    This routine disarms the timer, stopping interrupts from firing.
+
+Arguments:
+
+    Context - Supplies the pointer to the timer's context, provided by the
+        hardware module upon initialization.
+
+Return Value:
+
+    None.
+
+--*/
+
+{
+
+    HlpGtSetVirtualTimerControl(0);
+    return;
+}
+
+VOID
+HlpGtAcknowledgeInterrupt (
+    PVOID Context
+    )
+
+/*++
+
+Routine Description:
+
+    This routine performs any actions necessary upon reciept of a timer's
+    interrupt. This may involve writing to an acknowledge register to re-enable
+    the timer to fire again, or other hardware specific actions.
+
+Arguments:
+
+    Context - Supplies the pointer to the timer's context, provided by the
+        hardware module upon initialization.
+
+Return Value:
+
+    None.
+
+--*/
+
+{
+
+    //
+    // The only way to stop an interrupt from continuing to fire is to either
+    // reprogram the compare register or to disable the interrupt. As the timer
+    // must await further instruction, disable the interrupt.
+    //
+
+    HlpGtSetVirtualTimerControl(0);
+    return;
+}
+

+ 159 - 0
kernel/hl/armv7/gta.S

@@ -0,0 +1,159 @@
+/*++
+
+Copyright (c) 2016 Minoca Corp. All Rights Reserved
+
+Module Name:
+
+    gta.S
+
+Abstract:
+
+    This module implements support for accessing ARM Generic Timer registers.
+
+Author:
+
+    Chris Stevens 23-May-2016
+
+Environment:
+
+    Kernel mode
+
+--*/
+
+##
+## ------------------------------------------------------------------ Includes
+##
+
+#include <minoca/kernel/arm.inc>
+
+##
+## --------------------------------------------------------------- Definitions
+##
+
+##
+## ---------------------------------------------------------------------- Code
+##
+
+ASSEMBLY_FILE_HEADER
+
+##
+## ULONG
+## HlpGtGetFrequency (
+##     VOID
+##     )
+##
+
+/*++
+
+Routine Description:
+
+    This routine retrieves the CNTFRQ register.
+
+Arguments:
+
+    None.
+
+Return Value:
+
+    Returns the value of the CNTFRQ.
+
+--*/
+
+FUNCTION HlpGtGetFrequency
+    mrc     p15, 0, %r0, %c14, %c0, 0          @ Get the CNTFRQ
+    bx      %lr                                @
+
+END_FUNCTION HlpGtGetFrequency
+
+##
+## VOID
+## HlpGtSetVirtualTimerControl (
+##     ULONG Control
+##     )
+##
+
+/*++
+
+Routine Description:
+
+    This routine sets the CNTV_CTL register.
+
+Arguments:
+
+    Control - Supplies the control value to set in the CNTV_CTL.
+
+Return Value:
+
+    None.
+
+--*/
+
+FUNCTION HlpGtSetVirtualTimerControl
+    mcr     p15, 0, %r0, %c14, %c3, 1          @ Set the CNTV_CTL
+    bx      %lr                                @
+
+END_FUNCTION HlpGtSetVirtualTimerControl
+
+##
+## ULONGLONG
+## HlpGtGetVirtualCount (
+##     VOID
+##     )
+##
+
+/*++
+
+Routine Description:
+
+    This routine retrieves the CNTVCT register.
+
+Arguments:
+
+    None.
+
+Return Value:
+
+    Returns the value of the CNTVCT.
+
+--*/
+
+FUNCTION HlpGtGetVirtualCount
+    mrrc    p15, 1, %r0, %r1, %c14             @ Get the CNTVCT
+    bx      %lr                                @
+
+END_FUNCTION HlpGtGetVirtualCount
+
+##
+## VOID
+## HlpGtSetVirtualTimerCompare (
+##     ULONGLONG CompareValue
+##     )
+##
+
+/*++
+
+Routine Description:
+
+    This routine retrieves the CNTV_CVAL register.
+
+Arguments:
+
+    CompareValue - Supplies the compare value to set in the CNTV_CVAL register.
+
+Return Value:
+
+    None.
+
+--*/
+
+FUNCTION HlpGtSetVirtualTimerCompare
+    mcrr    p15, 3, %r0, %r1, %c14             @ Set the CNTV_CVAL
+    bx      %lr                                @
+
+END_FUNCTION HlpGtSetVirtualTimerCompare
+
+##
+## --------------------------------------------------------- Internal Functions
+##
+
+

+ 2 - 0
kernel/hl/build.ck

@@ -69,6 +69,8 @@ function build() {
             "armv7/cycsupc.c",
             "armv7/gic.c",
             "armv7/gicid.S",
+            "armv7/gt.c",
+            "armv7/gta.S",
             "armv7/omapintr.c",
             "armv7/omap3pwr.c",
             "armv7/omap3tmr.c",