Mini-os updated to use the new timer interface.
Cheers
Gregor
# HG changeset patch
# User gmilos@xxxxxxxxxxxxxxxxxxxxx
# Node ID 3068565f6a32fde5fe1c11d44fd08d876d2b633f
# Parent 082a537ff4dec66574788126b3b047ef76e59803
Mini-os updated to use the new time interface.
Signed-off-by: Grzegorz Milos <gm281@xxxxxxxxx>
diff -r 082a537ff4de -r 3068565f6a32 extras/mini-os/include/time.h
--- a/extras/mini-os/include/time.h Thu Aug 18 17:04:48 2005
+++ b/extras/mini-os/include/time.h Fri Aug 19 16:42:51 2005
@@ -28,7 +28,7 @@
* of real time into system time
*/
typedef s64 s_time_t;
-#define NOW() ((s_time_t)get_s_time())
+#define NOW() ((s_time_t)monotonic_clock())
#define SECONDS(_s) (((s_time_t)(_s)) * 1000000000UL )
#define TENTHS(_ts) (((s_time_t)(_ts)) * 100000000UL )
#define HUNDREDTHS(_hs) (((s_time_t)(_hs)) * 10000000UL )
@@ -36,7 +36,8 @@
#define MICROSECS(_us) (((s_time_t)(_us)) * 1000UL )
#define Time_Max ((s_time_t) 0x7fffffffffffffffLL)
#define FOREVER Time_Max
-
+#define NSEC_TO_USEC(_nsec) (_nsec / 1000UL)
+#define NSEC_TO_SEC(_nsec) (_nsec / 1000000000ULL)
/* wall clock time */
typedef long time_t;
@@ -44,6 +45,11 @@
struct timeval {
time_t tv_sec; /* seconds */
suseconds_t tv_usec; /* microseconds */
+};
+
+struct timespec {
+ time_t ts_sec;
+ long ts_nsec;
};
diff -r 082a537ff4de -r 3068565f6a32 extras/mini-os/kernel.c
--- a/extras/mini-os/kernel.c Thu Aug 18 17:04:48 2005
+++ b/extras/mini-os/kernel.c Fri Aug 19 16:42:51 2005
@@ -132,20 +132,6 @@
i = 0;
for ( ; ; )
{
- if(i >= 1000)
- {
- {
- unsigned long saved;
- __asm__ ("movl %%esp, %0"
- :"=r"(saved) /* y is output operand */
- /* x is input operand */);
-// :"a"); /* %eax is clobbered register */
- printk("ESP=0x%lx\n", saved);
- }
-
- printk("1000 bloks\n");
- i=0;
- }
// HYPERVISOR_yield();
block(1);
i++;
diff -r 082a537ff4de -r 3068565f6a32 extras/mini-os/time.c
--- a/extras/mini-os/time.c Thu Aug 18 17:04:48 2005
+++ b/extras/mini-os/time.c Fri Aug 19 16:42:51 2005
@@ -43,19 +43,20 @@
* Time functions
*************************************************************************/
-/* Cached *multiplier* to convert TSC counts to microseconds.
- * (see the equation below).
- * Equal to 2^32 * (1 / (clocks per usec) ).
- * Initialized in time_init.
- */
-static unsigned long fast_gettimeoffset_quotient;
-
-
/* These are peridically updated in shared_info, and then copied here. */
-static u32 shadow_tsc_stamp;
-static s64 shadow_system_time;
-static u32 shadow_time_version;
-static struct timeval shadow_tv;
+struct shadow_time_info {
+ u64 tsc_timestamp; /* TSC at last update of time vals. */
+ u64 system_timestamp; /* Time, in nanosecs, since boot. */
+ u32 tsc_to_nsec_mul;
+ u32 tsc_to_usec_mul;
+ int tsc_shift;
+ u32 version;
+};
+static struct timespec shadow_ts;
+static u32 shadow_ts_version;
+
+static struct shadow_time_info shadow;
+
#ifndef rmb
#define rmb() __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory")
@@ -63,116 +64,150 @@
#define HANDLE_USEC_OVERFLOW(_tv) \
do { \
- while ( (_tv).tv_usec >= 1000000 ) \
+ while ( (_tv)->tv_usec >= 1000000 ) \
{ \
- (_tv).tv_usec -= 1000000; \
- (_tv).tv_sec++; \
+ (_tv)->tv_usec -= 1000000; \
+ (_tv)->tv_sec++; \
} \
} while ( 0 )
+static inline int time_values_up_to_date(void)
+{
+ struct vcpu_time_info *src = &HYPERVISOR_shared_info->vcpu_time[0];
+
+ return (shadow.version == src->version);
+}
+
+
+/*
+ * Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction,
+ * yielding a 64-bit result.
+ */
+static inline u64 scale_delta(u64 delta, u32 mul_frac, int shift)
+{
+ u64 product;
+#ifdef __i386__
+ u32 tmp1, tmp2;
+#endif
+
+ if ( shift < 0 )
+ delta >>= -shift;
+ else
+ delta <<= shift;
+
+#ifdef __i386__
+ __asm__ (
+ "mul %5 ; "
+ "mov %4,%%eax ; "
+ "mov %%edx,%4 ; "
+ "mul %5 ; "
+ "add %4,%%eax ; "
+ "xor %5,%5 ; "
+ "adc %5,%%edx ; "
+ : "=A" (product), "=r" (tmp1), "=r" (tmp2)
+ : "a" ((u32)delta), "1" ((u32)(delta >> 32)), "2" (mul_frac) );
+#else
+ __asm__ (
+ "mul %%rdx ; shrd $32,%%rdx,%%rax"
+ : "=a" (product) : "0" (delta), "d" ((u64)mul_frac) );
+#endif
+
+ return product;
+}
+
+
+static unsigned long get_nsec_offset(void)
+{
+ u64 now, delta;
+ rdtscll(now);
+ delta = now - shadow.tsc_timestamp;
+ return scale_delta(delta, shadow.tsc_to_nsec_mul, shadow.tsc_shift);
+}
+
+
static void get_time_values_from_xen(void)
{
- do {
- shadow_time_version = HYPERVISOR_shared_info->time_version2;
- rmb();
- shadow_tv.tv_sec = HYPERVISOR_shared_info->wc_sec;
- shadow_tv.tv_usec = HYPERVISOR_shared_info->wc_usec;
- shadow_tsc_stamp = (u32)HYPERVISOR_shared_info->tsc_timestamp;
- shadow_system_time = HYPERVISOR_shared_info->system_time;
- rmb();
- }
- while ( shadow_time_version != HYPERVISOR_shared_info->time_version1 );
-}
-
-
-#define TIME_VALUES_UP_TO_DATE \
- (shadow_time_version == HYPERVISOR_shared_info->time_version2)
-
-static u32 get_time_delta_usecs(void)
-{
- register unsigned long eax, edx;
-
- /* Read the Time Stamp Counter */
-
- rdtsc(eax,edx);
-
- /* .. relative to previous jiffy (32 bits is enough) */
- eax -= shadow_tsc_stamp;
-
- /*
- * Time offset = (tsc_low delta) * fast_gettimeoffset_quotient
- * = (tsc_low delta) * (usecs_per_clock)
- * = (tsc_low delta) * (usecs_per_jiffy / clocks_per_jiffy)
- *
- * Using a mull instead of a divl saves up to 31 clock cycles
- * in the critical path.
- */
-
- __asm__("mull %2"
- :"=a" (eax), "=d" (edx)
- :"rm" (fast_gettimeoffset_quotient),
- "0" (eax));
-
- /* our adjusted time offset in microseconds */
- return edx;
-}
-
-s64 get_s_time (void)
-{
- u64 u_delta;
- s64 ret;
-
- again:
-
- u_delta = get_time_delta_usecs();
- ret = shadow_system_time + (1000 * u_delta);
-
- if ( unlikely(!TIME_VALUES_UP_TO_DATE) )
- {
- /*
- * We may have blocked for a long time, rendering our calculations
- * invalid (e.g. the time delta may have overflowed). Detect that
- * and recalculate with fresh values.
- */
- get_time_values_from_xen();
- goto again;
- }
-
- return ret;
-}
+ struct vcpu_time_info *src = &HYPERVISOR_shared_info->vcpu_time[0];
+
+ do {
+ shadow.version = src->version;
+ rmb();
+ shadow.tsc_timestamp = src->tsc_timestamp;
+ shadow.system_timestamp = src->system_time;
+ shadow.tsc_to_nsec_mul = src->tsc_to_system_mul;
+ shadow.tsc_shift = src->tsc_shift;
+ rmb();
+ }
+ while ((src->version & 1) | (shadow.version ^ src->version));
+
+ shadow.tsc_to_usec_mul = shadow.tsc_to_nsec_mul / 1000;
+}
+
+
+
+
+/* monotonic_clock(): returns # of nanoseconds passed since time_init()
+ * Note: This function is required to return accurate
+ * time even in the absence of multiple timer ticks.
+ */
+u64 monotonic_clock(void)
+{
+ u64 time;
+ u32 local_time_version;
+
+ do {
+ local_time_version = shadow.version;
+ rmb();
+ time = shadow.system_timestamp + get_nsec_offset();
+ if (!time_values_up_to_date())
+ get_time_values_from_xen();
+ rmb();
+ } while (local_time_version != shadow.version);
+
+ return time;
+}
+
+static void update_wallclock(void)
+{
+ shared_info_t *s = HYPERVISOR_shared_info;
+
+ do {
+ shadow_ts_version = s->wc_version;
+ rmb();
+ shadow_ts.ts_sec = s->wc_sec;
+ shadow_ts.ts_nsec = s->wc_nsec;
+ rmb();
+ }
+ while ((s->wc_version & 1) | (shadow_ts_version ^ s->wc_version));
+}
+
void gettimeofday(struct timeval *tv)
{
- struct timeval _tv;
-
- do {
- get_time_values_from_xen();
- _tv.tv_usec = get_time_delta_usecs();
- _tv.tv_sec = shadow_tv.tv_sec;
- _tv.tv_usec += shadow_tv.tv_usec;
- }
- while ( unlikely(!TIME_VALUES_UP_TO_DATE) );
-
- HANDLE_USEC_OVERFLOW(_tv);
- *tv = _tv;
-}
+ u64 nsec = monotonic_clock();
+ nsec += shadow_ts.ts_nsec;
+
+
+ tv->tv_sec = shadow_ts.ts_sec;
+ tv->tv_sec += NSEC_TO_SEC(nsec);
+ tv->tv_usec = NSEC_TO_USEC(nsec % 1000000000UL);
+}
+
static void print_current_time(void)
{
- struct timeval tv;
-
- get_time_values_from_xen();
+ struct timeval tv;
gettimeofday(&tv);
printk("T(s=%ld us=%ld)\n", tv.tv_sec, tv.tv_usec);
}
+
void block(u32 millisecs)
{
struct timeval tv;
gettimeofday(&tv);
- //printk("tv.tv_sec=%ld, tv.tv_usec=%ld, shadow_system_time=%lld\n",
tv.tv_sec, tv.tv_usec, shadow_system_time );
- HYPERVISOR_set_timer_op(get_s_time() + 1000000LL * (s64) millisecs);
+ HYPERVISOR_set_timer_op(monotonic_clock() + 1000000LL * (s64) millisecs);
HYPERVISOR_block();
}
@@ -185,7 +220,7 @@
static int i;
get_time_values_from_xen();
-
+ update_wallclock();
i++;
if (i >= 1000) {
print_current_time();
@@ -197,24 +232,5 @@
void init_time(void)
{
- u64 __cpu_khz;
- unsigned long cpu_khz;
-
- __cpu_khz = HYPERVISOR_shared_info->cpu_freq;
-
- cpu_khz = (u32) (__cpu_khz/1000);
-
- printk("Xen reported: %lu.%03lu MHz processor.\n",
- cpu_khz / 1000, cpu_khz % 1000);
- /* (10^6 * 2^32) / cpu_hz = (10^3 * 2^32) / cpu_khz =
- (2^32 * 1 / (clocks/us)) */
- {
- unsigned long eax=0, edx=1000;
- __asm__("divl %2"
- :"=a" (fast_gettimeoffset_quotient), "=d" (edx)
- :"r" (cpu_khz),
- "0" (eax), "1" (edx));
- }
-
bind_virq(VIRQ_TIMER, &timer_handler);
}
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
|