source: trunk/packages/xen-common/xen-common/extras/mini-os/arch/x86/time.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 17 years ago

Add xen and xen-common

File size: 5.8 KB
Line 
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 */
33
34
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>
42
43/************************************************************************
44 * Time functions
45 *************************************************************************/
46
47/* These are peridically updated in shared_info, and then copied here. */
48struct 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};
56static struct timespec shadow_ts;
57static u32 shadow_ts_version;
58
59static struct shadow_time_info shadow;
60
61
62#ifndef rmb
63#define rmb()  __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory")
64#endif
65
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 )
74
75static inline int time_values_up_to_date(void)
76{
77        struct vcpu_time_info *src = &HYPERVISOR_shared_info->vcpu_info[0].time; 
78
79        return (shadow.version == src->version);
80}
81
82
83/*
84 * Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction,
85 * yielding a 64-bit result.
86 */
87static inline u64 scale_delta(u64 delta, u32 mul_frac, int shift)
88{
89        u64 product;
90#ifdef __i386__
91        u32 tmp1, tmp2;
92#endif
93
94        if ( shift < 0 )
95                delta >>= -shift;
96        else
97                delta <<= shift;
98
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
115
116        return product;
117}
118
119
120static 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}
127
128
129static void get_time_values_from_xen(void)
130{
131        struct vcpu_time_info    *src = &HYPERVISOR_shared_info->vcpu_info[0].time;
132
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));
143
144        shadow.tsc_to_usec_mul = shadow.tsc_to_nsec_mul / 1000;
145}
146
147
148
149
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 */
154u64 monotonic_clock(void)
155{
156        u64 time;
157        u32 local_time_version;
158
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);
167
168        return time;
169}
170
171static void update_wallclock(void)
172{
173        shared_info_t *s = HYPERVISOR_shared_info;
174
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}
184
185
186void gettimeofday(struct timeval *tv)
187{
188    u64 nsec = monotonic_clock();
189    nsec += shadow_ts.ts_nsec;
190   
191   
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}
196
197
198void 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}
208
209
210/*
211 * Just a dummy
212 */
213static void timer_handler(evtchn_port_t ev, struct pt_regs *regs, void *ign)
214{
215    get_time_values_from_xen();
216    update_wallclock();
217}
218
219
220
221void init_time(void)
222{
223    printk("Initialising timer interface\n");
224    bind_virq(VIRQ_TIMER, &timer_handler, NULL);
225}
Note: See TracBrowser for help on using the repository browser.