Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


lot of changes
[palacios.git] / palacios / src / geekos / timer.c
index 113a17f..e0311a4 100644 (file)
@@ -2,7 +2,7 @@
  * GeekOS timer interrupt support
  * Copyright (c) 2001,2003 David H. Hovemeyer <daveho@cs.umd.edu>
  * Copyright (c) 2003, Jeffrey K. Hollingsworth <hollings@cs.umd.edu>
- * $Revision: 1.3 $
+ * $Revision: 1.4 $
  * 
  * This is free software.  You are permitted to use,
  * redistribute, and modify it as specified in the file "COPYING".
 #include <geekos/serial.h>
 #include <geekos/debug.h>
 
-#define HZ 100
+
+/* JRL Add a cpu frequency measurement */
+uint_t cpu_khz_freq;
+
+
+#define __SLOW_DOWN_IO "\noutb %%al,$0x80"
+
+#ifdef REALLY_SLOW_IO
+#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO
+#else
+#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO
+#endif
+
+
+
+#define __OUT1(s,x) \
+static inline void out##s(unsigned x value, unsigned short port) {
+
+#define __OUT2(s,s1,s2) \
+__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1"
+
+#define __OUT(s,s1,x) \
+__OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); } \
+__OUT1(s##_p,x) __OUT2(s,s1,"w") __FULL_SLOW_DOWN_IO : : "a" (value), "Nd" (port));} \
+
+
+#define __IN1(s) \
+static inline RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v;
+
+#define __IN2(s,s1,s2) \
+__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0"
+
+#define __IN(s,s1,i...) \
+__IN1(s) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
+__IN1(s##_p) __IN2(s,s1,"w") __FULL_SLOW_DOWN_IO : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
+
+
+#define RETURN_TYPE unsigned char
+__IN(b,"")
+#undef RETURN_TYPE
+#define RETURN_TYPE unsigned short
+__IN(w,"")
+#undef RETURN_TYPE
+#define RETURN_TYPE unsigned int
+__IN(l,"")
+#undef RETURN_TYPE
+
+
+
+__OUT(b,"b",char)
+__OUT(w,"w",short)
+
+
+
+
+
+#if defined(__i386__)
+
+#define rdtscll(val)                            \
+     __asm__ __volatile__("rdtsc" : "=A" (val))
+
+#elif defined(__x86_64__)
+
+#define rdtscll(val) do {                                   \
+    unsigned int a,d;                                       \
+    asm volatile("rdtsc" : "=a" (a), "=d" (d));             \
+    (val) = ((unsigned long)a) | (((unsigned long)d)<<32);  \
+  } while(0)
+
+#endif
+
+#define do_div(n,base) ({                                   \
+      unsigned long __upper, __low, __high, __mod, __base;   \
+      __base = (base);                                      \
+      asm("":"=a" (__low), "=d" (__high):"A" (n));          \
+      __upper = __high;                                             \
+      if (__high) {                                         \
+       __upper = __high % (__base);                         \
+       __high = __high / (__base);                          \
+      }                                                                        \
+      asm("divl %2":"=a" (__low), "=d" (__mod):"rm" (__base), "0" (__low), "1" (__upper)); \
+      asm("":"=A" (n):"a" (__low),"d" (__high));                       \
+      __mod;                                                           \
+    })
+
+
+/**
+ * This uses the Programmable Interval Timer that is standard on all
+ * PC-compatible systems to determine the time stamp counter frequency.
+ *
+ * This uses the speaker output (channel 2) of the PIT. This is better than
+ * using the timer interrupt output because we can read the value of the
+ * speaker with just one inb(), where we need three i/o operations for the
+ * interrupt channel. We count how many ticks the TSC does in 50 ms.
+ *
+ * Returns the detected time stamp counter frequency in KHz.
+ */
+
+
+static unsigned int 
+pit_calibrate_tsc(void)
+{
+  uint_t khz = 0;
+  ullong_t start, end;
+  //        unsigned long flags;
+  unsigned long pit_tick_rate = 1193182UL;  /* 1.193182 MHz */
+  
+  //        spin_lock_irqsave(&pit_lock, flags);
+  
+  outb((inb(0x61) & ~0x02) | 0x01, 0x61);
+  
+  outb(0xb0, 0x43);
+  outb((pit_tick_rate / (1000 / 50)) & 0xff, 0x42);
+  outb((pit_tick_rate / (1000 / 50)) >> 8, 0x42);
+  //        start = get_cycles_sync();
+  rdtscll(start);
+  while ((inb(0x61) & 0x20) == 0);
+  rdtscll(end);
+  //   end = get_cycles_sync();
+  
+  //        spin_unlock_irqrestore(&pit_lock, flags);
+  
+  
+  //  return (end - start) / 50;
+  khz = end - start;
+;
+
+  return khz / 50;
+}
+
+
+
+/* END JRL */
+
+
+
 
 
 /*
@@ -51,7 +186,8 @@ int g_Quantum = DEFAULT_MAX_TICKS;
  * Ticks per second.
  * FIXME: should set this to something more reasonable, like 100.
  */
-#define TICKS_PER_SEC 18
+#define HZ 100
+//#define TICKS_PER_SEC 18
 
 /*#define DEBUG_TIMER */
 #ifdef DEBUG_TIMER
@@ -155,12 +291,16 @@ static void Calibrate_Delay(void)
        ;
 
     /*
-     * Execute the spin loop.
+     * Execute the spin loop.xs
      * The temporary interrupt handler will overwrite the
      * loop counter when the next tick occurs.
      */
+
+
     Spin(INT_MAX);
 
+
+
     Disable_Interrupts();
 
     /*
@@ -179,6 +319,9 @@ void Init_Timer(void)
 {
   ushort_t foo = 1193182L / HZ;
   
+  cpu_khz_freq = pit_calibrate_tsc();
+  PrintBoth("CPU KHZ=%lu\n", (ulong_t)cpu_khz_freq);
+
   PrintBoth("Initializing timer and setting to %d Hz...\n",HZ);
   
   /* Calibrate for delay loop */
@@ -198,7 +341,7 @@ void Init_Timer(void)
 }
 
 
-#define US_PER_TICK (TICKS_PER_SEC * 1000000)
+#define US_PER_TICK (HZ * 1000000)
 
 /*
  * Spin for at least given number of microseconds.