• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * QEMU 8253/8254 interval timer emulation
3  *
4  * Copyright (c) 2003-2004 Fabrice Bellard
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24 #include "hw.h"
25 #include "pc.h"
26 #include "isa.h"
27 #include "qemu-timer.h"
28 
29 //#define DEBUG_PIT
30 
31 #define RW_STATE_LSB 1
32 #define RW_STATE_MSB 2
33 #define RW_STATE_WORD0 3
34 #define RW_STATE_WORD1 4
35 
36 typedef struct PITChannelState {
37     int count; /* can be 65536 */
38     uint16_t latched_count;
39     uint8_t count_latched;
40     uint8_t status_latched;
41     uint8_t status;
42     uint8_t read_state;
43     uint8_t write_state;
44     uint8_t write_latch;
45     uint8_t rw_mode;
46     uint8_t mode;
47     uint8_t bcd; /* not supported */
48     uint8_t gate; /* timer start */
49     int64_t count_load_time;
50     /* irq handling */
51     int64_t next_transition_time;
52     QEMUTimer *irq_timer;
53     qemu_irq irq;
54 } PITChannelState;
55 
56 struct PITState {
57     PITChannelState channels[3];
58 };
59 
60 static PITState pit_state;
61 
62 static void pit_irq_timer_update(PITChannelState *s, int64_t current_time);
63 
pit_get_count(PITChannelState * s)64 static int pit_get_count(PITChannelState *s)
65 {
66     uint64_t d;
67     int counter;
68 
69     d = muldiv64(qemu_get_clock_ns(vm_clock) - s->count_load_time, PIT_FREQ, get_ticks_per_sec());
70     switch(s->mode) {
71     case 0:
72     case 1:
73     case 4:
74     case 5:
75         counter = (s->count - d) & 0xffff;
76         break;
77     case 3:
78         /* XXX: may be incorrect for odd counts */
79         counter = s->count - ((2 * d) % s->count);
80         break;
81     default:
82         counter = s->count - (d % s->count);
83         break;
84     }
85     return counter;
86 }
87 
88 /* get pit output bit */
pit_get_out1(PITChannelState * s,int64_t current_time)89 static int pit_get_out1(PITChannelState *s, int64_t current_time)
90 {
91     uint64_t d;
92     int out;
93 
94     d = muldiv64(current_time - s->count_load_time, PIT_FREQ, get_ticks_per_sec());
95     switch(s->mode) {
96     default:
97     case 0:
98         out = (d >= s->count);
99         break;
100     case 1:
101         out = (d < s->count);
102         break;
103     case 2:
104         if ((d % s->count) == 0 && d != 0)
105             out = 1;
106         else
107             out = 0;
108         break;
109     case 3:
110         out = (d % s->count) < ((s->count + 1) >> 1);
111         break;
112     case 4:
113     case 5:
114         out = (d == s->count);
115         break;
116     }
117     return out;
118 }
119 
pit_get_out(PITState * pit,int channel,int64_t current_time)120 int pit_get_out(PITState *pit, int channel, int64_t current_time)
121 {
122     PITChannelState *s = &pit->channels[channel];
123     return pit_get_out1(s, current_time);
124 }
125 
126 /* return -1 if no transition will occur.  */
pit_get_next_transition_time(PITChannelState * s,int64_t current_time)127 static int64_t pit_get_next_transition_time(PITChannelState *s,
128                                             int64_t current_time)
129 {
130     uint64_t d, next_time, base;
131     int period2;
132 
133     d = muldiv64(current_time - s->count_load_time, PIT_FREQ, get_ticks_per_sec());
134     switch(s->mode) {
135     default:
136     case 0:
137     case 1:
138         if (d < s->count)
139             next_time = s->count;
140         else
141             return -1;
142         break;
143     case 2:
144         base = (d / s->count) * s->count;
145         if ((d - base) == 0 && d != 0)
146             next_time = base + s->count;
147         else
148             next_time = base + s->count + 1;
149         break;
150     case 3:
151         base = (d / s->count) * s->count;
152         period2 = ((s->count + 1) >> 1);
153         if ((d - base) < period2)
154             next_time = base + period2;
155         else
156             next_time = base + s->count;
157         break;
158     case 4:
159     case 5:
160         if (d < s->count)
161             next_time = s->count;
162         else if (d == s->count)
163             next_time = s->count + 1;
164         else
165             return -1;
166         break;
167     }
168     /* convert to timer units */
169     next_time = s->count_load_time + muldiv64(next_time, get_ticks_per_sec(), PIT_FREQ);
170     /* fix potential rounding problems */
171     /* XXX: better solution: use a clock at PIT_FREQ Hz */
172     if (next_time <= current_time)
173         next_time = current_time + 1;
174     return next_time;
175 }
176 
177 /* val must be 0 or 1 */
pit_set_gate(PITState * pit,int channel,int val)178 void pit_set_gate(PITState *pit, int channel, int val)
179 {
180     PITChannelState *s = &pit->channels[channel];
181 
182     switch(s->mode) {
183     default:
184     case 0:
185     case 4:
186         /* XXX: just disable/enable counting */
187         break;
188     case 1:
189     case 5:
190         if (s->gate < val) {
191             /* restart counting on rising edge */
192             s->count_load_time = qemu_get_clock_ns(vm_clock);
193             pit_irq_timer_update(s, s->count_load_time);
194         }
195         break;
196     case 2:
197     case 3:
198         if (s->gate < val) {
199             /* restart counting on rising edge */
200             s->count_load_time = qemu_get_clock_ns(vm_clock);
201             pit_irq_timer_update(s, s->count_load_time);
202         }
203         /* XXX: disable/enable counting */
204         break;
205     }
206     s->gate = val;
207 }
208 
pit_get_gate(PITState * pit,int channel)209 int pit_get_gate(PITState *pit, int channel)
210 {
211     PITChannelState *s = &pit->channels[channel];
212     return s->gate;
213 }
214 
pit_get_initial_count(PITState * pit,int channel)215 int pit_get_initial_count(PITState *pit, int channel)
216 {
217     PITChannelState *s = &pit->channels[channel];
218     return s->count;
219 }
220 
pit_get_mode(PITState * pit,int channel)221 int pit_get_mode(PITState *pit, int channel)
222 {
223     PITChannelState *s = &pit->channels[channel];
224     return s->mode;
225 }
226 
pit_load_count(PITChannelState * s,int val)227 static inline void pit_load_count(PITChannelState *s, int val)
228 {
229     if (val == 0)
230         val = 0x10000;
231     s->count_load_time = qemu_get_clock_ns(vm_clock);
232     s->count = val;
233     pit_irq_timer_update(s, s->count_load_time);
234 }
235 
236 /* if already latched, do not latch again */
pit_latch_count(PITChannelState * s)237 static void pit_latch_count(PITChannelState *s)
238 {
239     if (!s->count_latched) {
240         s->latched_count = pit_get_count(s);
241         s->count_latched = s->rw_mode;
242     }
243 }
244 
pit_ioport_write(void * opaque,uint32_t addr,uint32_t val)245 static void pit_ioport_write(void *opaque, uint32_t addr, uint32_t val)
246 {
247     PITState *pit = opaque;
248     int channel, access;
249     PITChannelState *s;
250 
251     addr &= 3;
252     if (addr == 3) {
253         channel = val >> 6;
254         if (channel == 3) {
255             /* read back command */
256             for(channel = 0; channel < 3; channel++) {
257                 s = &pit->channels[channel];
258                 if (val & (2 << channel)) {
259                     if (!(val & 0x20)) {
260                         pit_latch_count(s);
261                     }
262                     if (!(val & 0x10) && !s->status_latched) {
263                         /* status latch */
264                         /* XXX: add BCD and null count */
265                         s->status =  (pit_get_out1(s, qemu_get_clock_ns(vm_clock)) << 7) |
266                             (s->rw_mode << 4) |
267                             (s->mode << 1) |
268                             s->bcd;
269                         s->status_latched = 1;
270                     }
271                 }
272             }
273         } else {
274             s = &pit->channels[channel];
275             access = (val >> 4) & 3;
276             if (access == 0) {
277                 pit_latch_count(s);
278             } else {
279                 s->rw_mode = access;
280                 s->read_state = access;
281                 s->write_state = access;
282 
283                 s->mode = (val >> 1) & 7;
284                 s->bcd = val & 1;
285                 /* XXX: update irq timer ? */
286             }
287         }
288     } else {
289         s = &pit->channels[addr];
290         switch(s->write_state) {
291         default:
292         case RW_STATE_LSB:
293             pit_load_count(s, val);
294             break;
295         case RW_STATE_MSB:
296             pit_load_count(s, val << 8);
297             break;
298         case RW_STATE_WORD0:
299             s->write_latch = val;
300             s->write_state = RW_STATE_WORD1;
301             break;
302         case RW_STATE_WORD1:
303             pit_load_count(s, s->write_latch | (val << 8));
304             s->write_state = RW_STATE_WORD0;
305             break;
306         }
307     }
308 }
309 
pit_ioport_read(void * opaque,uint32_t addr)310 static uint32_t pit_ioport_read(void *opaque, uint32_t addr)
311 {
312     PITState *pit = opaque;
313     int ret, count;
314     PITChannelState *s;
315 
316     addr &= 3;
317     s = &pit->channels[addr];
318     if (s->status_latched) {
319         s->status_latched = 0;
320         ret = s->status;
321     } else if (s->count_latched) {
322         switch(s->count_latched) {
323         default:
324         case RW_STATE_LSB:
325             ret = s->latched_count & 0xff;
326             s->count_latched = 0;
327             break;
328         case RW_STATE_MSB:
329             ret = s->latched_count >> 8;
330             s->count_latched = 0;
331             break;
332         case RW_STATE_WORD0:
333             ret = s->latched_count & 0xff;
334             s->count_latched = RW_STATE_MSB;
335             break;
336         }
337     } else {
338         switch(s->read_state) {
339         default:
340         case RW_STATE_LSB:
341             count = pit_get_count(s);
342             ret = count & 0xff;
343             break;
344         case RW_STATE_MSB:
345             count = pit_get_count(s);
346             ret = (count >> 8) & 0xff;
347             break;
348         case RW_STATE_WORD0:
349             count = pit_get_count(s);
350             ret = count & 0xff;
351             s->read_state = RW_STATE_WORD1;
352             break;
353         case RW_STATE_WORD1:
354             count = pit_get_count(s);
355             ret = (count >> 8) & 0xff;
356             s->read_state = RW_STATE_WORD0;
357             break;
358         }
359     }
360     return ret;
361 }
362 
pit_irq_timer_update(PITChannelState * s,int64_t current_time)363 static void pit_irq_timer_update(PITChannelState *s, int64_t current_time)
364 {
365     int64_t expire_time;
366     int irq_level;
367 
368     if (!s->irq_timer)
369         return;
370     expire_time = pit_get_next_transition_time(s, current_time);
371     irq_level = pit_get_out1(s, current_time);
372     qemu_set_irq(s->irq, irq_level);
373 #ifdef DEBUG_PIT
374     printf("irq_level=%d next_delay=%f\n",
375            irq_level,
376            (double)(expire_time - current_time) / get_ticks_per_sec());
377 #endif
378     s->next_transition_time = expire_time;
379     if (expire_time != -1)
380         qemu_mod_timer(s->irq_timer, expire_time);
381     else
382         qemu_del_timer(s->irq_timer);
383 }
384 
pit_irq_timer(void * opaque)385 static void pit_irq_timer(void *opaque)
386 {
387     PITChannelState *s = opaque;
388 
389     pit_irq_timer_update(s, s->next_transition_time);
390 }
391 
pit_save(QEMUFile * f,void * opaque)392 static void pit_save(QEMUFile *f, void *opaque)
393 {
394     PITState *pit = opaque;
395     PITChannelState *s;
396     int i;
397 
398     for(i = 0; i < 3; i++) {
399         s = &pit->channels[i];
400         qemu_put_be32(f, s->count);
401         qemu_put_be16s(f, &s->latched_count);
402         qemu_put_8s(f, &s->count_latched);
403         qemu_put_8s(f, &s->status_latched);
404         qemu_put_8s(f, &s->status);
405         qemu_put_8s(f, &s->read_state);
406         qemu_put_8s(f, &s->write_state);
407         qemu_put_8s(f, &s->write_latch);
408         qemu_put_8s(f, &s->rw_mode);
409         qemu_put_8s(f, &s->mode);
410         qemu_put_8s(f, &s->bcd);
411         qemu_put_8s(f, &s->gate);
412         qemu_put_be64(f, s->count_load_time);
413         if (s->irq_timer) {
414             qemu_put_be64(f, s->next_transition_time);
415             qemu_put_timer(f, s->irq_timer);
416         }
417     }
418 }
419 
pit_load(QEMUFile * f,void * opaque,int version_id)420 static int pit_load(QEMUFile *f, void *opaque, int version_id)
421 {
422     PITState *pit = opaque;
423     PITChannelState *s;
424     int i;
425 
426     if (version_id != 1)
427         return -EINVAL;
428 
429     for(i = 0; i < 3; i++) {
430         s = &pit->channels[i];
431         s->count=qemu_get_be32(f);
432         qemu_get_be16s(f, &s->latched_count);
433         qemu_get_8s(f, &s->count_latched);
434         qemu_get_8s(f, &s->status_latched);
435         qemu_get_8s(f, &s->status);
436         qemu_get_8s(f, &s->read_state);
437         qemu_get_8s(f, &s->write_state);
438         qemu_get_8s(f, &s->write_latch);
439         qemu_get_8s(f, &s->rw_mode);
440         qemu_get_8s(f, &s->mode);
441         qemu_get_8s(f, &s->bcd);
442         qemu_get_8s(f, &s->gate);
443         s->count_load_time=qemu_get_be64(f);
444         if (s->irq_timer) {
445             s->next_transition_time=qemu_get_be64(f);
446             qemu_get_timer(f, s->irq_timer);
447         }
448     }
449     return 0;
450 }
451 
pit_reset(void * opaque)452 static void pit_reset(void *opaque)
453 {
454     PITState *pit = opaque;
455     PITChannelState *s;
456     int i;
457 
458     for(i = 0;i < 3; i++) {
459         s = &pit->channels[i];
460         s->mode = 3;
461         s->gate = (i != 2);
462         pit_load_count(s, 0);
463     }
464 }
465 
466 /* When HPET is operating in legacy mode, i8254 timer0 is disabled */
hpet_pit_disable(void)467 void hpet_pit_disable(void) {
468     PITChannelState *s;
469     s = &pit_state.channels[0];
470     if (s->irq_timer)
471         qemu_del_timer(s->irq_timer);
472 }
473 
474 /* When HPET is reset or leaving legacy mode, it must reenable i8254
475  * timer 0
476  */
477 
hpet_pit_enable(void)478 void hpet_pit_enable(void)
479 {
480     PITState *pit = &pit_state;
481     PITChannelState *s;
482     s = &pit->channels[0];
483     s->mode = 3;
484     s->gate = 1;
485     pit_load_count(s, 0);
486 }
487 
pit_init(int base,qemu_irq irq)488 PITState *pit_init(int base, qemu_irq irq)
489 {
490     PITState *pit = &pit_state;
491     PITChannelState *s;
492 
493     s = &pit->channels[0];
494     /* the timer 0 is connected to an IRQ */
495     s->irq_timer = qemu_new_timer_ns(vm_clock, pit_irq_timer, s);
496     s->irq = irq;
497 
498     register_savevm("i8254", base, 1, pit_save, pit_load, pit);
499 
500     qemu_register_reset(pit_reset, 0, pit);
501     register_ioport_write(base, 4, 1, pit_ioport_write, pit);
502     register_ioport_read(base, 3, 1, pit_ioport_read, pit);
503 
504     pit_reset(pit);
505 
506     return pit;
507 }
508