[haiku-gsoc] Re: New timer patch (again) (Was: Re: First timer.diff (from private e-mails))

  • From: "Dustin Howett" <alaricx@xxxxxxxxx>
  • To: haiku-gsoc@xxxxxxxxxxxxx
  • Date: Fri, 27 Jun 2008 18:18:26 -0400

New version with more fixes from Axel's suggestions, a lot of which
can be credited to Stefano.
I reworked the priority/init system.. prio is now -1 until
initialized, set by the module when it's initialized, and the timer
loading code treats -1 as non-initialized. This introduces another
function into the structure, but removes the initialized bool, so it
can be const.

On Thu, Jun 26, 2008 at 8:29 AM, Stefano Ceccherini
<stefano.ceccherini@xxxxxxxxx> wrote:
> 2008/6/25 Axel Dörfler <axeld@xxxxxxxxxxxxxxxx>:
>
>> I still have a few comments mostly on the coding style, and I would
>> like to see them resolved before applying the patch:
>
> The final word is yours, of course.
>
>



-- 

- DH
Index: src/system/kernel/arch/x86/arch_timer.c
===================================================================
--- src/system/kernel/arch/x86/arch_timer.c     (revision 26138)
+++ src/system/kernel/arch/x86/arch_timer.c     (working copy)
@@ -32,82 +32,80 @@
 #      define TRACE(x) ;
 #endif
 
+extern timer_info gPITTimer;
+extern timer_info gAPICTimer;
+extern timer_info gHPETTimer;
 
-#define PIT_CLOCK_RATE 1193180
-#define PIT_MAX_TIMER_INTERVAL (0xffff * 1000000ll / PIT_CLOCK_RATE)
+static timer_info *sTimers[] = {
+       &gPITTimer,
+       &gAPICTimer,
+       &gHPETTimer,
+       NULL
+};
 
+static timer_info *sBestTimer = NULL;
 
-static void
-set_isa_hardware_timer(bigtime_t relative_timeout)
-{
-       uint16 next_event_clocks;
-
-       if (relative_timeout <= 0)
-               next_event_clocks = 2;                  
-       else if (relative_timeout < PIT_MAX_TIMER_INTERVAL)
-               next_event_clocks = relative_timeout * PIT_CLOCK_RATE / 1000000;
-       else
-               next_event_clocks = 0xffff;
-
-       out8(0x30, 0x43);               
-       out8(next_event_clocks & 0xff, 0x40);
-       out8((next_event_clocks >> 8) & 0xff, 0x40);
-
-       arch_int_enable_io_interrupt(0);
-}
-
-
-static void
-clear_isa_hardware_timer(void)
-{
-       // mask out the timer
-       arch_int_disable_io_interrupt(0);
-}
-
-
-static int32
-isa_timer_interrupt(void *data)
-{
-       return timer_interrupt();
-}
-
-
-int
-apic_timer_interrupt(void)
-{
-       return timer_interrupt();
-}
-
-
 void
 arch_timer_set_hardware_timer(bigtime_t timeout)
 {
-       TRACE(("arch_timer_set_hardware_timer: timeout %lld\n", timeout));
-       // try the apic timer first
-       if (arch_smp_set_apic_timer(timeout) != B_OK)
-               set_isa_hardware_timer(timeout);
+//     TRACE(("arch_timer_set_hardware_timer: timeout %lld\n", timeout));
+       if(sBestTimer != NULL)
+               sBestTimer->set_hardware_timer(timeout);
 }
 
 
 void
 arch_timer_clear_hardware_timer(void)
 {
-       TRACE(("arch_timer_clear_hardware_timer\n"));
-       if (arch_smp_clear_apic_timer() != B_OK)
-               clear_isa_hardware_timer();
+//     TRACE(("arch_timer_clear_hardware_timer\n"));
+       if(sBestTimer != NULL)
+               sBestTimer->clear_hardware_timer();
 }
 
 
 int
 arch_init_timer(kernel_args *args)
 {
-       //dprintf("arch_init_timer: entry\n");
+       int i = 0;
+       int currentPriority = -1;
+       int timerPriority = -1; // Priority of the timer we're checking.
+                               // Does gcc2 allow mixed declarations?
+       timer_info *timer = NULL;
+       cpu_status state = disable_interrupts();
 
-       install_io_interrupt_handler(0, &isa_timer_interrupt, NULL, 0);
-       clear_isa_hardware_timer();
+       for (i = 0; (timer = sTimers[i]) != NULL; i++) {
+               timerPriority = timer->get_priority();
+               if (timerPriority == -1) {
+                       TRACE(("arch_init_timer: %s was not initialized. 
Attempting.\n", timer->name));
+                       if (timer->init(args, 1) != B_OK) {
+                               TRACE(("arch_init_timer: %s would not 
initialize. Skipping.\n", timer->name));
+                               continue;
+                       }
+               }
 
-       // apic timer interrupt set up by smp code
+               if (timerPriority == -1) {
+                       TRACE(("arch_init_timer: %s still not valid but didn't 
fail init..\n", timer->name));
+                       continue;
+               }
 
+               if (timerPriority > currentPriority) {
+                       currentPriority = timerPriority;
+                       sBestTimer = timer;
+                       TRACE(("arch_init_timer: %s is now best timer module 
with prio %d.\n", timer->name, currentPriority));
+               }
+       }
+
+       if (sBestTimer != NULL) {
+               dprintf("arch_init_timer: using %s timer.\n", sBestTimer->name);
+       } else {
+               dprintf("arch_init_timer: No timers were found to be 
usable.\n");
+               // TODO: panic() ? I don't think we can do much without timers,
+               // and panicking here would have the advantage that we wouldn't
+               // have to check for sBestTimer != NULL in the functions above.
+       }
+
+       restore_interrupts(state);
+
        return 0;
 }
 
Index: src/system/kernel/arch/x86/timers/pit.h
===================================================================
--- src/system/kernel/arch/x86/timers/pit.h     (revision 0)
+++ src/system/kernel/arch/x86/timers/pit.h     (revision 0)
@@ -0,0 +1,16 @@
+/*
+ * Copyright 2008, Dustin Howett, dustin.howett@xxxxxxxxxx All rights reserved.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _KERNEL_ARCH_x86_TIMERS_PIT_H
+#define _KERNEL_ARCH_x86_TIMERS_PIT_H
+
+#include <SupportDefs.h>
+
+/* Method Prototypes */
+static int pit_get_prio();
+static status_t pit_set_hardware_timer(bigtime_t relativeTimeout);
+static status_t pit_clear_hardware_timer(void);
+static status_t pit_init(struct kernel_args *args, int32 data);
+
+#endif /* _KERNEL_ARCH_x86_TIMERS_PIT_H */
Index: src/system/kernel/arch/x86/timers/x86_pit.c
===================================================================
--- src/system/kernel/arch/x86/timers/x86_pit.c (revision 0)
+++ src/system/kernel/arch/x86/timers/x86_pit.c (revision 0)
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2008, Dustin Howett, dustin.howett@xxxxxxxxxx All rights reserved.
+ * Copyright 2005, Axel Dörfler, axeld@xxxxxxxxxxxxxxxxx All rights reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Copyright 2001, Travis Geiselbrecht. All rights reserved.
+ * Distributed under the terms of the NewOS License.
+ */
+
+#include <timer.h>
+#include <arch/x86/timer.h>
+
+#include <arch/int.h>
+#include <arch/cpu.h>
+
+#include "pit.h"
+
+#define PIT_CLOCK_RATE 1193180
+#define PIT_MAX_TIMER_INTERVAL (0xffff * 1000000ll / PIT_CLOCK_RATE)
+
+static bool sPITTimerIsValid = false;
+static int sPriority = -1;
+
+struct timer_info gPITTimer = {
+       "PIT",
+       &pit_get_prio,
+       &pit_set_hardware_timer,
+       &pit_clear_hardware_timer,
+       &pit_init,
+       NULL,
+};
+
+
+static int
+pit_get_prio() {
+       return sPriority;
+}
+
+static int32
+pit_timer_interrupt(void *data)
+{
+       return timer_interrupt();
+}
+
+
+static status_t
+pit_set_hardware_timer(bigtime_t relativeTimeout)
+{
+       uint16 nextEventClocks;
+
+       if (relativeTimeout <= 0)
+               nextEventClocks = 2;
+       else if (relativeTimeout < PIT_MAX_TIMER_INTERVAL)
+               nextEventClocks = relativeTimeout * PIT_CLOCK_RATE / 1000000;
+       else
+               nextEventClocks = 0xffff;
+
+       out8(0x30, 0x43);
+       out8(nextEventClocks & 0xff, 0x40);
+       out8((nextEventClocks >> 8) & 0xff, 0x40);
+
+       arch_int_enable_io_interrupt(0);
+       return B_OK;
+}
+
+
+static status_t
+pit_clear_hardware_timer()
+{
+       arch_int_disable_io_interrupt(0);
+       return B_OK;
+}
+
+
+static status_t
+pit_init(struct kernel_args *args, int32 data)
+{
+       install_io_interrupt_handler(0, &pit_timer_interrupt, NULL, 0);
+       pit_clear_hardware_timer();
+
+       sPriority = 1; // Make sure the prio isn't -1, we have initialized.
+       return B_OK;
+}
Index: src/system/kernel/arch/x86/timers/apic.h
===================================================================
--- src/system/kernel/arch/x86/timers/apic.h    (revision 0)
+++ src/system/kernel/arch/x86/timers/apic.h    (revision 0)
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2008, Dustin Howett, dustin.howett@xxxxxxxxxx All rights reserved.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _KERNEL_ARCH_x86_TIMERS_APIC_H
+#define _KERNEL_ARCH_x86_TIMERS_APIC_H
+
+#include <SupportDefs.h>
+
+/* Method Prototypes */
+static int apic_get_prio();
+static status_t apic_set_hardware_timer(bigtime_t relativeTimeout);
+static status_t apic_clear_hardware_timer(void);
+static status_t apic_init(struct kernel_args *args, int32 data);
+static void apic_preinit(struct kernel_args *args);
+
+#endif /* _KERNEL_ARCH_x86_TIMERS_APIC_H */
Index: src/system/kernel/arch/x86/timers/x86_apic.c
===================================================================
--- src/system/kernel/arch/x86/timers/x86_apic.c        (revision 0)
+++ src/system/kernel/arch/x86/timers/x86_apic.c        (revision 0)
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2008, Dustin Howett, dustin.howett@xxxxxxxxxx All rights reserved.
+ * Copyright 2002-2005, Axel Dörfler, axeld@xxxxxxxxxxxxxxxxx All rights 
reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
+ * Distributed under the terms of the NewOS License.
+ */
+
+#include <timer.h>
+#include <arch/x86/timer.h>
+
+#include <int.h>
+#include <arch/x86/smp_apic.h>
+
+#include <arch/cpu.h>
+#include <arch/smp.h>
+
+#include "apic.h"
+
+static void *sApicPtr = NULL;
+static uint32 sApicTicsPerSec = 0;
+static int sPriority = -1;
+
+struct timer_info gAPICTimer = {
+       "APIC",
+       &apic_get_prio,
+       &apic_set_hardware_timer,
+       &apic_clear_hardware_timer,
+       &apic_init,
+       &apic_preinit,
+};
+
+
+static int
+apic_get_prio()
+{
+       return sPriority;
+}
+
+
+static uint32
+_apic_read(uint32 offset)
+{
+       return *(volatile uint32 *)((char *)sApicPtr + offset);
+}
+
+
+static void
+_apic_write(uint32 offset, uint32 data)
+{
+       *(volatile uint32 *)((char *)sApicPtr + offset) = data;
+}
+
+
+static void
+_apic_ack_interrupt(void)
+{
+       _apic_write(APIC_EOI, 0);
+}
+
+
+static int32
+apic_timer_interrupt()
+{
+       _apic_ack_interrupt();
+       return timer_interrupt();
+}
+
+
+#define MIN_TIMEOUT 1000
+
+static status_t
+apic_set_hardware_timer(bigtime_t relativeTimeout)
+{
+       cpu_status state;
+       uint32 config;
+       uint32 ticks;
+
+       if (sApicPtr == NULL)
+               return B_ERROR;
+
+       if (relativeTimeout < MIN_TIMEOUT)
+               relativeTimeout = MIN_TIMEOUT;
+
+       // calculation should be ok, since it's going to be 64-bit
+       ticks = ((relativeTimeout * sApicTicsPerSec) / 1000000);
+
+       state = disable_interrupts();
+
+       config = _apic_read(APIC_LVT_TIMER) | APIC_LVT_MASKED; // mask the timer
+       _apic_write(APIC_LVT_TIMER, config);
+
+       _apic_write(APIC_INITIAL_TIMER_COUNT, 0); // zero out the timer
+
+       config = _apic_read(APIC_LVT_TIMER) & ~APIC_LVT_MASKED; // unmask the 
timer
+       _apic_write(APIC_LVT_TIMER, config);
+
+       //TRACE_TIMER(("arch_smp_set_apic_timer: config 0x%lx, timeout %Ld, 
tics/sec %lu, tics %lu\n",
+       //      config, relativeTimeout, sApicTicsPerSec, ticks));
+
+       _apic_write(APIC_INITIAL_TIMER_COUNT, ticks); // start it up
+
+       restore_interrupts(state);
+
+       return B_OK;
+}
+
+
+static status_t
+apic_clear_hardware_timer()
+{
+       cpu_status state;
+       uint32 config;
+
+       if (sApicPtr == NULL)
+               return B_ERROR;
+
+       state = disable_interrupts();
+
+       config = _apic_read(APIC_LVT_TIMER) | APIC_LVT_MASKED; // mask the timer
+       _apic_write(APIC_LVT_TIMER, config);
+
+       _apic_write(APIC_INITIAL_TIMER_COUNT, 0); // zero out the timer
+
+       restore_interrupts(state);
+       return B_OK;
+}
+
+
+static status_t
+apic_init(struct kernel_args *args, int32 data)
+{
+       uint32 config;
+
+       if (sApicPtr == NULL) {
+               sPriority = -1; // Set the priority to -1 to mark invalidity.
+               return B_ERROR;
+       }
+
+       /* setup timer */
+       config = _apic_read(APIC_LVT_TIMER) & APIC_LVT_TIMER_MASK;
+       config |= 0xfb | APIC_LVT_MASKED; // vector 0xfb, timer masked
+       _apic_write(APIC_LVT_TIMER, config);
+
+       _apic_write(APIC_INITIAL_TIMER_COUNT, 0); // zero out the clock
+
+       config = _apic_read(APIC_TIMER_DIVIDE_CONFIG) & 0xfffffff0;
+       config |= APIC_TIMER_DIVIDE_CONFIG_1; // clock division by 1
+       _apic_write(APIC_TIMER_DIVIDE_CONFIG, config);
+
+       sPriority = 2; // Set the timer priority because we've initialized.
+       return B_OK;
+}
+
+
+static void
+apic_preinit(struct kernel_args *args)
+{
+       sApicPtr = (void *)args->arch_args.apic;
+       sApicTicsPerSec = args->arch_args.apic_time_cv_factor;
+
+       install_io_interrupt_handler(0xfb - ARCH_INTERRUPT_BASE, 
&apic_timer_interrupt, NULL, B_NO_LOCK_VECTOR);
+}
Index: src/system/kernel/arch/x86/timers/hpet.h
===================================================================
--- src/system/kernel/arch/x86/timers/hpet.h    (revision 0)
+++ src/system/kernel/arch/x86/timers/hpet.h    (revision 0)
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2008, Dustin Howett, dustin.howett@xxxxxxxxxx All rights reserved.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _KERNEL_ARCH_x86_TIMERS_HPET_H
+#define _KERNEL_ARCH_x86_TIMERS_HPET_H
+
+#include <SupportDefs.h>
+
+/* All masks are 64 bits wide to represent bit locations;
+   the HPET registers are 64 bits wide. */
+
+/* Global Capability Register Masks */
+#define HPET_CAP_MASK_ID                       0x00000000000000FF
+#define HPET_CAP_MASK_NUMTIMERS                        0x0000000000001F00
+#define HPET_CAP_MASK_WIDTH                    0x0000000000002000
+#define HPET_CAP_MASK_LEGACY                   0x0000000000008000
+#define HPET_CAP_MASK_VENDOR_ID                        0x00000000FFFF0000
+#define HPET_CAP_MASK_PERIOD                   0xFFFFFFFF00000000
+
+/* Convenience macros for Capability masks */
+#define HPET_GET_ID(regs)              ((regs)->caps & HPET_CAP_MASK_ID)
+#define HPET_GET_NUM_TIMERS(regs)      (((regs)->caps & 
HPET_CAP_MASK_NUMTIMERS) >> 8)
+#define HPET_IS_64BIT_CAPABLE(regs)    (((regs)->caps & HPET_CAP_MASK_WIDTH) 
>> 13)
+#define HPET_IS_LEGACY_CAPABLE(regs)   (((regs)->caps & HPET_CAP_MASK_LEGACY) 
>> 15)
+#define HPET_GET_VENDOR_ID(regs)       (((regs)->caps & 
HPET_CAP_MASK_VENDOR_ID) >> 16)
+#define HPET_GET_PERIOD(regs)          (((regs)->caps & HPET_CAP_MASK_PERIOD) 
>> 32)
+
+/* Global Configuration Masks */
+#define HPET_CONF_MASK_ENABLED                 0x0000000000000001
+#define HPET_CONF_MASK_LEGACY                  0x0000000000000002
+
+/* Convenience macros for Config masks */
+#define HPET_IS_ENABLED(regs)          ((regs)->config & 
HPET_CONF_MASK_ENABLED)
+#define HPET_IS_LEGACY(regs)           (((regs)->config & 
HPET_CONF_MASK_LEGACY) >> 1)
+
+struct hpet_timer {
+       uint64 config;                  /* Timer configuration and capabilities 
*/
+       uint64 comparator;              /* Comparator value */
+       uint64 introute;                /* FSB Interrupt Routing */
+       uint64 reserved;
+};
+
+
+struct hpet_regs {
+       uint64 caps;                    /* HPET Capabilities and ID */
+       uint64 reserved1;
+       uint64 config;                  /* General Configuration */
+       uint64 reserved2;
+       uint64 intstatus;               /* General Interrupt Status */
+       uint8 reserved3[200];
+       uint64 mainvalue;               /* Main Counter Value */
+       uint64 reserved4;
+       struct hpet_timer timers[1];    /* Timers */
+};
+
+/* Method prototypes */
+static int hpet_get_prio();
+static status_t hpet_set_hardware_timer(bigtime_t relativeTimeout);
+static status_t hpet_clear_hardware_timer();
+static status_t hpet_init(struct kernel_args *args, int32 data);
+
+#endif /* _KERNEL_ARCH_x86_TIMERS_HPET_H */
Index: src/system/kernel/arch/x86/timers/x86_hpet.c
===================================================================
--- src/system/kernel/arch/x86/timers/x86_hpet.c        (revision 0)
+++ src/system/kernel/arch/x86/timers/x86_hpet.c        (revision 0)
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2008, Dustin Howett, dustin.howett@xxxxxxxxxx All rights reserved.
+ * Distributed under the terms of the MIT License.
+ */
+
+#include <timer.h>
+#include <arch/x86/timer.h>
+
+#include "hpet.h"
+
+static int32 sHPETAddr;
+static struct hpet_regs *sHPETRegs;
+static int sPriority = -1;
+
+struct timer_info gHPETTimer = {
+       "HPET",
+       &hpet_get_prio,
+       &hpet_set_hardware_timer,
+       &hpet_clear_hardware_timer,
+       &hpet_init,
+       NULL
+};
+
+
+static int
+hpet_get_prio() {
+       return sPriority;
+}
+
+
+// TODO: Implement something similar to smp_acpi_probe from boot/.../smp.cpp-
+//     we need to get the hpet base address without talking to the acpi module,
+//     because there's no guarantee that it's actually present at this early 
point.
+
+static int
+hpet_set_enabled(struct hpet_regs *regs, bool enabled)
+{
+       if (enabled)
+               regs->config |= HPET_CONF_MASK_ENABLED;
+       else
+               regs->config &= ~HPET_CONF_MASK_ENABLED;
+       return B_OK;
+}
+
+
+static int
+hpet_set_legacy(struct hpet_regs *regs, bool enabled)
+{
+       if (!HPET_IS_LEGACY_CAPABLE(regs))
+               return B_NOT_SUPPORTED;
+
+       if (enabled)
+               regs->config |= HPET_CONF_MASK_LEGACY;
+       else
+               regs->config &= ~HPET_CONF_MASK_LEGACY;
+       return B_OK;
+}
+
+
+static int32
+hpet_timer_interrupt()
+{
+       return timer_interrupt();
+}
+
+
+static status_t
+hpet_set_hardware_timer(bigtime_t relative_timeout)
+{
+       return B_ERROR;
+}
+
+
+static status_t
+hpet_clear_hardware_timer()
+{
+       return B_ERROR;
+}
+
+
+static status_t
+hpet_init(struct kernel_args *args, int32 data)
+{
+       // hpet_acpi_probe() through a similar "scan spots" table to that of 
smp.cpp.
+       // Seems to be the most elegant solution right now.
+
+       // If we successfully initialize, we should set the priority to 3.
+
+       sPriority = -1; // -1 prio = invalid
+       return B_ERROR;
+}
Index: src/system/kernel/arch/x86/Jamfile
===================================================================
--- src/system/kernel/arch/x86/Jamfile  (revision 26138)
+++ src/system/kernel/arch/x86/Jamfile  (working copy)
@@ -4,11 +4,14 @@
        # for syscall_numbers.h
 SubDirHdrs $(HAIKU_TOP) src add-ons kernel bus_managers ps2 ;
 SubDirHdrs $(SUBDIR) $(DOTDOT) generic ;
+SubDirHdrs $(SUBDIR) timers ;
 
 UsePrivateKernelHeaders ;
 
 SEARCH_SOURCE += [ FDirName $(SUBDIR) $(DOTDOT) generic ] ;
 
+SEARCH_SOURCE += [ FDirName $(SUBDIR) timers ] ;
+
 KernelMergeObject kernel_arch_x86.o :
        arch_commpage.cpp
        arch_cpu.c
@@ -35,6 +38,10 @@
        cpuid.S
        syscall.S
        vm86.cpp
+       
+       x86_pit.c
+       x86_apic.c
+       x86_hpet.c
 
        generic_vm_physical_page_mapper.cpp
        :
Index: src/system/kernel/arch/x86/arch_smp.c
===================================================================
--- src/system/kernel/arch/x86/arch_smp.c       (revision 26138)
+++ src/system/kernel/arch/x86/arch_smp.c       (working copy)
@@ -17,6 +17,8 @@
 #include <arch/vm.h>
 #include <arch/smp.h>
 
+#include <timer.h>
+
 #include <arch/x86/smp_priv.h>
 #include <arch/x86/smp_apic.h>
 #include <arch/x86/timer.h>
@@ -39,25 +41,15 @@
 #      define TRACE_TIMER(x) ;
 #endif
 
+extern timer_info gAPICTimer;
 
 static void *apic = NULL;
 static uint32 cpu_apic_id[B_MAX_CPU_COUNT] = {0, 0};
 static uint32 cpu_os_id[B_MAX_CPU_COUNT] = {0, 0};
 static uint32 cpu_apic_version[B_MAX_CPU_COUNT] = {0, 0};
 static void *ioapic = NULL;
-static uint32 apic_timer_tics_per_sec = 0;
 
-
 static int32
-i386_timer_interrupt(void *data)
-{
-       arch_smp_ack_interrupt();
-
-       return apic_timer_interrupt();
-}
-
-
-static int32
 i386_ici_interrupt(void *data)
 {
        // genuine inter-cpu interrupt
@@ -147,17 +139,8 @@
        }
 #endif
 
-       /* setup timer */
-       config = apic_read(APIC_LVT_TIMER) & APIC_LVT_TIMER_MASK;
-       config |= 0xfb | APIC_LVT_MASKED; // vector 0xfb, timer masked
-       apic_write(APIC_LVT_TIMER, config);
+       gAPICTimer.init(args, cpu);
 
-       apic_write(APIC_INITIAL_TIMER_COUNT, 0); // zero out the clock
-
-       config = apic_read(APIC_TIMER_DIVIDE_CONFIG) & 0xfffffff0;
-       config |= APIC_TIMER_DIVIDE_CONFIG_1; // clock division by 1
-       apic_write(APIC_TIMER_DIVIDE_CONFIG, config);
-
        /* setup error vector to 0xfe */
        config = (apic_read(APIC_LVT_ERROR) & 0xffffff00) | 0xfe;
        apic_write(APIC_LVT_ERROR, config);
@@ -185,7 +168,6 @@
                memcpy(cpu_apic_id, args->arch_args.cpu_apic_id, 
sizeof(args->arch_args.cpu_apic_id));
                memcpy(cpu_os_id, args->arch_args.cpu_os_id, 
sizeof(args->arch_args.cpu_os_id));
                memcpy(cpu_apic_version, args->arch_args.cpu_apic_version, 
sizeof(args->arch_args.cpu_apic_version));
-               apic_timer_tics_per_sec = args->arch_args.apic_time_cv_factor;
 
                // setup regions that represent the apic & ioapic
                map_physical_memory("local apic", (void 
*)args->arch_args.apic_phys, B_PAGE_SIZE,
@@ -193,11 +175,12 @@
                map_physical_memory("ioapic", (void 
*)args->arch_args.ioapic_phys, B_PAGE_SIZE,
                        B_EXACT_ADDRESS, B_KERNEL_READ_AREA | 
B_KERNEL_WRITE_AREA, &ioapic);
 
+               gAPICTimer.preinit(args);
+
                // set up the local apic on the boot cpu
                arch_smp_per_cpu_init(args, 0);
 
                // I/O interrupts start at ARCH_INTERRUPT_BASE, so all 
interrupts are shifted
-               install_io_interrupt_handler(0xfb - ARCH_INTERRUPT_BASE, 
&i386_timer_interrupt, NULL, B_NO_LOCK_VECTOR);
                install_io_interrupt_handler(0xfd - ARCH_INTERRUPT_BASE, 
&i386_ici_interrupt, NULL, B_NO_LOCK_VECTOR);
                install_io_interrupt_handler(0xfe - ARCH_INTERRUPT_BASE, 
&i386_smp_error_interrupt, NULL, B_NO_LOCK_VECTOR);
                install_io_interrupt_handler(0xff - ARCH_INTERRUPT_BASE, 
&i386_spurious_interrupt, NULL, B_NO_LOCK_VECTOR);
@@ -268,63 +251,3 @@
 {
        apic_write(APIC_EOI, 0);
 }
-
-#define MIN_TIMEOUT 1000
-
-status_t
-arch_smp_set_apic_timer(bigtime_t relativeTimeout)
-{
-       cpu_status state;
-       uint32 config;
-       uint32 ticks;
-
-       if (apic == NULL)
-               return B_ERROR;
-
-       if (relativeTimeout < MIN_TIMEOUT)
-               relativeTimeout = MIN_TIMEOUT;
-
-       // calculation should be ok, since it's going to be 64-bit
-       ticks = ((relativeTimeout * apic_timer_tics_per_sec) / 1000000);
-
-       state = disable_interrupts();
-
-       config = apic_read(APIC_LVT_TIMER) | APIC_LVT_MASKED; // mask the timer
-       apic_write(APIC_LVT_TIMER, config);
-
-       apic_write(APIC_INITIAL_TIMER_COUNT, 0); // zero out the timer
-
-       config = apic_read(APIC_LVT_TIMER) & ~APIC_LVT_MASKED; // unmask the 
timer
-       apic_write(APIC_LVT_TIMER, config);
-
-       TRACE_TIMER(("arch_smp_set_apic_timer: config 0x%lx, timeout %Ld, 
tics/sec %lu, tics %lu\n",
-               config, relativeTimeout, apic_timer_tics_per_sec, ticks));
-
-       apic_write(APIC_INITIAL_TIMER_COUNT, ticks); // start it up
-
-       restore_interrupts(state);
-
-       return B_OK;
-}
-
-
-status_t
-arch_smp_clear_apic_timer(void)
-{
-       cpu_status state;
-       uint32 config;
-
-       if (apic == NULL)
-               return B_ERROR;
-
-       state = disable_interrupts();
-
-       config = apic_read(APIC_LVT_TIMER) | APIC_LVT_MASKED; // mask the timer
-       apic_write(APIC_LVT_TIMER, config);
-
-       apic_write(APIC_INITIAL_TIMER_COUNT, 0); // zero out the timer
-
-       restore_interrupts(state);
-       return B_OK;
-}
-
Index: src/system/kernel/arch/x86/arch_hpet.c
===================================================================
--- src/system/kernel/arch/x86/arch_hpet.c      (revision 26138)
+++ src/system/kernel/arch/x86/arch_hpet.c      (working copy)
@@ -2,5 +2,45 @@
  * Copyright 2008, Dustin Howett, dustin.howett@xxxxxxxxxx All rights reserved.
  * Distributed under the terms of the MIT License.
  */
+/*
+#include <kernel.h>
+#include <boot/stage2.h>
 
 #include <arch/x86/arch_hpet.h>
+
+static int32 hpet_phys_addr;
+static struct hpet_regs *hpet_register;
+
+// TODO: Implement something similar to smp_acpi_probe from boot/.../smp.cpp-
+//     we need to get the hpet base address without talking to the acpi module,
+//     because there's no guarantee that it's actually present at this early 
point.
+
+static int
+hpet_set_enabled(struct hpet_regs *regs, bool enabled)
+{
+       if(enabled == true) regs->config |= HPET_CONF_MASK_ENABLED;
+       else regs->config &= ~HPET_CONF_MASK_ENABLED;
+       return B_OK;
+}
+
+
+static int
+hpet_set_legacy(struct hpet_regs *regs, bool enabled)
+{
+       if(!HPET_IS_LEGACY_CAPABLE(regs)) return B_NOT_SUPPORTED;
+       if(enabled == true) regs->config |= HPET_CONF_MASK_LEGACY;
+       else regs->config &= ~HPET_CONF_MASK_LEGACY;
+       return B_OK;
+}
+
+
+int
+arch_init_hpet(kernel_args *args)
+{
+       // hpet_acpi_probe() through a similar "scan spots" table to that of 
smp.cpp.
+       // Seems to be the most elegant solution right now.
+
+       // Return EOPNOTSUPP for the time being.
+       return B_NOT_SUPPORTED;
+}
+*/
Index: headers/private/kernel/arch/x86/arch_hpet.h
===================================================================
--- headers/private/kernel/arch/x86/arch_hpet.h (working copy)
+++ headers/private/kernel/arch/x86/arch_hpet.h (working copy)
@@ -1,49 +0,0 @@
-/*
- * Copyright 2008, Dustin Howett, dustin.howett@xxxxxxxxxx All rights reserved.
- * Distributed under the terms of the MIT License.
- */
-#ifndef _KERNEL_ARCH_x86_HPET_H
-#define _KERNEL_ARCH_x86_HPET_H
-
-#include <types.h>
-
-/* All masks are 64 bits wide to represent bit locations;
-   the HPET registers are 64 bits wide. */
-
-/* Global Capability Register Masks */
-#define HPET_CAP_MASK_ID                       0x00000000000000FF
-#define HPET_CAP_MASK_NUMTIMERS                        0x0000000000001F00
-#define HPET_CAP_MASK_WIDTH                    0x0000000000002000
-#define HPET_CAP_MASK_LEGACY                   0x0000000000008000
-#define HPET_CAP_MASK_VENDOR_ID                        0x00000000FFFF0000
-#define HPET_CAP_MASK_PERIOD                   0xFFFFFFFF00000000
-
-/* Retrieve Global Capabilities */
-#define HPET_GET_ID(regs)              ((regs)->caps & HPET_CAP_MASK_ID)
-#define HPET_GET_NUM_TIMERS(regs)      (((regs)->caps & 
HPET_CAP_MASK_NUMTIMERS) >> 8)
-#define HPET_IS_64BIT_CAPABLE(regs)    (((regs)->caps & HPET_CAP_MASK_WIDTH) 
>> 13)
-#define HPET_IS_LEGACY_CAPABLE(regs)   (((regs)->caps & HPET_CAP_MASK_LEGACY) 
>> 15)
-#define HPET_GET_VENDOR_ID(regs)       (((regs)->caps & 
HPET_CAP_MASK_VENDOR_ID) >> 16)
-#define HPET_GET_PERIOD(regs)          (((regs)->caps & HPET_CAP_MASK_PERIOD) 
>> 32)
-
-struct hpet_timer {
-       uint64 config;                  /* Timer configuration and capabilities 
*/
-       uint64 comparator;              /* Comparator value */
-       uint64 introute;                /* FSB Interrupt Routing */
-       uint64 reserved;
-};
-
-
-struct hpet_regs {
-       uint64 caps;                    /* HPET Capabilities and ID */
-       uint64 reserved1;
-       uint64 config;                  /* General Configuration */
-       uint64 reserved2;
-       uint64 intstatus;               /* General Interrupt Status */
-       uint8 reserved3[200];
-       uint64 mainvalue;               /* Main Counter Value */
-       uint64 reserved4;
-       struct hpet_timer timers[1];    /* Timers */
-};
-
-#endif
Index: headers/private/kernel/arch/x86/timer.h
===================================================================
--- headers/private/kernel/arch/x86/timer.h     (revision 26138)
+++ headers/private/kernel/arch/x86/timer.h     (working copy)
@@ -2,10 +2,12 @@
 ** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
 ** Distributed under the terms of the NewOS License.
 */
-#ifndef _NEWOS_KERNEL_ARCH_I386_TIMER
-#define _NEWOS_KERNEL_ARCH_I386_TIMER
+#ifndef _KERNEL_ARCH_X86_TIMER
+#define _KERNEL_ARCH_X86_TIMER
 
-int apic_timer_interrupt(void);
+#define ISA_TIMER_MODULE_NAME "timers/x86/isa/v1"
+#define APIC_TIMER_MODULE_NAME "timers/x86/apic/v1"
+#define HPET_TIMER_MODULE_NAME "timers/x86/hpet/v1"
 
 #endif
 
Index: headers/private/kernel/timer.h
===================================================================
--- headers/private/kernel/timer.h      (revision 26138)
+++ headers/private/kernel/timer.h      (working copy)
@@ -18,6 +18,19 @@
 #define B_TIMER_ACQUIRE_THREAD_LOCK    0x8000
 #define B_TIMER_FLAGS                          B_TIMER_ACQUIRE_THREAD_LOCK
 
+/* Timer info structure */
+struct timer_info {
+       char *name;
+       int (*get_priority)();
+       status_t (*set_hardware_timer)(bigtime_t timeout);
+       status_t (*clear_hardware_timer)();
+       status_t (*init)(struct kernel_args *args, int32 data);
+       void (*preinit)(struct kernel_args *args);
+};
+
+typedef struct timer_info timer_info;
+
+
 /* kernel functions */
 status_t timer_init(struct kernel_args *);
 int32 timer_interrupt(void);

Other related posts: