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.


Working odin - x86 only - do 0 and then F5 to avoid startup files
[palacios.git] / palacios / src / geekos / timer.c
index cd89f86..34f752b 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.1 $
+ * $Revision: 1.5 $
  * 
  * This is free software.  You are permitted to use,
  * redistribute, and modify it as specified in the file "COPYING".
 #include <geekos/timer.h>
 
 #include <geekos/serial.h>
+#include <geekos/debug.h>
+
+
+/* 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 */
+
+
 
-#define HZ 100
 
 
 /*
@@ -50,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
@@ -65,11 +202,11 @@ int g_Quantum = DEFAULT_MAX_TICKS;
 
 static void Timer_Interrupt_Handler(struct Interrupt_State* state)
 {
-    struct Kernel_Thread* current = g_currentThread;
+   struct Kernel_Thread* current = g_currentThread;
 
     Begin_IRQ(state);
 
-    SerialPrintLevel(10,"Host Timer Interrupt Handler Running\n");
+    SerialPrintLevel(1,"Host Timer Interrupt Handler Running\n");
 
     /* Update global and per-thread number of ticks */
     ++g_numTicks;
@@ -82,7 +219,7 @@ static void Timer_Interrupt_Handler(struct Interrupt_State* state)
      * to choose a new thread.
      */
     if (current->numTicks >= g_Quantum) {
-       g_needReschedule = true;
+       g_needReschedule = true;
     }
 
 
@@ -154,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();
 
     /*
@@ -178,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 */
@@ -197,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.