x86: moves the PIT into time.{h,c}
authorBarret Rhoden <brho@cs.berkeley.edu>
Wed, 12 Mar 2014 03:18:28 +0000 (20:18 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Sat, 29 Mar 2014 01:16:10 +0000 (18:16 -0700)
It's been cluttering the unrelated APIC files for about five years now.

kern/arch/x86/Kbuild
kern/arch/x86/apic.c
kern/arch/x86/apic.h
kern/arch/x86/time.c [new file with mode: 0644]
kern/arch/x86/time.h

index 920096c..0720bda 100644 (file)
@@ -23,6 +23,7 @@ obj-y                                         += setjmp$(BITS).o
 obj-y                                          += smp.o
 obj-y                                          += smp_boot.o
 obj-y                                          += smp_entry$(BITS).o
 obj-y                                          += smp.o
 obj-y                                          += smp_boot.o
 obj-y                                          += smp_entry$(BITS).o
+obj-y                                          += time.o
 obj-y                                          += trap.o trap$(BITS).o
 obj-y                                          += trapentry$(BITS).o
 
 obj-y                                          += trap.o trap$(BITS).o
 obj-y                                          += trapentry$(BITS).o
 
index 7df5d35..3a9908a 100644 (file)
@@ -18,9 +18,7 @@
 #include <stdio.h>
 #include <bitmask.h>
 #include <arch/coreid.h>
 #include <stdio.h>
 #include <bitmask.h>
 #include <arch/coreid.h>
-#include <arch/pic.h>
 
 
-system_timing_t RO system_timing = {0, 0, 0xffff, 0};
 bool core_id_ready = FALSE;
 
 bool lapic_check_spurious(int trap_nr)
 bool core_id_ready = FALSE;
 
 bool lapic_check_spurious(int trap_nr)
@@ -128,14 +126,6 @@ void lapic_set_timer(uint32_t usec, bool periodic)
                          LAPIC_TIMER_DIVISOR_BITS);
 }
 
                          LAPIC_TIMER_DIVISOR_BITS);
 }
 
-void set_core_timer(uint32_t usec, bool periodic)
-{
-       if (usec)
-               lapic_set_timer(usec, periodic);
-       else
-               lapic_disable_timer();
-}
-
 uint32_t lapic_get_default_id(void)
 {
        uint32_t ebx;
 uint32_t lapic_get_default_id(void)
 {
        uint32_t ebx;
@@ -143,133 +133,3 @@ uint32_t lapic_get_default_id(void)
        // p6 family only uses 4 bits here, and 0xf is reserved for the IOAPIC
        return (ebx & 0xFF000000) >> 24;
 }
        // p6 family only uses 4 bits here, and 0xf is reserved for the IOAPIC
        return (ebx & 0xFF000000) >> 24;
 }
-
-// timer init calibrates both tsc timer and lapic timer using PIT
-void timer_init(void){
-       /* some boards have this unmasked early on. */
-       pic_mask_irq(0 + PIC1_OFFSET);
-       uint64_t tscval[2];
-       long timercount[2];
-       pit_set_timer(0xffff, TIMER_RATEGEN);
-       // assume tsc exist
-       tscval[0] = read_tsc();
-       udelay_pit(1000000);
-       tscval[1] = read_tsc();
-       system_timing.tsc_freq = SINIT(tscval[1] - tscval[0]);
-       cprintf("TSC Frequency: %llu\n", system_timing.tsc_freq);
-       __lapic_set_timer(0xffffffff, LAPIC_TIMER_DEFAULT_VECTOR, FALSE,
-                         LAPIC_TIMER_DIVISOR_BITS);
-       // Mask the LAPIC Timer, so we never receive this interrupt (minor race)
-       mask_lapic_lvt(LAPIC_LVT_TIMER);
-       timercount[0] = read_mmreg32(LAPIC_TIMER_CURRENT);
-       udelay_pit(1000000);
-       timercount[1] = read_mmreg32(LAPIC_TIMER_CURRENT);
-       system_timing.bus_freq = (timercount[0] - timercount[1])
-                                * LAPIC_TIMER_DIVISOR_VAL;
-       /* The time base for the timer is derived from the processor's bus clock,
-        * divided by the value specified in the divide configuration register.
-        * Note we mult and div by the divisor, saving the actual freq (even though
-        * we don't use it yet). */
-       cprintf("Bus Frequency: %llu\n", system_timing.bus_freq);
-}
-
-void pit_set_timer(uint32_t divisor, uint32_t mode)
-{
-       if (divisor & 0xffff0000)
-               warn("Divisor too large!");
-       mode = TIMER_SEL0|TIMER_16BIT|mode;
-       outb(TIMER_MODE, mode); 
-       outb(TIMER_CNTR0, divisor & 0xff);
-       outb(TIMER_CNTR0, (divisor >> 8) );
-       system_timing.pit_mode = SINIT(mode);
-       system_timing.pit_divisor = SINIT(divisor);
-       // cprintf("timer mode set to %d, divisor %d\n",mode, divisor);
-}
-
-static int getpit()
-{
-    int high, low;
-       // TODO: need a lock to protect access to PIT
-
-    /* Select counter 0 and latch counter value. */
-    outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
-    
-    low = inb(TIMER_CNTR0);
-    high = inb(TIMER_CNTR0);
-
-    return ((high << 8) | low);
-}
-
-// forces cpu to relax for usec miliseconds.  declared in kern/include/time.h
-void udelay(uint64_t usec)
-{
-       #if !defined(__BOCHS__)
-       if (system_timing.tsc_freq != 0)
-       {
-               uint64_t start, end, now;
-
-               start = read_tsc();
-        end = start + usec2tsc(usec);
-        //cprintf("start %llu, end %llu\n", start, end);
-               if (end == 0) cprintf("This is terribly wrong \n");
-               do {
-            cpu_relax();
-            now = read_tsc();
-                       //cprintf("now %llu\n", now);
-               } while (now < end || (now > start && end < start));
-        return;
-
-       } else
-       #endif
-       {
-               udelay_pit(usec);
-       }
-}
-
-void udelay_pit(uint64_t usec)
-{
-       
-       int64_t delta, prev_tick, tick, ticks_left;
-       prev_tick = getpit();
-       /*
-        * Calculate (n * (i8254_freq / 1e6)) without using floating point
-        * and without any avoidable overflows.
-        */
-       if (usec <= 0)
-               ticks_left = 0;
-       // some optimization from bsd code
-       else if (usec < 256)
-               /*
-                * Use fixed point to avoid a slow division by 1000000.
-                * 39099 = 1193182 * 2^15 / 10^6 rounded to nearest.
-                * 2^15 is the first power of 2 that gives exact results
-                * for n between 0 and 256.
-                */
-               ticks_left = ((uint64_t)usec * 39099 + (1 << 15) - 1) >> 15;
-       else
-               // round up the ticks left
-               ticks_left = ((uint64_t)usec * (long long)PIT_FREQ+ 999999)
-                            / 1000000; 
-       while (ticks_left > 0) {
-               tick = getpit();
-               delta = prev_tick - tick;
-               prev_tick = tick;
-               if (delta < 0) {
-                       // counter looped around during the delta time period
-                       delta += system_timing.pit_divisor; // maximum count 
-                       if (delta < 0)
-                               delta = 0;
-               }
-               ticks_left -= delta;
-       }
-}
-
-uint64_t gettimer(void)
-{
-       return read_tsc();      
-}
-
-uint64_t getfreq(void)
-{
-       return system_timing.tsc_freq;
-}
index 363d2af..e128d9e 100644 (file)
 #define LAPIC_ISR                                      (LAPIC_BASE + 0x100)
 #define LAPIC_IRR                                      (LAPIC_BASE + 0x200)
 
 #define LAPIC_ISR                                      (LAPIC_BASE + 0x100)
 #define LAPIC_IRR                                      (LAPIC_BASE + 0x200)
 
-// PIT (Programmable Interval Timer)
-#define        TIMER_REG_CNTR0 0       /* timer counter 0 port */
-#define        TIMER_REG_CNTR1 1       /* timer counter 1 port */
-#define        TIMER_REG_CNTR2 2       /* timer counter 2 port */
-#define        TIMER_REG_MODE  3       /* timer mode port */
-#define        TIMER_SEL0      0x00    /* select counter 0 */
-#define        TIMER_SEL1      0x40    /* select counter 1 */
-#define        TIMER_SEL2      0x80    /* select counter 2 */
-#define        TIMER_INTTC     0x00    /* mode 0, intr on terminal cnt */
-#define        TIMER_ONESHOT   0x02    /* mode 1, one shot */
-#define        TIMER_RATEGEN   0x04    /* mode 2, rate generator */
-#define        TIMER_SQWAVE    0x06    /* mode 3, square wave */
-#define        TIMER_SWSTROBE  0x08    /* mode 4, s/w triggered strobe */
-#define        TIMER_HWSTROBE  0x0a    /* mode 5, h/w triggered strobe */
-#define        TIMER_LATCH     0x00    /* latch counter for reading */
-#define        TIMER_LSB       0x10    /* r/w counter LSB */
-#define        TIMER_MSB       0x20    /* r/w counter MSB */
-#define        TIMER_16BIT     0x30    /* r/w counter 16 bits, LSB first */
-#define        TIMER_BCD       0x01    /* count in BCD */
-
-#define PIT_FREQ                                       1193182
-
-#define IO_TIMER1   0x40       /* 8253 Timer #1 */
-#define TIMER_CNTR0 (IO_TIMER1 + TIMER_REG_CNTR0)
-#define TIMER_CNTR1 (IO_TIMER1 + TIMER_REG_CNTR1)
-#define TIMER_CNTR2 (IO_TIMER1 + TIMER_REG_CNTR2)
-#define TIMER_MODE  (IO_TIMER1 + TIMER_REG_MODE)
-
-typedef struct system_timing {
-       uint64_t tsc_freq;
-       uint64_t bus_freq;
-       uint64_t timing_overhead;
-       uint16_t pit_divisor;
-       uint8_t pit_mode;
-} system_timing_t;
-
-extern system_timing_t system_timing;
-
 /* Tracks whether it is safe to execute core_id() or not.  If we're using the
  * LAPIC, we need to have the LAPIC mapped into VM.  vm_init() sets this to
  * TRUE.
 /* Tracks whether it is safe to execute core_id() or not.  If we're using the
  * LAPIC, we need to have the LAPIC mapped into VM.  vm_init() sets this to
  * TRUE.
@@ -124,13 +86,6 @@ bool ipi_is_pending(uint8_t vector);
 void __lapic_set_timer(uint32_t ticks, uint8_t vec, bool periodic, uint8_t div);
 void lapic_set_timer(uint32_t usec, bool periodic);
 uint32_t lapic_get_default_id(void);
 void __lapic_set_timer(uint32_t ticks, uint8_t vec, bool periodic, uint8_t div);
 void lapic_set_timer(uint32_t usec, bool periodic);
 uint32_t lapic_get_default_id(void);
-// PIT related
-void pit_set_timer(uint32_t freq, uint32_t mode);
-void timer_init(void);
-void udelay_pit(uint64_t usec);
-// TODO: right now timer defaults to TSC
-uint64_t gettimer(void);
-uint64_t getfreq(void);
 
 static inline void lapic_send_eoi(int unused);
 static inline uint32_t lapic_get_version(void);
 
 static inline void lapic_send_eoi(int unused);
 static inline uint32_t lapic_get_version(void);
diff --git a/kern/arch/x86/time.c b/kern/arch/x86/time.c
new file mode 100644 (file)
index 0000000..9762787
--- /dev/null
@@ -0,0 +1,152 @@
+/* Copyright (c) 2009 The Regents of the University of California
+ * David (Yu) Zhu <yuzhu@cs.berkeley.edu>
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ *
+ * See LICENSE for details. */
+
+#include <arch/x86.h>
+#include <arch/arch.h>
+#include <arch/pic.h>
+#include <arch/apic.h>
+#include <time.h>
+#include <assert.h>
+#include <stdio.h>
+
+system_timing_t system_timing = {0, 0, 0xffff, 0};
+
+// timer init calibrates both tsc timer and lapic timer using PIT
+void timer_init(void){
+       /* some boards have this unmasked early on. */
+       pic_mask_irq(0 + PIC1_OFFSET);
+       uint64_t tscval[2];
+       long timercount[2];
+       pit_set_timer(0xffff, TIMER_RATEGEN);
+       // assume tsc exist
+       tscval[0] = read_tsc();
+       udelay_pit(1000000);
+       tscval[1] = read_tsc();
+       system_timing.tsc_freq = SINIT(tscval[1] - tscval[0]);
+       cprintf("TSC Frequency: %llu\n", system_timing.tsc_freq);
+       __lapic_set_timer(0xffffffff, LAPIC_TIMER_DEFAULT_VECTOR, FALSE,
+                         LAPIC_TIMER_DIVISOR_BITS);
+       // Mask the LAPIC Timer, so we never receive this interrupt (minor race)
+       mask_lapic_lvt(LAPIC_LVT_TIMER);
+       timercount[0] = read_mmreg32(LAPIC_TIMER_CURRENT);
+       udelay_pit(1000000);
+       timercount[1] = read_mmreg32(LAPIC_TIMER_CURRENT);
+       system_timing.bus_freq = (timercount[0] - timercount[1])
+                                * LAPIC_TIMER_DIVISOR_VAL;
+       /* The time base for the timer is derived from the processor's bus clock,
+        * divided by the value specified in the divide configuration register.
+        * Note we mult and div by the divisor, saving the actual freq (even though
+        * we don't use it yet). */
+       cprintf("Bus Frequency: %llu\n", system_timing.bus_freq);
+}
+
+void pit_set_timer(uint32_t divisor, uint32_t mode)
+{
+       if (divisor & 0xffff0000)
+               warn("Divisor too large!");
+       mode = TIMER_SEL0|TIMER_16BIT|mode;
+       outb(TIMER_MODE, mode); 
+       outb(TIMER_CNTR0, divisor & 0xff);
+       outb(TIMER_CNTR0, (divisor >> 8) );
+       system_timing.pit_mode = SINIT(mode);
+       system_timing.pit_divisor = SINIT(divisor);
+       // cprintf("timer mode set to %d, divisor %d\n",mode, divisor);
+}
+
+static int getpit()
+{
+    int high, low;
+       // TODO: need a lock to protect access to PIT
+
+    /* Select counter 0 and latch counter value. */
+    outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
+    
+    low = inb(TIMER_CNTR0);
+    high = inb(TIMER_CNTR0);
+
+    return ((high << 8) | low);
+}
+
+// forces cpu to relax for usec miliseconds.  declared in kern/include/time.h
+void udelay(uint64_t usec)
+{
+       #if !defined(__BOCHS__)
+       if (system_timing.tsc_freq != 0)
+       {
+               uint64_t start, end, now;
+
+               start = read_tsc();
+        end = start + usec2tsc(usec);
+        //cprintf("start %llu, end %llu\n", start, end);
+               if (end == 0) cprintf("This is terribly wrong \n");
+               do {
+            cpu_relax();
+            now = read_tsc();
+                       //cprintf("now %llu\n", now);
+               } while (now < end || (now > start && end < start));
+        return;
+
+       } else
+       #endif
+       {
+               udelay_pit(usec);
+       }
+}
+
+void udelay_pit(uint64_t usec)
+{
+       int64_t delta, prev_tick, tick, ticks_left;
+       prev_tick = getpit();
+       /*
+        * Calculate (n * (i8254_freq / 1e6)) without using floating point
+        * and without any avoidable overflows.
+        */
+       if (usec <= 0)
+               ticks_left = 0;
+       // some optimization from bsd code
+       else if (usec < 256)
+               /*
+                * Use fixed point to avoid a slow division by 1000000.
+                * 39099 = 1193182 * 2^15 / 10^6 rounded to nearest.
+                * 2^15 is the first power of 2 that gives exact results
+                * for n between 0 and 256.
+                */
+               ticks_left = ((uint64_t)usec * 39099 + (1 << 15) - 1) >> 15;
+       else
+               // round up the ticks left
+               ticks_left = ((uint64_t)usec * (long long)PIT_FREQ+ 999999)
+                            / 1000000; 
+       while (ticks_left > 0) {
+               tick = getpit();
+               delta = prev_tick - tick;
+               prev_tick = tick;
+               if (delta < 0) {
+                       // counter looped around during the delta time period
+                       delta += system_timing.pit_divisor; // maximum count 
+                       if (delta < 0)
+                               delta = 0;
+               }
+               ticks_left -= delta;
+       }
+}
+
+uint64_t gettimer(void)
+{
+       return read_tsc();      
+}
+
+uint64_t getfreq(void)
+{
+       return system_timing.tsc_freq;
+}
+
+void set_core_timer(uint32_t usec, bool periodic)
+{
+       if (usec)
+               lapic_set_timer(usec, periodic);
+       else
+               lapic_disable_timer();
+}
index 7976c9b..f1b48a0 100644 (file)
@@ -1,6 +1,56 @@
+/* Copyright (c) 2009 The Regents of the University of California
+ * David (Yu) Zhu <yuzhu@cs.berkeley.edu>
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ *
+ * See LICENSE for details. */
+
 #ifndef ROS_KERN_ARCH_TIME_H
 #define ROS_KERN_ARCH_TIME_H
 
 #ifndef ROS_KERN_ARCH_TIME_H
 #define ROS_KERN_ARCH_TIME_H
 
-#include <arch/apic.h>
+// PIT (Programmable Interval Timer)
+#define        TIMER_REG_CNTR0 0       /* timer counter 0 port */
+#define        TIMER_REG_CNTR1 1       /* timer counter 1 port */
+#define        TIMER_REG_CNTR2 2       /* timer counter 2 port */
+#define        TIMER_REG_MODE  3       /* timer mode port */
+#define        TIMER_SEL0      0x00    /* select counter 0 */
+#define        TIMER_SEL1      0x40    /* select counter 1 */
+#define        TIMER_SEL2      0x80    /* select counter 2 */
+#define        TIMER_INTTC     0x00    /* mode 0, intr on terminal cnt */
+#define        TIMER_ONESHOT   0x02    /* mode 1, one shot */
+#define        TIMER_RATEGEN   0x04    /* mode 2, rate generator */
+#define        TIMER_SQWAVE    0x06    /* mode 3, square wave */
+#define        TIMER_SWSTROBE  0x08    /* mode 4, s/w triggered strobe */
+#define        TIMER_HWSTROBE  0x0a    /* mode 5, h/w triggered strobe */
+#define        TIMER_LATCH     0x00    /* latch counter for reading */
+#define        TIMER_LSB       0x10    /* r/w counter LSB */
+#define        TIMER_MSB       0x20    /* r/w counter MSB */
+#define        TIMER_16BIT     0x30    /* r/w counter 16 bits, LSB first */
+#define        TIMER_BCD       0x01    /* count in BCD */
+
+#define PIT_FREQ                                       1193182
+
+#define IO_TIMER1   0x40       /* 8253 Timer #1 */
+#define TIMER_CNTR0 (IO_TIMER1 + TIMER_REG_CNTR0)
+#define TIMER_CNTR1 (IO_TIMER1 + TIMER_REG_CNTR1)
+#define TIMER_CNTR2 (IO_TIMER1 + TIMER_REG_CNTR2)
+#define TIMER_MODE  (IO_TIMER1 + TIMER_REG_MODE)
+
+typedef struct system_timing {
+       uint64_t tsc_freq;
+       uint64_t bus_freq;
+       uint64_t timing_overhead;
+       uint16_t pit_divisor;
+       uint8_t pit_mode;
+} system_timing_t;
+
+extern system_timing_t system_timing;
+
+// PIT related
+void pit_set_timer(uint32_t freq, uint32_t mode);
+void timer_init(void);
+void udelay_pit(uint64_t usec);
+// TODO: right now timer defaults to TSC
+uint64_t gettimer(void);
+uint64_t getfreq(void);
 
 #endif /* ROS_KERN_ARCH_TIME_H */
 
 #endif /* ROS_KERN_ARCH_TIME_H */