debuggers.hg

view xen/arch/x86/hvm/rtc.c @ 19950:721c14d7f60b

x86 hvm: Use 'x' as parameter name for macros converting between
{vcpu,domain} and {vlapic,vpic,vrtc,hpet}. Completely avoids
accidental aliasing.

Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Jul 08 14:22:00 2009 +0100 (2009-07-08)
parents a29bb4efff00
children 809b20f066fb
line source
1 /*
2 * QEMU MC146818 RTC emulation
3 *
4 * Copyright (c) 2003-2004 Fabrice Bellard
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 * IN THE SOFTWARE.
23 */
25 #include <asm/mc146818rtc.h>
26 #include <asm/hvm/vpt.h>
27 #include <asm/hvm/io.h>
28 #include <asm/hvm/support.h>
29 #include <asm/current.h>
31 #define domain_vrtc(x) (&(x)->arch.hvm_domain.pl_time.vrtc)
32 #define vcpu_vrtc(x) (domain_vrtc((x)->domain))
33 #define vrtc_domain(x) (container_of((x), struct domain, \
34 arch.hvm_domain.pl_time.vrtc))
35 #define vrtc_vcpu(x) (pt_global_vcpu_target(vrtc_domain(x)))
37 static void rtc_periodic_cb(struct vcpu *v, void *opaque)
38 {
39 RTCState *s = opaque;
40 spin_lock(&s->lock);
41 s->hw.cmos_data[RTC_REG_C] |= 0xc0;
42 spin_unlock(&s->lock);
43 }
45 /* Enable/configure/disable the periodic timer based on the RTC_PIE and
46 * RTC_RATE_SELECT settings */
47 static void rtc_timer_update(RTCState *s)
48 {
49 int period_code, period;
50 struct vcpu *v = vrtc_vcpu(s);
52 ASSERT(spin_is_locked(&s->lock));
54 period_code = s->hw.cmos_data[RTC_REG_A] & RTC_RATE_SELECT;
55 if ( (period_code != 0) && (s->hw.cmos_data[RTC_REG_B] & RTC_PIE) )
56 {
57 if ( period_code <= 2 )
58 period_code += 7;
60 period = 1 << (period_code - 1); /* period in 32 Khz cycles */
61 period = DIV_ROUND((period * 1000000000ULL), 32768); /* period in ns */
62 create_periodic_time(v, &s->pt, period, period, RTC_IRQ,
63 rtc_periodic_cb, s);
64 }
65 else
66 {
67 destroy_periodic_time(&s->pt);
68 }
69 }
71 static void rtc_set_time(RTCState *s);
73 static int rtc_ioport_write(void *opaque, uint32_t addr, uint32_t data)
74 {
75 RTCState *s = opaque;
77 spin_lock(&s->lock);
79 if ( (addr & 1) == 0 )
80 {
81 data &= 0x7f;
82 s->hw.cmos_index = data;
83 spin_unlock(&s->lock);
84 return (data < RTC_CMOS_SIZE);
85 }
87 if ( s->hw.cmos_index >= RTC_CMOS_SIZE )
88 {
89 spin_unlock(&s->lock);
90 return 0;
91 }
93 switch ( s->hw.cmos_index )
94 {
95 case RTC_SECONDS_ALARM:
96 case RTC_MINUTES_ALARM:
97 case RTC_HOURS_ALARM:
98 s->hw.cmos_data[s->hw.cmos_index] = data;
99 break;
100 case RTC_SECONDS:
101 case RTC_MINUTES:
102 case RTC_HOURS:
103 case RTC_DAY_OF_WEEK:
104 case RTC_DAY_OF_MONTH:
105 case RTC_MONTH:
106 case RTC_YEAR:
107 s->hw.cmos_data[s->hw.cmos_index] = data;
108 /* if in set mode, do not update the time */
109 if ( !(s->hw.cmos_data[RTC_REG_B] & RTC_SET) )
110 rtc_set_time(s);
111 break;
112 case RTC_REG_A:
113 /* UIP bit is read only */
114 s->hw.cmos_data[RTC_REG_A] = (data & ~RTC_UIP) |
115 (s->hw.cmos_data[RTC_REG_A] & RTC_UIP);
116 rtc_timer_update(s);
117 break;
118 case RTC_REG_B:
119 if ( data & RTC_SET )
120 {
121 /* set mode: reset UIP mode */
122 s->hw.cmos_data[RTC_REG_A] &= ~RTC_UIP;
123 }
124 else
125 {
126 /* if disabling set mode, update the time */
127 if ( s->hw.cmos_data[RTC_REG_B] & RTC_SET )
128 rtc_set_time(s);
129 }
130 s->hw.cmos_data[RTC_REG_B] = data;
131 rtc_timer_update(s);
132 break;
133 case RTC_REG_C:
134 case RTC_REG_D:
135 /* cannot write to them */
136 break;
137 }
139 spin_unlock(&s->lock);
141 return 1;
142 }
144 static inline int to_bcd(RTCState *s, int a)
145 {
146 if ( s->hw.cmos_data[RTC_REG_B] & 0x04 )
147 return a;
148 else
149 return ((a / 10) << 4) | (a % 10);
150 }
152 static inline int from_bcd(RTCState *s, int a)
153 {
154 if ( s->hw.cmos_data[RTC_REG_B] & 0x04 )
155 return a;
156 else
157 return ((a >> 4) * 10) + (a & 0x0f);
158 }
160 static void rtc_set_time(RTCState *s)
161 {
162 struct tm *tm = &s->current_tm;
163 struct domain *d = vrtc_domain(s);
164 unsigned long before, after; /* XXX s_time_t */
166 ASSERT(spin_is_locked(&s->lock));
168 before = mktime(tm->tm_year, tm->tm_mon, tm->tm_mday,
169 tm->tm_hour, tm->tm_min, tm->tm_sec);
171 tm->tm_sec = from_bcd(s, s->hw.cmos_data[RTC_SECONDS]);
172 tm->tm_min = from_bcd(s, s->hw.cmos_data[RTC_MINUTES]);
173 tm->tm_hour = from_bcd(s, s->hw.cmos_data[RTC_HOURS] & 0x7f);
174 if ( !(s->hw.cmos_data[RTC_REG_B] & 0x02) &&
175 (s->hw.cmos_data[RTC_HOURS] & 0x80) )
176 tm->tm_hour += 12;
177 tm->tm_wday = from_bcd(s, s->hw.cmos_data[RTC_DAY_OF_WEEK]);
178 tm->tm_mday = from_bcd(s, s->hw.cmos_data[RTC_DAY_OF_MONTH]);
179 tm->tm_mon = from_bcd(s, s->hw.cmos_data[RTC_MONTH]) - 1;
180 tm->tm_year = from_bcd(s, s->hw.cmos_data[RTC_YEAR]) + 100;
182 after = mktime(tm->tm_year, tm->tm_mon, tm->tm_mday,
183 tm->tm_hour, tm->tm_min, tm->tm_sec);
185 /* We use the guest's setting of the RTC to define the local-time
186 * offset for this domain. */
187 d->time_offset_seconds += (after - before);
188 update_domain_wallclock_time(d);
189 /* Also tell qemu-dm about it so it will be remembered for next boot. */
190 send_timeoffset_req(after - before);
191 }
193 static void rtc_copy_date(RTCState *s)
194 {
195 const struct tm *tm = &s->current_tm;
197 ASSERT(spin_is_locked(&s->lock));
199 s->hw.cmos_data[RTC_SECONDS] = to_bcd(s, tm->tm_sec);
200 s->hw.cmos_data[RTC_MINUTES] = to_bcd(s, tm->tm_min);
201 if ( s->hw.cmos_data[RTC_REG_B] & RTC_24H )
202 {
203 /* 24 hour format */
204 s->hw.cmos_data[RTC_HOURS] = to_bcd(s, tm->tm_hour);
205 }
206 else
207 {
208 /* 12 hour format */
209 s->hw.cmos_data[RTC_HOURS] = to_bcd(s, tm->tm_hour % 12);
210 if ( tm->tm_hour >= 12 )
211 s->hw.cmos_data[RTC_HOURS] |= 0x80;
212 }
213 s->hw.cmos_data[RTC_DAY_OF_WEEK] = to_bcd(s, tm->tm_wday);
214 s->hw.cmos_data[RTC_DAY_OF_MONTH] = to_bcd(s, tm->tm_mday);
215 s->hw.cmos_data[RTC_MONTH] = to_bcd(s, tm->tm_mon + 1);
216 s->hw.cmos_data[RTC_YEAR] = to_bcd(s, tm->tm_year % 100);
217 }
219 /* month is between 0 and 11. */
220 static int get_days_in_month(int month, int year)
221 {
222 static const int days_tab[12] = {
223 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
224 };
225 int d;
226 if ( (unsigned)month >= 12 )
227 return 31;
228 d = days_tab[month];
229 if ( month == 1 )
230 if ( (year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0) )
231 d++;
232 return d;
233 }
235 /* update 'tm' to the next second */
236 static void rtc_next_second(RTCState *s)
237 {
238 struct tm *tm = &s->current_tm;
239 int days_in_month;
241 ASSERT(spin_is_locked(&s->lock));
243 tm->tm_sec++;
244 if ( (unsigned)tm->tm_sec >= 60 )
245 {
246 tm->tm_sec = 0;
247 tm->tm_min++;
248 if ( (unsigned)tm->tm_min >= 60 )
249 {
250 tm->tm_min = 0;
251 tm->tm_hour++;
252 if ( (unsigned)tm->tm_hour >= 24 )
253 {
254 tm->tm_hour = 0;
255 /* next day */
256 tm->tm_wday++;
257 if ( (unsigned)tm->tm_wday >= 7 )
258 tm->tm_wday = 0;
259 days_in_month = get_days_in_month(tm->tm_mon,
260 tm->tm_year + 1900);
261 tm->tm_mday++;
262 if ( tm->tm_mday < 1 )
263 {
264 tm->tm_mday = 1;
265 }
266 else if ( tm->tm_mday > days_in_month )
267 {
268 tm->tm_mday = 1;
269 tm->tm_mon++;
270 if ( tm->tm_mon >= 12 )
271 {
272 tm->tm_mon = 0;
273 tm->tm_year++;
274 }
275 }
276 }
277 }
278 }
279 }
281 static void rtc_update_second(void *opaque)
282 {
283 RTCState *s = opaque;
285 spin_lock(&s->lock);
287 /* if the oscillator is not in normal operation, we do not update */
288 if ( (s->hw.cmos_data[RTC_REG_A] & RTC_DIV_CTL) != RTC_REF_CLCK_32KHZ )
289 {
290 s->next_second_time += 1000000000ULL;
291 set_timer(&s->second_timer, s->next_second_time);
292 }
293 else
294 {
295 rtc_next_second(s);
297 if ( !(s->hw.cmos_data[RTC_REG_B] & RTC_SET) )
298 s->hw.cmos_data[RTC_REG_A] |= RTC_UIP;
300 /* Delay time before update cycle */
301 set_timer(&s->second_timer2, s->next_second_time + 244000);
302 }
304 spin_unlock(&s->lock);
305 }
307 static void rtc_update_second2(void *opaque)
308 {
309 RTCState *s = opaque;
310 struct domain *d = vrtc_domain(s);
312 spin_lock(&s->lock);
314 if ( !(s->hw.cmos_data[RTC_REG_B] & RTC_SET) )
315 rtc_copy_date(s);
317 /* check alarm */
318 if ( s->hw.cmos_data[RTC_REG_B] & RTC_AIE )
319 {
320 if ( ((s->hw.cmos_data[RTC_SECONDS_ALARM] & 0xc0) == 0xc0 ||
321 from_bcd(s, s->hw.cmos_data[RTC_SECONDS_ALARM]) ==
322 s->current_tm.tm_sec) &&
323 ((s->hw.cmos_data[RTC_MINUTES_ALARM] & 0xc0) == 0xc0 ||
324 from_bcd(s, s->hw.cmos_data[RTC_MINUTES_ALARM]) ==
325 s->current_tm.tm_min) &&
326 ((s->hw.cmos_data[RTC_HOURS_ALARM] & 0xc0) == 0xc0 ||
327 from_bcd(s, s->hw.cmos_data[RTC_HOURS_ALARM]) ==
328 s->current_tm.tm_hour) )
329 {
330 s->hw.cmos_data[RTC_REG_C] |= 0xa0;
331 hvm_isa_irq_deassert(d, RTC_IRQ);
332 hvm_isa_irq_assert(d, RTC_IRQ);
333 }
334 }
336 /* update ended interrupt */
337 if ( (s->hw.cmos_data[RTC_REG_B] & (RTC_UIE|RTC_SET)) == RTC_UIE )
338 {
339 s->hw.cmos_data[RTC_REG_C] |= 0x90;
340 hvm_isa_irq_deassert(d, RTC_IRQ);
341 hvm_isa_irq_assert(d, RTC_IRQ);
342 }
344 /* clear update in progress bit */
345 s->hw.cmos_data[RTC_REG_A] &= ~RTC_UIP;
347 s->next_second_time += 1000000000ULL;
348 set_timer(&s->second_timer, s->next_second_time);
350 spin_unlock(&s->lock);
351 }
353 static uint32_t rtc_ioport_read(RTCState *s, uint32_t addr)
354 {
355 int ret;
357 if ( (addr & 1) == 0 )
358 return 0xff;
360 spin_lock(&s->lock);
362 switch ( s->hw.cmos_index )
363 {
364 case RTC_SECONDS:
365 case RTC_MINUTES:
366 case RTC_HOURS:
367 case RTC_DAY_OF_WEEK:
368 case RTC_DAY_OF_MONTH:
369 case RTC_MONTH:
370 case RTC_YEAR:
371 ret = s->hw.cmos_data[s->hw.cmos_index];
372 break;
373 case RTC_REG_A:
374 ret = s->hw.cmos_data[s->hw.cmos_index];
375 break;
376 case RTC_REG_C:
377 ret = s->hw.cmos_data[s->hw.cmos_index];
378 hvm_isa_irq_deassert(vrtc_domain(s), RTC_IRQ);
379 s->hw.cmos_data[RTC_REG_C] = 0x00;
380 break;
381 default:
382 ret = s->hw.cmos_data[s->hw.cmos_index];
383 break;
384 }
386 spin_unlock(&s->lock);
388 return ret;
389 }
391 static int handle_rtc_io(
392 int dir, uint32_t port, uint32_t bytes, uint32_t *val)
393 {
394 struct RTCState *vrtc = vcpu_vrtc(current);
396 if ( bytes != 1 )
397 {
398 gdprintk(XENLOG_WARNING, "HVM_RTC bas access\n");
399 return X86EMUL_OKAY;
400 }
402 if ( dir == IOREQ_WRITE )
403 {
404 if ( rtc_ioport_write(vrtc, port, (uint8_t)*val) )
405 return X86EMUL_OKAY;
406 }
407 else if ( vrtc->hw.cmos_index < RTC_CMOS_SIZE )
408 {
409 *val = rtc_ioport_read(vrtc, port);
410 return X86EMUL_OKAY;
411 }
413 return X86EMUL_UNHANDLEABLE;
414 }
416 void rtc_migrate_timers(struct vcpu *v)
417 {
418 RTCState *s = vcpu_vrtc(v);
420 if ( v->vcpu_id == 0 )
421 {
422 migrate_timer(&s->second_timer, v->processor);
423 migrate_timer(&s->second_timer2, v->processor);
424 }
425 }
427 /* Save RTC hardware state */
428 static int rtc_save(struct domain *d, hvm_domain_context_t *h)
429 {
430 RTCState *s = domain_vrtc(d);
431 int rc;
432 spin_lock(&s->lock);
433 rc = hvm_save_entry(RTC, 0, h, &s->hw);
434 spin_unlock(&s->lock);
435 return rc;
436 }
438 /* Reload the hardware state from a saved domain */
439 static int rtc_load(struct domain *d, hvm_domain_context_t *h)
440 {
441 RTCState *s = domain_vrtc(d);
443 spin_lock(&s->lock);
445 /* Restore the registers */
446 if ( hvm_load_entry(RTC, h, &s->hw) != 0 )
447 {
448 spin_unlock(&s->lock);
449 return -EINVAL;
450 }
452 /* Reset the wall-clock time. In normal running, this runs with host
453 * time, so let's keep doing that. */
454 s->current_tm = gmtime(get_localtime(d));
455 rtc_copy_date(s);
456 s->next_second_time = NOW() + 1000000000ULL;
457 stop_timer(&s->second_timer);
458 set_timer(&s->second_timer2, s->next_second_time);
460 /* Reset the periodic interrupt timer based on the registers */
461 rtc_timer_update(s);
463 spin_unlock(&s->lock);
465 return 0;
466 }
468 HVM_REGISTER_SAVE_RESTORE(RTC, rtc_save, rtc_load, 1, HVMSR_PER_DOM);
470 void rtc_reset(struct domain *d)
471 {
472 RTCState *s = domain_vrtc(d);
474 destroy_periodic_time(&s->pt);
475 s->pt.source = PTSRC_isa;
476 }
478 void rtc_init(struct domain *d)
479 {
480 RTCState *s = domain_vrtc(d);
482 spin_lock_init(&s->lock);
484 init_timer(&s->second_timer, rtc_update_second, s, smp_processor_id());
485 init_timer(&s->second_timer2, rtc_update_second2, s, smp_processor_id());
487 register_portio_handler(d, RTC_PORT(0), 2, handle_rtc_io);
489 rtc_reset(d);
491 spin_lock(&s->lock);
493 s->hw.cmos_data[RTC_REG_A] = RTC_REF_CLCK_32KHZ | 6; /* ~1kHz */
494 s->hw.cmos_data[RTC_REG_B] = RTC_24H;
495 s->hw.cmos_data[RTC_REG_C] = 0;
496 s->hw.cmos_data[RTC_REG_D] = RTC_VRT;
498 s->current_tm = gmtime(get_localtime(d));
500 rtc_copy_date(s);
502 s->next_second_time = NOW() + 1000000000ULL;
503 stop_timer(&s->second_timer);
504 set_timer(&s->second_timer2, s->next_second_time);
506 spin_unlock(&s->lock);
507 }
509 void rtc_deinit(struct domain *d)
510 {
511 RTCState *s = domain_vrtc(d);
513 spin_barrier(&s->lock);
515 destroy_periodic_time(&s->pt);
516 kill_timer(&s->second_timer);
517 kill_timer(&s->second_timer2);
518 }
520 void rtc_update_clock(struct domain *d)
521 {
522 RTCState *s = domain_vrtc(d);
524 spin_lock(&s->lock);
525 s->current_tm = gmtime(get_localtime(d));
526 spin_unlock(&s->lock);
527 }