提交 f6503059 编写于 作者: B balrog

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
上级 a0d69e00
...@@ -53,7 +53,7 @@ struct m48t59_t { ...@@ -53,7 +53,7 @@ struct m48t59_t {
time_t time_offset; time_t time_offset;
time_t stop_time; time_t stop_time;
/* Alarm & watchdog */ /* Alarm & watchdog */
time_t alarm; struct tm alarm;
struct QEMUTimer *alrm_timer; struct QEMUTimer *alrm_timer;
struct QEMUTimer *wd_timer; struct QEMUTimer *wd_timer;
/* NVRAM storage */ /* NVRAM storage */
...@@ -74,35 +74,10 @@ static inline uint8_t fromBCD (uint8_t BCD) ...@@ -74,35 +74,10 @@ static inline uint8_t fromBCD (uint8_t BCD)
return ((BCD >> 4) * 10) + (BCD & 0x0F); 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 */ /* Alarm management */
static void alarm_cb (void *opaque) static void alarm_cb (void *opaque)
{ {
struct tm tm, tm_now; struct tm tm;
uint64_t next_time; uint64_t next_time;
m48t59_t *NVRAM = opaque; m48t59_t *NVRAM = opaque;
...@@ -112,61 +87,61 @@ static void alarm_cb (void *opaque) ...@@ -112,61 +87,61 @@ static void alarm_cb (void *opaque)
(NVRAM->buffer[0x1FF3] & 0x80) == 0 && (NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
(NVRAM->buffer[0x1FF2] & 0x80) == 0) { (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
/* Repeat once a month */ /* Repeat once a month */
get_time(NVRAM, &tm_now); qemu_get_timedate(&tm, NVRAM->time_offset);
memcpy(&tm, &tm_now, sizeof(struct tm));
tm.tm_mon++; tm.tm_mon++;
if (tm.tm_mon == 13) { if (tm.tm_mon == 13) {
tm.tm_mon = 1; tm.tm_mon = 1;
tm.tm_year++; tm.tm_year++;
} }
next_time = mktime(&tm); next_time = qemu_timedate_diff(&tm) - NVRAM->time_offset;
} else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 && } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
(NVRAM->buffer[0x1FF4] & 0x80) == 0 && (NVRAM->buffer[0x1FF4] & 0x80) == 0 &&
(NVRAM->buffer[0x1FF3] & 0x80) == 0 && (NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
(NVRAM->buffer[0x1FF2] & 0x80) == 0) { (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
/* Repeat once a day */ /* Repeat once a day */
next_time = 24 * 60 * 60 + mktime(&tm_now); next_time = 24 * 60 * 60;
} else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 && } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
(NVRAM->buffer[0x1FF4] & 0x80) != 0 && (NVRAM->buffer[0x1FF4] & 0x80) != 0 &&
(NVRAM->buffer[0x1FF3] & 0x80) == 0 && (NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
(NVRAM->buffer[0x1FF2] & 0x80) == 0) { (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
/* Repeat once an hour */ /* Repeat once an hour */
next_time = 60 * 60 + mktime(&tm_now); next_time = 60 * 60;
} else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 && } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
(NVRAM->buffer[0x1FF4] & 0x80) != 0 && (NVRAM->buffer[0x1FF4] & 0x80) != 0 &&
(NVRAM->buffer[0x1FF3] & 0x80) != 0 && (NVRAM->buffer[0x1FF3] & 0x80) != 0 &&
(NVRAM->buffer[0x1FF2] & 0x80) == 0) { (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
/* Repeat once a minute */ /* Repeat once a minute */
next_time = 60 + mktime(&tm_now); next_time = 60;
} else { } else {
/* Repeat once a second */ /* Repeat once a second */
next_time = 1 + mktime(&tm_now); 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); 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 qemu_get_timedate(tm, NVRAM->time_offset);
memcpy(tm,localtime(&NVRAM->alarm),sizeof(*tm));
#else
if (rtc_utc)
gmtime_r (&NVRAM->alarm, tm);
else
localtime_r (&NVRAM->alarm, tm);
#endif
} }
static void set_alarm (m48t59_t *NVRAM, struct tm *tm) static void set_time (m48t59_t *NVRAM, struct tm *tm)
{ {
NVRAM->alarm = mktime(tm); NVRAM->time_offset = qemu_timedate_diff(tm);
if (NVRAM->alrm_timer != NULL) { set_alarm(NVRAM);
qemu_del_timer(NVRAM->alrm_timer);
if (NVRAM->alarm - time(NULL) > 0)
qemu_mod_timer(NVRAM->alrm_timer, NVRAM->alarm * 1000);
}
} }
/* Watchdog management */ /* Watchdog management */
...@@ -229,40 +204,36 @@ void m48t59_write (void *opaque, uint32_t addr, uint32_t val) ...@@ -229,40 +204,36 @@ void m48t59_write (void *opaque, uint32_t addr, uint32_t val)
/* alarm seconds */ /* alarm seconds */
tmp = fromBCD(val & 0x7F); tmp = fromBCD(val & 0x7F);
if (tmp >= 0 && tmp <= 59) { if (tmp >= 0 && tmp <= 59) {
get_alarm(NVRAM, &tm); NVRAM->alarm.tm_sec = tmp;
tm.tm_sec = tmp;
NVRAM->buffer[0x1FF2] = val; NVRAM->buffer[0x1FF2] = val;
set_alarm(NVRAM, &tm); set_alarm(NVRAM);
} }
break; break;
case 0x1FF3: case 0x1FF3:
/* alarm minutes */ /* alarm minutes */
tmp = fromBCD(val & 0x7F); tmp = fromBCD(val & 0x7F);
if (tmp >= 0 && tmp <= 59) { if (tmp >= 0 && tmp <= 59) {
get_alarm(NVRAM, &tm); NVRAM->alarm.tm_min = tmp;
tm.tm_min = tmp;
NVRAM->buffer[0x1FF3] = val; NVRAM->buffer[0x1FF3] = val;
set_alarm(NVRAM, &tm); set_alarm(NVRAM);
} }
break; break;
case 0x1FF4: case 0x1FF4:
/* alarm hours */ /* alarm hours */
tmp = fromBCD(val & 0x3F); tmp = fromBCD(val & 0x3F);
if (tmp >= 0 && tmp <= 23) { if (tmp >= 0 && tmp <= 23) {
get_alarm(NVRAM, &tm); NVRAM->alarm.tm_hour = tmp;
tm.tm_hour = tmp;
NVRAM->buffer[0x1FF4] = val; NVRAM->buffer[0x1FF4] = val;
set_alarm(NVRAM, &tm); set_alarm(NVRAM);
} }
break; break;
case 0x1FF5: case 0x1FF5:
/* alarm date */ /* alarm date */
tmp = fromBCD(val & 0x1F); tmp = fromBCD(val & 0x1F);
if (tmp != 0) { if (tmp != 0) {
get_alarm(NVRAM, &tm); NVRAM->alarm.tm_mday = tmp;
tm.tm_mday = tmp;
NVRAM->buffer[0x1FF5] = val; NVRAM->buffer[0x1FF5] = val;
set_alarm(NVRAM, &tm); set_alarm(NVRAM);
} }
break; break;
case 0x1FF6: case 0x1FF6:
...@@ -682,6 +653,7 @@ m48t59_t *m48t59_init (qemu_irq IRQ, target_phys_addr_t mem_base, ...@@ -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->wd_timer = qemu_new_timer(vm_clock, &watchdog_cb, s);
} }
s->lock = 0; s->lock = 0;
qemu_get_timedate(&s->alarm, 0);
qemu_register_reset(m48t59_reset, s); qemu_register_reset(m48t59_reset, s);
save_base = mem_base ? mem_base : io_base; save_base = mem_base ? mem_base : io_base;
......
...@@ -392,24 +392,14 @@ void rtc_set_date(RTCState *s, const struct tm *tm) ...@@ -392,24 +392,14 @@ void rtc_set_date(RTCState *s, const struct tm *tm)
static void rtc_set_date_from_host(RTCState *s) static void rtc_set_date_from_host(RTCState *s)
{ {
time_t ti; struct tm tm;
struct tm *tm;
int val; int val;
/* set the CMOS date */ /* set the CMOS date */
if (rtc_start_date == -1) { qemu_get_timedate(&tm, 0);
time(&ti); rtc_set_date(s, &tm);
if (rtc_utc)
tm = gmtime(&ti);
else
tm = localtime(&ti);
} else {
ti = rtc_start_date;
tm = gmtime(&ti);
}
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_CENTURY_BYTE, val);
rtc_set_memory(s, REG_IBM_PS2_CENTURY_BYTE, val); rtc_set_memory(s, REG_IBM_PS2_CENTURY_BYTE, val);
} }
......
...@@ -4345,7 +4345,6 @@ struct omap_rtc_s { ...@@ -4345,7 +4345,6 @@ struct omap_rtc_s {
int pm_am; int pm_am;
int auto_comp; int auto_comp;
int round; int round;
struct tm *(*convert)(const time_t *timep, struct tm *result);
struct tm alarm_tm; struct tm alarm_tm;
time_t alarm_ti; time_t alarm_ti;
...@@ -4668,7 +4667,7 @@ static void omap_rtc_tick(void *opaque) ...@@ -4668,7 +4667,7 @@ static void omap_rtc_tick(void *opaque)
s->round = 0; 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) { if ((s->interrupts & 0x08) && s->ti == s->alarm_ti) {
s->status |= 0x40; s->status |= 0x40;
...@@ -4719,6 +4718,8 @@ static void omap_rtc_tick(void *opaque) ...@@ -4719,6 +4718,8 @@ static void omap_rtc_tick(void *opaque)
static void omap_rtc_reset(struct omap_rtc_s *s) static void omap_rtc_reset(struct omap_rtc_s *s)
{ {
struct tm tm;
s->interrupts = 0; s->interrupts = 0;
s->comp_reg = 0; s->comp_reg = 0;
s->running = 0; s->running = 0;
...@@ -4729,8 +4730,8 @@ static void omap_rtc_reset(struct omap_rtc_s *s) ...@@ -4729,8 +4730,8 @@ static void omap_rtc_reset(struct omap_rtc_s *s)
memset(&s->alarm_tm, 0, sizeof(s->alarm_tm)); memset(&s->alarm_tm, 0, sizeof(s->alarm_tm));
s->alarm_tm.tm_mday = 0x01; s->alarm_tm.tm_mday = 0x01;
s->status = 1 << 7; s->status = 1 << 7;
time(&s->ti); qemu_get_timedate(&tm, 0);
s->ti = mktime(s->convert(&s->ti, &s->current_tm)); s->ti = mktime(&tm);
omap_rtc_alarm_update(s); omap_rtc_alarm_update(s);
omap_rtc_tick(s); omap_rtc_tick(s);
...@@ -4747,7 +4748,6 @@ struct omap_rtc_s *omap_rtc_init(target_phys_addr_t base, ...@@ -4747,7 +4748,6 @@ struct omap_rtc_s *omap_rtc_init(target_phys_addr_t base,
s->irq = irq[0]; s->irq = irq[0];
s->alarm = irq[1]; s->alarm = irq[1];
s->clk = qemu_new_timer(rt_clock, omap_rtc_tick, s); s->clk = qemu_new_timer(rt_clock, omap_rtc_tick, s);
s->convert = rtc_utc ? gmtime_r : localtime_r;
omap_rtc_reset(s); omap_rtc_reset(s);
......
...@@ -195,8 +195,7 @@ void pl031_init(uint32_t base, qemu_irq irq) ...@@ -195,8 +195,7 @@ void pl031_init(uint32_t base, qemu_irq irq)
{ {
int iomemtype; int iomemtype;
pl031_state *s; pl031_state *s;
time_t ti; struct tm tm;
struct tm *tm;
s = qemu_mallocz(sizeof(pl031_state)); s = qemu_mallocz(sizeof(pl031_state));
if (!s) if (!s)
...@@ -211,12 +210,8 @@ void pl031_init(uint32_t base, qemu_irq irq) ...@@ -211,12 +210,8 @@ void pl031_init(uint32_t base, qemu_irq irq)
s->base = base; s->base = base;
s->irq = irq; s->irq = irq;
/* ??? We assume vm_clock is zero at this point. */ /* ??? We assume vm_clock is zero at this point. */
time(&ti); qemu_get_timedate(&tm, 0);
if (rtc_utc) s->tick_offset = mktime(&tm);
tm = gmtime(&ti);
else
tm = localtime(&ti);
s->tick_offset = mktime(tm);
s->timer = qemu_new_timer(vm_clock, pl031_interrupt, s); s->timer = qemu_new_timer(vm_clock, pl031_interrupt, s);
} }
...@@ -1183,27 +1183,22 @@ static CPUWriteMemoryFunc *pxa2xx_rtc_writefn[] = { ...@@ -1183,27 +1183,22 @@ static CPUWriteMemoryFunc *pxa2xx_rtc_writefn[] = {
static void pxa2xx_rtc_init(struct pxa2xx_state_s *s) static void pxa2xx_rtc_init(struct pxa2xx_state_s *s)
{ {
struct tm *tm; struct tm tm;
time_t ti;
int wom; int wom;
s->rttr = 0x7fff; s->rttr = 0x7fff;
s->rtsr = 0; s->rtsr = 0;
time(&ti); qemu_get_timedate(&tm, 0);
if (rtc_utc) wom = ((tm.tm_mday - 1) / 7) + 1;
tm = gmtime(&ti);
else s->last_rcnr = (uint32_t) mktime(&tm);
tm = localtime(&ti); s->last_rdcr = (wom << 20) | ((tm.tm_wday + 1) << 17) |
wom = ((tm->tm_mday - 1) / 7) + 1; (tm.tm_hour << 12) | (tm.tm_min << 6) | tm.tm_sec;
s->last_rycr = ((tm.tm_year + 1900) << 9) |
s->last_rcnr = (uint32_t) ti; ((tm.tm_mon + 1) << 5) | tm.tm_mday;
s->last_rdcr = (wom << 20) | ((tm->tm_wday + 1) << 17) | s->last_swcr = (tm.tm_hour << 19) |
(tm->tm_hour << 12) | (tm->tm_min << 6) | tm->tm_sec; (tm.tm_min << 13) | (tm.tm_sec << 7);
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_rtcpicr = 0;
s->last_hz = s->last_sw = s->last_pi = qemu_get_clock(rt_clock); s->last_hz = s->last_sw = s->last_pi = qemu_get_clock(rt_clock);
......
...@@ -76,6 +76,9 @@ int qemu_bh_poll(void); ...@@ -76,6 +76,9 @@ int qemu_bh_poll(void);
uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c); 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 */ /* cutils.c */
void pstrcpy(char *buf, int buf_size, const char *str); void pstrcpy(char *buf, int buf_size, const char *str);
char *pstrcat(char *buf, int buf_size, const char *s); char *pstrcat(char *buf, int buf_size, const char *s);
......
...@@ -71,8 +71,6 @@ void do_info_slirp(void); ...@@ -71,8 +71,6 @@ void do_info_slirp(void);
extern int ram_size; extern int ram_size;
extern int bios_size; extern int bios_size;
extern int rtc_utc;
extern int rtc_start_date;
extern int cirrus_vga_enabled; extern int cirrus_vga_enabled;
extern int vmsvga_enabled; extern int vmsvga_enabled;
extern int graphic_width; extern int graphic_width;
......
...@@ -180,8 +180,8 @@ int pit_min_timer_count = 0; ...@@ -180,8 +180,8 @@ int pit_min_timer_count = 0;
int nb_nics; int nb_nics;
NICInfo nd_table[MAX_NICS]; NICInfo nd_table[MAX_NICS];
int vm_running; int vm_running;
int rtc_utc = 1; static int rtc_utc = 1;
int rtc_start_date = -1; /* -1 means now */ static int rtc_date_offset = -1; /* -1 means no change */
int cirrus_vga_enabled = 1; int cirrus_vga_enabled = 1;
int vmsvga_enabled = 0; int vmsvga_enabled = 0;
#ifdef TARGET_SPARC #ifdef TARGET_SPARC
...@@ -1564,6 +1564,43 @@ static void quit_timers(void) ...@@ -1564,6 +1564,43 @@ static void quit_timers(void)
alarm_timer = NULL; alarm_timer = NULL;
} }
/***********************************************************/
/* 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 */ /* character device */
...@@ -8698,8 +8735,9 @@ int main(int argc, char **argv) ...@@ -8698,8 +8735,9 @@ int main(int argc, char **argv)
case QEMU_OPTION_startdate: case QEMU_OPTION_startdate:
{ {
struct tm tm; struct tm tm;
time_t rtc_start_date;
if (!strcmp(optarg, "now")) { if (!strcmp(optarg, "now")) {
rtc_start_date = -1; rtc_date_offset = -1;
} else { } else {
if (sscanf(optarg, "%d-%d-%dT%d:%d:%d", if (sscanf(optarg, "%d-%d-%dT%d:%d:%d",
&tm.tm_year, &tm.tm_year,
...@@ -8728,6 +8766,7 @@ int main(int argc, char **argv) ...@@ -8728,6 +8766,7 @@ int main(int argc, char **argv)
"'now' or '2006-06-17T16:01:21' or '2006-06-17'\n"); "'now' or '2006-06-17T16:01:21' or '2006-06-17'\n");
exit(1); exit(1);
} }
rtc_date_offset = time(NULL) - rtc_start_date;
} }
} }
break; break;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册