ia64/xen-unstable

annotate tools/ioemu/hw/mc146818rtc.c @ 10078:345464c2fd47

Allow to specify different time-of-day clock offsets for HVM guests.

There are some usage scenarios in which differing user domains want
to be using different base TOD clocks. This patch adds the ability
to specify the base TOD time difference. The patch also adds a
hook point to notify another entity when the domain changes this
offset. This might occur, for instance, on a Linux domain using
hwclock -w.

Signed-off-by: Ben Thomas <ben@virtualiron.com>
author kaf24@firebug.cl.cam.ac.uk
date Wed May 17 23:43:32 2006 +0100 (2006-05-17)
parents 8e5fc5fe636c
children
rev   line source
kaf24@5028 1 /*
kaf24@5028 2 * QEMU MC146818 RTC emulation
kaf24@5028 3 *
kaf24@5028 4 * Copyright (c) 2003-2004 Fabrice Bellard
kaf24@5028 5 *
kaf24@5028 6 * Permission is hereby granted, free of charge, to any person obtaining a copy
kaf24@5028 7 * of this software and associated documentation files (the "Software"), to deal
kaf24@5028 8 * in the Software without restriction, including without limitation the rights
kaf24@5028 9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
kaf24@5028 10 * copies of the Software, and to permit persons to whom the Software is
kaf24@5028 11 * furnished to do so, subject to the following conditions:
kaf24@5028 12 *
kaf24@5028 13 * The above copyright notice and this permission notice shall be included in
kaf24@5028 14 * all copies or substantial portions of the Software.
kaf24@5028 15 *
kaf24@5028 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
kaf24@5028 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
kaf24@5028 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
kaf24@5028 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
kaf24@5028 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
kaf24@5028 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
kaf24@5028 22 * THE SOFTWARE.
kaf24@5028 23 */
kaf24@5028 24 #include "vl.h"
kaf24@5028 25
kaf24@5028 26 //#define DEBUG_CMOS
kaf24@5028 27
kaf24@5028 28 #define RTC_SECONDS 0
kaf24@5028 29 #define RTC_SECONDS_ALARM 1
kaf24@5028 30 #define RTC_MINUTES 2
kaf24@5028 31 #define RTC_MINUTES_ALARM 3
kaf24@5028 32 #define RTC_HOURS 4
kaf24@5028 33 #define RTC_HOURS_ALARM 5
kaf24@5028 34 #define RTC_ALARM_DONT_CARE 0xC0
kaf24@5028 35
kaf24@5028 36 #define RTC_DAY_OF_WEEK 6
kaf24@5028 37 #define RTC_DAY_OF_MONTH 7
kaf24@5028 38 #define RTC_MONTH 8
kaf24@5028 39 #define RTC_YEAR 9
kaf24@5028 40
kaf24@5028 41 #define RTC_REG_A 10
kaf24@5028 42 #define RTC_REG_B 11
kaf24@5028 43 #define RTC_REG_C 12
kaf24@5028 44 #define RTC_REG_D 13
kaf24@5028 45
kaf24@5028 46 #define REG_A_UIP 0x80
kaf24@5028 47
kaf24@5028 48 #define REG_B_SET 0x80
kaf24@5028 49 #define REG_B_PIE 0x40
kaf24@5028 50 #define REG_B_AIE 0x20
kaf24@5028 51 #define REG_B_UIE 0x10
kaf24@5028 52
kaf24@5028 53 struct RTCState {
kaf24@5028 54 uint8_t cmos_data[128];
kaf24@5028 55 uint8_t cmos_index;
kaf24@5028 56 struct tm current_tm;
kaf24@5028 57 int irq;
kaf24@5028 58 /* periodic timer */
kaf24@5028 59 QEMUTimer *periodic_timer;
kaf24@5028 60 int64_t next_periodic_time;
kaf24@5028 61 /* second update */
kaf24@5028 62 int64_t next_second_time;
kaf24@5028 63 QEMUTimer *second_timer;
kaf24@5028 64 QEMUTimer *second_timer2;
kaf24@5028 65 };
kaf24@5028 66
kaf24@5028 67 static void rtc_set_time(RTCState *s);
kaf24@5028 68 static void rtc_copy_date(RTCState *s);
kaf24@5028 69
kaf24@5028 70 static void rtc_timer_update(RTCState *s, int64_t current_time)
kaf24@5028 71 {
kaf24@5028 72 int period_code, period;
kaf24@5028 73 int64_t cur_clock, next_irq_clock;
kaf24@5028 74
kaf24@5028 75 period_code = s->cmos_data[RTC_REG_A] & 0x0f;
kaf24@5028 76 if (period_code != 0 &&
kaf24@5028 77 (s->cmos_data[RTC_REG_B] & REG_B_PIE)) {
kaf24@5028 78 if (period_code <= 2)
kaf24@5028 79 period_code += 7;
kaf24@5028 80 /* period in 32 Khz cycles */
kaf24@5028 81 period = 1 << (period_code - 1);
kaf24@5028 82 /* compute 32 khz clock */
kaf24@5028 83 cur_clock = muldiv64(current_time, 32768, ticks_per_sec);
kaf24@5028 84 next_irq_clock = (cur_clock & ~(period - 1)) + period;
kaf24@5028 85 s->next_periodic_time = muldiv64(next_irq_clock, ticks_per_sec, 32768) + 1;
kaf24@5028 86 qemu_mod_timer(s->periodic_timer, s->next_periodic_time);
kaf24@5028 87 } else {
kaf24@5028 88 qemu_del_timer(s->periodic_timer);
kaf24@5028 89 }
kaf24@5028 90 }
kaf24@5028 91
kaf24@5028 92 static void rtc_periodic_timer(void *opaque)
kaf24@5028 93 {
kaf24@5028 94 RTCState *s = opaque;
kaf24@5028 95
kaf24@5028 96 rtc_timer_update(s, s->next_periodic_time);
kaf24@5028 97 s->cmos_data[RTC_REG_C] |= 0xc0;
kaf24@5028 98 pic_set_irq(s->irq, 1);
kaf24@5028 99 }
kaf24@5028 100
kaf24@5028 101 static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data)
kaf24@5028 102 {
kaf24@5028 103 RTCState *s = opaque;
kaf24@5028 104
kaf24@5028 105 if ((addr & 1) == 0) {
kaf24@5028 106 s->cmos_index = data & 0x7f;
kaf24@5028 107 } else {
kaf24@5028 108 #ifdef DEBUG_CMOS
kaf24@5028 109 printf("cmos: write index=0x%02x val=0x%02x\n",
kaf24@5028 110 s->cmos_index, data);
kaf24@5028 111 #endif
kaf24@5028 112 switch(s->cmos_index) {
kaf24@5028 113 case RTC_SECONDS_ALARM:
kaf24@5028 114 case RTC_MINUTES_ALARM:
kaf24@5028 115 case RTC_HOURS_ALARM:
kaf24@5028 116 /* XXX: not supported */
kaf24@5028 117 s->cmos_data[s->cmos_index] = data;
kaf24@5028 118 break;
kaf24@5028 119 case RTC_SECONDS:
kaf24@5028 120 case RTC_MINUTES:
kaf24@5028 121 case RTC_HOURS:
kaf24@5028 122 case RTC_DAY_OF_WEEK:
kaf24@5028 123 case RTC_DAY_OF_MONTH:
kaf24@5028 124 case RTC_MONTH:
kaf24@5028 125 case RTC_YEAR:
kaf24@5028 126 s->cmos_data[s->cmos_index] = data;
kaf24@5028 127 /* if in set mode, do not update the time */
kaf24@5028 128 if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
kaf24@5028 129 rtc_set_time(s);
kaf24@5028 130 }
kaf24@5028 131 break;
kaf24@5028 132 case RTC_REG_A:
kaf24@5028 133 /* UIP bit is read only */
kaf24@5028 134 s->cmos_data[RTC_REG_A] = (data & ~REG_A_UIP) |
kaf24@5028 135 (s->cmos_data[RTC_REG_A] & REG_A_UIP);
kaf24@5028 136 rtc_timer_update(s, qemu_get_clock(vm_clock));
kaf24@5028 137 break;
kaf24@5028 138 case RTC_REG_B:
kaf24@5028 139 if (data & REG_B_SET) {
kaf24@5028 140 /* set mode: reset UIP mode */
kaf24@5028 141 s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
kaf24@5028 142 data &= ~REG_B_UIE;
kaf24@5028 143 } else {
kaf24@5028 144 /* if disabling set mode, update the time */
kaf24@5028 145 if (s->cmos_data[RTC_REG_B] & REG_B_SET) {
kaf24@5028 146 rtc_set_time(s);
kaf24@5028 147 }
kaf24@5028 148 }
kaf24@5028 149 s->cmos_data[RTC_REG_B] = data;
kaf24@5028 150 rtc_timer_update(s, qemu_get_clock(vm_clock));
kaf24@5028 151 break;
kaf24@5028 152 case RTC_REG_C:
kaf24@5028 153 case RTC_REG_D:
kaf24@5028 154 /* cannot write to them */
kaf24@5028 155 break;
kaf24@5028 156 default:
kaf24@5028 157 s->cmos_data[s->cmos_index] = data;
kaf24@5028 158 break;
kaf24@5028 159 }
kaf24@5028 160 }
kaf24@5028 161 }
kaf24@5028 162
kaf24@5028 163 static inline int to_bcd(RTCState *s, int a)
kaf24@5028 164 {
kaf24@5028 165 if (s->cmos_data[RTC_REG_B] & 0x04) {
kaf24@5028 166 return a;
kaf24@5028 167 } else {
kaf24@5028 168 return ((a / 10) << 4) | (a % 10);
kaf24@5028 169 }
kaf24@5028 170 }
kaf24@5028 171
kaf24@5028 172 static inline int from_bcd(RTCState *s, int a)
kaf24@5028 173 {
kaf24@5028 174 if (s->cmos_data[RTC_REG_B] & 0x04) {
kaf24@5028 175 return a;
kaf24@5028 176 } else {
kaf24@5028 177 return ((a >> 4) * 10) + (a & 0x0f);
kaf24@5028 178 }
kaf24@5028 179 }
kaf24@5028 180
kaf24@10078 181 static void send_timeoffset_msg(time_t delta)
kaf24@10078 182 {
kaf24@10078 183
kaf24@10078 184 /* This routine is used to inform another entity that the
kaf24@10078 185 base time offset has changed. For instance, if you
kaf24@10078 186 were using xenstore, you might want to write to the store
kaf24@10078 187 at this point. Or, you might use some other method.
kaf24@10078 188 Whatever you might choose, here's a hook point to implement it.
kaf24@10078 189
kaf24@10078 190 One item of note is that this delta is in addition to
kaf24@10078 191 any existing offset you might be already using. */
kaf24@10078 192
kaf24@10078 193 return;
kaf24@10078 194 }
kaf24@10078 195
kaf24@5028 196 static void rtc_set_time(RTCState *s)
kaf24@5028 197 {
kaf24@5028 198 struct tm *tm = &s->current_tm;
kaf24@10078 199 time_t before, after;
kaf24@10078 200
kaf24@10078 201 before = mktime(tm);
kaf24@5028 202 tm->tm_sec = from_bcd(s, s->cmos_data[RTC_SECONDS]);
kaf24@5028 203 tm->tm_min = from_bcd(s, s->cmos_data[RTC_MINUTES]);
kaf24@5028 204 tm->tm_hour = from_bcd(s, s->cmos_data[RTC_HOURS] & 0x7f);
kaf24@5028 205 if (!(s->cmos_data[RTC_REG_B] & 0x02) &&
kaf24@5028 206 (s->cmos_data[RTC_HOURS] & 0x80)) {
kaf24@5028 207 tm->tm_hour += 12;
kaf24@5028 208 }
kaf24@5028 209 tm->tm_wday = from_bcd(s, s->cmos_data[RTC_DAY_OF_WEEK]);
kaf24@5028 210 tm->tm_mday = from_bcd(s, s->cmos_data[RTC_DAY_OF_MONTH]);
kaf24@5028 211 tm->tm_mon = from_bcd(s, s->cmos_data[RTC_MONTH]) - 1;
kaf24@5028 212 tm->tm_year = from_bcd(s, s->cmos_data[RTC_YEAR]) + 100;
kaf24@10078 213
kaf24@10078 214 /* Compute, and send, the additional time delta
kaf24@10078 215 We could compute the total time delta, but this is
kaf24@10078 216 sufficient, and simple. */
kaf24@10078 217 after = mktime(tm);
kaf24@10078 218 send_timeoffset_msg(after-before);
kaf24@5028 219 }
kaf24@5028 220
kaf24@5028 221 static void rtc_copy_date(RTCState *s)
kaf24@5028 222 {
kaf24@5028 223 const struct tm *tm = &s->current_tm;
kaf24@5028 224
kaf24@5028 225 s->cmos_data[RTC_SECONDS] = to_bcd(s, tm->tm_sec);
kaf24@5028 226 s->cmos_data[RTC_MINUTES] = to_bcd(s, tm->tm_min);
kaf24@5028 227 if (s->cmos_data[RTC_REG_B] & 0x02) {
kaf24@5028 228 /* 24 hour format */
kaf24@5028 229 s->cmos_data[RTC_HOURS] = to_bcd(s, tm->tm_hour);
kaf24@5028 230 } else {
kaf24@5028 231 /* 12 hour format */
kaf24@5028 232 s->cmos_data[RTC_HOURS] = to_bcd(s, tm->tm_hour % 12);
kaf24@5028 233 if (tm->tm_hour >= 12)
kaf24@5028 234 s->cmos_data[RTC_HOURS] |= 0x80;
kaf24@5028 235 }
kaf24@5028 236 s->cmos_data[RTC_DAY_OF_WEEK] = to_bcd(s, tm->tm_wday);
kaf24@5028 237 s->cmos_data[RTC_DAY_OF_MONTH] = to_bcd(s, tm->tm_mday);
kaf24@5028 238 s->cmos_data[RTC_MONTH] = to_bcd(s, tm->tm_mon + 1);
kaf24@5028 239 s->cmos_data[RTC_YEAR] = to_bcd(s, tm->tm_year % 100);
kaf24@5028 240 }
kaf24@5028 241
kaf24@5028 242 /* month is between 0 and 11. */
kaf24@5028 243 static int get_days_in_month(int month, int year)
kaf24@5028 244 {
kaf24@5028 245 static const int days_tab[12] = {
kaf24@5028 246 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
kaf24@5028 247 };
kaf24@5028 248 int d;
kaf24@5028 249 if ((unsigned )month >= 12)
kaf24@5028 250 return 31;
kaf24@5028 251 d = days_tab[month];
kaf24@5028 252 if (month == 1) {
kaf24@5028 253 if ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0))
kaf24@5028 254 d++;
kaf24@5028 255 }
kaf24@5028 256 return d;
kaf24@5028 257 }
kaf24@5028 258
kaf24@5028 259 /* update 'tm' to the next second */
kaf24@5028 260 static void rtc_next_second(struct tm *tm)
kaf24@5028 261 {
kaf24@5028 262 int days_in_month;
kaf24@5028 263
kaf24@5028 264 tm->tm_sec++;
kaf24@5028 265 if ((unsigned)tm->tm_sec >= 60) {
kaf24@5028 266 tm->tm_sec = 0;
kaf24@5028 267 tm->tm_min++;
kaf24@5028 268 if ((unsigned)tm->tm_min >= 60) {
kaf24@5028 269 tm->tm_min = 0;
kaf24@5028 270 tm->tm_hour++;
kaf24@5028 271 if ((unsigned)tm->tm_hour >= 24) {
kaf24@5028 272 tm->tm_hour = 0;
kaf24@5028 273 /* next day */
kaf24@5028 274 tm->tm_wday++;
kaf24@5028 275 if ((unsigned)tm->tm_wday >= 7)
kaf24@5028 276 tm->tm_wday = 0;
kaf24@5028 277 days_in_month = get_days_in_month(tm->tm_mon,
kaf24@5028 278 tm->tm_year + 1900);
kaf24@5028 279 tm->tm_mday++;
kaf24@5028 280 if (tm->tm_mday < 1) {
kaf24@5028 281 tm->tm_mday = 1;
kaf24@5028 282 } else if (tm->tm_mday > days_in_month) {
kaf24@5028 283 tm->tm_mday = 1;
kaf24@5028 284 tm->tm_mon++;
kaf24@5028 285 if (tm->tm_mon >= 12) {
kaf24@5028 286 tm->tm_mon = 0;
kaf24@5028 287 tm->tm_year++;
kaf24@5028 288 }
kaf24@5028 289 }
kaf24@5028 290 }
kaf24@5028 291 }
kaf24@5028 292 }
kaf24@5028 293 }
kaf24@5028 294
kaf24@5028 295
kaf24@5028 296 static void rtc_update_second(void *opaque)
kaf24@5028 297 {
kaf24@5028 298 RTCState *s = opaque;
kaf24@5028 299 int64_t delay;
kaf24@5028 300
kaf24@5028 301 /* if the oscillator is not in normal operation, we do not update */
kaf24@5028 302 if ((s->cmos_data[RTC_REG_A] & 0x70) != 0x20) {
kaf24@5028 303 s->next_second_time += ticks_per_sec;
kaf24@5028 304 qemu_mod_timer(s->second_timer, s->next_second_time);
kaf24@5028 305 } else {
kaf24@5028 306 rtc_next_second(&s->current_tm);
kaf24@5028 307
kaf24@5028 308 if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
kaf24@5028 309 /* update in progress bit */
kaf24@5028 310 s->cmos_data[RTC_REG_A] |= REG_A_UIP;
kaf24@5028 311 }
kaf24@5028 312 /* should be 244 us = 8 / 32768 seconds, but currently the
kaf24@5028 313 timers do not have the necessary resolution. */
kaf24@5028 314 delay = (ticks_per_sec * 1) / 100;
kaf24@5028 315 if (delay < 1)
kaf24@5028 316 delay = 1;
kaf24@5028 317 qemu_mod_timer(s->second_timer2,
kaf24@5028 318 s->next_second_time + delay);
kaf24@5028 319 }
kaf24@5028 320 }
kaf24@5028 321
kaf24@5028 322 static void rtc_update_second2(void *opaque)
kaf24@5028 323 {
kaf24@5028 324 RTCState *s = opaque;
kaf24@5028 325
kaf24@5028 326 if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
kaf24@5028 327 rtc_copy_date(s);
kaf24@5028 328 }
kaf24@5028 329
kaf24@5028 330 /* check alarm */
kaf24@5028 331 if (s->cmos_data[RTC_REG_B] & REG_B_AIE) {
kaf24@5028 332 if (((s->cmos_data[RTC_SECONDS_ALARM] & 0xc0) == 0xc0 ||
kaf24@5028 333 s->cmos_data[RTC_SECONDS_ALARM] == s->current_tm.tm_sec) &&
kaf24@5028 334 ((s->cmos_data[RTC_MINUTES_ALARM] & 0xc0) == 0xc0 ||
kaf24@5028 335 s->cmos_data[RTC_MINUTES_ALARM] == s->current_tm.tm_mon) &&
kaf24@5028 336 ((s->cmos_data[RTC_HOURS_ALARM] & 0xc0) == 0xc0 ||
kaf24@5028 337 s->cmos_data[RTC_HOURS_ALARM] == s->current_tm.tm_hour)) {
kaf24@5028 338
kaf24@5028 339 s->cmos_data[RTC_REG_C] |= 0xa0;
kaf24@5028 340 pic_set_irq(s->irq, 1);
kaf24@5028 341 }
kaf24@5028 342 }
kaf24@5028 343
kaf24@5028 344 /* update ended interrupt */
kaf24@5028 345 if (s->cmos_data[RTC_REG_B] & REG_B_UIE) {
kaf24@5028 346 s->cmos_data[RTC_REG_C] |= 0x90;
kaf24@5028 347 pic_set_irq(s->irq, 1);
kaf24@5028 348 }
kaf24@5028 349
kaf24@5028 350 /* clear update in progress bit */
kaf24@5028 351 s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
kaf24@5028 352
kaf24@5028 353 s->next_second_time += ticks_per_sec;
kaf24@5028 354 qemu_mod_timer(s->second_timer, s->next_second_time);
kaf24@5028 355 }
kaf24@5028 356
kaf24@5028 357 static uint32_t cmos_ioport_read(void *opaque, uint32_t addr)
kaf24@5028 358 {
kaf24@5028 359 RTCState *s = opaque;
kaf24@5028 360 int ret;
kaf24@5028 361 if ((addr & 1) == 0) {
kaf24@5028 362 return 0xff;
kaf24@5028 363 } else {
kaf24@5028 364 switch(s->cmos_index) {
kaf24@5028 365 case RTC_SECONDS:
kaf24@5028 366 case RTC_MINUTES:
kaf24@5028 367 case RTC_HOURS:
kaf24@5028 368 case RTC_DAY_OF_WEEK:
kaf24@5028 369 case RTC_DAY_OF_MONTH:
kaf24@5028 370 case RTC_MONTH:
kaf24@5028 371 case RTC_YEAR:
kaf24@5028 372 ret = s->cmos_data[s->cmos_index];
kaf24@5028 373 break;
kaf24@5028 374 case RTC_REG_A:
kaf24@5028 375 ret = s->cmos_data[s->cmos_index];
kaf24@5028 376 break;
kaf24@5028 377 case RTC_REG_C:
kaf24@5028 378 ret = s->cmos_data[s->cmos_index];
kaf24@5028 379 pic_set_irq(s->irq, 0);
kaf24@5028 380 s->cmos_data[RTC_REG_C] = 0x00;
kaf24@5028 381 break;
kaf24@5028 382 default:
kaf24@5028 383 ret = s->cmos_data[s->cmos_index];
kaf24@5028 384 break;
kaf24@5028 385 }
kaf24@5028 386 #ifdef DEBUG_CMOS
kaf24@5028 387 printf("cmos: read index=0x%02x val=0x%02x\n",
kaf24@5028 388 s->cmos_index, ret);
kaf24@5028 389 #endif
kaf24@5028 390 return ret;
kaf24@5028 391 }
kaf24@5028 392 }
kaf24@5028 393
kaf24@5028 394 void rtc_set_memory(RTCState *s, int addr, int val)
kaf24@5028 395 {
kaf24@5028 396 if (addr >= 0 && addr <= 127)
kaf24@5028 397 s->cmos_data[addr] = val;
kaf24@5028 398 }
kaf24@5028 399
kaf24@5028 400 void rtc_set_date(RTCState *s, const struct tm *tm)
kaf24@5028 401 {
kaf24@5028 402 s->current_tm = *tm;
kaf24@5028 403 rtc_copy_date(s);
kaf24@5028 404 }
kaf24@5028 405
kaf24@5028 406 static void rtc_save(QEMUFile *f, void *opaque)
kaf24@5028 407 {
kaf24@5028 408 RTCState *s = opaque;
kaf24@5028 409
kaf24@5028 410 qemu_put_buffer(f, s->cmos_data, 128);
kaf24@5028 411 qemu_put_8s(f, &s->cmos_index);
kaf24@5028 412
kaf24@5028 413 qemu_put_be32s(f, &s->current_tm.tm_sec);
kaf24@5028 414 qemu_put_be32s(f, &s->current_tm.tm_min);
kaf24@5028 415 qemu_put_be32s(f, &s->current_tm.tm_hour);
kaf24@5028 416 qemu_put_be32s(f, &s->current_tm.tm_wday);
kaf24@5028 417 qemu_put_be32s(f, &s->current_tm.tm_mday);
kaf24@5028 418 qemu_put_be32s(f, &s->current_tm.tm_mon);
kaf24@5028 419 qemu_put_be32s(f, &s->current_tm.tm_year);
kaf24@5028 420
kaf24@5028 421 qemu_put_timer(f, s->periodic_timer);
kaf24@5028 422 qemu_put_be64s(f, &s->next_periodic_time);
kaf24@5028 423
kaf24@5028 424 qemu_put_be64s(f, &s->next_second_time);
kaf24@5028 425 qemu_put_timer(f, s->second_timer);
kaf24@5028 426 qemu_put_timer(f, s->second_timer2);
kaf24@5028 427 }
kaf24@5028 428
kaf24@5028 429 static int rtc_load(QEMUFile *f, void *opaque, int version_id)
kaf24@5028 430 {
kaf24@5028 431 RTCState *s = opaque;
kaf24@5028 432
kaf24@5028 433 if (version_id != 1)
kaf24@5028 434 return -EINVAL;
kaf24@5028 435
kaf24@5028 436 qemu_get_buffer(f, s->cmos_data, 128);
kaf24@5028 437 qemu_get_8s(f, &s->cmos_index);
kaf24@5028 438
kaf24@5028 439 qemu_get_be32s(f, &s->current_tm.tm_sec);
kaf24@5028 440 qemu_get_be32s(f, &s->current_tm.tm_min);
kaf24@5028 441 qemu_get_be32s(f, &s->current_tm.tm_hour);
kaf24@5028 442 qemu_get_be32s(f, &s->current_tm.tm_wday);
kaf24@5028 443 qemu_get_be32s(f, &s->current_tm.tm_mday);
kaf24@5028 444 qemu_get_be32s(f, &s->current_tm.tm_mon);
kaf24@5028 445 qemu_get_be32s(f, &s->current_tm.tm_year);
kaf24@5028 446
kaf24@5028 447 qemu_get_timer(f, s->periodic_timer);
kaf24@5028 448 qemu_get_be64s(f, &s->next_periodic_time);
kaf24@5028 449
kaf24@5028 450 qemu_get_be64s(f, &s->next_second_time);
kaf24@5028 451 qemu_get_timer(f, s->second_timer);
kaf24@5028 452 qemu_get_timer(f, s->second_timer2);
kaf24@5028 453 return 0;
kaf24@5028 454 }
kaf24@5028 455
kaf24@5028 456 RTCState *rtc_init(int base, int irq)
kaf24@5028 457 {
kaf24@5028 458 RTCState *s;
kaf24@5028 459
kaf24@5028 460 s = qemu_mallocz(sizeof(RTCState));
kaf24@5028 461 if (!s)
kaf24@5028 462 return NULL;
kaf24@5028 463
kaf24@5028 464 s->irq = irq;
kaf24@5028 465 s->cmos_data[RTC_REG_A] = 0x26;
kaf24@5028 466 s->cmos_data[RTC_REG_B] = 0x02;
kaf24@5028 467 s->cmos_data[RTC_REG_C] = 0x00;
kaf24@5028 468 s->cmos_data[RTC_REG_D] = 0x80;
kaf24@5028 469
kaf24@5028 470 s->periodic_timer = qemu_new_timer(vm_clock,
kaf24@5028 471 rtc_periodic_timer, s);
kaf24@5028 472 s->second_timer = qemu_new_timer(vm_clock,
kaf24@5028 473 rtc_update_second, s);
kaf24@5028 474 s->second_timer2 = qemu_new_timer(vm_clock,
kaf24@5028 475 rtc_update_second2, s);
kaf24@5028 476
kaf24@5028 477 s->next_second_time = qemu_get_clock(vm_clock) + (ticks_per_sec * 99) / 100;
kaf24@5028 478 qemu_mod_timer(s->second_timer2, s->next_second_time);
kaf24@5028 479
kaf24@5028 480 register_ioport_write(base, 2, 1, cmos_ioport_write, s);
kaf24@5028 481 register_ioport_read(base, 2, 1, cmos_ioport_read, s);
kaf24@5028 482
kaf24@5028 483 register_savevm("mc146818rtc", base, 1, rtc_save, rtc_load, s);
kaf24@5028 484 return s;
kaf24@5028 485 }
kaf24@5028 486