]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/rtc/lib/client/librtc.cc
d8f07461319efafe7ed329ee9c726cdcc5198150
[l4.git] / l4 / pkg / rtc / lib / client / librtc.cc
1 /**
2  * \file   rtc/lib/client/librtc.cc
3  * \brief  client stub
4  *
5  * \date   09/23/2003
6  * \author Frank Mehnert <fm3@os.inf.tu-dresden.de> */
7
8 /*
9  * (c) 2003-2009 Author(s)
10  *     economic rights: Technische Universität Dresden (Germany)
11  *
12  * This file is part of TUD:OS and distributed under the terms of the
13  * GNU General Public License 2.
14  * Please see the COPYING-GPL-2 file for details.
15  */
16
17 #if defined(ARCH_x86) || defined(ARCH_amd64)
18 #define RTC_AVAIL
19 #endif
20
21
22 #include <l4/sys/err.h>
23 #include <l4/rtc/rtc.h>
24 #include <l4/sys/types.h>
25 #include <l4/re/env>
26 #include <l4/re/namespace>
27 #include <l4/re/util/cap_alloc>
28 #include <l4/cxx/ipc_stream>
29
30 #include <cstdio>
31
32 #ifdef RTC_AVAIL
33 #include <l4/util/rdtsc.h>
34 #endif
35
36 //#include "rtc-client.h"
37
38 static l4_uint32_t s_offs_to_systime;
39 static l4_uint32_t linux_scaler;
40
41 /* We need to define this scaler here for use with l4_tsc_to_ns */
42 // l4_uint32_t l4_scaler_tsc_to_ns;
43
44 #ifdef RTC_AVAIL
45
46 static int server_tried;
47 static L4::Cap<void> server(L4_INVALID_CAP);
48
49 /**
50  * A fast and cheap way to calculate without violate the 32-bit range */
51 static inline l4_uint32_t
52 muldiv (l4_uint32_t val, l4_uint32_t mul, l4_uint32_t div)
53 {
54   l4_uint32_t dummy;
55
56   asm volatile ("mull %3 ; divl %4\n\t"
57                :"=a" (val), "=d" (dummy)
58                : "0" (val),  "d" (mul),  "c" (div));
59   return val;
60 }
61
62 int
63 l4rtc_if_get_offset_call(L4::Cap<void> server, l4_uint32_t *offset)
64 {
65   L4::Ipc_iostream _(l4_utcb());
66   _ << l4_umword_t(L4RTC_OPCODE_get_offset);
67   l4_msgtag_t res = _.call(server.cap());
68   if (l4_ipc_error(res, l4_utcb()))
69     return 1;
70   _ >> *offset;
71   return 0; // ok
72 }
73
74 int
75 l4rtc_if_get_linux_tsc_scaler_call(L4::Cap<void> server, l4_uint32_t *scaler)
76 {
77   L4::Ipc_iostream _(l4_utcb());
78   _ << l4_umword_t(L4RTC_OPCODE_get_linux_tsc_scaler);
79   l4_msgtag_t res = _.call(server.cap());
80   if (l4_ipc_error(res, l4_utcb()))
81     return 1;
82   _ >> *scaler;
83   return 0; // ok
84 }
85
86 /**
87  * Connect to server and retreive general values */
88 static int
89 init_done(void)
90 {
91   if (!server_tried)
92     {
93       server = L4Re::Env::env()->get_cap<void>("rtc");
94       if (!server.is_valid())
95         {
96           printf("rtc not found\n");
97           return -L4_EINVAL;
98         }
99
100       server_tried = 1;
101
102       if (l4rtc_if_get_offset_call(server, &s_offs_to_systime))
103         return -L4_EINVAL;
104
105       if (l4rtc_if_get_linux_tsc_scaler_call(server, &linux_scaler))
106         return -L4_EINVAL;
107
108       l4_scaler_tsc_to_ns = muldiv(linux_scaler, 1000, 1<<5);
109       l4_scaler_tsc_to_us =        linux_scaler;
110       l4_scaler_ns_to_tsc = muldiv(1U<<27, 1U<<29, 125*linux_scaler);
111     }
112
113   return 0;
114 }
115
116 static inline void gettime(l4_uint32_t *s, l4_uint32_t *ns)
117 {
118   l4_tsc_to_s_and_ns(l4_rdtsc(), s, ns);
119 }
120
121 #else
122 static int
123 init_done(void)
124 {
125   return 0;
126 }
127
128 static inline void gettime(l4_uint32_t *s, l4_uint32_t *ns)
129 {
130   *s = *ns = 0;
131 }
132 #endif
133
134 /**
135  * Deliver the numbers of seconds elapsed since 01.01.1970. This value is
136  * needed by Linux. */
137 int
138 l4rtc_get_seconds_since_1970(l4_uint32_t *seconds)
139 {
140   l4_uint32_t s, ns;
141
142   if (init_done())
143     return -L4_EINVAL;
144
145   gettime(&s, &ns);
146   *seconds = s + s_offs_to_systime;
147   return 0;
148 }
149
150 /**
151  * Deliver the offset between real time and system's uptime in seconds.
152  * Some applications want to compute their time in other ways as done
153  * in l4rtc_get_seconds_since_1970(). */
154 int
155 l4rtc_get_offset_to_realtime(l4_uint32_t *offset)
156 {
157   if (init_done())
158     return -L4_EINVAL;
159
160   *offset = s_offs_to_systime;
161   return 0;
162 }
163
164 /**
165  * Deliver the scaler 2^32 / (tsc clocks per usec). This value is needed by
166  * Linux. */
167 int
168 l4rtc_get_linux_tsc_scaler(l4_uint32_t *scaler)
169 {
170   if (init_done())
171     return -L4_EINVAL;
172
173   *scaler = linux_scaler;
174   return 0;
175 }
176