Annotation of qemu/hw/mc146818rtc.c, revision 1.1.1.4

1.1       root        1: /*
                      2:  * QEMU MC146818 RTC emulation
1.1.1.3   root        3:  *
1.1       root        4:  * Copyright (c) 2003-2004 Fabrice Bellard
1.1.1.3   root        5:  *
1.1       root        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:  */
1.1.1.3   root       24: #include "hw.h"
                     25: #include "qemu-timer.h"
                     26: #include "sysemu.h"
                     27: #include "pc.h"
                     28: #include "isa.h"
1.1.1.4 ! root       29: #include "hpet_emul.h"
1.1       root       30: 
                     31: //#define DEBUG_CMOS
                     32: 
                     33: #define RTC_SECONDS             0
                     34: #define RTC_SECONDS_ALARM       1
                     35: #define RTC_MINUTES             2
                     36: #define RTC_MINUTES_ALARM       3
                     37: #define RTC_HOURS               4
                     38: #define RTC_HOURS_ALARM         5
                     39: #define RTC_ALARM_DONT_CARE    0xC0
                     40: 
                     41: #define RTC_DAY_OF_WEEK         6
                     42: #define RTC_DAY_OF_MONTH        7
                     43: #define RTC_MONTH               8
                     44: #define RTC_YEAR                9
                     45: 
                     46: #define RTC_REG_A               10
                     47: #define RTC_REG_B               11
                     48: #define RTC_REG_C               12
                     49: #define RTC_REG_D               13
                     50: 
                     51: #define REG_A_UIP 0x80
                     52: 
                     53: #define REG_B_SET 0x80
                     54: #define REG_B_PIE 0x40
                     55: #define REG_B_AIE 0x20
                     56: #define REG_B_UIE 0x10
1.1.1.4 ! root       57: #define REG_B_DM  0x04
1.1       root       58: 
                     59: struct RTCState {
                     60:     uint8_t cmos_data[128];
                     61:     uint8_t cmos_index;
                     62:     struct tm current_tm;
1.1.1.4 ! root       63:     int base_year;
1.1.1.3   root       64:     qemu_irq irq;
                     65:     int it_shift;
1.1       root       66:     /* periodic timer */
                     67:     QEMUTimer *periodic_timer;
                     68:     int64_t next_periodic_time;
                     69:     /* second update */
                     70:     int64_t next_second_time;
1.1.1.4 ! root       71: #ifdef TARGET_I386
        !            72:     uint32_t irq_coalesced;
        !            73:     uint32_t period;
        !            74: #endif
1.1       root       75:     QEMUTimer *second_timer;
                     76:     QEMUTimer *second_timer2;
                     77: };
                     78: 
1.1.1.4 ! root       79: static void rtc_irq_raise(qemu_irq irq) {
        !            80:     /* When HPET is operating in legacy mode, RTC interrupts are disabled
        !            81:      * We block qemu_irq_raise, but not qemu_irq_lower, in case legacy
        !            82:      * mode is established while interrupt is raised. We want it to
        !            83:      * be lowered in any case
        !            84:      */
        !            85: #if defined TARGET_I386 || defined TARGET_X86_64
        !            86:     if (!hpet_in_legacy_mode())
        !            87: #endif
        !            88:         qemu_irq_raise(irq);
        !            89: }
        !            90: 
1.1       root       91: static void rtc_set_time(RTCState *s);
                     92: static void rtc_copy_date(RTCState *s);
                     93: 
                     94: static void rtc_timer_update(RTCState *s, int64_t current_time)
                     95: {
                     96:     int period_code, period;
                     97:     int64_t cur_clock, next_irq_clock;
                     98: 
                     99:     period_code = s->cmos_data[RTC_REG_A] & 0x0f;
1.1.1.4 ! root      100: #if defined TARGET_I386 || defined TARGET_X86_64
        !           101:     /* disable periodic timer if hpet is in legacy mode, since interrupts are
        !           102:      * disabled anyway.
        !           103:      */
        !           104:     if (period_code != 0 && (s->cmos_data[RTC_REG_B] & REG_B_PIE) && !hpet_in_legacy_mode()) {
        !           105: #else
        !           106:     if (period_code != 0 && (s->cmos_data[RTC_REG_B] & REG_B_PIE)) {
        !           107: #endif
1.1       root      108:         if (period_code <= 2)
                    109:             period_code += 7;
                    110:         /* period in 32 Khz cycles */
                    111:         period = 1 << (period_code - 1);
1.1.1.4 ! root      112: #ifdef TARGET_I386
        !           113:         if(period != s->period)
        !           114:             s->irq_coalesced = (s->irq_coalesced * s->period) / period;
        !           115:         s->period = period;
        !           116: #endif
1.1       root      117:         /* compute 32 khz clock */
                    118:         cur_clock = muldiv64(current_time, 32768, ticks_per_sec);
                    119:         next_irq_clock = (cur_clock & ~(period - 1)) + period;
                    120:         s->next_periodic_time = muldiv64(next_irq_clock, ticks_per_sec, 32768) + 1;
                    121:         qemu_mod_timer(s->periodic_timer, s->next_periodic_time);
                    122:     } else {
1.1.1.4 ! root      123: #ifdef TARGET_I386
        !           124:         s->irq_coalesced = 0;
        !           125: #endif
1.1       root      126:         qemu_del_timer(s->periodic_timer);
                    127:     }
                    128: }
                    129: 
                    130: static void rtc_periodic_timer(void *opaque)
                    131: {
                    132:     RTCState *s = opaque;
                    133: 
                    134:     rtc_timer_update(s, s->next_periodic_time);
1.1.1.4 ! root      135: #ifdef TARGET_I386
        !           136:     if ((s->cmos_data[RTC_REG_C] & 0xc0) && rtc_td_hack) {
        !           137:         s->irq_coalesced++;
        !           138:         return;
        !           139:     }
        !           140: #endif
1.1       root      141:     s->cmos_data[RTC_REG_C] |= 0xc0;
1.1.1.4 ! root      142:     rtc_irq_raise(s->irq);
1.1       root      143: }
                    144: 
                    145: static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data)
                    146: {
                    147:     RTCState *s = opaque;
                    148: 
                    149:     if ((addr & 1) == 0) {
                    150:         s->cmos_index = data & 0x7f;
                    151:     } else {
                    152: #ifdef DEBUG_CMOS
                    153:         printf("cmos: write index=0x%02x val=0x%02x\n",
                    154:                s->cmos_index, data);
1.1.1.3   root      155: #endif
1.1       root      156:         switch(s->cmos_index) {
                    157:         case RTC_SECONDS_ALARM:
                    158:         case RTC_MINUTES_ALARM:
                    159:         case RTC_HOURS_ALARM:
                    160:             /* XXX: not supported */
                    161:             s->cmos_data[s->cmos_index] = data;
                    162:             break;
                    163:         case RTC_SECONDS:
                    164:         case RTC_MINUTES:
                    165:         case RTC_HOURS:
                    166:         case RTC_DAY_OF_WEEK:
                    167:         case RTC_DAY_OF_MONTH:
                    168:         case RTC_MONTH:
                    169:         case RTC_YEAR:
                    170:             s->cmos_data[s->cmos_index] = data;
                    171:             /* if in set mode, do not update the time */
                    172:             if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
                    173:                 rtc_set_time(s);
                    174:             }
                    175:             break;
                    176:         case RTC_REG_A:
                    177:             /* UIP bit is read only */
                    178:             s->cmos_data[RTC_REG_A] = (data & ~REG_A_UIP) |
                    179:                 (s->cmos_data[RTC_REG_A] & REG_A_UIP);
                    180:             rtc_timer_update(s, qemu_get_clock(vm_clock));
                    181:             break;
                    182:         case RTC_REG_B:
                    183:             if (data & REG_B_SET) {
                    184:                 /* set mode: reset UIP mode */
                    185:                 s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
                    186:                 data &= ~REG_B_UIE;
                    187:             } else {
                    188:                 /* if disabling set mode, update the time */
                    189:                 if (s->cmos_data[RTC_REG_B] & REG_B_SET) {
                    190:                     rtc_set_time(s);
                    191:                 }
                    192:             }
                    193:             s->cmos_data[RTC_REG_B] = data;
                    194:             rtc_timer_update(s, qemu_get_clock(vm_clock));
                    195:             break;
                    196:         case RTC_REG_C:
                    197:         case RTC_REG_D:
                    198:             /* cannot write to them */
                    199:             break;
                    200:         default:
                    201:             s->cmos_data[s->cmos_index] = data;
                    202:             break;
                    203:         }
                    204:     }
                    205: }
                    206: 
                    207: static inline int to_bcd(RTCState *s, int a)
                    208: {
1.1.1.4 ! root      209:     if (s->cmos_data[RTC_REG_B] & REG_B_DM) {
1.1       root      210:         return a;
                    211:     } else {
                    212:         return ((a / 10) << 4) | (a % 10);
                    213:     }
                    214: }
                    215: 
                    216: static inline int from_bcd(RTCState *s, int a)
                    217: {
1.1.1.4 ! root      218:     if (s->cmos_data[RTC_REG_B] & REG_B_DM) {
1.1       root      219:         return a;
                    220:     } else {
                    221:         return ((a >> 4) * 10) + (a & 0x0f);
                    222:     }
                    223: }
                    224: 
                    225: static void rtc_set_time(RTCState *s)
                    226: {
                    227:     struct tm *tm = &s->current_tm;
                    228: 
                    229:     tm->tm_sec = from_bcd(s, s->cmos_data[RTC_SECONDS]);
                    230:     tm->tm_min = from_bcd(s, s->cmos_data[RTC_MINUTES]);
                    231:     tm->tm_hour = from_bcd(s, s->cmos_data[RTC_HOURS] & 0x7f);
                    232:     if (!(s->cmos_data[RTC_REG_B] & 0x02) &&
                    233:         (s->cmos_data[RTC_HOURS] & 0x80)) {
                    234:         tm->tm_hour += 12;
                    235:     }
1.1.1.4 ! root      236:     tm->tm_wday = from_bcd(s, s->cmos_data[RTC_DAY_OF_WEEK]) - 1;
1.1       root      237:     tm->tm_mday = from_bcd(s, s->cmos_data[RTC_DAY_OF_MONTH]);
                    238:     tm->tm_mon = from_bcd(s, s->cmos_data[RTC_MONTH]) - 1;
1.1.1.4 ! root      239:     tm->tm_year = from_bcd(s, s->cmos_data[RTC_YEAR]) + s->base_year - 1900;
1.1       root      240: }
                    241: 
                    242: static void rtc_copy_date(RTCState *s)
                    243: {
                    244:     const struct tm *tm = &s->current_tm;
1.1.1.4 ! root      245:     int year;
1.1       root      246: 
                    247:     s->cmos_data[RTC_SECONDS] = to_bcd(s, tm->tm_sec);
                    248:     s->cmos_data[RTC_MINUTES] = to_bcd(s, tm->tm_min);
                    249:     if (s->cmos_data[RTC_REG_B] & 0x02) {
                    250:         /* 24 hour format */
                    251:         s->cmos_data[RTC_HOURS] = to_bcd(s, tm->tm_hour);
                    252:     } else {
                    253:         /* 12 hour format */
                    254:         s->cmos_data[RTC_HOURS] = to_bcd(s, tm->tm_hour % 12);
                    255:         if (tm->tm_hour >= 12)
                    256:             s->cmos_data[RTC_HOURS] |= 0x80;
                    257:     }
1.1.1.4 ! root      258:     s->cmos_data[RTC_DAY_OF_WEEK] = to_bcd(s, tm->tm_wday + 1);
1.1       root      259:     s->cmos_data[RTC_DAY_OF_MONTH] = to_bcd(s, tm->tm_mday);
                    260:     s->cmos_data[RTC_MONTH] = to_bcd(s, tm->tm_mon + 1);
1.1.1.4 ! root      261:     year = (tm->tm_year - s->base_year) % 100;
        !           262:     if (year < 0)
        !           263:         year += 100;
        !           264:     s->cmos_data[RTC_YEAR] = to_bcd(s, year);
1.1       root      265: }
                    266: 
                    267: /* month is between 0 and 11. */
                    268: static int get_days_in_month(int month, int year)
                    269: {
1.1.1.3   root      270:     static const int days_tab[12] = {
                    271:         31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
1.1       root      272:     };
                    273:     int d;
                    274:     if ((unsigned )month >= 12)
                    275:         return 31;
                    276:     d = days_tab[month];
                    277:     if (month == 1) {
                    278:         if ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0))
                    279:             d++;
                    280:     }
                    281:     return d;
                    282: }
                    283: 
                    284: /* update 'tm' to the next second */
                    285: static void rtc_next_second(struct tm *tm)
                    286: {
                    287:     int days_in_month;
                    288: 
                    289:     tm->tm_sec++;
                    290:     if ((unsigned)tm->tm_sec >= 60) {
                    291:         tm->tm_sec = 0;
                    292:         tm->tm_min++;
                    293:         if ((unsigned)tm->tm_min >= 60) {
                    294:             tm->tm_min = 0;
                    295:             tm->tm_hour++;
                    296:             if ((unsigned)tm->tm_hour >= 24) {
                    297:                 tm->tm_hour = 0;
                    298:                 /* next day */
                    299:                 tm->tm_wday++;
                    300:                 if ((unsigned)tm->tm_wday >= 7)
                    301:                     tm->tm_wday = 0;
1.1.1.3   root      302:                 days_in_month = get_days_in_month(tm->tm_mon,
1.1       root      303:                                                   tm->tm_year + 1900);
                    304:                 tm->tm_mday++;
                    305:                 if (tm->tm_mday < 1) {
                    306:                     tm->tm_mday = 1;
                    307:                 } else if (tm->tm_mday > days_in_month) {
                    308:                     tm->tm_mday = 1;
                    309:                     tm->tm_mon++;
                    310:                     if (tm->tm_mon >= 12) {
                    311:                         tm->tm_mon = 0;
                    312:                         tm->tm_year++;
                    313:                     }
                    314:                 }
                    315:             }
                    316:         }
                    317:     }
                    318: }
                    319: 
                    320: 
                    321: static void rtc_update_second(void *opaque)
                    322: {
                    323:     RTCState *s = opaque;
                    324:     int64_t delay;
                    325: 
                    326:     /* if the oscillator is not in normal operation, we do not update */
                    327:     if ((s->cmos_data[RTC_REG_A] & 0x70) != 0x20) {
                    328:         s->next_second_time += ticks_per_sec;
                    329:         qemu_mod_timer(s->second_timer, s->next_second_time);
                    330:     } else {
                    331:         rtc_next_second(&s->current_tm);
1.1.1.3   root      332: 
1.1       root      333:         if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
                    334:             /* update in progress bit */
                    335:             s->cmos_data[RTC_REG_A] |= REG_A_UIP;
                    336:         }
                    337:         /* should be 244 us = 8 / 32768 seconds, but currently the
                    338:            timers do not have the necessary resolution. */
                    339:         delay = (ticks_per_sec * 1) / 100;
                    340:         if (delay < 1)
                    341:             delay = 1;
1.1.1.3   root      342:         qemu_mod_timer(s->second_timer2,
1.1       root      343:                        s->next_second_time + delay);
                    344:     }
                    345: }
                    346: 
                    347: static void rtc_update_second2(void *opaque)
                    348: {
                    349:     RTCState *s = opaque;
                    350: 
                    351:     if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
                    352:         rtc_copy_date(s);
                    353:     }
                    354: 
                    355:     /* check alarm */
                    356:     if (s->cmos_data[RTC_REG_B] & REG_B_AIE) {
                    357:         if (((s->cmos_data[RTC_SECONDS_ALARM] & 0xc0) == 0xc0 ||
                    358:              s->cmos_data[RTC_SECONDS_ALARM] == s->current_tm.tm_sec) &&
                    359:             ((s->cmos_data[RTC_MINUTES_ALARM] & 0xc0) == 0xc0 ||
                    360:              s->cmos_data[RTC_MINUTES_ALARM] == s->current_tm.tm_mon) &&
                    361:             ((s->cmos_data[RTC_HOURS_ALARM] & 0xc0) == 0xc0 ||
                    362:              s->cmos_data[RTC_HOURS_ALARM] == s->current_tm.tm_hour)) {
                    363: 
1.1.1.3   root      364:             s->cmos_data[RTC_REG_C] |= 0xa0;
1.1.1.4 ! root      365:             rtc_irq_raise(s->irq);
1.1       root      366:         }
                    367:     }
                    368: 
                    369:     /* update ended interrupt */
                    370:     if (s->cmos_data[RTC_REG_B] & REG_B_UIE) {
1.1.1.3   root      371:         s->cmos_data[RTC_REG_C] |= 0x90;
1.1.1.4 ! root      372:         rtc_irq_raise(s->irq);
1.1       root      373:     }
                    374: 
                    375:     /* clear update in progress bit */
                    376:     s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
                    377: 
                    378:     s->next_second_time += ticks_per_sec;
                    379:     qemu_mod_timer(s->second_timer, s->next_second_time);
                    380: }
                    381: 
                    382: static uint32_t cmos_ioport_read(void *opaque, uint32_t addr)
                    383: {
                    384:     RTCState *s = opaque;
                    385:     int ret;
                    386:     if ((addr & 1) == 0) {
                    387:         return 0xff;
                    388:     } else {
                    389:         switch(s->cmos_index) {
                    390:         case RTC_SECONDS:
                    391:         case RTC_MINUTES:
                    392:         case RTC_HOURS:
                    393:         case RTC_DAY_OF_WEEK:
                    394:         case RTC_DAY_OF_MONTH:
                    395:         case RTC_MONTH:
                    396:         case RTC_YEAR:
                    397:             ret = s->cmos_data[s->cmos_index];
                    398:             break;
                    399:         case RTC_REG_A:
                    400:             ret = s->cmos_data[s->cmos_index];
                    401:             break;
                    402:         case RTC_REG_C:
                    403:             ret = s->cmos_data[s->cmos_index];
1.1.1.3   root      404:             qemu_irq_lower(s->irq);
1.1.1.4 ! root      405: #ifdef TARGET_I386
        !           406:             if(s->irq_coalesced) {
        !           407:                 apic_reset_irq_delivered();
        !           408:                 qemu_irq_raise(s->irq);
        !           409:                 if (apic_get_irq_delivered())
        !           410:                     s->irq_coalesced--;
        !           411:                 break;
        !           412:             }
        !           413: #endif
1.1.1.3   root      414:             s->cmos_data[RTC_REG_C] = 0x00;
1.1       root      415:             break;
                    416:         default:
                    417:             ret = s->cmos_data[s->cmos_index];
                    418:             break;
                    419:         }
                    420: #ifdef DEBUG_CMOS
                    421:         printf("cmos: read index=0x%02x val=0x%02x\n",
                    422:                s->cmos_index, ret);
                    423: #endif
                    424:         return ret;
                    425:     }
                    426: }
                    427: 
                    428: void rtc_set_memory(RTCState *s, int addr, int val)
                    429: {
                    430:     if (addr >= 0 && addr <= 127)
                    431:         s->cmos_data[addr] = val;
                    432: }
                    433: 
                    434: void rtc_set_date(RTCState *s, const struct tm *tm)
                    435: {
                    436:     s->current_tm = *tm;
                    437:     rtc_copy_date(s);
                    438: }
                    439: 
1.1.1.2   root      440: /* PC cmos mappings */
                    441: #define REG_IBM_CENTURY_BYTE        0x32
                    442: #define REG_IBM_PS2_CENTURY_BYTE    0x37
                    443: 
1.1.1.3   root      444: static void rtc_set_date_from_host(RTCState *s)
1.1.1.2   root      445: {
1.1.1.4 ! root      446:     struct tm tm;
1.1.1.2   root      447:     int val;
                    448: 
                    449:     /* set the CMOS date */
1.1.1.4 ! root      450:     qemu_get_timedate(&tm, 0);
        !           451:     rtc_set_date(s, &tm);
1.1.1.2   root      452: 
1.1.1.4 ! root      453:     val = to_bcd(s, (tm.tm_year / 100) + 19);
1.1.1.2   root      454:     rtc_set_memory(s, REG_IBM_CENTURY_BYTE, val);
                    455:     rtc_set_memory(s, REG_IBM_PS2_CENTURY_BYTE, val);
                    456: }
                    457: 
1.1       root      458: static void rtc_save(QEMUFile *f, void *opaque)
                    459: {
                    460:     RTCState *s = opaque;
                    461: 
                    462:     qemu_put_buffer(f, s->cmos_data, 128);
                    463:     qemu_put_8s(f, &s->cmos_index);
1.1.1.3   root      464: 
                    465:     qemu_put_be32(f, s->current_tm.tm_sec);
                    466:     qemu_put_be32(f, s->current_tm.tm_min);
                    467:     qemu_put_be32(f, s->current_tm.tm_hour);
                    468:     qemu_put_be32(f, s->current_tm.tm_wday);
                    469:     qemu_put_be32(f, s->current_tm.tm_mday);
                    470:     qemu_put_be32(f, s->current_tm.tm_mon);
                    471:     qemu_put_be32(f, s->current_tm.tm_year);
1.1       root      472: 
                    473:     qemu_put_timer(f, s->periodic_timer);
1.1.1.3   root      474:     qemu_put_be64(f, s->next_periodic_time);
1.1       root      475: 
1.1.1.3   root      476:     qemu_put_be64(f, s->next_second_time);
1.1       root      477:     qemu_put_timer(f, s->second_timer);
                    478:     qemu_put_timer(f, s->second_timer2);
                    479: }
                    480: 
                    481: static int rtc_load(QEMUFile *f, void *opaque, int version_id)
                    482: {
                    483:     RTCState *s = opaque;
                    484: 
                    485:     if (version_id != 1)
                    486:         return -EINVAL;
                    487: 
                    488:     qemu_get_buffer(f, s->cmos_data, 128);
                    489:     qemu_get_8s(f, &s->cmos_index);
                    490: 
1.1.1.3   root      491:     s->current_tm.tm_sec=qemu_get_be32(f);
                    492:     s->current_tm.tm_min=qemu_get_be32(f);
                    493:     s->current_tm.tm_hour=qemu_get_be32(f);
                    494:     s->current_tm.tm_wday=qemu_get_be32(f);
                    495:     s->current_tm.tm_mday=qemu_get_be32(f);
                    496:     s->current_tm.tm_mon=qemu_get_be32(f);
                    497:     s->current_tm.tm_year=qemu_get_be32(f);
1.1       root      498: 
                    499:     qemu_get_timer(f, s->periodic_timer);
1.1.1.3   root      500:     s->next_periodic_time=qemu_get_be64(f);
1.1       root      501: 
1.1.1.3   root      502:     s->next_second_time=qemu_get_be64(f);
1.1       root      503:     qemu_get_timer(f, s->second_timer);
                    504:     qemu_get_timer(f, s->second_timer2);
                    505:     return 0;
                    506: }
                    507: 
1.1.1.4 ! root      508: #ifdef TARGET_I386
        !           509: static void rtc_save_td(QEMUFile *f, void *opaque)
        !           510: {
        !           511:     RTCState *s = opaque;
        !           512: 
        !           513:     qemu_put_be32(f, s->irq_coalesced);
        !           514:     qemu_put_be32(f, s->period);
        !           515: }
        !           516: 
        !           517: static int rtc_load_td(QEMUFile *f, void *opaque, int version_id)
        !           518: {
        !           519:     RTCState *s = opaque;
        !           520: 
        !           521:     if (version_id != 1)
        !           522:         return -EINVAL;
        !           523: 
        !           524:     s->irq_coalesced = qemu_get_be32(f);
        !           525:     s->period = qemu_get_be32(f);
        !           526:     return 0;
        !           527: }
        !           528: #endif
        !           529: 
        !           530: RTCState *rtc_init(int base, qemu_irq irq, int base_year)
1.1       root      531: {
                    532:     RTCState *s;
                    533: 
                    534:     s = qemu_mallocz(sizeof(RTCState));
                    535: 
                    536:     s->irq = irq;
                    537:     s->cmos_data[RTC_REG_A] = 0x26;
                    538:     s->cmos_data[RTC_REG_B] = 0x02;
                    539:     s->cmos_data[RTC_REG_C] = 0x00;
                    540:     s->cmos_data[RTC_REG_D] = 0x80;
                    541: 
1.1.1.4 ! root      542:     s->base_year = base_year;
1.1.1.2   root      543:     rtc_set_date_from_host(s);
                    544: 
1.1.1.3   root      545:     s->periodic_timer = qemu_new_timer(vm_clock,
1.1       root      546:                                        rtc_periodic_timer, s);
1.1.1.3   root      547:     s->second_timer = qemu_new_timer(vm_clock,
1.1       root      548:                                      rtc_update_second, s);
1.1.1.3   root      549:     s->second_timer2 = qemu_new_timer(vm_clock,
1.1       root      550:                                       rtc_update_second2, s);
                    551: 
                    552:     s->next_second_time = qemu_get_clock(vm_clock) + (ticks_per_sec * 99) / 100;
                    553:     qemu_mod_timer(s->second_timer2, s->next_second_time);
                    554: 
                    555:     register_ioport_write(base, 2, 1, cmos_ioport_write, s);
                    556:     register_ioport_read(base, 2, 1, cmos_ioport_read, s);
                    557: 
                    558:     register_savevm("mc146818rtc", base, 1, rtc_save, rtc_load, s);
1.1.1.4 ! root      559: #ifdef TARGET_I386
        !           560:     if (rtc_td_hack)
        !           561:         register_savevm("mc146818rtc-td", base, 1, rtc_save_td, rtc_load_td, s);
        !           562: #endif
1.1       root      563:     return s;
                    564: }
                    565: 
1.1.1.3   root      566: /* Memory mapped interface */
                    567: static uint32_t cmos_mm_readb (void *opaque, target_phys_addr_t addr)
                    568: {
                    569:     RTCState *s = opaque;
                    570: 
1.1.1.4 ! root      571:     return cmos_ioport_read(s, addr >> s->it_shift) & 0xFF;
1.1.1.3   root      572: }
                    573: 
                    574: static void cmos_mm_writeb (void *opaque,
                    575:                             target_phys_addr_t addr, uint32_t value)
                    576: {
                    577:     RTCState *s = opaque;
                    578: 
1.1.1.4 ! root      579:     cmos_ioport_write(s, addr >> s->it_shift, value & 0xFF);
1.1.1.3   root      580: }
                    581: 
                    582: static uint32_t cmos_mm_readw (void *opaque, target_phys_addr_t addr)
                    583: {
                    584:     RTCState *s = opaque;
                    585:     uint32_t val;
                    586: 
1.1.1.4 ! root      587:     val = cmos_ioport_read(s, addr >> s->it_shift) & 0xFFFF;
1.1.1.3   root      588: #ifdef TARGET_WORDS_BIGENDIAN
                    589:     val = bswap16(val);
                    590: #endif
                    591:     return val;
                    592: }
                    593: 
                    594: static void cmos_mm_writew (void *opaque,
                    595:                             target_phys_addr_t addr, uint32_t value)
                    596: {
                    597:     RTCState *s = opaque;
                    598: #ifdef TARGET_WORDS_BIGENDIAN
                    599:     value = bswap16(value);
                    600: #endif
1.1.1.4 ! root      601:     cmos_ioport_write(s, addr >> s->it_shift, value & 0xFFFF);
1.1.1.3   root      602: }
                    603: 
                    604: static uint32_t cmos_mm_readl (void *opaque, target_phys_addr_t addr)
                    605: {
                    606:     RTCState *s = opaque;
                    607:     uint32_t val;
                    608: 
1.1.1.4 ! root      609:     val = cmos_ioport_read(s, addr >> s->it_shift);
1.1.1.3   root      610: #ifdef TARGET_WORDS_BIGENDIAN
                    611:     val = bswap32(val);
                    612: #endif
                    613:     return val;
                    614: }
                    615: 
                    616: static void cmos_mm_writel (void *opaque,
                    617:                             target_phys_addr_t addr, uint32_t value)
                    618: {
                    619:     RTCState *s = opaque;
                    620: #ifdef TARGET_WORDS_BIGENDIAN
                    621:     value = bswap32(value);
                    622: #endif
1.1.1.4 ! root      623:     cmos_ioport_write(s, addr >> s->it_shift, value);
1.1.1.3   root      624: }
                    625: 
                    626: static CPUReadMemoryFunc *rtc_mm_read[] = {
                    627:     &cmos_mm_readb,
                    628:     &cmos_mm_readw,
                    629:     &cmos_mm_readl,
                    630: };
                    631: 
                    632: static CPUWriteMemoryFunc *rtc_mm_write[] = {
                    633:     &cmos_mm_writeb,
                    634:     &cmos_mm_writew,
                    635:     &cmos_mm_writel,
                    636: };
                    637: 
1.1.1.4 ! root      638: RTCState *rtc_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq,
        !           639:                       int base_year)
1.1.1.3   root      640: {
                    641:     RTCState *s;
                    642:     int io_memory;
                    643: 
                    644:     s = qemu_mallocz(sizeof(RTCState));
                    645: 
                    646:     s->irq = irq;
                    647:     s->cmos_data[RTC_REG_A] = 0x26;
                    648:     s->cmos_data[RTC_REG_B] = 0x02;
                    649:     s->cmos_data[RTC_REG_C] = 0x00;
                    650:     s->cmos_data[RTC_REG_D] = 0x80;
                    651: 
1.1.1.4 ! root      652:     s->base_year = base_year;
1.1.1.3   root      653:     rtc_set_date_from_host(s);
                    654: 
                    655:     s->periodic_timer = qemu_new_timer(vm_clock,
                    656:                                        rtc_periodic_timer, s);
                    657:     s->second_timer = qemu_new_timer(vm_clock,
                    658:                                      rtc_update_second, s);
                    659:     s->second_timer2 = qemu_new_timer(vm_clock,
                    660:                                       rtc_update_second2, s);
                    661: 
                    662:     s->next_second_time = qemu_get_clock(vm_clock) + (ticks_per_sec * 99) / 100;
                    663:     qemu_mod_timer(s->second_timer2, s->next_second_time);
                    664: 
                    665:     io_memory = cpu_register_io_memory(0, rtc_mm_read, rtc_mm_write, s);
                    666:     cpu_register_physical_memory(base, 2 << it_shift, io_memory);
                    667: 
                    668:     register_savevm("mc146818rtc", base, 1, rtc_save, rtc_load, s);
1.1.1.4 ! root      669: #ifdef TARGET_I386
        !           670:     if (rtc_td_hack)
        !           671:         register_savevm("mc146818rtc-td", base, 1, rtc_save_td, rtc_load_td, s);
        !           672: #endif
1.1.1.3   root      673:     return s;
                    674: }

unix.superglobalmegacorp.com