You need to sign in or sign up before continuing.
mc146818rtc.c 21.5 KB
Newer Older
B
bellard 已提交
1 2
/*
 * QEMU MC146818 RTC emulation
3
 *
B
bellard 已提交
4
 * Copyright (c) 2003-2004 Fabrice Bellard
5
 *
B
bellard 已提交
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
P
pbrook 已提交
24 25 26
#include "hw.h"
#include "qemu-timer.h"
#include "sysemu.h"
27
#include "mc146818rtc.h"
B
bellard 已提交
28

29 30 31 32
#ifdef TARGET_I386
#include "apic.h"
#endif

B
bellard 已提交
33
//#define DEBUG_CMOS
B
Blue Swirl 已提交
34
//#define DEBUG_COALESCED
B
bellard 已提交
35

36 37 38 39 40 41
#ifdef DEBUG_CMOS
# define CMOS_DPRINTF(format, ...)      printf(format, ## __VA_ARGS__)
#else
# define CMOS_DPRINTF(format, ...)      do { } while (0)
#endif

B
Blue Swirl 已提交
42 43 44 45 46 47
#ifdef DEBUG_COALESCED
# define DPRINTF_C(format, ...)      printf(format, ## __VA_ARGS__)
#else
# define DPRINTF_C(format, ...)      do { } while (0)
#endif

G
Gleb Natapov 已提交
48
#define RTC_REINJECT_ON_ACK_COUNT 20
P
Paolo Bonzini 已提交
49
#define RTC_CLOCK_RATE            32768
50

51
typedef struct RTCState {
52
    ISADevice dev;
53
    MemoryRegion io;
54 55
    uint8_t cmos_data[128];
    uint8_t cmos_index;
56
    struct tm current_tm;
57
    int32_t base_year;
P
pbrook 已提交
58
    qemu_irq irq;
59
    qemu_irq sqw_irq;
60
    int it_shift;
61 62 63 64 65
    /* periodic timer */
    QEMUTimer *periodic_timer;
    int64_t next_periodic_time;
    /* second update */
    int64_t next_second_time;
66
    uint16_t irq_reinject_on_ack_count;
67 68
    uint32_t irq_coalesced;
    uint32_t period;
69
    QEMUTimer *coalesced_timer;
70 71
    QEMUTimer *second_timer;
    QEMUTimer *second_timer2;
72
    Notifier clock_reset_notifier;
73
    LostTickPolicy lost_tick_policy;
74
    Notifier suspend_notifier;
75
} RTCState;
76 77 78 79

static void rtc_set_time(RTCState *s);
static void rtc_copy_date(RTCState *s);

80 81 82 83 84 85 86 87
#ifdef TARGET_I386
static void rtc_coalesced_timer_update(RTCState *s)
{
    if (s->irq_coalesced == 0) {
        qemu_del_timer(s->coalesced_timer);
    } else {
        /* divide each RTC interval to 2 - 8 smaller intervals */
        int c = MIN(s->irq_coalesced, 7) + 1; 
88
        int64_t next_clock = qemu_get_clock_ns(rtc_clock) +
P
Paolo Bonzini 已提交
89
            muldiv64(s->period / c, get_ticks_per_sec(), RTC_CLOCK_RATE);
90 91 92 93 94 95 96 97 98 99 100
        qemu_mod_timer(s->coalesced_timer, next_clock);
    }
}

static void rtc_coalesced_timer(void *opaque)
{
    RTCState *s = opaque;

    if (s->irq_coalesced != 0) {
        apic_reset_irq_delivered();
        s->cmos_data[RTC_REG_C] |= 0xc0;
B
Blue Swirl 已提交
101
        DPRINTF_C("cmos: injecting from timer\n");
102
        qemu_irq_raise(s->irq);
103 104
        if (apic_get_irq_delivered()) {
            s->irq_coalesced--;
B
Blue Swirl 已提交
105 106
            DPRINTF_C("cmos: coalesced irqs decreased to %d\n",
                      s->irq_coalesced);
107 108 109 110 111 112 113
        }
    }

    rtc_coalesced_timer_update(s);
}
#endif

Y
Yang Zhang 已提交
114
static void periodic_timer_update(RTCState *s, int64_t current_time)
115 116 117 118 119
{
    int period_code, period;
    int64_t cur_clock, next_irq_clock;

    period_code = s->cmos_data[RTC_REG_A] & 0x0f;
120
    if (period_code != 0
121
        && ((s->cmos_data[RTC_REG_B] & REG_B_PIE)
122
            || ((s->cmos_data[RTC_REG_B] & REG_B_SQWE) && s->sqw_irq))) {
123 124 125 126
        if (period_code <= 2)
            period_code += 7;
        /* period in 32 Khz cycles */
        period = 1 << (period_code - 1);
127
#ifdef TARGET_I386
B
Blue Swirl 已提交
128
        if (period != s->period) {
129
            s->irq_coalesced = (s->irq_coalesced * s->period) / period;
B
Blue Swirl 已提交
130 131
            DPRINTF_C("cmos: coalesced irqs scaled to %d\n", s->irq_coalesced);
        }
132 133
        s->period = period;
#endif
134
        /* compute 32 khz clock */
P
Paolo Bonzini 已提交
135
        cur_clock = muldiv64(current_time, RTC_CLOCK_RATE, get_ticks_per_sec());
136
        next_irq_clock = (cur_clock & ~(period - 1)) + period;
J
Jan Kiszka 已提交
137
        s->next_periodic_time =
P
Paolo Bonzini 已提交
138
            muldiv64(next_irq_clock, get_ticks_per_sec(), RTC_CLOCK_RATE) + 1;
139 140
        qemu_mod_timer(s->periodic_timer, s->next_periodic_time);
    } else {
141 142 143
#ifdef TARGET_I386
        s->irq_coalesced = 0;
#endif
144 145 146 147 148 149 150 151
        qemu_del_timer(s->periodic_timer);
    }
}

static void rtc_periodic_timer(void *opaque)
{
    RTCState *s = opaque;

Y
Yang Zhang 已提交
152
    periodic_timer_update(s, s->next_periodic_time);
153
    s->cmos_data[RTC_REG_C] |= REG_C_PF;
154
    if (s->cmos_data[RTC_REG_B] & REG_B_PIE) {
155
        s->cmos_data[RTC_REG_C] |= REG_C_IRQF;
156
#ifdef TARGET_I386
157
        if (s->lost_tick_policy == LOST_TICK_SLEW) {
158 159
            if (s->irq_reinject_on_ack_count >= RTC_REINJECT_ON_ACK_COUNT)
                s->irq_reinject_on_ack_count = 0;		
160
            apic_reset_irq_delivered();
161
            qemu_irq_raise(s->irq);
162 163 164
            if (!apic_get_irq_delivered()) {
                s->irq_coalesced++;
                rtc_coalesced_timer_update(s);
B
Blue Swirl 已提交
165 166
                DPRINTF_C("cmos: coalesced irqs increased to %d\n",
                          s->irq_coalesced);
167 168 169
            }
        } else
#endif
170
        qemu_irq_raise(s->irq);
171 172 173 174 175 176
    }
    if (s->cmos_data[RTC_REG_B] & REG_B_SQWE) {
        /* Not square wave at all but we don't want 2048Hz interrupts!
           Must be seen as a pulse.  */
        qemu_irq_raise(s->sqw_irq);
    }
177
}
B
bellard 已提交
178

B
bellard 已提交
179
static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data)
B
bellard 已提交
180
{
B
bellard 已提交
181
    RTCState *s = opaque;
B
bellard 已提交
182 183 184 185

    if ((addr & 1) == 0) {
        s->cmos_index = data & 0x7f;
    } else {
186 187
        CMOS_DPRINTF("cmos: write index=0x%02x val=0x%02x\n",
                     s->cmos_index, data);
188
        switch(s->cmos_index) {
B
bellard 已提交
189 190 191 192 193 194 195 196 197 198 199 200 201
        case RTC_SECONDS_ALARM:
        case RTC_MINUTES_ALARM:
        case RTC_HOURS_ALARM:
            s->cmos_data[s->cmos_index] = data;
            break;
        case RTC_SECONDS:
        case RTC_MINUTES:
        case RTC_HOURS:
        case RTC_DAY_OF_WEEK:
        case RTC_DAY_OF_MONTH:
        case RTC_MONTH:
        case RTC_YEAR:
            s->cmos_data[s->cmos_index] = data;
202 203 204 205
            /* if in set mode, do not update the time */
            if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
                rtc_set_time(s);
            }
B
bellard 已提交
206 207
            break;
        case RTC_REG_A:
208 209 210
            /* UIP bit is read only */
            s->cmos_data[RTC_REG_A] = (data & ~REG_A_UIP) |
                (s->cmos_data[RTC_REG_A] & REG_A_UIP);
Y
Yang Zhang 已提交
211
            periodic_timer_update(s, qemu_get_clock_ns(rtc_clock));
212
            break;
B
bellard 已提交
213
        case RTC_REG_B:
214 215 216 217 218 219 220 221 222 223
            if (data & REG_B_SET) {
                /* set mode: reset UIP mode */
                s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
                data &= ~REG_B_UIE;
            } else {
                /* if disabling set mode, update the time */
                if (s->cmos_data[RTC_REG_B] & REG_B_SET) {
                    rtc_set_time(s);
                }
            }
224
            s->cmos_data[RTC_REG_B] = data;
Y
Yang Zhang 已提交
225
            periodic_timer_update(s, qemu_get_clock_ns(rtc_clock));
B
bellard 已提交
226 227 228 229 230 231 232 233 234 235 236 237
            break;
        case RTC_REG_C:
        case RTC_REG_D:
            /* cannot write to them */
            break;
        default:
            s->cmos_data[s->cmos_index] = data;
            break;
        }
    }
}

P
Paul Brook 已提交
238
static inline int rtc_to_bcd(RTCState *s, int a)
B
bellard 已提交
239
{
A
aurel32 已提交
240
    if (s->cmos_data[RTC_REG_B] & REG_B_DM) {
241 242 243 244
        return a;
    } else {
        return ((a / 10) << 4) | (a % 10);
    }
B
bellard 已提交
245 246
}

P
Paul Brook 已提交
247
static inline int rtc_from_bcd(RTCState *s, int a)
B
bellard 已提交
248
{
A
aurel32 已提交
249
    if (s->cmos_data[RTC_REG_B] & REG_B_DM) {
250 251 252 253 254 255 256 257
        return a;
    } else {
        return ((a >> 4) * 10) + (a & 0x0f);
    }
}

static void rtc_set_time(RTCState *s)
{
258
    struct tm *tm = &s->current_tm;
259

P
Paul Brook 已提交
260 261 262
    tm->tm_sec = rtc_from_bcd(s, s->cmos_data[RTC_SECONDS]);
    tm->tm_min = rtc_from_bcd(s, s->cmos_data[RTC_MINUTES]);
    tm->tm_hour = rtc_from_bcd(s, s->cmos_data[RTC_HOURS] & 0x7f);
P
Paolo Bonzini 已提交
263 264 265 266 267
    if (!(s->cmos_data[RTC_REG_B] & REG_B_24H)) {
        tm->tm_hour %= 12;
        if (s->cmos_data[RTC_HOURS] & 0x80) {
            tm->tm_hour += 12;
        }
268
    }
P
Paul Brook 已提交
269 270 271 272
    tm->tm_wday = rtc_from_bcd(s, s->cmos_data[RTC_DAY_OF_WEEK]) - 1;
    tm->tm_mday = rtc_from_bcd(s, s->cmos_data[RTC_DAY_OF_MONTH]);
    tm->tm_mon = rtc_from_bcd(s, s->cmos_data[RTC_MONTH]) - 1;
    tm->tm_year = rtc_from_bcd(s, s->cmos_data[RTC_YEAR]) + s->base_year - 1900;
273 274

    rtc_change_mon_event(tm);
275 276 277 278 279
}

static void rtc_copy_date(RTCState *s)
{
    const struct tm *tm = &s->current_tm;
280
    int year;
281

P
Paul Brook 已提交
282 283
    s->cmos_data[RTC_SECONDS] = rtc_to_bcd(s, tm->tm_sec);
    s->cmos_data[RTC_MINUTES] = rtc_to_bcd(s, tm->tm_min);
A
Aurelien Jarno 已提交
284
    if (s->cmos_data[RTC_REG_B] & REG_B_24H) {
285
        /* 24 hour format */
P
Paul Brook 已提交
286
        s->cmos_data[RTC_HOURS] = rtc_to_bcd(s, tm->tm_hour);
287 288
    } else {
        /* 12 hour format */
P
Paolo Bonzini 已提交
289 290
        int h = (tm->tm_hour % 12) ? tm->tm_hour % 12 : 12;
        s->cmos_data[RTC_HOURS] = rtc_to_bcd(s, h);
291 292 293
        if (tm->tm_hour >= 12)
            s->cmos_data[RTC_HOURS] |= 0x80;
    }
P
Paul Brook 已提交
294 295 296
    s->cmos_data[RTC_DAY_OF_WEEK] = rtc_to_bcd(s, tm->tm_wday + 1);
    s->cmos_data[RTC_DAY_OF_MONTH] = rtc_to_bcd(s, tm->tm_mday);
    s->cmos_data[RTC_MONTH] = rtc_to_bcd(s, tm->tm_mon + 1);
297 298 299
    year = (tm->tm_year - s->base_year) % 100;
    if (year < 0)
        year += 100;
P
Paul Brook 已提交
300
    s->cmos_data[RTC_YEAR] = rtc_to_bcd(s, year);
301 302 303 304 305
}

/* month is between 0 and 11. */
static int get_days_in_month(int month, int year)
{
306 307
    static const int days_tab[12] = {
        31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337
    };
    int d;
    if ((unsigned )month >= 12)
        return 31;
    d = days_tab[month];
    if (month == 1) {
        if ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0))
            d++;
    }
    return d;
}

/* update 'tm' to the next second */
static void rtc_next_second(struct tm *tm)
{
    int days_in_month;

    tm->tm_sec++;
    if ((unsigned)tm->tm_sec >= 60) {
        tm->tm_sec = 0;
        tm->tm_min++;
        if ((unsigned)tm->tm_min >= 60) {
            tm->tm_min = 0;
            tm->tm_hour++;
            if ((unsigned)tm->tm_hour >= 24) {
                tm->tm_hour = 0;
                /* next day */
                tm->tm_wday++;
                if ((unsigned)tm->tm_wday >= 7)
                    tm->tm_wday = 0;
338
                days_in_month = get_days_in_month(tm->tm_mon,
339 340 341 342 343 344 345 346 347 348 349 350 351 352 353
                                                  tm->tm_year + 1900);
                tm->tm_mday++;
                if (tm->tm_mday < 1) {
                    tm->tm_mday = 1;
                } else if (tm->tm_mday > days_in_month) {
                    tm->tm_mday = 1;
                    tm->tm_mon++;
                    if (tm->tm_mon >= 12) {
                        tm->tm_mon = 0;
                        tm->tm_year++;
                    }
                }
            }
        }
    }
354 355
}

356

357 358 359
static void rtc_update_second(void *opaque)
{
    RTCState *s = opaque;
B
bellard 已提交
360
    int64_t delay;
361 362 363

    /* if the oscillator is not in normal operation, we do not update */
    if ((s->cmos_data[RTC_REG_A] & 0x70) != 0x20) {
364
        s->next_second_time += get_ticks_per_sec();
365 366
        qemu_mod_timer(s->second_timer, s->next_second_time);
    } else {
367
        rtc_next_second(&s->current_tm);
368

369 370 371 372
        if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
            /* update in progress bit */
            s->cmos_data[RTC_REG_A] |= REG_A_UIP;
        }
P
Paolo Bonzini 已提交
373
        /* should be 244 us = 8 / RTC_CLOCK_RATE seconds, but currently the
B
bellard 已提交
374
           timers do not have the necessary resolution. */
375
        delay = (get_ticks_per_sec() * 1) / 100;
B
bellard 已提交
376 377
        if (delay < 1)
            delay = 1;
378
        qemu_mod_timer(s->second_timer2,
B
bellard 已提交
379
                       s->next_second_time + delay);
380 381 382 383 384 385 386 387 388 389 390 391
    }
}

static void rtc_update_second2(void *opaque)
{
    RTCState *s = opaque;

    if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
        rtc_copy_date(s);
    }

    /* check alarm */
392 393 394 395 396 397 398 399 400
    if (((s->cmos_data[RTC_SECONDS_ALARM] & 0xc0) == 0xc0 ||
         rtc_from_bcd(s, s->cmos_data[RTC_SECONDS_ALARM]) == s->current_tm.tm_sec) &&
        ((s->cmos_data[RTC_MINUTES_ALARM] & 0xc0) == 0xc0 ||
         rtc_from_bcd(s, s->cmos_data[RTC_MINUTES_ALARM]) == s->current_tm.tm_min) &&
        ((s->cmos_data[RTC_HOURS_ALARM] & 0xc0) == 0xc0 ||
         rtc_from_bcd(s, s->cmos_data[RTC_HOURS_ALARM]) == s->current_tm.tm_hour)) {

        s->cmos_data[RTC_REG_C] |= REG_C_AF;
        if (s->cmos_data[RTC_REG_B] & REG_B_AIE) {
401
            qemu_system_wakeup_request(QEMU_WAKEUP_REASON_RTC);
402
            qemu_irq_raise(s->irq);
403
            s->cmos_data[RTC_REG_C] |= REG_C_IRQF;
404 405 406 407
        }
    }

    /* update ended interrupt */
B
Bernhard Kauer 已提交
408
    s->cmos_data[RTC_REG_C] |= REG_C_UF;
409
    if (s->cmos_data[RTC_REG_B] & REG_B_UIE) {
410 411
        s->cmos_data[RTC_REG_C] |= REG_C_IRQF;
        qemu_irq_raise(s->irq);
412 413 414 415 416
    }

    /* clear update in progress bit */
    s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;

417
    s->next_second_time += get_ticks_per_sec();
418
    qemu_mod_timer(s->second_timer, s->next_second_time);
B
bellard 已提交
419 420
}

B
bellard 已提交
421
static uint32_t cmos_ioport_read(void *opaque, uint32_t addr)
B
bellard 已提交
422
{
B
bellard 已提交
423
    RTCState *s = opaque;
B
bellard 已提交
424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442
    int ret;
    if ((addr & 1) == 0) {
        return 0xff;
    } else {
        switch(s->cmos_index) {
        case RTC_SECONDS:
        case RTC_MINUTES:
        case RTC_HOURS:
        case RTC_DAY_OF_WEEK:
        case RTC_DAY_OF_MONTH:
        case RTC_MONTH:
        case RTC_YEAR:
            ret = s->cmos_data[s->cmos_index];
            break;
        case RTC_REG_A:
            ret = s->cmos_data[s->cmos_index];
            break;
        case RTC_REG_C:
            ret = s->cmos_data[s->cmos_index];
P
pbrook 已提交
443
            qemu_irq_lower(s->irq);
444
            s->cmos_data[RTC_REG_C] = 0x00;
445 446
#ifdef TARGET_I386
            if(s->irq_coalesced &&
447
                    (s->cmos_data[RTC_REG_B] & REG_B_PIE) &&
448 449
                    s->irq_reinject_on_ack_count < RTC_REINJECT_ON_ACK_COUNT) {
                s->irq_reinject_on_ack_count++;
450
                s->cmos_data[RTC_REG_C] |= REG_C_IRQF | REG_C_PF;
451
                apic_reset_irq_delivered();
B
Blue Swirl 已提交
452
                DPRINTF_C("cmos: injecting on ack\n");
453
                qemu_irq_raise(s->irq);
B
Blue Swirl 已提交
454
                if (apic_get_irq_delivered()) {
455
                    s->irq_coalesced--;
B
Blue Swirl 已提交
456 457 458
                    DPRINTF_C("cmos: coalesced irqs decreased to %d\n",
                              s->irq_coalesced);
                }
459 460
            }
#endif
B
bellard 已提交
461 462 463 464 465
            break;
        default:
            ret = s->cmos_data[s->cmos_index];
            break;
        }
466 467
        CMOS_DPRINTF("cmos: read index=0x%02x val=0x%02x\n",
                     s->cmos_index, ret);
B
bellard 已提交
468 469 470 471
        return ret;
    }
}

472
void rtc_set_memory(ISADevice *dev, int addr, int val)
473
{
474
    RTCState *s = DO_UPCAST(RTCState, dev, dev);
475 476 477 478
    if (addr >= 0 && addr <= 127)
        s->cmos_data[addr] = val;
}

479
void rtc_set_date(ISADevice *dev, const struct tm *tm)
480
{
481
    RTCState *s = DO_UPCAST(RTCState, dev, dev);
482
    s->current_tm = *tm;
483 484 485
    rtc_copy_date(s);
}

486 487 488 489
/* PC cmos mappings */
#define REG_IBM_CENTURY_BYTE        0x32
#define REG_IBM_PS2_CENTURY_BYTE    0x37

490
static void rtc_set_date_from_host(ISADevice *dev)
491
{
492
    RTCState *s = DO_UPCAST(RTCState, dev, dev);
493
    struct tm tm;
494 495 496
    int val;

    /* set the CMOS date */
497
    qemu_get_timedate(&tm, 0);
498
    rtc_set_date(dev, &tm);
499

P
Paul Brook 已提交
500
    val = rtc_to_bcd(s, (tm.tm_year / 100) + 19);
501 502
    rtc_set_memory(dev, REG_IBM_CENTURY_BYTE, val);
    rtc_set_memory(dev, REG_IBM_PS2_CENTURY_BYTE, val);
503 504
}

J
Juan Quintela 已提交
505
static int rtc_post_load(void *opaque, int version_id)
B
bellard 已提交
506
{
J
Juan Quintela 已提交
507
#ifdef TARGET_I386
508 509
    RTCState *s = opaque;

510
    if (version_id >= 2) {
511
        if (s->lost_tick_policy == LOST_TICK_SLEW) {
512 513 514
            rtc_coalesced_timer_update(s);
        }
    }
J
Juan Quintela 已提交
515
#endif
516 517 518
    return 0;
}

J
Juan Quintela 已提交
519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545
static const VMStateDescription vmstate_rtc = {
    .name = "mc146818rtc",
    .version_id = 2,
    .minimum_version_id = 1,
    .minimum_version_id_old = 1,
    .post_load = rtc_post_load,
    .fields      = (VMStateField []) {
        VMSTATE_BUFFER(cmos_data, RTCState),
        VMSTATE_UINT8(cmos_index, RTCState),
        VMSTATE_INT32(current_tm.tm_sec, RTCState),
        VMSTATE_INT32(current_tm.tm_min, RTCState),
        VMSTATE_INT32(current_tm.tm_hour, RTCState),
        VMSTATE_INT32(current_tm.tm_wday, RTCState),
        VMSTATE_INT32(current_tm.tm_mday, RTCState),
        VMSTATE_INT32(current_tm.tm_mon, RTCState),
        VMSTATE_INT32(current_tm.tm_year, RTCState),
        VMSTATE_TIMER(periodic_timer, RTCState),
        VMSTATE_INT64(next_periodic_time, RTCState),
        VMSTATE_INT64(next_second_time, RTCState),
        VMSTATE_TIMER(second_timer, RTCState),
        VMSTATE_TIMER(second_timer2, RTCState),
        VMSTATE_UINT32_V(irq_coalesced, RTCState, 2),
        VMSTATE_UINT32_V(period, RTCState, 2),
        VMSTATE_END_OF_LIST()
    }
};

546 547 548 549 550 551 552 553
static void rtc_notify_clock_reset(Notifier *notifier, void *data)
{
    RTCState *s = container_of(notifier, RTCState, clock_reset_notifier);
    int64_t now = *(int64_t *)data;

    rtc_set_date_from_host(&s->dev);
    s->next_second_time = now + (get_ticks_per_sec() * 99) / 100;
    qemu_mod_timer(s->second_timer2, s->next_second_time);
Y
Yang Zhang 已提交
554
    periodic_timer_update(s, now);
555
#ifdef TARGET_I386
556
    if (s->lost_tick_policy == LOST_TICK_SLEW) {
557 558 559 560 561
        rtc_coalesced_timer_update(s);
    }
#endif
}

562 563 564 565 566 567 568 569
/* set CMOS shutdown status register (index 0xF) as S3_resume(0xFE)
   BIOS will read it and start S3 resume at POST Entry */
static void rtc_notify_suspend(Notifier *notifier, void *data)
{
    RTCState *s = container_of(notifier, RTCState, suspend_notifier);
    rtc_set_memory(&s->dev, 0xF, 0xFE);
}

G
Gleb Natapov 已提交
570 571 572 573
static void rtc_reset(void *opaque)
{
    RTCState *s = opaque;

574 575
    s->cmos_data[RTC_REG_B] &= ~(REG_B_PIE | REG_B_AIE | REG_B_SQWE);
    s->cmos_data[RTC_REG_C] &= ~(REG_C_UF | REG_C_IRQF | REG_C_PF | REG_C_AF);
G
Gleb Natapov 已提交
576

577
    qemu_irq_lower(s->irq);
G
Gleb Natapov 已提交
578 579

#ifdef TARGET_I386
580 581 582
    if (s->lost_tick_policy == LOST_TICK_SLEW) {
        s->irq_coalesced = 0;
    }
G
Gleb Natapov 已提交
583 584 585
#endif
}

586 587 588 589 590 591 592 593 594
static const MemoryRegionPortio cmos_portio[] = {
    {0, 2, 1, .read = cmos_ioport_read, .write = cmos_ioport_write },
    PORTIO_END_OF_LIST(),
};

static const MemoryRegionOps cmos_ops = {
    .old_portio = cmos_portio
};

595
static void rtc_get_date(Object *obj, Visitor *v, void *opaque,
596 597
                         const char *name, Error **errp)
{
598
    ISADevice *isa = ISA_DEVICE(obj);
599 600 601 602 603 604 605 606 607 608 609 610
    RTCState *s = DO_UPCAST(RTCState, dev, isa);

    visit_start_struct(v, NULL, "struct tm", name, 0, errp);
    visit_type_int32(v, &s->current_tm.tm_year, "tm_year", errp);
    visit_type_int32(v, &s->current_tm.tm_mon, "tm_mon", errp);
    visit_type_int32(v, &s->current_tm.tm_mday, "tm_mday", errp);
    visit_type_int32(v, &s->current_tm.tm_hour, "tm_hour", errp);
    visit_type_int32(v, &s->current_tm.tm_min, "tm_min", errp);
    visit_type_int32(v, &s->current_tm.tm_sec, "tm_sec", errp);
    visit_end_struct(v, errp);
}

611
static int rtc_initfn(ISADevice *dev)
612
{
613 614
    RTCState *s = DO_UPCAST(RTCState, dev, dev);
    int base = 0x70;
B
bellard 已提交
615 616 617 618 619 620

    s->cmos_data[RTC_REG_A] = 0x26;
    s->cmos_data[RTC_REG_B] = 0x02;
    s->cmos_data[RTC_REG_C] = 0x00;
    s->cmos_data[RTC_REG_D] = 0x80;

621
    rtc_set_date_from_host(dev);
622

623
#ifdef TARGET_I386
624 625
    switch (s->lost_tick_policy) {
    case LOST_TICK_SLEW:
J
Jan Kiszka 已提交
626
        s->coalesced_timer =
627
            qemu_new_timer_ns(rtc_clock, rtc_coalesced_timer, s);
628 629 630 631 632 633
        break;
    case LOST_TICK_DISCARD:
        break;
    default:
        return -EINVAL;
    }
634
#endif
635 636

    s->periodic_timer = qemu_new_timer_ns(rtc_clock, rtc_periodic_timer, s);
637 638
    s->second_timer = qemu_new_timer_ns(rtc_clock, rtc_update_second, s);
    s->second_timer2 = qemu_new_timer_ns(rtc_clock, rtc_update_second2, s);
639

640 641 642
    s->clock_reset_notifier.notify = rtc_notify_clock_reset;
    qemu_register_clock_reset_notifier(rtc_clock, &s->clock_reset_notifier);

643 644 645
    s->suspend_notifier.notify = rtc_notify_suspend;
    qemu_register_suspend_notifier(&s->suspend_notifier);

J
Jan Kiszka 已提交
646
    s->next_second_time =
647
        qemu_get_clock_ns(rtc_clock) + (get_ticks_per_sec() * 99) / 100;
648 649
    qemu_mod_timer(s->second_timer2, s->next_second_time);

650 651
    memory_region_init_io(&s->io, &cmos_ops, s, "rtc", 2);
    isa_register_ioport(dev, &s->io, base);
652

653
    qdev_set_legacy_instance_id(&dev->qdev, base, 2);
654
    qemu_register_reset(rtc_reset, s);
655

656 657
    object_property_add(OBJECT(s), "date", "struct tm",
                        rtc_get_date, NULL, NULL, s, NULL);
658

659 660 661
    return 0;
}

662
ISADevice *rtc_init(ISABus *bus, int base_year, qemu_irq intercept_irq)
663 664
{
    ISADevice *dev;
665
    RTCState *s;
G
Gleb Natapov 已提交
666

667
    dev = isa_create(bus, "mc146818rtc");
668
    s = DO_UPCAST(RTCState, dev, dev);
669
    qdev_prop_set_int32(&dev->qdev, "base_year", base_year);
M
Markus Armbruster 已提交
670
    qdev_init_nofail(&dev->qdev);
671 672 673 674 675
    if (intercept_irq) {
        s->irq = intercept_irq;
    } else {
        isa_init_irq(dev, &s->irq, RTC_ISA_IRQ);
    }
676
    return dev;
B
bellard 已提交
677 678
}

679 680 681 682 683 684 685
static Property mc146818rtc_properties[] = {
    DEFINE_PROP_INT32("base_year", RTCState, base_year, 1980),
    DEFINE_PROP_LOSTTICKPOLICY("lost_tick_policy", RTCState,
                               lost_tick_policy, LOST_TICK_DISCARD),
    DEFINE_PROP_END_OF_LIST(),
};

686 687
static void rtc_class_initfn(ObjectClass *klass, void *data)
{
688
    DeviceClass *dc = DEVICE_CLASS(klass);
689 690
    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
    ic->init = rtc_initfn;
691 692 693
    dc->no_user = 1;
    dc->vmsd = &vmstate_rtc;
    dc->props = mc146818rtc_properties;
694 695
}

696 697 698 699 700
static TypeInfo mc146818rtc_info = {
    .name          = "mc146818rtc",
    .parent        = TYPE_ISA_DEVICE,
    .instance_size = sizeof(RTCState),
    .class_init    = rtc_class_initfn,
701 702
};

A
Andreas Färber 已提交
703
static void mc146818rtc_register_types(void)
704
{
705
    type_register_static(&mc146818rtc_info);
706
}
A
Andreas Färber 已提交
707 708

type_init(mc146818rtc_register_types)