mirror of https://gitee.com/openkylin/qemu.git
rtc: implement century byte
Implement the century byte in the RTC emulation, and test that it works.
This leads to some annoying compatibility code because we need to treat
a value of 2000 for the base_year property as "use the century byte
properly" (which would be a value of 0).
The century byte will now be always-zero, rather than always-20,
for the MIPS Magnum machine whose base_year is 1980. Commit 42fc73a
(Support epoch of 1980 in RTC emulation for MIPS Magnum, 2009-01-24)
correctly said:
With an epoch of 1980 and a year of 2009, one could argue that [the
century byte] should hold either 0, 1, 19 or 20. NT 3.50 on MIPS
does not read the century byte.
so I picked the simplest and most sensible implementation which is to
return 0 for 1980-2079, 1 for 2080-2179 and so on.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
parent
e67edb943f
commit
b8994faf2a
|
@ -519,7 +519,9 @@ static void rtc_get_time(RTCState *s, struct tm *tm)
|
|||
tm->tm_wday = rtc_from_bcd(s, s->cmos_data[RTC_DAY_OF_WEEK]) - 1;
|
||||
tm->tm_mday = rtc_from_bcd(s, s->cmos_data[RTC_DAY_OF_MONTH]);
|
||||
tm->tm_mon = rtc_from_bcd(s, s->cmos_data[RTC_MONTH]) - 1;
|
||||
tm->tm_year = rtc_from_bcd(s, s->cmos_data[RTC_YEAR]) + s->base_year - 1900;
|
||||
tm->tm_year =
|
||||
rtc_from_bcd(s, s->cmos_data[RTC_YEAR]) + s->base_year +
|
||||
rtc_from_bcd(s, s->cmos_data[RTC_CENTURY]) * 100 - 1900;
|
||||
}
|
||||
|
||||
static void rtc_set_time(RTCState *s)
|
||||
|
@ -552,10 +554,9 @@ static void rtc_set_cmos(RTCState *s, const struct tm *tm)
|
|||
s->cmos_data[RTC_DAY_OF_WEEK] = rtc_to_bcd(s, tm->tm_wday + 1);
|
||||
s->cmos_data[RTC_DAY_OF_MONTH] = rtc_to_bcd(s, tm->tm_mday);
|
||||
s->cmos_data[RTC_MONTH] = rtc_to_bcd(s, tm->tm_mon + 1);
|
||||
year = (tm->tm_year - s->base_year) % 100;
|
||||
if (year < 0)
|
||||
year += 100;
|
||||
s->cmos_data[RTC_YEAR] = rtc_to_bcd(s, year);
|
||||
year = tm->tm_year + 1900 - s->base_year;
|
||||
s->cmos_data[RTC_YEAR] = rtc_to_bcd(s, year % 100);
|
||||
s->cmos_data[RTC_CENTURY] = rtc_to_bcd(s, year / 100);
|
||||
}
|
||||
|
||||
static void rtc_update_time(RTCState *s)
|
||||
|
@ -673,7 +674,6 @@ static void rtc_set_date_from_host(ISADevice *dev)
|
|||
{
|
||||
RTCState *s = DO_UPCAST(RTCState, dev, dev);
|
||||
struct tm tm;
|
||||
int val;
|
||||
|
||||
qemu_get_timedate(&tm, 0);
|
||||
|
||||
|
@ -683,9 +683,6 @@ static void rtc_set_date_from_host(ISADevice *dev)
|
|||
|
||||
/* set the CMOS date */
|
||||
rtc_set_cmos(s, &tm);
|
||||
|
||||
val = rtc_to_bcd(s, (tm.tm_year / 100) + 19);
|
||||
rtc_set_memory(dev, RTC_CENTURY, val);
|
||||
}
|
||||
|
||||
static int rtc_post_load(void *opaque, int version_id)
|
||||
|
@ -810,6 +807,18 @@ static int rtc_initfn(ISADevice *dev)
|
|||
s->cmos_data[RTC_REG_C] = 0x00;
|
||||
s->cmos_data[RTC_REG_D] = 0x80;
|
||||
|
||||
/* This is for historical reasons. The default base year qdev property
|
||||
* was set to 2000 for most machine types before the century byte was
|
||||
* implemented.
|
||||
*
|
||||
* This if statement means that the century byte will be always 0
|
||||
* (at least until 2079...) for base_year = 1980, but will be set
|
||||
* correctly for base_year = 2000.
|
||||
*/
|
||||
if (s->base_year == 2000) {
|
||||
s->base_year = 0;
|
||||
}
|
||||
|
||||
rtc_set_date_from_host(dev);
|
||||
|
||||
#ifdef TARGET_I386
|
||||
|
|
|
@ -179,12 +179,13 @@ static void check_time(int wiggle)
|
|||
|
||||
static int wiggle = 2;
|
||||
|
||||
static void set_year(void)
|
||||
static void set_year_20xx(void)
|
||||
{
|
||||
/* Set BCD mode */
|
||||
cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) & ~REG_B_DM);
|
||||
cmos_write(RTC_REG_A, 0x76);
|
||||
cmos_write(RTC_YEAR, 0x11);
|
||||
cmos_write(RTC_CENTURY, 0x20);
|
||||
cmos_write(RTC_MONTH, 0x02);
|
||||
cmos_write(RTC_DAY_OF_MONTH, 0x02);
|
||||
cmos_write(RTC_HOURS, 0x02);
|
||||
|
@ -198,6 +199,7 @@ static void set_year(void)
|
|||
g_assert_cmpint(cmos_read(RTC_DAY_OF_MONTH), ==, 0x02);
|
||||
g_assert_cmpint(cmos_read(RTC_MONTH), ==, 0x02);
|
||||
g_assert_cmpint(cmos_read(RTC_YEAR), ==, 0x11);
|
||||
g_assert_cmpint(cmos_read(RTC_CENTURY), ==, 0x20);
|
||||
|
||||
/* Set a date in 2080 to ensure there is no year-2038 overflow. */
|
||||
cmos_write(RTC_REG_A, 0x76);
|
||||
|
@ -210,6 +212,7 @@ static void set_year(void)
|
|||
g_assert_cmpint(cmos_read(RTC_DAY_OF_MONTH), ==, 0x02);
|
||||
g_assert_cmpint(cmos_read(RTC_MONTH), ==, 0x02);
|
||||
g_assert_cmpint(cmos_read(RTC_YEAR), ==, 0x80);
|
||||
g_assert_cmpint(cmos_read(RTC_CENTURY), ==, 0x20);
|
||||
|
||||
cmos_write(RTC_REG_A, 0x76);
|
||||
cmos_write(RTC_YEAR, 0x11);
|
||||
|
@ -221,6 +224,30 @@ static void set_year(void)
|
|||
g_assert_cmpint(cmos_read(RTC_DAY_OF_MONTH), ==, 0x02);
|
||||
g_assert_cmpint(cmos_read(RTC_MONTH), ==, 0x02);
|
||||
g_assert_cmpint(cmos_read(RTC_YEAR), ==, 0x11);
|
||||
g_assert_cmpint(cmos_read(RTC_CENTURY), ==, 0x20);
|
||||
}
|
||||
|
||||
static void set_year_1980(void)
|
||||
{
|
||||
/* Set BCD mode */
|
||||
cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) & ~REG_B_DM);
|
||||
cmos_write(RTC_REG_A, 0x76);
|
||||
cmos_write(RTC_YEAR, 0x80);
|
||||
cmos_write(RTC_CENTURY, 0x19);
|
||||
cmos_write(RTC_MONTH, 0x02);
|
||||
cmos_write(RTC_DAY_OF_MONTH, 0x02);
|
||||
cmos_write(RTC_HOURS, 0x02);
|
||||
cmos_write(RTC_MINUTES, 0x04);
|
||||
cmos_write(RTC_SECONDS, 0x58);
|
||||
cmos_write(RTC_REG_A, 0x26);
|
||||
|
||||
g_assert_cmpint(cmos_read(RTC_HOURS), ==, 0x02);
|
||||
g_assert_cmpint(cmos_read(RTC_MINUTES), ==, 0x04);
|
||||
g_assert_cmpint(cmos_read(RTC_SECONDS), >=, 0x58);
|
||||
g_assert_cmpint(cmos_read(RTC_DAY_OF_MONTH), ==, 0x02);
|
||||
g_assert_cmpint(cmos_read(RTC_MONTH), ==, 0x02);
|
||||
g_assert_cmpint(cmos_read(RTC_YEAR), ==, 0x80);
|
||||
g_assert_cmpint(cmos_read(RTC_CENTURY), ==, 0x19);
|
||||
}
|
||||
|
||||
static void bcd_check_time(void)
|
||||
|
@ -313,7 +340,8 @@ int main(int argc, char **argv)
|
|||
qtest_add_func("/rtc/bcd/check-time", bcd_check_time);
|
||||
qtest_add_func("/rtc/dec/check-time", dec_check_time);
|
||||
qtest_add_func("/rtc/alarm-time", alarm_time);
|
||||
qtest_add_func("/rtc/set-year", set_year);
|
||||
qtest_add_func("/rtc/set-year/20xx", set_year_20xx);
|
||||
qtest_add_func("/rtc/set-year/1980", set_year_1980);
|
||||
qtest_add_func("/rtc/fuzz-registers", fuzz_registers);
|
||||
ret = g_test_run();
|
||||
|
||||
|
|
Loading…
Reference in New Issue