ia64/xen-unstable

view extras/mini-os/time.c @ 12473:0839db0aa611

[MINIOS] Add timer support.

Based on an original patch by Robert Kaiser.

Signed-off-by: Grzegorz Milos <gm281@cam.ac.uk>
author kfraser@localhost.localdomain
date Wed Nov 15 09:33:01 2006 +0000 (2006-11-15)
parents 98a802d25848
children
line source
1 /* -*- Mode:C; c-basic-offset:4; tab-width:4 -*-
2 ****************************************************************************
3 * (C) 2003 - Rolf Neugebauer - Intel Research Cambridge
4 * (C) 2002-2003 - Keir Fraser - University of Cambridge
5 * (C) 2005 - Grzegorz Milos - Intel Research Cambridge
6 * (C) 2006 - Robert Kaiser - FH Wiesbaden
7 ****************************************************************************
8 *
9 * File: time.c
10 * Author: Rolf Neugebauer and Keir Fraser
11 * Changes: Grzegorz Milos
12 *
13 * Description: Simple time and timer functions
14 *
15 * Permission is hereby granted, free of charge, to any person obtaining a copy
16 * of this software and associated documentation files (the "Software"), to
17 * deal in the Software without restriction, including without limitation the
18 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
19 * sell copies of the Software, and to permit persons to whom the Software is
20 * furnished to do so, subject to the following conditions:
21 *
22 * The above copyright notice and this permission notice shall be included in
23 * all copies or substantial portions of the Software.
24 *
25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
30 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
31 * DEALINGS IN THE SOFTWARE.
32 */
35 #include <os.h>
36 #include <traps.h>
37 #include <types.h>
38 #include <hypervisor.h>
39 #include <events.h>
40 #include <time.h>
41 #include <lib.h>
43 /************************************************************************
44 * Time functions
45 *************************************************************************/
47 /* These are peridically updated in shared_info, and then copied here. */
48 struct shadow_time_info {
49 u64 tsc_timestamp; /* TSC at last update of time vals. */
50 u64 system_timestamp; /* Time, in nanosecs, since boot. */
51 u32 tsc_to_nsec_mul;
52 u32 tsc_to_usec_mul;
53 int tsc_shift;
54 u32 version;
55 };
56 static struct timespec shadow_ts;
57 static u32 shadow_ts_version;
59 static struct shadow_time_info shadow;
62 #ifndef rmb
63 #define rmb() __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory")
64 #endif
66 #define HANDLE_USEC_OVERFLOW(_tv) \
67 do { \
68 while ( (_tv)->tv_usec >= 1000000 ) \
69 { \
70 (_tv)->tv_usec -= 1000000; \
71 (_tv)->tv_sec++; \
72 } \
73 } while ( 0 )
75 static inline int time_values_up_to_date(void)
76 {
77 struct vcpu_time_info *src = &HYPERVISOR_shared_info->vcpu_info[0].time;
79 return (shadow.version == src->version);
80 }
83 /*
84 * Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction,
85 * yielding a 64-bit result.
86 */
87 static inline u64 scale_delta(u64 delta, u32 mul_frac, int shift)
88 {
89 u64 product;
90 #ifdef __i386__
91 u32 tmp1, tmp2;
92 #endif
94 if ( shift < 0 )
95 delta >>= -shift;
96 else
97 delta <<= shift;
99 #ifdef __i386__
100 __asm__ (
101 "mul %5 ; "
102 "mov %4,%%eax ; "
103 "mov %%edx,%4 ; "
104 "mul %5 ; "
105 "add %4,%%eax ; "
106 "xor %5,%5 ; "
107 "adc %5,%%edx ; "
108 : "=A" (product), "=r" (tmp1), "=r" (tmp2)
109 : "a" ((u32)delta), "1" ((u32)(delta >> 32)), "2" (mul_frac) );
110 #else
111 __asm__ (
112 "mul %%rdx ; shrd $32,%%rdx,%%rax"
113 : "=a" (product) : "0" (delta), "d" ((u64)mul_frac) );
114 #endif
116 return product;
117 }
120 static unsigned long get_nsec_offset(void)
121 {
122 u64 now, delta;
123 rdtscll(now);
124 delta = now - shadow.tsc_timestamp;
125 return scale_delta(delta, shadow.tsc_to_nsec_mul, shadow.tsc_shift);
126 }
129 static void get_time_values_from_xen(void)
130 {
131 struct vcpu_time_info *src = &HYPERVISOR_shared_info->vcpu_info[0].time;
133 do {
134 shadow.version = src->version;
135 rmb();
136 shadow.tsc_timestamp = src->tsc_timestamp;
137 shadow.system_timestamp = src->system_time;
138 shadow.tsc_to_nsec_mul = src->tsc_to_system_mul;
139 shadow.tsc_shift = src->tsc_shift;
140 rmb();
141 }
142 while ((src->version & 1) | (shadow.version ^ src->version));
144 shadow.tsc_to_usec_mul = shadow.tsc_to_nsec_mul / 1000;
145 }
150 /* monotonic_clock(): returns # of nanoseconds passed since time_init()
151 * Note: This function is required to return accurate
152 * time even in the absence of multiple timer ticks.
153 */
154 u64 monotonic_clock(void)
155 {
156 u64 time;
157 u32 local_time_version;
159 do {
160 local_time_version = shadow.version;
161 rmb();
162 time = shadow.system_timestamp + get_nsec_offset();
163 if (!time_values_up_to_date())
164 get_time_values_from_xen();
165 rmb();
166 } while (local_time_version != shadow.version);
168 return time;
169 }
171 static void update_wallclock(void)
172 {
173 shared_info_t *s = HYPERVISOR_shared_info;
175 do {
176 shadow_ts_version = s->wc_version;
177 rmb();
178 shadow_ts.ts_sec = s->wc_sec;
179 shadow_ts.ts_nsec = s->wc_nsec;
180 rmb();
181 }
182 while ((s->wc_version & 1) | (shadow_ts_version ^ s->wc_version));
183 }
186 void gettimeofday(struct timeval *tv)
187 {
188 u64 nsec = monotonic_clock();
189 nsec += shadow_ts.ts_nsec;
192 tv->tv_sec = shadow_ts.ts_sec;
193 tv->tv_sec += NSEC_TO_SEC(nsec);
194 tv->tv_usec = NSEC_TO_USEC(nsec % 1000000000UL);
195 }
198 void block_domain(s_time_t until)
199 {
200 struct timeval tv;
201 gettimeofday(&tv);
202 if(monotonic_clock() < until)
203 {
204 HYPERVISOR_set_timer_op(until);
205 HYPERVISOR_sched_op(SCHEDOP_block, 0);
206 }
207 }
210 /*
211 * Just a dummy
212 */
213 static void timer_handler(evtchn_port_t ev, struct pt_regs *regs, void *ign)
214 {
215 get_time_values_from_xen();
216 update_wallclock();
217 }
221 void init_time(void)
222 {
223 printk("Initialising timer interface\n");
224 bind_virq(VIRQ_TIMER, &timer_handler, NULL);
225 }