ia64/xen-unstable

annotate extras/mini-os/time.c @ 10843:4f6d858ea570

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