| 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 deal |
| 8 | * in the Software without restriction, including without limitation the rights |
| 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| 10 | * 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 FROM, |
| 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| 22 | * THE SOFTWARE. |
| 23 | */ |
| 24 | |
| 25 | #include "qemu/osdep.h" |
| 26 | #include "qemu/cutils.h" |
| 27 | #include "qemu/module.h" |
| 28 | #include "qemu/bcd.h" |
| 29 | #include "hw/acpi/acpi_aml_interface.h" |
| 30 | #include "hw/intc/kvm_irqcount.h" |
| 31 | #include "hw/core/irq.h" |
| 32 | #include "hw/core/qdev-properties.h" |
| 33 | #include "hw/core/qdev-properties-system.h" |
| 34 | #include "qemu/timer.h" |
| 35 | #include "system/system.h" |
| 36 | #include "system/replay.h" |
| 37 | #include "system/reset.h" |
| 38 | #include "system/runstate.h" |
| 39 | #include "system/rtc.h" |
| 40 | #include "hw/rtc/mc146818rtc.h" |
| 41 | #include "hw/rtc/mc146818rtc_regs.h" |
| 42 | #include "migration/vmstate.h" |
| 43 | #include "qapi/error.h" |
| 44 | #include "qapi/qapi-events-misc.h" |
| 45 | #include "qapi/visitor.h" |
| 46 | #include "trace.h" |
| 47 | |
| 48 | //#define DEBUG_COALESCED |
| 49 | |
| 50 | #ifdef DEBUG_COALESCED |
| 51 | # define DPRINTF_C(format, ...) printf(format, ## __VA_ARGS__) |
| 52 | #else |
| 53 | # define DPRINTF_C(format, ...) do { } while (0) |
| 54 | #endif |
| 55 | |
| 56 | #define SEC_PER_MIN 60 |
| 57 | #define MIN_PER_HOUR 60 |
| 58 | #define SEC_PER_HOUR 3600 |
| 59 | #define HOUR_PER_DAY 24 |
| 60 | #define SEC_PER_DAY 86400 |
| 61 | |
| 62 | #define RTC_REINJECT_ON_ACK_COUNT 20 |
| 63 | #define RTC_CLOCK_RATE 32768 |
| 64 | #define UIP_HOLD_LENGTH (8 * NANOSECONDS_PER_SECOND / 32768) |
| 65 | |
| 66 | #define RTC_ISA_BASE 0x70 |
| 67 | |
| 68 | static void rtc_set_time(MC146818RtcState *s); |
| 69 | static void rtc_update_time(MC146818RtcState *s); |
| 70 | static void rtc_set_cmos(MC146818RtcState *s, const struct tm *tm); |
| 71 | static inline int rtc_from_bcd(MC146818RtcState *s, int a); |
| 72 | static uint64_t get_next_alarm(MC146818RtcState *s); |
| 73 | |
| 74 | static inline bool rtc_running(MC146818RtcState *s) |
| 75 | { |
| 76 | return (!(s->cmos_data[RTC_REG_B] & REG_B_SET) && |
| 77 | (s->cmos_data[RTC_REG_A] & 0x70) <= 0x20); |
| 78 | } |
| 79 | |
| 80 | /* |
| 81 | * Note: get_rtc_ns_since_last_update() does not include the base_rtc seconds |
| 82 | * value. This does not matter if the caller only needs the nanoseconds part. |
| 83 | */ |
| 84 | static uint64_t get_rtc_ns_since_last_update(MC146818RtcState *s) |
| 85 | { |
| 86 | return qemu_clock_get_ns(rtc_clock) - s->last_update + s->offset; |
| 87 | } |
| 88 | |
| 89 | static void rtc_coalesced_timer_update(MC146818RtcState *s) |
| 90 | { |
| 91 | if (s->irq_coalesced == 0) { |
| 92 | timer_del(s->coalesced_timer); |
| 93 | } else { |
| 94 | /* divide each RTC interval to 2 - 8 smaller intervals */ |
| 95 | int c = MIN(s->irq_coalesced, 7) + 1; |
| 96 | int64_t next_clock = qemu_clock_get_ns(rtc_clock) + |
| 97 | periodic_clock_to_ns(s->period / c); |
| 98 | timer_mod(s->coalesced_timer, next_clock); |
| 99 | } |
| 100 | } |
| 101 | |
| 102 | void rtc_reset_reinjection(MC146818RtcState *rtc) |
| 103 | { |
| 104 | rtc->irq_coalesced = 0; |
| 105 | } |
| 106 | |
| 107 | static bool rtc_policy_slew_deliver_irq(MC146818RtcState *s) |
| 108 | { |
| 109 | kvm_reset_irq_delivered(); |
| 110 | qemu_irq_raise(s->irq); |
| 111 | return kvm_get_irq_delivered(); |
| 112 | } |
| 113 | |
| 114 | static void rtc_coalesced_timer(void *opaque) |
| 115 | { |
| 116 | MC146818RtcState *s = opaque; |
| 117 | |
| 118 | if (s->irq_coalesced != 0) { |
| 119 | s->cmos_data[RTC_REG_C] |= 0xc0; |
| 120 | DPRINTF_C("cmos: injecting from timer\n"); |
| 121 | if (rtc_policy_slew_deliver_irq(s)) { |
| 122 | s->irq_coalesced--; |
| 123 | DPRINTF_C("cmos: coalesced irqs decreased to %d\n", |
| 124 | s->irq_coalesced); |
| 125 | } |
| 126 | } |
| 127 | |
| 128 | rtc_coalesced_timer_update(s); |
| 129 | } |
| 130 | |
| 131 | static uint32_t rtc_periodic_clock_ticks(MC146818RtcState *s) |
| 132 | { |
| 133 | int period_code; |
| 134 | |
| 135 | if (!(s->cmos_data[RTC_REG_B] & REG_B_PIE)) { |
| 136 | return 0; |
| 137 | } |
| 138 | |
| 139 | period_code = s->cmos_data[RTC_REG_A] & 0x0f; |
| 140 | |
| 141 | return periodic_period_to_clock(period_code); |
| 142 | } |
| 143 | |
| 144 | /* |
| 145 | * handle periodic timer. @old_period indicates the periodic timer update |
| 146 | * is just due to period adjustment. |
| 147 | */ |
| 148 | static void periodic_timer_update(MC146818RtcState *s, int64_t current_time, |
| 149 | uint32_t old_period, bool period_change) |
| 150 | { |
| 151 | uint32_t period; |
| 152 | int64_t cur_clock, next_irq_clock, lost_clock = 0; |
| 153 | |
| 154 | period = rtc_periodic_clock_ticks(s); |
| 155 | s->period = period; |
| 156 | |
| 157 | if (!period) { |
| 158 | s->irq_coalesced = 0; |
| 159 | timer_del(s->periodic_timer); |
| 160 | return; |
| 161 | } |
| 162 | |
| 163 | /* compute 32 khz clock */ |
| 164 | cur_clock = |
| 165 | muldiv64(current_time, RTC_CLOCK_RATE, NANOSECONDS_PER_SECOND); |
| 166 | |
| 167 | /* |
| 168 | * if the periodic timer's update is due to period re-configuration, |
| 169 | * we should count the clock since last interrupt. |
| 170 | */ |
| 171 | if (old_period && period_change) { |
| 172 | int64_t last_periodic_clock, next_periodic_clock; |
| 173 | |
| 174 | next_periodic_clock = muldiv64(s->next_periodic_time, |
| 175 | RTC_CLOCK_RATE, NANOSECONDS_PER_SECOND); |
| 176 | last_periodic_clock = next_periodic_clock - old_period; |
| 177 | lost_clock = cur_clock - last_periodic_clock; |
| 178 | assert(lost_clock >= 0); |
| 179 | } |
| 180 | |
| 181 | /* |
| 182 | * s->irq_coalesced can change for two reasons: |
| 183 | * |
| 184 | * a) if one or more periodic timer interrupts have been lost, |
| 185 | * lost_clock will be more that a period. |
| 186 | * |
| 187 | * b) when the period may be reconfigured, we expect the OS to |
| 188 | * treat delayed tick as the new period. So, when switching |
| 189 | * from a shorter to a longer period, scale down the missing, |
| 190 | * because the OS will treat past delayed ticks as longer |
| 191 | * (leftovers are put back into lost_clock). When switching |
| 192 | * to a shorter period, scale up the missing ticks since the |
| 193 | * OS handler will treat past delayed ticks as shorter. |
| 194 | */ |
| 195 | if (s->lost_tick_policy == LOST_TICK_POLICY_SLEW) { |
| 196 | uint32_t old_irq_coalesced = s->irq_coalesced; |
| 197 | |
| 198 | lost_clock += old_irq_coalesced * old_period; |
| 199 | s->irq_coalesced = lost_clock / s->period; |
| 200 | lost_clock %= s->period; |
| 201 | if (old_irq_coalesced != s->irq_coalesced || |
| 202 | old_period != s->period) { |
| 203 | DPRINTF_C("cmos: coalesced irqs scaled from %d to %d, " |
| 204 | "period scaled from %d to %d\n", old_irq_coalesced, |
| 205 | s->irq_coalesced, old_period, s->period); |
| 206 | rtc_coalesced_timer_update(s); |
| 207 | } |
| 208 | } else { |
| 209 | /* |
| 210 | * no way to compensate the interrupt if LOST_TICK_POLICY_SLEW |
| 211 | * is not used, we should make the time progress anyway. |
| 212 | */ |
| 213 | lost_clock = MIN(lost_clock, period); |
| 214 | } |
| 215 | |
| 216 | assert(lost_clock >= 0 && lost_clock <= period); |
| 217 | |
| 218 | next_irq_clock = cur_clock + period - lost_clock; |
| 219 | s->next_periodic_time = periodic_clock_to_ns(next_irq_clock) + 1; |
| 220 | timer_mod(s->periodic_timer, s->next_periodic_time); |
| 221 | } |
| 222 | |
| 223 | static void rtc_periodic_timer(void *opaque) |
| 224 | { |
| 225 | MC146818RtcState *s = opaque; |
| 226 | |
| 227 | periodic_timer_update(s, s->next_periodic_time, s->period, false); |
| 228 | s->cmos_data[RTC_REG_C] |= REG_C_PF; |
| 229 | if (s->cmos_data[RTC_REG_B] & REG_B_PIE) { |
| 230 | s->cmos_data[RTC_REG_C] |= REG_C_IRQF; |
| 231 | if (s->lost_tick_policy == LOST_TICK_POLICY_SLEW) { |
| 232 | if (s->irq_reinject_on_ack_count >= RTC_REINJECT_ON_ACK_COUNT) |
| 233 | s->irq_reinject_on_ack_count = 0; |
| 234 | if (!rtc_policy_slew_deliver_irq(s)) { |
| 235 | s->irq_coalesced++; |
| 236 | rtc_coalesced_timer_update(s); |
| 237 | DPRINTF_C("cmos: coalesced irqs increased to %d\n", |
| 238 | s->irq_coalesced); |
| 239 | } |
| 240 | } else |
| 241 | qemu_irq_raise(s->irq); |
| 242 | } |
| 243 | } |
| 244 | |
| 245 | /* handle update-ended timer */ |
| 246 | static void check_update_timer(MC146818RtcState *s) |
| 247 | { |
| 248 | uint64_t next_update_time; |
| 249 | uint64_t guest_nsec; |
| 250 | int next_alarm_sec; |
| 251 | |
| 252 | /* From the data sheet: "Holding the dividers in reset prevents |
| 253 | * interrupts from operating, while setting the SET bit allows" |
| 254 | * them to occur. |
| 255 | */ |
| 256 | if ((s->cmos_data[RTC_REG_A] & 0x60) == 0x60) { |
| 257 | assert((s->cmos_data[RTC_REG_A] & REG_A_UIP) == 0); |
| 258 | timer_del(s->update_timer); |
| 259 | return; |
| 260 | } |
| 261 | |
| 262 | guest_nsec = get_rtc_ns_since_last_update(s) % NANOSECONDS_PER_SECOND; |
| 263 | next_update_time = qemu_clock_get_ns(rtc_clock) |
| 264 | + NANOSECONDS_PER_SECOND - guest_nsec; |
| 265 | |
| 266 | /* Compute time of next alarm. One second is already accounted |
| 267 | * for in next_update_time. |
| 268 | */ |
| 269 | next_alarm_sec = get_next_alarm(s); |
| 270 | s->next_alarm_time = next_update_time + |
| 271 | (next_alarm_sec - 1) * NANOSECONDS_PER_SECOND; |
| 272 | |
| 273 | /* If update_in_progress latched the UIP bit, we must keep the timer |
| 274 | * programmed to the next second, so that UIP is cleared. Otherwise, |
| 275 | * if UF is already set, we might be able to optimize. |
| 276 | */ |
| 277 | if (!(s->cmos_data[RTC_REG_A] & REG_A_UIP) && |
| 278 | (s->cmos_data[RTC_REG_C] & REG_C_UF)) { |
| 279 | /* If AF cannot change (i.e. either it is set already, or |
| 280 | * SET=1 and then the time is not updated), nothing to do. |
| 281 | */ |
| 282 | if ((s->cmos_data[RTC_REG_B] & REG_B_SET) || |
| 283 | (s->cmos_data[RTC_REG_C] & REG_C_AF)) { |
| 284 | timer_del(s->update_timer); |
| 285 | return; |
| 286 | } |
| 287 | |
| 288 | /* UF is set, but AF is clear. Program the timer to target |
| 289 | * the alarm time. */ |
| 290 | next_update_time = s->next_alarm_time; |
| 291 | } |
| 292 | if (next_update_time != timer_expire_time_ns(s->update_timer)) { |
| 293 | timer_mod(s->update_timer, next_update_time); |
| 294 | } |
| 295 | } |
| 296 | |
| 297 | static inline uint8_t convert_hour(MC146818RtcState *s, uint8_t hour) |
| 298 | { |
| 299 | if (!(s->cmos_data[RTC_REG_B] & REG_B_24H)) { |
| 300 | hour %= 12; |
| 301 | if (s->cmos_data[RTC_HOURS] & 0x80) { |
| 302 | hour += 12; |
| 303 | } |
| 304 | } |
| 305 | return hour; |
| 306 | } |
| 307 | |
| 308 | static uint64_t get_next_alarm(MC146818RtcState *s) |
| 309 | { |
| 310 | int32_t alarm_sec, alarm_min, alarm_hour, cur_hour, cur_min, cur_sec; |
| 311 | int32_t hour, min, sec; |
| 312 | |
| 313 | rtc_update_time(s); |
| 314 | |
| 315 | alarm_sec = rtc_from_bcd(s, s->cmos_data[RTC_SECONDS_ALARM]); |
| 316 | alarm_min = rtc_from_bcd(s, s->cmos_data[RTC_MINUTES_ALARM]); |
| 317 | alarm_hour = rtc_from_bcd(s, s->cmos_data[RTC_HOURS_ALARM]); |
| 318 | alarm_hour = alarm_hour == -1 ? -1 : convert_hour(s, alarm_hour); |
| 319 | |
| 320 | cur_sec = rtc_from_bcd(s, s->cmos_data[RTC_SECONDS]); |
| 321 | cur_min = rtc_from_bcd(s, s->cmos_data[RTC_MINUTES]); |
| 322 | cur_hour = rtc_from_bcd(s, s->cmos_data[RTC_HOURS]); |
| 323 | cur_hour = convert_hour(s, cur_hour); |
| 324 | |
| 325 | if (alarm_hour == -1) { |
| 326 | alarm_hour = cur_hour; |
| 327 | if (alarm_min == -1) { |
| 328 | alarm_min = cur_min; |
| 329 | if (alarm_sec == -1) { |
| 330 | alarm_sec = cur_sec + 1; |
| 331 | } else if (cur_sec > alarm_sec) { |
| 332 | alarm_min++; |
| 333 | } |
| 334 | } else if (cur_min == alarm_min) { |
| 335 | if (alarm_sec == -1) { |
| 336 | alarm_sec = cur_sec + 1; |
| 337 | } else { |
| 338 | if (cur_sec > alarm_sec) { |
| 339 | alarm_hour++; |
| 340 | } |
| 341 | } |
| 342 | if (alarm_sec == SEC_PER_MIN) { |
| 343 | /* wrap to next hour, minutes is not in don't care mode */ |
| 344 | alarm_sec = 0; |
| 345 | alarm_hour++; |
| 346 | } |
| 347 | } else if (cur_min > alarm_min) { |
| 348 | alarm_hour++; |
| 349 | } |
| 350 | } else if (cur_hour == alarm_hour) { |
| 351 | if (alarm_min == -1) { |
| 352 | alarm_min = cur_min; |
| 353 | if (alarm_sec == -1) { |
| 354 | alarm_sec = cur_sec + 1; |
| 355 | } else if (cur_sec > alarm_sec) { |
| 356 | alarm_min++; |
| 357 | } |
| 358 | |
| 359 | if (alarm_sec == SEC_PER_MIN) { |
| 360 | alarm_sec = 0; |
| 361 | alarm_min++; |
| 362 | } |
| 363 | /* wrap to next day, hour is not in don't care mode */ |
| 364 | alarm_min %= MIN_PER_HOUR; |
| 365 | } else if (cur_min == alarm_min) { |
| 366 | if (alarm_sec == -1) { |
| 367 | alarm_sec = cur_sec + 1; |
| 368 | } |
| 369 | /* wrap to next day, hours+minutes not in don't care mode */ |
| 370 | alarm_sec %= SEC_PER_MIN; |
| 371 | } |
| 372 | } |
| 373 | |
| 374 | /* values that are still don't care fire at the next min/sec */ |
| 375 | if (alarm_min == -1) { |
| 376 | alarm_min = 0; |
| 377 | } |
| 378 | if (alarm_sec == -1) { |
| 379 | alarm_sec = 0; |
| 380 | } |
| 381 | |
| 382 | /* keep values in range */ |
| 383 | if (alarm_sec == SEC_PER_MIN) { |
| 384 | alarm_sec = 0; |
| 385 | alarm_min++; |
| 386 | } |
| 387 | if (alarm_min == MIN_PER_HOUR) { |
| 388 | alarm_min = 0; |
| 389 | alarm_hour++; |
| 390 | } |
| 391 | alarm_hour %= HOUR_PER_DAY; |
| 392 | |
| 393 | hour = alarm_hour - cur_hour; |
| 394 | min = hour * MIN_PER_HOUR + alarm_min - cur_min; |
| 395 | sec = min * SEC_PER_MIN + alarm_sec - cur_sec; |
| 396 | return sec <= 0 ? sec + SEC_PER_DAY : sec; |
| 397 | } |
| 398 | |
| 399 | static void rtc_update_timer(void *opaque) |
| 400 | { |
| 401 | MC146818RtcState *s = opaque; |
| 402 | int32_t irqs = REG_C_UF; |
| 403 | int32_t new_irqs; |
| 404 | |
| 405 | assert((s->cmos_data[RTC_REG_A] & 0x60) != 0x60); |
| 406 | |
| 407 | /* UIP might have been latched, update time and clear it. */ |
| 408 | rtc_update_time(s); |
| 409 | s->cmos_data[RTC_REG_A] &= ~REG_A_UIP; |
| 410 | |
| 411 | if (qemu_clock_get_ns(rtc_clock) >= s->next_alarm_time) { |
| 412 | irqs |= REG_C_AF; |
| 413 | if (s->cmos_data[RTC_REG_B] & REG_B_AIE) { |
| 414 | qemu_system_wakeup_request(QEMU_WAKEUP_REASON_RTC, NULL); |
| 415 | } |
| 416 | } |
| 417 | |
| 418 | new_irqs = irqs & ~s->cmos_data[RTC_REG_C]; |
| 419 | s->cmos_data[RTC_REG_C] |= irqs; |
| 420 | if ((new_irqs & s->cmos_data[RTC_REG_B]) != 0) { |
| 421 | s->cmos_data[RTC_REG_C] |= REG_C_IRQF; |
| 422 | qemu_irq_raise(s->irq); |
| 423 | } |
| 424 | check_update_timer(s); |
| 425 | } |
| 426 | |
| 427 | static void cmos_ioport_write(void *opaque, hwaddr addr, |
| 428 | uint64_t data, unsigned size) |
| 429 | { |
| 430 | MC146818RtcState *s = opaque; |
| 431 | uint32_t old_period; |
| 432 | bool update_periodic_timer; |
| 433 | |
| 434 | if ((addr & 1) == 0) { |
| 435 | s->cmos_index = data & 0x7f; |
| 436 | } else { |
| 437 | trace_mc146818_rtc_ioport_write(s->cmos_index, data); |
| 438 | switch(s->cmos_index) { |
| 439 | case RTC_SECONDS_ALARM: |
| 440 | case RTC_MINUTES_ALARM: |
| 441 | case RTC_HOURS_ALARM: |
| 442 | s->cmos_data[s->cmos_index] = data; |
| 443 | check_update_timer(s); |
| 444 | break; |
| 445 | case RTC_IBM_PS2_CENTURY_BYTE: |
| 446 | s->cmos_index = RTC_CENTURY; |
| 447 | /* fall through */ |
| 448 | case RTC_CENTURY: |
| 449 | case RTC_SECONDS: |
| 450 | case RTC_MINUTES: |
| 451 | case RTC_HOURS: |
| 452 | case RTC_DAY_OF_WEEK: |
| 453 | case RTC_DAY_OF_MONTH: |
| 454 | case RTC_MONTH: |
| 455 | case RTC_YEAR: |
| 456 | s->cmos_data[s->cmos_index] = data; |
| 457 | /* if in set mode, do not update the time */ |
| 458 | if (rtc_running(s)) { |
| 459 | rtc_set_time(s); |
| 460 | check_update_timer(s); |
| 461 | } |
| 462 | break; |
| 463 | case RTC_REG_A: |
| 464 | update_periodic_timer = (s->cmos_data[RTC_REG_A] ^ data) & 0x0f; |
| 465 | old_period = rtc_periodic_clock_ticks(s); |
| 466 | |
| 467 | if ((data & 0x60) == 0x60) { |
| 468 | if (rtc_running(s)) { |
| 469 | rtc_update_time(s); |
| 470 | } |
| 471 | /* What happens to UIP when divider reset is enabled is |
| 472 | * unclear from the datasheet. Shouldn't matter much |
| 473 | * though. |
| 474 | */ |
| 475 | s->cmos_data[RTC_REG_A] &= ~REG_A_UIP; |
| 476 | } else if (((s->cmos_data[RTC_REG_A] & 0x60) == 0x60) && |
| 477 | (data & 0x70) <= 0x20) { |
| 478 | /* when the divider reset is removed, the first update cycle |
| 479 | * begins one-half second later*/ |
| 480 | if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) { |
| 481 | s->offset = 500000000; |
| 482 | rtc_set_time(s); |
| 483 | } |
| 484 | s->cmos_data[RTC_REG_A] &= ~REG_A_UIP; |
| 485 | } |
| 486 | /* UIP bit is read only */ |
| 487 | s->cmos_data[RTC_REG_A] = (data & ~REG_A_UIP) | |
| 488 | (s->cmos_data[RTC_REG_A] & REG_A_UIP); |
| 489 | |
| 490 | if (update_periodic_timer) { |
| 491 | periodic_timer_update(s, qemu_clock_get_ns(rtc_clock), |
| 492 | old_period, true); |
| 493 | } |
| 494 | |
| 495 | check_update_timer(s); |
| 496 | break; |
| 497 | case RTC_REG_B: |
| 498 | update_periodic_timer = (s->cmos_data[RTC_REG_B] ^ data) |
| 499 | & REG_B_PIE; |
| 500 | old_period = rtc_periodic_clock_ticks(s); |
| 501 | |
| 502 | if (data & REG_B_SET) { |
| 503 | /* update cmos to when the rtc was stopping */ |
| 504 | if (rtc_running(s)) { |
| 505 | rtc_update_time(s); |
| 506 | } |
| 507 | /* set mode: reset UIP mode */ |
| 508 | s->cmos_data[RTC_REG_A] &= ~REG_A_UIP; |
| 509 | data &= ~REG_B_UIE; |
| 510 | } else { |
| 511 | /* if disabling set mode, update the time */ |
| 512 | if ((s->cmos_data[RTC_REG_B] & REG_B_SET) && |
| 513 | (s->cmos_data[RTC_REG_A] & 0x70) <= 0x20) { |
| 514 | s->offset = get_rtc_ns_since_last_update(s) % NANOSECONDS_PER_SECOND; |
| 515 | rtc_set_time(s); |
| 516 | } |
| 517 | } |
| 518 | /* if an interrupt flag is already set when the interrupt |
| 519 | * becomes enabled, raise an interrupt immediately. */ |
| 520 | if (data & s->cmos_data[RTC_REG_C] & REG_C_MASK) { |
| 521 | s->cmos_data[RTC_REG_C] |= REG_C_IRQF; |
| 522 | qemu_irq_raise(s->irq); |
| 523 | } else { |
| 524 | s->cmos_data[RTC_REG_C] &= ~REG_C_IRQF; |
| 525 | qemu_irq_lower(s->irq); |
| 526 | } |
| 527 | s->cmos_data[RTC_REG_B] = data; |
| 528 | |
| 529 | if (update_periodic_timer) { |
| 530 | periodic_timer_update(s, qemu_clock_get_ns(rtc_clock), |
| 531 | old_period, true); |
| 532 | } |
| 533 | |
| 534 | check_update_timer(s); |
| 535 | break; |
| 536 | case RTC_REG_C: |
| 537 | case RTC_REG_D: |
| 538 | /* cannot write to them */ |
| 539 | break; |
| 540 | default: |
| 541 | s->cmos_data[s->cmos_index] = data; |
| 542 | break; |
| 543 | } |
| 544 | } |
| 545 | } |
| 546 | |
| 547 | static inline int rtc_to_bcd(MC146818RtcState *s, int a) |
| 548 | { |
| 549 | if (s->cmos_data[RTC_REG_B] & REG_B_DM) { |
| 550 | return a; |
| 551 | } else { |
| 552 | return ((a / 10) << 4) | (a % 10); |
| 553 | } |
| 554 | } |
| 555 | |
| 556 | static inline int rtc_from_bcd(MC146818RtcState *s, int a) |
| 557 | { |
| 558 | if ((a & 0xc0) == 0xc0) { |
| 559 | return -1; |
| 560 | } |
| 561 | if (s->cmos_data[RTC_REG_B] & REG_B_DM) { |
| 562 | return a; |
| 563 | } else { |
| 564 | return ((a >> 4) * 10) + (a & 0x0f); |
| 565 | } |
| 566 | } |
| 567 | |
| 568 | static void rtc_get_time(MC146818RtcState *s, struct tm *tm) |
| 569 | { |
| 570 | tm->tm_sec = rtc_from_bcd(s, s->cmos_data[RTC_SECONDS]); |
| 571 | tm->tm_min = rtc_from_bcd(s, s->cmos_data[RTC_MINUTES]); |
| 572 | tm->tm_hour = rtc_from_bcd(s, s->cmos_data[RTC_HOURS] & 0x7f); |
| 573 | if (!(s->cmos_data[RTC_REG_B] & REG_B_24H)) { |
| 574 | tm->tm_hour %= 12; |
| 575 | if (s->cmos_data[RTC_HOURS] & 0x80) { |
| 576 | tm->tm_hour += 12; |
| 577 | } |
| 578 | } |
| 579 | tm->tm_wday = rtc_from_bcd(s, s->cmos_data[RTC_DAY_OF_WEEK]) - 1; |
| 580 | tm->tm_mday = rtc_from_bcd(s, s->cmos_data[RTC_DAY_OF_MONTH]); |
| 581 | tm->tm_mon = rtc_from_bcd(s, s->cmos_data[RTC_MONTH]) - 1; |
| 582 | tm->tm_year = |
| 583 | rtc_from_bcd(s, s->cmos_data[RTC_YEAR]) + s->base_year + |
| 584 | rtc_from_bcd(s, s->cmos_data[RTC_CENTURY]) * 100 - 1900; |
| 585 | } |
| 586 | |
| 587 | static void rtc_set_time(MC146818RtcState *s) |
| 588 | { |
| 589 | struct tm tm = {}; |
| 590 | g_autofree const char *qom_path = object_get_canonical_path(OBJECT(s)); |
| 591 | |
| 592 | rtc_get_time(s, &tm); |
| 593 | s->base_rtc = mktimegm(&tm); |
| 594 | s->last_update = qemu_clock_get_ns(rtc_clock); |
| 595 | |
| 596 | qapi_event_send_rtc_change(qemu_timedate_diff(&tm), qom_path); |
| 597 | } |
| 598 | |
| 599 | static void rtc_set_cmos(MC146818RtcState *s, const struct tm *tm) |
| 600 | { |
| 601 | int year; |
| 602 | |
| 603 | s->cmos_data[RTC_SECONDS] = rtc_to_bcd(s, tm->tm_sec); |
| 604 | s->cmos_data[RTC_MINUTES] = rtc_to_bcd(s, tm->tm_min); |
| 605 | if (s->cmos_data[RTC_REG_B] & REG_B_24H) { |
| 606 | /* 24 hour format */ |
| 607 | s->cmos_data[RTC_HOURS] = rtc_to_bcd(s, tm->tm_hour); |
| 608 | } else { |
| 609 | /* 12 hour format */ |
| 610 | int h = (tm->tm_hour % 12) ? tm->tm_hour % 12 : 12; |
| 611 | s->cmos_data[RTC_HOURS] = rtc_to_bcd(s, h); |
| 612 | if (tm->tm_hour >= 12) |
| 613 | s->cmos_data[RTC_HOURS] |= 0x80; |
| 614 | } |
| 615 | s->cmos_data[RTC_DAY_OF_WEEK] = rtc_to_bcd(s, tm->tm_wday + 1); |
| 616 | s->cmos_data[RTC_DAY_OF_MONTH] = rtc_to_bcd(s, tm->tm_mday); |
| 617 | s->cmos_data[RTC_MONTH] = rtc_to_bcd(s, tm->tm_mon + 1); |
| 618 | year = tm->tm_year + 1900 - s->base_year; |
| 619 | s->cmos_data[RTC_YEAR] = rtc_to_bcd(s, year % 100); |
| 620 | s->cmos_data[RTC_CENTURY] = rtc_to_bcd(s, year / 100); |
| 621 | } |
| 622 | |
| 623 | static void rtc_update_time(MC146818RtcState *s) |
| 624 | { |
| 625 | struct tm ret; |
| 626 | time_t guest_sec; |
| 627 | |
| 628 | guest_sec = s->base_rtc + get_rtc_ns_since_last_update(s) / NANOSECONDS_PER_SECOND; |
| 629 | gmtime_r(&guest_sec, &ret); |
| 630 | |
| 631 | /* Is SET flag of Register B disabled? */ |
| 632 | if ((s->cmos_data[RTC_REG_B] & REG_B_SET) == 0) { |
| 633 | rtc_set_cmos(s, &ret); |
| 634 | } |
| 635 | } |
| 636 | |
| 637 | static int update_in_progress(MC146818RtcState *s) |
| 638 | { |
| 639 | uint64_t guest_nsec; |
| 640 | |
| 641 | if (!rtc_running(s)) { |
| 642 | return 0; |
| 643 | } |
| 644 | if (timer_pending(s->update_timer)) { |
| 645 | int64_t next_update_time = timer_expire_time_ns(s->update_timer); |
| 646 | /* Latch UIP until the timer expires. */ |
| 647 | if (qemu_clock_get_ns(rtc_clock) >= |
| 648 | (next_update_time - UIP_HOLD_LENGTH)) { |
| 649 | s->cmos_data[RTC_REG_A] |= REG_A_UIP; |
| 650 | return 1; |
| 651 | } |
| 652 | } |
| 653 | |
| 654 | guest_nsec = get_rtc_ns_since_last_update(s); |
| 655 | /* UIP bit will be set at last 244us of every second. */ |
| 656 | if ((guest_nsec % NANOSECONDS_PER_SECOND) >= |
| 657 | (NANOSECONDS_PER_SECOND - UIP_HOLD_LENGTH)) { |
| 658 | return 1; |
| 659 | } |
| 660 | return 0; |
| 661 | } |
| 662 | |
| 663 | static uint64_t cmos_ioport_read(void *opaque, hwaddr addr, |
| 664 | unsigned size) |
| 665 | { |
| 666 | MC146818RtcState *s = opaque; |
| 667 | int ret; |
| 668 | if ((addr & 1) == 0) { |
| 669 | return 0xff; |
| 670 | } else { |
| 671 | switch(s->cmos_index) { |
| 672 | case RTC_IBM_PS2_CENTURY_BYTE: |
| 673 | s->cmos_index = RTC_CENTURY; |
| 674 | /* fall through */ |
| 675 | case RTC_CENTURY: |
| 676 | case RTC_SECONDS: |
| 677 | case RTC_MINUTES: |
| 678 | case RTC_HOURS: |
| 679 | case RTC_DAY_OF_WEEK: |
| 680 | case RTC_DAY_OF_MONTH: |
| 681 | case RTC_MONTH: |
| 682 | case RTC_YEAR: |
| 683 | /* if not in set mode, calibrate cmos before |
| 684 | * reading*/ |
| 685 | if (rtc_running(s)) { |
| 686 | rtc_update_time(s); |
| 687 | } |
| 688 | ret = s->cmos_data[s->cmos_index]; |
| 689 | break; |
| 690 | case RTC_REG_A: |
| 691 | ret = s->cmos_data[s->cmos_index]; |
| 692 | if (update_in_progress(s)) { |
| 693 | ret |= REG_A_UIP; |
| 694 | } |
| 695 | break; |
| 696 | case RTC_REG_C: |
| 697 | ret = s->cmos_data[s->cmos_index]; |
| 698 | qemu_irq_lower(s->irq); |
| 699 | s->cmos_data[RTC_REG_C] = 0x00; |
| 700 | if (ret & (REG_C_UF | REG_C_AF)) { |
| 701 | check_update_timer(s); |
| 702 | } |
| 703 | |
| 704 | if(s->irq_coalesced && |
| 705 | (s->cmos_data[RTC_REG_B] & REG_B_PIE) && |
| 706 | s->irq_reinject_on_ack_count < RTC_REINJECT_ON_ACK_COUNT) { |
| 707 | s->irq_reinject_on_ack_count++; |
| 708 | s->cmos_data[RTC_REG_C] |= REG_C_IRQF | REG_C_PF; |
| 709 | DPRINTF_C("cmos: injecting on ack\n"); |
| 710 | if (rtc_policy_slew_deliver_irq(s)) { |
| 711 | s->irq_coalesced--; |
| 712 | DPRINTF_C("cmos: coalesced irqs decreased to %d\n", |
| 713 | s->irq_coalesced); |
| 714 | } |
| 715 | } |
| 716 | break; |
| 717 | default: |
| 718 | ret = s->cmos_data[s->cmos_index]; |
| 719 | break; |
| 720 | } |
| 721 | trace_mc146818_rtc_ioport_read(s->cmos_index, ret); |
| 722 | return ret; |
| 723 | } |
| 724 | } |
| 725 | |
| 726 | void mc146818rtc_set_cmos_data(MC146818RtcState *s, int addr, int val) |
| 727 | { |
| 728 | assert(addr >= 0 && addr < ARRAY_SIZE(s->cmos_data)); |
| 729 | s->cmos_data[addr] = val; |
| 730 | } |
| 731 | |
| 732 | int mc146818rtc_get_cmos_data(MC146818RtcState *s, int addr) |
| 733 | { |
| 734 | assert(addr >= 0 && addr < ARRAY_SIZE(s->cmos_data)); |
| 735 | return s->cmos_data[addr]; |
| 736 | } |
| 737 | |
| 738 | static void rtc_set_date_from_host(ISADevice *dev) |
| 739 | { |
| 740 | MC146818RtcState *s = MC146818_RTC(dev); |
| 741 | struct tm tm; |
| 742 | |
| 743 | qemu_get_timedate(&tm, 0); |
| 744 | |
| 745 | s->base_rtc = mktimegm(&tm); |
| 746 | s->last_update = qemu_clock_get_ns(rtc_clock); |
| 747 | s->offset = 0; |
| 748 | |
| 749 | /* set the CMOS date */ |
| 750 | rtc_set_cmos(s, &tm); |
| 751 | } |
| 752 | |
| 753 | static int rtc_pre_save(void *opaque) |
| 754 | { |
| 755 | MC146818RtcState *s = opaque; |
| 756 | |
| 757 | rtc_update_time(s); |
| 758 | |
| 759 | return 0; |
| 760 | } |
| 761 | |
| 762 | static int rtc_post_load(void *opaque, int version_id) |
| 763 | { |
| 764 | MC146818RtcState *s = opaque; |
| 765 | |
| 766 | if (version_id <= 2 || rtc_clock == QEMU_CLOCK_REALTIME) { |
| 767 | rtc_set_time(s); |
| 768 | s->offset = 0; |
| 769 | check_update_timer(s); |
| 770 | } |
| 771 | s->period = rtc_periodic_clock_ticks(s); |
| 772 | |
| 773 | /* The periodic timer is deterministic in record/replay mode, |
| 774 | * so there is no need to update it after loading the vmstate. |
| 775 | * Reading RTC here would misalign record and replay. |
| 776 | */ |
| 777 | if (replay_mode == REPLAY_MODE_NONE) { |
| 778 | uint64_t now = qemu_clock_get_ns(rtc_clock); |
| 779 | if (now < s->next_periodic_time || |
| 780 | now > (s->next_periodic_time + get_max_clock_jump())) { |
| 781 | periodic_timer_update(s, qemu_clock_get_ns(rtc_clock), s->period, false); |
| 782 | } |
| 783 | } |
| 784 | |
| 785 | if (version_id >= 2) { |
| 786 | if (s->lost_tick_policy == LOST_TICK_POLICY_SLEW) { |
| 787 | rtc_coalesced_timer_update(s); |
| 788 | } |
| 789 | } |
| 790 | return 0; |
| 791 | } |
| 792 | |
| 793 | static bool rtc_irq_reinject_on_ack_count_needed(void *opaque) |
| 794 | { |
| 795 | MC146818RtcState *s = (MC146818RtcState *)opaque; |
| 796 | return s->irq_reinject_on_ack_count != 0; |
| 797 | } |
| 798 | |
| 799 | static const VMStateDescription vmstate_rtc_irq_reinject_on_ack_count = { |
| 800 | .name = "mc146818rtc/irq_reinject_on_ack_count", |
| 801 | .version_id = 1, |
| 802 | .minimum_version_id = 1, |
| 803 | .needed = rtc_irq_reinject_on_ack_count_needed, |
| 804 | .fields = (const VMStateField[]) { |
| 805 | VMSTATE_UINT16(irq_reinject_on_ack_count, MC146818RtcState), |
| 806 | VMSTATE_END_OF_LIST() |
| 807 | } |
| 808 | }; |
| 809 | |
| 810 | static const VMStateDescription vmstate_rtc = { |
| 811 | .name = "mc146818rtc", |
| 812 | .version_id = 3, |
| 813 | .minimum_version_id = 3, |
| 814 | .pre_save = rtc_pre_save, |
| 815 | .post_load = rtc_post_load, |
| 816 | .fields = (const VMStateField[]) { |
| 817 | VMSTATE_BUFFER(cmos_data, MC146818RtcState), |
| 818 | VMSTATE_UINT8(cmos_index, MC146818RtcState), |
| 819 | VMSTATE_UNUSED(7*4), |
| 820 | VMSTATE_TIMER_PTR(periodic_timer, MC146818RtcState), |
| 821 | VMSTATE_INT64(next_periodic_time, MC146818RtcState), |
| 822 | VMSTATE_UNUSED(3*8), |
| 823 | VMSTATE_UINT32(irq_coalesced, MC146818RtcState), |
| 824 | VMSTATE_UINT32(period, MC146818RtcState), |
| 825 | VMSTATE_UINT64(base_rtc, MC146818RtcState), |
| 826 | VMSTATE_UINT64(last_update, MC146818RtcState), |
| 827 | VMSTATE_INT64(offset, MC146818RtcState), |
| 828 | VMSTATE_TIMER_PTR(update_timer, MC146818RtcState), |
| 829 | VMSTATE_UINT64(next_alarm_time, MC146818RtcState), |
| 830 | VMSTATE_END_OF_LIST() |
| 831 | }, |
| 832 | .subsections = (const VMStateDescription * const []) { |
| 833 | &vmstate_rtc_irq_reinject_on_ack_count, |
| 834 | NULL |
| 835 | } |
| 836 | }; |
| 837 | |
| 838 | /* set CMOS shutdown status register (index 0xF) as S3_resume(0xFE) |
| 839 | BIOS will read it and start S3 resume at POST Entry */ |
| 840 | static void rtc_notify_suspend(Notifier *notifier, void *data) |
| 841 | { |
| 842 | MC146818RtcState *s = container_of(notifier, MC146818RtcState, |
| 843 | suspend_notifier); |
| 844 | mc146818rtc_set_cmos_data(s, 0xF, 0xFE); |
| 845 | } |
| 846 | |
| 847 | static const MemoryRegionOps cmos_ops = { |
| 848 | .read = cmos_ioport_read, |
| 849 | .write = cmos_ioport_write, |
| 850 | .impl = { |
| 851 | .min_access_size = 1, |
| 852 | .max_access_size = 1, |
| 853 | }, |
| 854 | .endianness = DEVICE_LITTLE_ENDIAN, |
| 855 | }; |
| 856 | |
| 857 | static void rtc_get_date(Object *obj, struct tm *current_tm, Error **errp) |
| 858 | { |
| 859 | MC146818RtcState *s = MC146818_RTC(obj); |
| 860 | |
| 861 | rtc_update_time(s); |
| 862 | rtc_get_time(s, current_tm); |
| 863 | } |
| 864 | |
| 865 | static void rtc_realizefn(DeviceState *dev, Error **errp) |
| 866 | { |
| 867 | ISADevice *isadev = ISA_DEVICE(dev); |
| 868 | MC146818RtcState *s = MC146818_RTC(dev); |
| 869 | |
| 870 | s->cmos_data[RTC_REG_A] = 0x26; |
| 871 | s->cmos_data[RTC_REG_B] = 0x02; |
| 872 | s->cmos_data[RTC_REG_C] = 0x00; |
| 873 | s->cmos_data[RTC_REG_D] = 0x80; |
| 874 | |
| 875 | /* This is for historical reasons. The default base year qdev property |
| 876 | * was set to 2000 for most machine types before the century byte was |
| 877 | * implemented. |
| 878 | * |
| 879 | * This if statement means that the century byte will be always 0 |
| 880 | * (at least until 2079...) for base_year = 1980, but will be set |
| 881 | * correctly for base_year = 2000. |
| 882 | */ |
| 883 | if (s->base_year == 2000) { |
| 884 | s->base_year = 0; |
| 885 | } |
| 886 | |
| 887 | if (s->isairq >= ISA_NUM_IRQS) { |
| 888 | error_setg(errp, "Maximum value for \"irq\" is: %u", ISA_NUM_IRQS - 1); |
| 889 | return; |
| 890 | } |
| 891 | |
| 892 | rtc_set_date_from_host(isadev); |
| 893 | |
| 894 | switch (s->lost_tick_policy) { |
| 895 | case LOST_TICK_POLICY_SLEW: |
| 896 | s->coalesced_timer = |
| 897 | timer_new_ns(rtc_clock, rtc_coalesced_timer, s); |
| 898 | break; |
| 899 | case LOST_TICK_POLICY_DISCARD: |
| 900 | break; |
| 901 | default: |
| 902 | error_setg(errp, "Invalid lost tick policy."); |
| 903 | return; |
| 904 | } |
| 905 | |
| 906 | s->periodic_timer = timer_new_ns(rtc_clock, rtc_periodic_timer, s); |
| 907 | s->update_timer = timer_new_ns(rtc_clock, rtc_update_timer, s); |
| 908 | check_update_timer(s); |
| 909 | |
| 910 | s->suspend_notifier.notify = rtc_notify_suspend; |
| 911 | qemu_register_suspend_notifier(&s->suspend_notifier); |
| 912 | |
| 913 | memory_region_init_io(&s->io, OBJECT(s), &cmos_ops, s, "rtc", 2); |
| 914 | isa_register_ioport(isadev, &s->io, s->io_base); |
| 915 | |
| 916 | /* register rtc 0x70 port for coalesced_pio */ |
| 917 | memory_region_set_flush_coalesced(&s->io); |
| 918 | memory_region_init_io(&s->coalesced_io, OBJECT(s), &cmos_ops, |
| 919 | s, "rtc-index", 1); |
| 920 | memory_region_add_subregion(&s->io, 0, &s->coalesced_io); |
| 921 | memory_region_add_coalescing(&s->coalesced_io, 0, 1); |
| 922 | |
| 923 | qdev_init_gpio_out(dev, &s->irq, 1); |
| 924 | } |
| 925 | |
| 926 | MC146818RtcState *mc146818_rtc_init(ISABus *bus, int base_year, |
| 927 | qemu_irq intercept_irq) |
| 928 | { |
| 929 | DeviceState *dev; |
| 930 | ISADevice *isadev; |
| 931 | MC146818RtcState *s; |
| 932 | |
| 933 | isadev = isa_new(TYPE_MC146818_RTC); |
| 934 | dev = DEVICE(isadev); |
| 935 | s = MC146818_RTC(isadev); |
| 936 | qdev_prop_set_int32(dev, "base_year", base_year); |
| 937 | isa_realize_and_unref(isadev, bus, &error_fatal); |
| 938 | if (intercept_irq) { |
| 939 | qdev_connect_gpio_out(dev, 0, intercept_irq); |
| 940 | } else { |
| 941 | isa_connect_gpio_out(isadev, 0, s->isairq); |
| 942 | } |
| 943 | |
| 944 | object_property_add_alias(qdev_get_machine(), "rtc-time", OBJECT(isadev), |
| 945 | "date"); |
| 946 | |
| 947 | return s; |
| 948 | } |
| 949 | |
| 950 | static const Property mc146818rtc_properties[] = { |
| 951 | DEFINE_PROP_INT32("base_year", MC146818RtcState, base_year, 1980), |
| 952 | DEFINE_PROP_UINT16("iobase", MC146818RtcState, io_base, RTC_ISA_BASE), |
| 953 | DEFINE_PROP_UINT8("irq", MC146818RtcState, isairq, RTC_ISA_IRQ), |
| 954 | DEFINE_PROP_LOSTTICKPOLICY("lost_tick_policy", MC146818RtcState, |
| 955 | lost_tick_policy, LOST_TICK_POLICY_DISCARD), |
| 956 | }; |
| 957 | |
| 958 | static void rtc_reset_enter(Object *obj, ResetType type) |
| 959 | { |
| 960 | MC146818RtcState *s = MC146818_RTC(obj); |
| 961 | |
| 962 | /* Reason: VM do suspend self will set 0xfe |
| 963 | * Reset any values other than 0xfe(Guest suspend case) */ |
| 964 | if (s->cmos_data[0x0f] != 0xfe) { |
| 965 | s->cmos_data[0x0f] = 0x00; |
| 966 | } |
| 967 | |
| 968 | s->cmos_data[RTC_REG_B] &= ~(REG_B_PIE | REG_B_AIE | REG_B_SQWE); |
| 969 | s->cmos_data[RTC_REG_C] &= ~(REG_C_UF | REG_C_IRQF | REG_C_PF | REG_C_AF); |
| 970 | check_update_timer(s); |
| 971 | |
| 972 | |
| 973 | if (s->lost_tick_policy == LOST_TICK_POLICY_SLEW) { |
| 974 | s->irq_coalesced = 0; |
| 975 | s->irq_reinject_on_ack_count = 0; |
| 976 | } |
| 977 | } |
| 978 | |
| 979 | static void rtc_reset_hold(Object *obj, ResetType type) |
| 980 | { |
| 981 | MC146818RtcState *s = MC146818_RTC(obj); |
| 982 | |
| 983 | qemu_irq_lower(s->irq); |
| 984 | } |
| 985 | |
| 986 | static void rtc_build_aml(AcpiDevAmlIf *adev, Aml *scope) |
| 987 | { |
| 988 | MC146818RtcState *s = MC146818_RTC(adev); |
| 989 | Aml *dev; |
| 990 | Aml *crs; |
| 991 | |
| 992 | /* |
| 993 | * Reserving 8 io ports here, following what physical hardware |
| 994 | * does, even though qemu only responds to the first two ports. |
| 995 | */ |
| 996 | crs = aml_resource_template(); |
| 997 | aml_append(crs, aml_io(AML_DECODE16, s->io_base, s->io_base, |
| 998 | 0x01, 0x08)); |
| 999 | aml_append(crs, aml_irq_no_flags(s->isairq)); |
| 1000 | |
| 1001 | dev = aml_device("RTC"); |
| 1002 | aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0B00"))); |
| 1003 | aml_append(dev, aml_name_decl("_CRS", crs)); |
| 1004 | |
| 1005 | aml_append(scope, dev); |
| 1006 | } |
| 1007 | |
| 1008 | static void rtc_class_initfn(ObjectClass *klass, const void *data) |
| 1009 | { |
| 1010 | DeviceClass *dc = DEVICE_CLASS(klass); |
| 1011 | ResettableClass *rc = RESETTABLE_CLASS(klass); |
| 1012 | AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass); |
| 1013 | |
| 1014 | dc->realize = rtc_realizefn; |
| 1015 | dc->vmsd = &vmstate_rtc; |
| 1016 | rc->phases.enter = rtc_reset_enter; |
| 1017 | rc->phases.hold = rtc_reset_hold; |
| 1018 | adevc->build_dev_aml = rtc_build_aml; |
| 1019 | device_class_set_props(dc, mc146818rtc_properties); |
| 1020 | set_bit(DEVICE_CATEGORY_MISC, dc->categories); |
| 1021 | |
| 1022 | object_class_property_add_tm(klass, "date", rtc_get_date); |
| 1023 | } |
| 1024 | |
| 1025 | static const TypeInfo mc146818rtc_info = { |
| 1026 | .name = TYPE_MC146818_RTC, |
| 1027 | .parent = TYPE_ISA_DEVICE, |
| 1028 | .instance_size = sizeof(MC146818RtcState), |
| 1029 | .class_init = rtc_class_initfn, |
| 1030 | .interfaces = (const InterfaceInfo[]) { |
| 1031 | { TYPE_ACPI_DEV_AML_IF }, |
| 1032 | { }, |
| 1033 | }, |
| 1034 | }; |
| 1035 | |
| 1036 | static void mc146818rtc_register_types(void) |
| 1037 | { |
| 1038 | type_register_static(&mc146818rtc_info); |
| 1039 | } |
| 1040 | |
| 1041 | type_init(mc146818rtc_register_types) |