ia64/xen-unstable

view extras/mini-os/time.c @ 9788:bdcc838b9a72

Add small memory warning message to domain configuration examples.

Signed-off-by: Daniel Stekloff <dsteklof@us.ibm.com>
author stekloff@dyn9047022152.beaverton.ibm.com
date Wed Apr 19 22:58:24 2006 +0100 (2006-04-19)
parents 198828cc103b
children 43474e663b3d
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 ****************************************************************************
7 *
8 * File: time.c
9 * Author: Rolf Neugebauer and Keir Fraser
10 * Changes: Grzegorz Milos
11 *
12 * Description: Simple time and timer functions
13 *
14 * Permission is hereby granted, free of charge, to any person obtaining a copy
15 * of this software and associated documentation files (the "Software"), to
16 * deal in the Software without restriction, including without limitation the
17 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
18 * sell copies of the Software, and to permit persons to whom the Software is
19 * furnished to do so, subject to the following conditions:
20 *
21 * The above copyright notice and this permission notice shall be included in
22 * all copies or substantial portions of the Software.
23 *
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
30 * DEALINGS IN THE SOFTWARE.
31 */
34 #include <os.h>
35 #include <traps.h>
36 #include <types.h>
37 #include <hypervisor.h>
38 #include <events.h>
39 #include <time.h>
40 #include <lib.h>
42 /************************************************************************
43 * Time functions
44 *************************************************************************/
46 /* These are peridically updated in shared_info, and then copied here. */
47 struct shadow_time_info {
48 u64 tsc_timestamp; /* TSC at last update of time vals. */
49 u64 system_timestamp; /* Time, in nanosecs, since boot. */
50 u32 tsc_to_nsec_mul;
51 u32 tsc_to_usec_mul;
52 int tsc_shift;
53 u32 version;
54 };
55 static struct timespec shadow_ts;
56 static u32 shadow_ts_version;
58 static struct shadow_time_info shadow;
61 #ifndef rmb
62 #define rmb() __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory")
63 #endif
65 #define HANDLE_USEC_OVERFLOW(_tv) \
66 do { \
67 while ( (_tv)->tv_usec >= 1000000 ) \
68 { \
69 (_tv)->tv_usec -= 1000000; \
70 (_tv)->tv_sec++; \
71 } \
72 } while ( 0 )
74 static inline int time_values_up_to_date(void)
75 {
76 struct vcpu_time_info *src = &HYPERVISOR_shared_info->vcpu_info[0].time;
78 return (shadow.version == src->version);
79 }
82 /*
83 * Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction,
84 * yielding a 64-bit result.
85 */
86 static inline u64 scale_delta(u64 delta, u32 mul_frac, int shift)
87 {
88 u64 product;
89 #ifdef __i386__
90 u32 tmp1, tmp2;
91 #endif
93 if ( shift < 0 )
94 delta >>= -shift;
95 else
96 delta <<= shift;
98 #ifdef __i386__
99 __asm__ (
100 "mul %5 ; "
101 "mov %4,%%eax ; "
102 "mov %%edx,%4 ; "
103 "mul %5 ; "
104 "add %4,%%eax ; "
105 "xor %5,%5 ; "
106 "adc %5,%%edx ; "
107 : "=A" (product), "=r" (tmp1), "=r" (tmp2)
108 : "a" ((u32)delta), "1" ((u32)(delta >> 32)), "2" (mul_frac) );
109 #else
110 __asm__ (
111 "mul %%rdx ; shrd $32,%%rdx,%%rax"
112 : "=a" (product) : "0" (delta), "d" ((u64)mul_frac) );
113 #endif
115 return product;
116 }
119 static unsigned long get_nsec_offset(void)
120 {
121 u64 now, delta;
122 rdtscll(now);
123 delta = now - shadow.tsc_timestamp;
124 return scale_delta(delta, shadow.tsc_to_nsec_mul, shadow.tsc_shift);
125 }
128 static void get_time_values_from_xen(void)
129 {
130 struct vcpu_time_info *src = &HYPERVISOR_shared_info->vcpu_info[0].time;
132 do {
133 shadow.version = src->version;
134 rmb();
135 shadow.tsc_timestamp = src->tsc_timestamp;
136 shadow.system_timestamp = src->system_time;
137 shadow.tsc_to_nsec_mul = src->tsc_to_system_mul;
138 shadow.tsc_shift = src->tsc_shift;
139 rmb();
140 }
141 while ((src->version & 1) | (shadow.version ^ src->version));
143 shadow.tsc_to_usec_mul = shadow.tsc_to_nsec_mul / 1000;
144 }
149 /* monotonic_clock(): returns # of nanoseconds passed since time_init()
150 * Note: This function is required to return accurate
151 * time even in the absence of multiple timer ticks.
152 */
153 u64 monotonic_clock(void)
154 {
155 u64 time;
156 u32 local_time_version;
158 do {
159 local_time_version = shadow.version;
160 rmb();
161 time = shadow.system_timestamp + get_nsec_offset();
162 if (!time_values_up_to_date())
163 get_time_values_from_xen();
164 rmb();
165 } while (local_time_version != shadow.version);
167 return time;
168 }
170 static void update_wallclock(void)
171 {
172 shared_info_t *s = HYPERVISOR_shared_info;
174 do {
175 shadow_ts_version = s->wc_version;
176 rmb();
177 shadow_ts.ts_sec = s->wc_sec;
178 shadow_ts.ts_nsec = s->wc_nsec;
179 rmb();
180 }
181 while ((s->wc_version & 1) | (shadow_ts_version ^ s->wc_version));
182 }
185 void gettimeofday(struct timeval *tv)
186 {
187 u64 nsec = monotonic_clock();
188 nsec += shadow_ts.ts_nsec;
191 tv->tv_sec = shadow_ts.ts_sec;
192 tv->tv_sec += NSEC_TO_SEC(nsec);
193 tv->tv_usec = NSEC_TO_USEC(nsec % 1000000000UL);
194 }
197 static void print_current_time(void)
198 {
199 struct timeval tv;
201 gettimeofday(&tv);
202 printk("T(s=%ld us=%ld)\n", tv.tv_sec, tv.tv_usec);
203 }
206 void block_domain(u32 millisecs)
207 {
208 struct timeval tv;
209 gettimeofday(&tv);
210 HYPERVISOR_set_timer_op(monotonic_clock() + 1000000LL * (s64) millisecs);
211 HYPERVISOR_sched_op(SCHEDOP_block, 0);
212 }
215 /*
216 * Just a dummy
217 */
218 static void timer_handler(int ev, struct pt_regs *regs)
219 {
220 static int i;
222 get_time_values_from_xen();
223 update_wallclock();
224 i++;
225 if (i >= 1000) {
226 print_current_time();
227 i = 0;
228 }
229 }
233 void init_time(void)
234 {
235 printk("Initialising timer interface\n");
236 bind_virq(VIRQ_TIMER, &timer_handler);
237 }