Statistics
| Branch: | Revision:

root / hw / mc146818rtc.c @ 4870852c

History | View | Annotate | Download (20.4 kB)

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