root / tests / m48t59-test.c @ 29b358f9
History | View | Annotate | Download (6 kB)
1 | f91837a7 | Blue Swirl | /*
|
---|---|---|---|
2 | f91837a7 | Blue Swirl | * QTest testcase for the M48T59 and M48T08 real-time clocks
|
3 | f91837a7 | Blue Swirl | *
|
4 | f91837a7 | Blue Swirl | * Based on MC146818 RTC test:
|
5 | f91837a7 | Blue Swirl | * Copyright IBM, Corp. 2012
|
6 | f91837a7 | Blue Swirl | *
|
7 | f91837a7 | Blue Swirl | * Authors:
|
8 | f91837a7 | Blue Swirl | * Anthony Liguori <aliguori@us.ibm.com>
|
9 | f91837a7 | Blue Swirl | *
|
10 | f91837a7 | Blue Swirl | * This work is licensed under the terms of the GNU GPL, version 2 or later.
|
11 | f91837a7 | Blue Swirl | * See the COPYING file in the top-level directory.
|
12 | f91837a7 | Blue Swirl | *
|
13 | f91837a7 | Blue Swirl | */
|
14 | f91837a7 | Blue Swirl | #include "libqtest.h" |
15 | f91837a7 | Blue Swirl | |
16 | f91837a7 | Blue Swirl | #include <glib.h> |
17 | f91837a7 | Blue Swirl | #include <stdio.h> |
18 | f91837a7 | Blue Swirl | #include <string.h> |
19 | f91837a7 | Blue Swirl | #include <stdlib.h> |
20 | f91837a7 | Blue Swirl | #include <unistd.h> |
21 | f91837a7 | Blue Swirl | |
22 | f91837a7 | Blue Swirl | #define RTC_SECONDS 0x9 |
23 | f91837a7 | Blue Swirl | #define RTC_MINUTES 0xa |
24 | f91837a7 | Blue Swirl | #define RTC_HOURS 0xb |
25 | f91837a7 | Blue Swirl | |
26 | f91837a7 | Blue Swirl | #define RTC_DAY_OF_WEEK 0xc |
27 | f91837a7 | Blue Swirl | #define RTC_DAY_OF_MONTH 0xd |
28 | f91837a7 | Blue Swirl | #define RTC_MONTH 0xe |
29 | f91837a7 | Blue Swirl | #define RTC_YEAR 0xf |
30 | f91837a7 | Blue Swirl | |
31 | f91837a7 | Blue Swirl | static uint32_t base;
|
32 | f91837a7 | Blue Swirl | static uint16_t reg_base = 0x1ff0; /* 0x7f0 for m48t02 */ |
33 | f91837a7 | Blue Swirl | static int base_year; |
34 | f91837a7 | Blue Swirl | static bool use_mmio; |
35 | f91837a7 | Blue Swirl | |
36 | f91837a7 | Blue Swirl | static uint8_t cmos_read_mmio(uint8_t reg)
|
37 | f91837a7 | Blue Swirl | { |
38 | 872536bf | Andreas Färber | return readb(base + (uint32_t)reg_base + (uint32_t)reg);
|
39 | f91837a7 | Blue Swirl | } |
40 | f91837a7 | Blue Swirl | |
41 | f91837a7 | Blue Swirl | static void cmos_write_mmio(uint8_t reg, uint8_t val) |
42 | f91837a7 | Blue Swirl | { |
43 | f91837a7 | Blue Swirl | uint8_t data = val; |
44 | f91837a7 | Blue Swirl | |
45 | 872536bf | Andreas Färber | writeb(base + (uint32_t)reg_base + (uint32_t)reg, data); |
46 | f91837a7 | Blue Swirl | } |
47 | f91837a7 | Blue Swirl | |
48 | f91837a7 | Blue Swirl | static uint8_t cmos_read_ioio(uint8_t reg)
|
49 | f91837a7 | Blue Swirl | { |
50 | f91837a7 | Blue Swirl | outw(base + 0, reg_base + (uint16_t)reg);
|
51 | f91837a7 | Blue Swirl | return inb(base + 3); |
52 | f91837a7 | Blue Swirl | } |
53 | f91837a7 | Blue Swirl | |
54 | f91837a7 | Blue Swirl | static void cmos_write_ioio(uint8_t reg, uint8_t val) |
55 | f91837a7 | Blue Swirl | { |
56 | f91837a7 | Blue Swirl | outw(base + 0, reg_base + (uint16_t)reg);
|
57 | f91837a7 | Blue Swirl | outb(base + 3, val);
|
58 | f91837a7 | Blue Swirl | } |
59 | f91837a7 | Blue Swirl | |
60 | f91837a7 | Blue Swirl | static uint8_t cmos_read(uint8_t reg)
|
61 | f91837a7 | Blue Swirl | { |
62 | f91837a7 | Blue Swirl | if (use_mmio) {
|
63 | f91837a7 | Blue Swirl | return cmos_read_mmio(reg);
|
64 | f91837a7 | Blue Swirl | } else {
|
65 | f91837a7 | Blue Swirl | return cmos_read_ioio(reg);
|
66 | f91837a7 | Blue Swirl | } |
67 | f91837a7 | Blue Swirl | } |
68 | f91837a7 | Blue Swirl | |
69 | f91837a7 | Blue Swirl | static void cmos_write(uint8_t reg, uint8_t val) |
70 | f91837a7 | Blue Swirl | { |
71 | f91837a7 | Blue Swirl | if (use_mmio) {
|
72 | f91837a7 | Blue Swirl | cmos_write_mmio(reg, val); |
73 | f91837a7 | Blue Swirl | } else {
|
74 | f91837a7 | Blue Swirl | cmos_write_ioio(reg, val); |
75 | f91837a7 | Blue Swirl | } |
76 | f91837a7 | Blue Swirl | } |
77 | f91837a7 | Blue Swirl | |
78 | f91837a7 | Blue Swirl | static int bcd2dec(int value) |
79 | f91837a7 | Blue Swirl | { |
80 | f91837a7 | Blue Swirl | return (((value >> 4) & 0x0F) * 10) + (value & 0x0F); |
81 | f91837a7 | Blue Swirl | } |
82 | f91837a7 | Blue Swirl | |
83 | f91837a7 | Blue Swirl | static int tm_cmp(struct tm *lhs, struct tm *rhs) |
84 | f91837a7 | Blue Swirl | { |
85 | f91837a7 | Blue Swirl | time_t a, b; |
86 | f91837a7 | Blue Swirl | struct tm d1, d2;
|
87 | f91837a7 | Blue Swirl | |
88 | f91837a7 | Blue Swirl | memcpy(&d1, lhs, sizeof(d1));
|
89 | f91837a7 | Blue Swirl | memcpy(&d2, rhs, sizeof(d2));
|
90 | f91837a7 | Blue Swirl | |
91 | f91837a7 | Blue Swirl | a = mktime(&d1); |
92 | f91837a7 | Blue Swirl | b = mktime(&d2); |
93 | f91837a7 | Blue Swirl | |
94 | f91837a7 | Blue Swirl | if (a < b) {
|
95 | f91837a7 | Blue Swirl | return -1; |
96 | f91837a7 | Blue Swirl | } else if (a > b) { |
97 | f91837a7 | Blue Swirl | return 1; |
98 | f91837a7 | Blue Swirl | } |
99 | f91837a7 | Blue Swirl | |
100 | f91837a7 | Blue Swirl | return 0; |
101 | f91837a7 | Blue Swirl | } |
102 | f91837a7 | Blue Swirl | |
103 | f91837a7 | Blue Swirl | #if 0
|
104 | f91837a7 | Blue Swirl | static void print_tm(struct tm *tm)
|
105 | f91837a7 | Blue Swirl | {
|
106 | f91837a7 | Blue Swirl | printf("%04d-%02d-%02d %02d:%02d:%02d %+02ld\n",
|
107 | f91837a7 | Blue Swirl | tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
|
108 | f91837a7 | Blue Swirl | tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_gmtoff);
|
109 | f91837a7 | Blue Swirl | }
|
110 | f91837a7 | Blue Swirl | #endif
|
111 | f91837a7 | Blue Swirl | |
112 | f91837a7 | Blue Swirl | static void cmos_get_date_time(struct tm *date) |
113 | f91837a7 | Blue Swirl | { |
114 | f91837a7 | Blue Swirl | int sec, min, hour, mday, mon, year;
|
115 | f91837a7 | Blue Swirl | time_t ts; |
116 | f91837a7 | Blue Swirl | struct tm dummy;
|
117 | f91837a7 | Blue Swirl | |
118 | f91837a7 | Blue Swirl | sec = cmos_read(RTC_SECONDS); |
119 | f91837a7 | Blue Swirl | min = cmos_read(RTC_MINUTES); |
120 | f91837a7 | Blue Swirl | hour = cmos_read(RTC_HOURS); |
121 | f91837a7 | Blue Swirl | mday = cmos_read(RTC_DAY_OF_MONTH); |
122 | f91837a7 | Blue Swirl | mon = cmos_read(RTC_MONTH); |
123 | f91837a7 | Blue Swirl | year = cmos_read(RTC_YEAR); |
124 | f91837a7 | Blue Swirl | |
125 | f91837a7 | Blue Swirl | sec = bcd2dec(sec); |
126 | f91837a7 | Blue Swirl | min = bcd2dec(min); |
127 | f91837a7 | Blue Swirl | hour = bcd2dec(hour); |
128 | f91837a7 | Blue Swirl | mday = bcd2dec(mday); |
129 | f91837a7 | Blue Swirl | mon = bcd2dec(mon); |
130 | f91837a7 | Blue Swirl | year = bcd2dec(year); |
131 | f91837a7 | Blue Swirl | |
132 | f91837a7 | Blue Swirl | ts = time(NULL);
|
133 | f91837a7 | Blue Swirl | localtime_r(&ts, &dummy); |
134 | f91837a7 | Blue Swirl | |
135 | f91837a7 | Blue Swirl | date->tm_isdst = dummy.tm_isdst; |
136 | f91837a7 | Blue Swirl | date->tm_sec = sec; |
137 | f91837a7 | Blue Swirl | date->tm_min = min; |
138 | f91837a7 | Blue Swirl | date->tm_hour = hour; |
139 | f91837a7 | Blue Swirl | date->tm_mday = mday; |
140 | f91837a7 | Blue Swirl | date->tm_mon = mon - 1;
|
141 | f91837a7 | Blue Swirl | date->tm_year = base_year + year - 1900;
|
142 | a05ddd92 | Andreas Färber | #ifndef __sun__
|
143 | f91837a7 | Blue Swirl | date->tm_gmtoff = 0;
|
144 | a05ddd92 | Andreas Färber | #endif
|
145 | f91837a7 | Blue Swirl | |
146 | f91837a7 | Blue Swirl | ts = mktime(date); |
147 | f91837a7 | Blue Swirl | } |
148 | f91837a7 | Blue Swirl | |
149 | f91837a7 | Blue Swirl | static void check_time(int wiggle) |
150 | f91837a7 | Blue Swirl | { |
151 | f91837a7 | Blue Swirl | struct tm start, date[4], end; |
152 | f91837a7 | Blue Swirl | struct tm *datep;
|
153 | f91837a7 | Blue Swirl | time_t ts; |
154 | f91837a7 | Blue Swirl | |
155 | f91837a7 | Blue Swirl | /*
|
156 | f91837a7 | Blue Swirl | * This check assumes a few things. First, we cannot guarantee that we get
|
157 | f91837a7 | Blue Swirl | * a consistent reading from the wall clock because we may hit an edge of
|
158 | f91837a7 | Blue Swirl | * the clock while reading. To work around this, we read four clock readings
|
159 | f91837a7 | Blue Swirl | * such that at least two of them should match. We need to assume that one
|
160 | f91837a7 | Blue Swirl | * reading is corrupt so we need four readings to ensure that we have at
|
161 | f91837a7 | Blue Swirl | * least two consecutive identical readings
|
162 | f91837a7 | Blue Swirl | *
|
163 | f91837a7 | Blue Swirl | * It's also possible that we'll cross an edge reading the host clock so
|
164 | f91837a7 | Blue Swirl | * simply check to make sure that the clock reading is within the period of
|
165 | f91837a7 | Blue Swirl | * when we expect it to be.
|
166 | f91837a7 | Blue Swirl | */
|
167 | f91837a7 | Blue Swirl | |
168 | f91837a7 | Blue Swirl | ts = time(NULL);
|
169 | f91837a7 | Blue Swirl | gmtime_r(&ts, &start); |
170 | f91837a7 | Blue Swirl | |
171 | f91837a7 | Blue Swirl | cmos_get_date_time(&date[0]);
|
172 | f91837a7 | Blue Swirl | cmos_get_date_time(&date[1]);
|
173 | f91837a7 | Blue Swirl | cmos_get_date_time(&date[2]);
|
174 | f91837a7 | Blue Swirl | cmos_get_date_time(&date[3]);
|
175 | f91837a7 | Blue Swirl | |
176 | f91837a7 | Blue Swirl | ts = time(NULL);
|
177 | f91837a7 | Blue Swirl | gmtime_r(&ts, &end); |
178 | f91837a7 | Blue Swirl | |
179 | f91837a7 | Blue Swirl | if (tm_cmp(&date[0], &date[1]) == 0) { |
180 | f91837a7 | Blue Swirl | datep = &date[0];
|
181 | f91837a7 | Blue Swirl | } else if (tm_cmp(&date[1], &date[2]) == 0) { |
182 | f91837a7 | Blue Swirl | datep = &date[1];
|
183 | f91837a7 | Blue Swirl | } else if (tm_cmp(&date[2], &date[3]) == 0) { |
184 | f91837a7 | Blue Swirl | datep = &date[2];
|
185 | f91837a7 | Blue Swirl | } else {
|
186 | f91837a7 | Blue Swirl | g_assert_not_reached(); |
187 | f91837a7 | Blue Swirl | } |
188 | f91837a7 | Blue Swirl | |
189 | f91837a7 | Blue Swirl | if (!(tm_cmp(&start, datep) <= 0 && tm_cmp(datep, &end) <= 0)) { |
190 | f91837a7 | Blue Swirl | long t, s;
|
191 | f91837a7 | Blue Swirl | |
192 | f91837a7 | Blue Swirl | start.tm_isdst = datep->tm_isdst; |
193 | f91837a7 | Blue Swirl | |
194 | f91837a7 | Blue Swirl | t = (long)mktime(datep);
|
195 | f91837a7 | Blue Swirl | s = (long)mktime(&start);
|
196 | f91837a7 | Blue Swirl | if (t < s) {
|
197 | f91837a7 | Blue Swirl | g_test_message("RTC is %ld second(s) behind wall-clock\n", (s - t));
|
198 | f91837a7 | Blue Swirl | } else {
|
199 | f91837a7 | Blue Swirl | g_test_message("RTC is %ld second(s) ahead of wall-clock\n", (t - s));
|
200 | f91837a7 | Blue Swirl | } |
201 | f91837a7 | Blue Swirl | |
202 | f91837a7 | Blue Swirl | g_assert_cmpint(ABS(t - s), <=, wiggle); |
203 | f91837a7 | Blue Swirl | } |
204 | f91837a7 | Blue Swirl | } |
205 | f91837a7 | Blue Swirl | |
206 | f91837a7 | Blue Swirl | static int wiggle = 2; |
207 | f91837a7 | Blue Swirl | |
208 | f91837a7 | Blue Swirl | static void bcd_check_time(void) |
209 | f91837a7 | Blue Swirl | { |
210 | f91837a7 | Blue Swirl | if (strcmp(qtest_get_arch(), "sparc64") == 0) { |
211 | f91837a7 | Blue Swirl | base = 0x74;
|
212 | f91837a7 | Blue Swirl | base_year = 1900;
|
213 | f91837a7 | Blue Swirl | use_mmio = false;
|
214 | f91837a7 | Blue Swirl | } else if (strcmp(qtest_get_arch(), "sparc") == 0) { |
215 | f91837a7 | Blue Swirl | base = 0x71200000;
|
216 | f91837a7 | Blue Swirl | base_year = 1968;
|
217 | f91837a7 | Blue Swirl | use_mmio = true;
|
218 | f91837a7 | Blue Swirl | } else { /* PPC: need to map macio in PCI */ |
219 | f91837a7 | Blue Swirl | g_assert_not_reached(); |
220 | f91837a7 | Blue Swirl | } |
221 | f91837a7 | Blue Swirl | check_time(wiggle); |
222 | f91837a7 | Blue Swirl | } |
223 | f91837a7 | Blue Swirl | |
224 | f91837a7 | Blue Swirl | /* success if no crash or abort */
|
225 | f91837a7 | Blue Swirl | static void fuzz_registers(void) |
226 | f91837a7 | Blue Swirl | { |
227 | f91837a7 | Blue Swirl | unsigned int i; |
228 | f91837a7 | Blue Swirl | |
229 | f91837a7 | Blue Swirl | for (i = 0; i < 1000; i++) { |
230 | f91837a7 | Blue Swirl | uint8_t reg, val; |
231 | f91837a7 | Blue Swirl | |
232 | f91837a7 | Blue Swirl | reg = (uint8_t)g_test_rand_int_range(0, 16); |
233 | f91837a7 | Blue Swirl | val = (uint8_t)g_test_rand_int_range(0, 256); |
234 | f91837a7 | Blue Swirl | |
235 | 067f0691 | Gerd Hoffmann | if (reg == 7) { |
236 | 067f0691 | Gerd Hoffmann | /* watchdog setup register, may trigger system reset, skip */
|
237 | 067f0691 | Gerd Hoffmann | continue;
|
238 | 067f0691 | Gerd Hoffmann | } |
239 | 067f0691 | Gerd Hoffmann | |
240 | f91837a7 | Blue Swirl | cmos_write(reg, val); |
241 | f91837a7 | Blue Swirl | cmos_read(reg); |
242 | f91837a7 | Blue Swirl | } |
243 | f91837a7 | Blue Swirl | } |
244 | f91837a7 | Blue Swirl | |
245 | f91837a7 | Blue Swirl | int main(int argc, char **argv) |
246 | f91837a7 | Blue Swirl | { |
247 | f91837a7 | Blue Swirl | QTestState *s = NULL;
|
248 | f91837a7 | Blue Swirl | int ret;
|
249 | f91837a7 | Blue Swirl | |
250 | f91837a7 | Blue Swirl | g_test_init(&argc, &argv, NULL);
|
251 | f91837a7 | Blue Swirl | |
252 | f91837a7 | Blue Swirl | s = qtest_start("-display none -rtc clock=vm");
|
253 | f91837a7 | Blue Swirl | |
254 | f91837a7 | Blue Swirl | qtest_add_func("/rtc/bcd/check-time", bcd_check_time);
|
255 | f91837a7 | Blue Swirl | qtest_add_func("/rtc/fuzz-registers", fuzz_registers);
|
256 | f91837a7 | Blue Swirl | ret = g_test_run(); |
257 | f91837a7 | Blue Swirl | |
258 | f91837a7 | Blue Swirl | if (s) {
|
259 | f91837a7 | Blue Swirl | qtest_quit(s); |
260 | f91837a7 | Blue Swirl | } |
261 | f91837a7 | Blue Swirl | |
262 | f91837a7 | Blue Swirl | return ret;
|
263 | f91837a7 | Blue Swirl | } |