From f650305967f3e9a2fe96f59de3062fd9e8b189d0 Mon Sep 17 00:00:00 2001 From: balrog Date: Sun, 17 Feb 2008 11:42:19 +0000 Subject: [PATCH] Unify RTCs that use host time, fix M48t59 alarm. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3984 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/m48t59.c | 122 +++++++++++++++++++++---------------------------------- hw/mc146818rtc.c | 18 ++------ hw/omap.c | 10 ++--- hw/pl031.c | 11 ++--- hw/pxa2xx.c | 27 +++++------- qemu-common.h | 3 ++ sysemu.h | 2 - vl.c | 45 ++++++++++++++++++-- 8 files changed, 115 insertions(+), 123 deletions(-) diff --git a/hw/m48t59.c b/hw/m48t59.c index 45c05a0..b781f50 100644 --- a/hw/m48t59.c +++ b/hw/m48t59.c @@ -53,7 +53,7 @@ struct m48t59_t { time_t time_offset; time_t stop_time; /* Alarm & watchdog */ - time_t alarm; + struct tm alarm; struct QEMUTimer *alrm_timer; struct QEMUTimer *wd_timer; /* NVRAM storage */ @@ -74,35 +74,10 @@ static inline uint8_t fromBCD (uint8_t BCD) return ((BCD >> 4) * 10) + (BCD & 0x0F); } -/* RTC management helpers */ -static void get_time (m48t59_t *NVRAM, struct tm *tm) -{ - time_t t; - - t = time(NULL) + NVRAM->time_offset; -#ifdef _WIN32 - memcpy(tm,localtime(&t),sizeof(*tm)); -#else - if (rtc_utc) - gmtime_r (&t, tm); - else - localtime_r (&t, tm) ; -#endif -} - -static void set_time (m48t59_t *NVRAM, struct tm *tm) -{ - time_t now, new_time; - - new_time = mktime(tm); - now = time(NULL); - NVRAM->time_offset = new_time - now; -} - /* Alarm management */ static void alarm_cb (void *opaque) { - struct tm tm, tm_now; + struct tm tm; uint64_t next_time; m48t59_t *NVRAM = opaque; @@ -111,62 +86,62 @@ static void alarm_cb (void *opaque) (NVRAM->buffer[0x1FF4] & 0x80) == 0 && (NVRAM->buffer[0x1FF3] & 0x80) == 0 && (NVRAM->buffer[0x1FF2] & 0x80) == 0) { - /* Repeat once a month */ - get_time(NVRAM, &tm_now); - memcpy(&tm, &tm_now, sizeof(struct tm)); - tm.tm_mon++; - if (tm.tm_mon == 13) { - tm.tm_mon = 1; - tm.tm_year++; - } - next_time = mktime(&tm); + /* Repeat once a month */ + qemu_get_timedate(&tm, NVRAM->time_offset); + tm.tm_mon++; + if (tm.tm_mon == 13) { + tm.tm_mon = 1; + tm.tm_year++; + } + next_time = qemu_timedate_diff(&tm) - NVRAM->time_offset; } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 && (NVRAM->buffer[0x1FF4] & 0x80) == 0 && (NVRAM->buffer[0x1FF3] & 0x80) == 0 && (NVRAM->buffer[0x1FF2] & 0x80) == 0) { - /* Repeat once a day */ - next_time = 24 * 60 * 60 + mktime(&tm_now); + /* Repeat once a day */ + next_time = 24 * 60 * 60; } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 && (NVRAM->buffer[0x1FF4] & 0x80) != 0 && (NVRAM->buffer[0x1FF3] & 0x80) == 0 && (NVRAM->buffer[0x1FF2] & 0x80) == 0) { - /* Repeat once an hour */ - next_time = 60 * 60 + mktime(&tm_now); + /* Repeat once an hour */ + next_time = 60 * 60; } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 && (NVRAM->buffer[0x1FF4] & 0x80) != 0 && (NVRAM->buffer[0x1FF3] & 0x80) != 0 && (NVRAM->buffer[0x1FF2] & 0x80) == 0) { - /* Repeat once a minute */ - next_time = 60 + mktime(&tm_now); + /* Repeat once a minute */ + next_time = 60; } else { - /* Repeat once a second */ - next_time = 1 + mktime(&tm_now); + /* Repeat once a second */ + next_time = 1; } - qemu_mod_timer(NVRAM->alrm_timer, next_time * 1000); + qemu_mod_timer(NVRAM->alrm_timer, qemu_get_clock(vm_clock) + + next_time * 1000); qemu_set_irq(NVRAM->IRQ, 0); } +static void set_alarm (m48t59_t *NVRAM) +{ + int diff; + if (NVRAM->alrm_timer != NULL) { + qemu_del_timer(NVRAM->alrm_timer); + diff = qemu_timedate_diff(&NVRAM->alarm) - NVRAM->time_offset; + if (diff > 0) + qemu_mod_timer(NVRAM->alrm_timer, diff * 1000); + } +} -static void get_alarm (m48t59_t *NVRAM, struct tm *tm) +/* RTC management helpers */ +static inline void get_time (m48t59_t *NVRAM, struct tm *tm) { -#ifdef _WIN32 - memcpy(tm,localtime(&NVRAM->alarm),sizeof(*tm)); -#else - if (rtc_utc) - gmtime_r (&NVRAM->alarm, tm); - else - localtime_r (&NVRAM->alarm, tm); -#endif + qemu_get_timedate(tm, NVRAM->time_offset); } -static void set_alarm (m48t59_t *NVRAM, struct tm *tm) +static void set_time (m48t59_t *NVRAM, struct tm *tm) { - NVRAM->alarm = mktime(tm); - if (NVRAM->alrm_timer != NULL) { - qemu_del_timer(NVRAM->alrm_timer); - if (NVRAM->alarm - time(NULL) > 0) - qemu_mod_timer(NVRAM->alrm_timer, NVRAM->alarm * 1000); - } + NVRAM->time_offset = qemu_timedate_diff(tm); + set_alarm(NVRAM); } /* Watchdog management */ @@ -229,40 +204,36 @@ void m48t59_write (void *opaque, uint32_t addr, uint32_t val) /* alarm seconds */ tmp = fromBCD(val & 0x7F); if (tmp >= 0 && tmp <= 59) { - get_alarm(NVRAM, &tm); - tm.tm_sec = tmp; + NVRAM->alarm.tm_sec = tmp; NVRAM->buffer[0x1FF2] = val; - set_alarm(NVRAM, &tm); + set_alarm(NVRAM); } break; case 0x1FF3: /* alarm minutes */ tmp = fromBCD(val & 0x7F); if (tmp >= 0 && tmp <= 59) { - get_alarm(NVRAM, &tm); - tm.tm_min = tmp; + NVRAM->alarm.tm_min = tmp; NVRAM->buffer[0x1FF3] = val; - set_alarm(NVRAM, &tm); + set_alarm(NVRAM); } break; case 0x1FF4: /* alarm hours */ tmp = fromBCD(val & 0x3F); if (tmp >= 0 && tmp <= 23) { - get_alarm(NVRAM, &tm); - tm.tm_hour = tmp; + NVRAM->alarm.tm_hour = tmp; NVRAM->buffer[0x1FF4] = val; - set_alarm(NVRAM, &tm); + set_alarm(NVRAM); } break; case 0x1FF5: /* alarm date */ tmp = fromBCD(val & 0x1F); if (tmp != 0) { - get_alarm(NVRAM, &tm); - tm.tm_mday = tmp; + NVRAM->alarm.tm_mday = tmp; NVRAM->buffer[0x1FF5] = val; - set_alarm(NVRAM, &tm); + set_alarm(NVRAM); } break; case 0x1FF6: @@ -288,7 +259,7 @@ void m48t59_write (void *opaque, uint32_t addr, uint32_t val) tm.tm_sec = tmp; set_time(NVRAM, &tm); } - if ((val & 0x80) ^ (NVRAM->buffer[addr] & 0x80)) { + if ((val & 0x80) ^ (NVRAM->buffer[addr] & 0x80)) { if (val & 0x80) { NVRAM->stop_time = time(NULL); } else { @@ -296,7 +267,7 @@ void m48t59_write (void *opaque, uint32_t addr, uint32_t val) NVRAM->stop_time = 0; } } - NVRAM->buffer[addr] = val & 0x80; + NVRAM->buffer[addr] = val & 0x80; break; case 0x1FFA: case 0x07FA: @@ -682,6 +653,7 @@ m48t59_t *m48t59_init (qemu_irq IRQ, target_phys_addr_t mem_base, s->wd_timer = qemu_new_timer(vm_clock, &watchdog_cb, s); } s->lock = 0; + qemu_get_timedate(&s->alarm, 0); qemu_register_reset(m48t59_reset, s); save_base = mem_base ? mem_base : io_base; diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index e1e6427..30bb044 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -392,24 +392,14 @@ void rtc_set_date(RTCState *s, const struct tm *tm) static void rtc_set_date_from_host(RTCState *s) { - time_t ti; - struct tm *tm; + struct tm tm; int val; /* set the CMOS date */ - if (rtc_start_date == -1) { - time(&ti); - if (rtc_utc) - tm = gmtime(&ti); - else - tm = localtime(&ti); - } else { - ti = rtc_start_date; - tm = gmtime(&ti); - } - rtc_set_date(s, tm); + qemu_get_timedate(&tm, 0); + rtc_set_date(s, &tm); - val = to_bcd(s, (tm->tm_year / 100) + 19); + val = to_bcd(s, (tm.tm_year / 100) + 19); rtc_set_memory(s, REG_IBM_CENTURY_BYTE, val); rtc_set_memory(s, REG_IBM_PS2_CENTURY_BYTE, val); } diff --git a/hw/omap.c b/hw/omap.c index ce63597..ee426dc 100644 --- a/hw/omap.c +++ b/hw/omap.c @@ -4345,7 +4345,6 @@ struct omap_rtc_s { int pm_am; int auto_comp; int round; - struct tm *(*convert)(const time_t *timep, struct tm *result); struct tm alarm_tm; time_t alarm_ti; @@ -4668,7 +4667,7 @@ static void omap_rtc_tick(void *opaque) s->round = 0; } - localtime_r(&s->ti, &s->current_tm); + memcpy(&s->current_tm, localtime(&s->ti), sizeof(s->current_tm)); if ((s->interrupts & 0x08) && s->ti == s->alarm_ti) { s->status |= 0x40; @@ -4719,6 +4718,8 @@ static void omap_rtc_tick(void *opaque) static void omap_rtc_reset(struct omap_rtc_s *s) { + struct tm tm; + s->interrupts = 0; s->comp_reg = 0; s->running = 0; @@ -4729,8 +4730,8 @@ static void omap_rtc_reset(struct omap_rtc_s *s) memset(&s->alarm_tm, 0, sizeof(s->alarm_tm)); s->alarm_tm.tm_mday = 0x01; s->status = 1 << 7; - time(&s->ti); - s->ti = mktime(s->convert(&s->ti, &s->current_tm)); + qemu_get_timedate(&tm, 0); + s->ti = mktime(&tm); omap_rtc_alarm_update(s); omap_rtc_tick(s); @@ -4747,7 +4748,6 @@ struct omap_rtc_s *omap_rtc_init(target_phys_addr_t base, s->irq = irq[0]; s->alarm = irq[1]; s->clk = qemu_new_timer(rt_clock, omap_rtc_tick, s); - s->convert = rtc_utc ? gmtime_r : localtime_r; omap_rtc_reset(s); diff --git a/hw/pl031.c b/hw/pl031.c index 68e9005..bb5a69d 100644 --- a/hw/pl031.c +++ b/hw/pl031.c @@ -195,8 +195,7 @@ void pl031_init(uint32_t base, qemu_irq irq) { int iomemtype; pl031_state *s; - time_t ti; - struct tm *tm; + struct tm tm; s = qemu_mallocz(sizeof(pl031_state)); if (!s) @@ -211,12 +210,8 @@ void pl031_init(uint32_t base, qemu_irq irq) s->base = base; s->irq = irq; /* ??? We assume vm_clock is zero at this point. */ - time(&ti); - if (rtc_utc) - tm = gmtime(&ti); - else - tm = localtime(&ti); - s->tick_offset = mktime(tm); + qemu_get_timedate(&tm, 0); + s->tick_offset = mktime(&tm); s->timer = qemu_new_timer(vm_clock, pl031_interrupt, s); } diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index 14e3b95..0cb1672 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -1183,27 +1183,22 @@ static CPUWriteMemoryFunc *pxa2xx_rtc_writefn[] = { static void pxa2xx_rtc_init(struct pxa2xx_state_s *s) { - struct tm *tm; - time_t ti; + struct tm tm; int wom; s->rttr = 0x7fff; s->rtsr = 0; - time(&ti); - if (rtc_utc) - tm = gmtime(&ti); - else - tm = localtime(&ti); - wom = ((tm->tm_mday - 1) / 7) + 1; - - s->last_rcnr = (uint32_t) ti; - s->last_rdcr = (wom << 20) | ((tm->tm_wday + 1) << 17) | - (tm->tm_hour << 12) | (tm->tm_min << 6) | tm->tm_sec; - s->last_rycr = ((tm->tm_year + 1900) << 9) | - ((tm->tm_mon + 1) << 5) | tm->tm_mday; - s->last_swcr = (tm->tm_hour << 19) | - (tm->tm_min << 13) | (tm->tm_sec << 7); + qemu_get_timedate(&tm, 0); + wom = ((tm.tm_mday - 1) / 7) + 1; + + s->last_rcnr = (uint32_t) mktime(&tm); + s->last_rdcr = (wom << 20) | ((tm.tm_wday + 1) << 17) | + (tm.tm_hour << 12) | (tm.tm_min << 6) | tm.tm_sec; + s->last_rycr = ((tm.tm_year + 1900) << 9) | + ((tm.tm_mon + 1) << 5) | tm.tm_mday; + s->last_swcr = (tm.tm_hour << 19) | + (tm.tm_min << 13) | (tm.tm_sec << 7); s->last_rtcpicr = 0; s->last_hz = s->last_sw = s->last_pi = qemu_get_clock(rt_clock); diff --git a/qemu-common.h b/qemu-common.h index e8ea687..746dcc5 100644 --- a/qemu-common.h +++ b/qemu-common.h @@ -76,6 +76,9 @@ int qemu_bh_poll(void); uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c); +void qemu_get_timedate(struct tm *tm, int offset); +int qemu_timedate_diff(struct tm *tm); + /* cutils.c */ void pstrcpy(char *buf, int buf_size, const char *str); char *pstrcat(char *buf, int buf_size, const char *s); diff --git a/sysemu.h b/sysemu.h index 29377bf..296f179 100644 --- a/sysemu.h +++ b/sysemu.h @@ -71,8 +71,6 @@ void do_info_slirp(void); extern int ram_size; extern int bios_size; -extern int rtc_utc; -extern int rtc_start_date; extern int cirrus_vga_enabled; extern int vmsvga_enabled; extern int graphic_width; diff --git a/vl.c b/vl.c index c87e8bc..d5a1dbc 100644 --- a/vl.c +++ b/vl.c @@ -180,8 +180,8 @@ int pit_min_timer_count = 0; int nb_nics; NICInfo nd_table[MAX_NICS]; int vm_running; -int rtc_utc = 1; -int rtc_start_date = -1; /* -1 means now */ +static int rtc_utc = 1; +static int rtc_date_offset = -1; /* -1 means no change */ int cirrus_vga_enabled = 1; int vmsvga_enabled = 0; #ifdef TARGET_SPARC @@ -1565,6 +1565,43 @@ static void quit_timers(void) } /***********************************************************/ +/* host time/date access */ +void qemu_get_timedate(struct tm *tm, int offset) +{ + time_t ti; + struct tm *ret; + + time(&ti); + ti += offset; + if (rtc_date_offset == -1) { + if (rtc_utc) + ret = gmtime(&ti); + else + ret = localtime(&ti); + } else { + ti -= rtc_date_offset; + ret = gmtime(&ti); + } + + memcpy(tm, ret, sizeof(struct tm)); +} + +int qemu_timedate_diff(struct tm *tm) +{ + time_t seconds; + + if (rtc_date_offset == -1) + if (rtc_utc) + seconds = mktimegm(tm); + else + seconds = mktime(tm); + else + seconds = mktimegm(tm) + rtc_date_offset; + + return seconds - time(NULL); +} + +/***********************************************************/ /* character device */ static void qemu_chr_event(CharDriverState *s, int event) @@ -8698,8 +8735,9 @@ int main(int argc, char **argv) case QEMU_OPTION_startdate: { struct tm tm; + time_t rtc_start_date; if (!strcmp(optarg, "now")) { - rtc_start_date = -1; + rtc_date_offset = -1; } else { if (sscanf(optarg, "%d-%d-%dT%d:%d:%d", &tm.tm_year, @@ -8728,6 +8766,7 @@ int main(int argc, char **argv) "'now' or '2006-06-17T16:01:21' or '2006-06-17'\n"); exit(1); } + rtc_date_offset = time(NULL) - rtc_start_date; } } break; -- 2.7.4