]> git.proxmox.com Git - qemu.git/blame - hw/i8254.c
qxl: create slots on post_load in vga state
[qemu.git] / hw / i8254.c
CommitLineData
80cabfad
FB
1/*
2 * QEMU 8253/8254 interval timer emulation
5fafdf24 3 *
80cabfad 4 * Copyright (c) 2003-2004 Fabrice Bellard
5fafdf24 5 *
80cabfad
FB
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 */
87ecb68b
PB
24#include "hw.h"
25#include "pc.h"
26#include "isa.h"
27#include "qemu-timer.h"
80cabfad 28
b0a21b53
FB
29//#define DEBUG_PIT
30
ec844b96
FB
31#define RW_STATE_LSB 1
32#define RW_STATE_MSB 2
33#define RW_STATE_WORD0 3
34#define RW_STATE_WORD1 4
80cabfad 35
ec844b96
FB
36typedef 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;
d537cf6c 53 qemu_irq irq;
ec844b96
FB
54} PITChannelState;
55
64d7e9a4
BS
56typedef struct PITState {
57 ISADevice dev;
60ea6aa8 58 MemoryRegion ioports;
64d7e9a4
BS
59 uint32_t irq;
60 uint32_t iobase;
ec844b96 61 PITChannelState channels[3];
64d7e9a4 62} PITState;
ec844b96
FB
63
64static PITState pit_state;
80cabfad 65
b0a21b53
FB
66static void pit_irq_timer_update(PITChannelState *s, int64_t current_time);
67
80cabfad
FB
68static int pit_get_count(PITChannelState *s)
69{
70 uint64_t d;
71 int counter;
72
74475455 73 d = muldiv64(qemu_get_clock_ns(vm_clock) - s->count_load_time, PIT_FREQ,
6ee093c9 74 get_ticks_per_sec());
80cabfad
FB
75 switch(s->mode) {
76 case 0:
77 case 1:
78 case 4:
79 case 5:
80 counter = (s->count - d) & 0xffff;
81 break;
82 case 3:
83 /* XXX: may be incorrect for odd counts */
84 counter = s->count - ((2 * d) % s->count);
85 break;
86 default:
87 counter = s->count - (d % s->count);
88 break;
89 }
90 return counter;
91}
92
93/* get pit output bit */
ec844b96 94static int pit_get_out1(PITChannelState *s, int64_t current_time)
80cabfad
FB
95{
96 uint64_t d;
97 int out;
98
6ee093c9
JQ
99 d = muldiv64(current_time - s->count_load_time, PIT_FREQ,
100 get_ticks_per_sec());
80cabfad
FB
101 switch(s->mode) {
102 default:
103 case 0:
104 out = (d >= s->count);
105 break;
106 case 1:
107 out = (d < s->count);
108 break;
109 case 2:
110 if ((d % s->count) == 0 && d != 0)
111 out = 1;
112 else
113 out = 0;
114 break;
115 case 3:
116 out = (d % s->count) < ((s->count + 1) >> 1);
117 break;
118 case 4:
119 case 5:
120 out = (d == s->count);
121 break;
122 }
123 return out;
124}
125
64d7e9a4 126int pit_get_out(ISADevice *dev, int channel, int64_t current_time)
ec844b96 127{
64d7e9a4 128 PITState *pit = DO_UPCAST(PITState, dev, dev);
ec844b96
FB
129 PITChannelState *s = &pit->channels[channel];
130 return pit_get_out1(s, current_time);
131}
132
b0a21b53 133/* return -1 if no transition will occur. */
5fafdf24 134static int64_t pit_get_next_transition_time(PITChannelState *s,
b0a21b53 135 int64_t current_time)
80cabfad 136{
b0a21b53
FB
137 uint64_t d, next_time, base;
138 int period2;
80cabfad 139
6ee093c9
JQ
140 d = muldiv64(current_time - s->count_load_time, PIT_FREQ,
141 get_ticks_per_sec());
80cabfad
FB
142 switch(s->mode) {
143 default:
144 case 0:
80cabfad 145 case 1:
b0a21b53
FB
146 if (d < s->count)
147 next_time = s->count;
148 else
149 return -1;
80cabfad
FB
150 break;
151 case 2:
b0a21b53
FB
152 base = (d / s->count) * s->count;
153 if ((d - base) == 0 && d != 0)
154 next_time = base + s->count;
155 else
156 next_time = base + s->count + 1;
80cabfad
FB
157 break;
158 case 3:
b0a21b53
FB
159 base = (d / s->count) * s->count;
160 period2 = ((s->count + 1) >> 1);
5fafdf24 161 if ((d - base) < period2)
b0a21b53
FB
162 next_time = base + period2;
163 else
164 next_time = base + s->count;
80cabfad
FB
165 break;
166 case 4:
167 case 5:
b0a21b53
FB
168 if (d < s->count)
169 next_time = s->count;
170 else if (d == s->count)
171 next_time = s->count + 1;
80cabfad 172 else
b0a21b53 173 return -1;
80cabfad
FB
174 break;
175 }
b0a21b53 176 /* convert to timer units */
6ee093c9
JQ
177 next_time = s->count_load_time + muldiv64(next_time, get_ticks_per_sec(),
178 PIT_FREQ);
1154e441
FB
179 /* fix potential rounding problems */
180 /* XXX: better solution: use a clock at PIT_FREQ Hz */
181 if (next_time <= current_time)
182 next_time = current_time + 1;
b0a21b53 183 return next_time;
80cabfad
FB
184}
185
186/* val must be 0 or 1 */
64d7e9a4 187void pit_set_gate(ISADevice *dev, int channel, int val)
80cabfad 188{
64d7e9a4 189 PITState *pit = DO_UPCAST(PITState, dev, dev);
ec844b96
FB
190 PITChannelState *s = &pit->channels[channel];
191
80cabfad
FB
192 switch(s->mode) {
193 default:
194 case 0:
195 case 4:
196 /* XXX: just disable/enable counting */
197 break;
198 case 1:
199 case 5:
200 if (s->gate < val) {
201 /* restart counting on rising edge */
74475455 202 s->count_load_time = qemu_get_clock_ns(vm_clock);
b0a21b53 203 pit_irq_timer_update(s, s->count_load_time);
80cabfad
FB
204 }
205 break;
206 case 2:
207 case 3:
208 if (s->gate < val) {
209 /* restart counting on rising edge */
74475455 210 s->count_load_time = qemu_get_clock_ns(vm_clock);
b0a21b53 211 pit_irq_timer_update(s, s->count_load_time);
80cabfad
FB
212 }
213 /* XXX: disable/enable counting */
214 break;
215 }
216 s->gate = val;
217}
218
64d7e9a4 219int pit_get_gate(ISADevice *dev, int channel)
ec844b96 220{
64d7e9a4 221 PITState *pit = DO_UPCAST(PITState, dev, dev);
ec844b96
FB
222 PITChannelState *s = &pit->channels[channel];
223 return s->gate;
224}
225
64d7e9a4 226int pit_get_initial_count(ISADevice *dev, int channel)
fd06c375 227{
64d7e9a4 228 PITState *pit = DO_UPCAST(PITState, dev, dev);
fd06c375
FB
229 PITChannelState *s = &pit->channels[channel];
230 return s->count;
231}
232
64d7e9a4 233int pit_get_mode(ISADevice *dev, int channel)
fd06c375 234{
64d7e9a4 235 PITState *pit = DO_UPCAST(PITState, dev, dev);
fd06c375
FB
236 PITChannelState *s = &pit->channels[channel];
237 return s->mode;
238}
239
80cabfad
FB
240static inline void pit_load_count(PITChannelState *s, int val)
241{
242 if (val == 0)
243 val = 0x10000;
74475455 244 s->count_load_time = qemu_get_clock_ns(vm_clock);
80cabfad 245 s->count = val;
b0a21b53 246 pit_irq_timer_update(s, s->count_load_time);
80cabfad
FB
247}
248
ec844b96
FB
249/* if already latched, do not latch again */
250static void pit_latch_count(PITChannelState *s)
251{
252 if (!s->count_latched) {
253 s->latched_count = pit_get_count(s);
254 s->count_latched = s->rw_mode;
255 }
256}
257
b41a2cd1 258static void pit_ioport_write(void *opaque, uint32_t addr, uint32_t val)
80cabfad 259{
ec844b96 260 PITState *pit = opaque;
80cabfad
FB
261 int channel, access;
262 PITChannelState *s;
263
264 addr &= 3;
265 if (addr == 3) {
266 channel = val >> 6;
ec844b96
FB
267 if (channel == 3) {
268 /* read back command */
269 for(channel = 0; channel < 3; channel++) {
270 s = &pit->channels[channel];
271 if (val & (2 << channel)) {
272 if (!(val & 0x20)) {
273 pit_latch_count(s);
274 }
275 if (!(val & 0x10) && !s->status_latched) {
276 /* status latch */
277 /* XXX: add BCD and null count */
74475455 278 s->status = (pit_get_out1(s, qemu_get_clock_ns(vm_clock)) << 7) |
ec844b96
FB
279 (s->rw_mode << 4) |
280 (s->mode << 1) |
281 s->bcd;
282 s->status_latched = 1;
283 }
284 }
285 }
286 } else {
287 s = &pit->channels[channel];
288 access = (val >> 4) & 3;
289 if (access == 0) {
290 pit_latch_count(s);
291 } else {
292 s->rw_mode = access;
293 s->read_state = access;
294 s->write_state = access;
295
296 s->mode = (val >> 1) & 7;
297 s->bcd = val & 1;
298 /* XXX: update irq timer ? */
299 }
80cabfad
FB
300 }
301 } else {
ec844b96
FB
302 s = &pit->channels[addr];
303 switch(s->write_state) {
304 default:
80cabfad
FB
305 case RW_STATE_LSB:
306 pit_load_count(s, val);
307 break;
308 case RW_STATE_MSB:
309 pit_load_count(s, val << 8);
310 break;
311 case RW_STATE_WORD0:
ec844b96
FB
312 s->write_latch = val;
313 s->write_state = RW_STATE_WORD1;
314 break;
80cabfad 315 case RW_STATE_WORD1:
ec844b96
FB
316 pit_load_count(s, s->write_latch | (val << 8));
317 s->write_state = RW_STATE_WORD0;
80cabfad
FB
318 break;
319 }
320 }
321}
322
b41a2cd1 323static uint32_t pit_ioport_read(void *opaque, uint32_t addr)
80cabfad 324{
ec844b96 325 PITState *pit = opaque;
80cabfad
FB
326 int ret, count;
327 PITChannelState *s;
3b46e624 328
80cabfad 329 addr &= 3;
ec844b96
FB
330 s = &pit->channels[addr];
331 if (s->status_latched) {
332 s->status_latched = 0;
333 ret = s->status;
334 } else if (s->count_latched) {
335 switch(s->count_latched) {
336 default:
337 case RW_STATE_LSB:
338 ret = s->latched_count & 0xff;
339 s->count_latched = 0;
340 break;
341 case RW_STATE_MSB:
80cabfad 342 ret = s->latched_count >> 8;
ec844b96
FB
343 s->count_latched = 0;
344 break;
345 case RW_STATE_WORD0:
80cabfad 346 ret = s->latched_count & 0xff;
ec844b96
FB
347 s->count_latched = RW_STATE_MSB;
348 break;
349 }
350 } else {
351 switch(s->read_state) {
352 default:
353 case RW_STATE_LSB:
354 count = pit_get_count(s);
355 ret = count & 0xff;
356 break;
357 case RW_STATE_MSB:
358 count = pit_get_count(s);
359 ret = (count >> 8) & 0xff;
360 break;
361 case RW_STATE_WORD0:
362 count = pit_get_count(s);
363 ret = count & 0xff;
364 s->read_state = RW_STATE_WORD1;
365 break;
366 case RW_STATE_WORD1:
367 count = pit_get_count(s);
368 ret = (count >> 8) & 0xff;
369 s->read_state = RW_STATE_WORD0;
370 break;
371 }
80cabfad
FB
372 }
373 return ret;
374}
375
b0a21b53
FB
376static void pit_irq_timer_update(PITChannelState *s, int64_t current_time)
377{
378 int64_t expire_time;
379 int irq_level;
380
381 if (!s->irq_timer)
382 return;
383 expire_time = pit_get_next_transition_time(s, current_time);
ec844b96 384 irq_level = pit_get_out1(s, current_time);
d537cf6c 385 qemu_set_irq(s->irq, irq_level);
b0a21b53
FB
386#ifdef DEBUG_PIT
387 printf("irq_level=%d next_delay=%f\n",
5fafdf24 388 irq_level,
6ee093c9 389 (double)(expire_time - current_time) / get_ticks_per_sec());
b0a21b53
FB
390#endif
391 s->next_transition_time = expire_time;
392 if (expire_time != -1)
393 qemu_mod_timer(s->irq_timer, expire_time);
394 else
395 qemu_del_timer(s->irq_timer);
396}
397
398static void pit_irq_timer(void *opaque)
399{
400 PITChannelState *s = opaque;
401
402 pit_irq_timer_update(s, s->next_transition_time);
403}
404
5122b431
JQ
405static const VMStateDescription vmstate_pit_channel = {
406 .name = "pit channel",
407 .version_id = 2,
408 .minimum_version_id = 2,
409 .minimum_version_id_old = 2,
410 .fields = (VMStateField []) {
411 VMSTATE_INT32(count, PITChannelState),
412 VMSTATE_UINT16(latched_count, PITChannelState),
413 VMSTATE_UINT8(count_latched, PITChannelState),
414 VMSTATE_UINT8(status_latched, PITChannelState),
415 VMSTATE_UINT8(status, PITChannelState),
416 VMSTATE_UINT8(read_state, PITChannelState),
417 VMSTATE_UINT8(write_state, PITChannelState),
418 VMSTATE_UINT8(write_latch, PITChannelState),
419 VMSTATE_UINT8(rw_mode, PITChannelState),
420 VMSTATE_UINT8(mode, PITChannelState),
421 VMSTATE_UINT8(bcd, PITChannelState),
422 VMSTATE_UINT8(gate, PITChannelState),
423 VMSTATE_INT64(count_load_time, PITChannelState),
424 VMSTATE_INT64(next_transition_time, PITChannelState),
425 VMSTATE_END_OF_LIST()
b0a21b53 426 }
5122b431 427};
b0a21b53 428
5122b431 429static int pit_load_old(QEMUFile *f, void *opaque, int version_id)
b0a21b53 430{
ec844b96 431 PITState *pit = opaque;
b0a21b53
FB
432 PITChannelState *s;
433 int i;
3b46e624 434
b0a21b53
FB
435 if (version_id != 1)
436 return -EINVAL;
437
438 for(i = 0; i < 3; i++) {
ec844b96 439 s = &pit->channels[i];
bee8d684 440 s->count=qemu_get_be32(f);
b0a21b53 441 qemu_get_be16s(f, &s->latched_count);
ec844b96
FB
442 qemu_get_8s(f, &s->count_latched);
443 qemu_get_8s(f, &s->status_latched);
444 qemu_get_8s(f, &s->status);
445 qemu_get_8s(f, &s->read_state);
446 qemu_get_8s(f, &s->write_state);
447 qemu_get_8s(f, &s->write_latch);
448 qemu_get_8s(f, &s->rw_mode);
b0a21b53
FB
449 qemu_get_8s(f, &s->mode);
450 qemu_get_8s(f, &s->bcd);
451 qemu_get_8s(f, &s->gate);
bee8d684 452 s->count_load_time=qemu_get_be64(f);
b0a21b53 453 if (s->irq_timer) {
bee8d684 454 s->next_transition_time=qemu_get_be64(f);
b0a21b53
FB
455 qemu_get_timer(f, s->irq_timer);
456 }
457 }
458 return 0;
459}
460
5122b431
JQ
461static const VMStateDescription vmstate_pit = {
462 .name = "i8254",
463 .version_id = 2,
464 .minimum_version_id = 2,
465 .minimum_version_id_old = 1,
466 .load_state_old = pit_load_old,
467 .fields = (VMStateField []) {
468 VMSTATE_STRUCT_ARRAY(channels, PITState, 3, 2, vmstate_pit_channel, PITChannelState),
469 VMSTATE_TIMER(channels[0].irq_timer, PITState),
470 VMSTATE_END_OF_LIST()
471 }
472};
473
64d7e9a4 474static void pit_reset(DeviceState *dev)
80cabfad 475{
64d7e9a4 476 PITState *pit = container_of(dev, PITState, dev.qdev);
80cabfad
FB
477 PITChannelState *s;
478 int i;
479
480 for(i = 0;i < 3; i++) {
ec844b96 481 s = &pit->channels[i];
80cabfad
FB
482 s->mode = 3;
483 s->gate = (i != 2);
484 pit_load_count(s, 0);
485 }
d7d02e3c
FB
486}
487
16b29ae1
AL
488/* When HPET is operating in legacy mode, i8254 timer0 is disabled */
489void hpet_pit_disable(void) {
490 PITChannelState *s;
491 s = &pit_state.channels[0];
e0dd114c
AL
492 if (s->irq_timer)
493 qemu_del_timer(s->irq_timer);
16b29ae1
AL
494}
495
c50c2d68 496/* When HPET is reset or leaving legacy mode, it must reenable i8254
16b29ae1
AL
497 * timer 0
498 */
499
500void hpet_pit_enable(void)
501{
502 PITState *pit = &pit_state;
503 PITChannelState *s;
504 s = &pit->channels[0];
505 s->mode = 3;
506 s->gate = 1;
507 pit_load_count(s, 0);
508}
509
60ea6aa8
RH
510static const MemoryRegionPortio pit_portio[] = {
511 { 0, 4, 1, .write = pit_ioport_write },
512 { 0, 3, 1, .read = pit_ioport_read },
513 PORTIO_END_OF_LIST()
514};
515
516static const MemoryRegionOps pit_ioport_ops = {
517 .old_portio = pit_portio
518};
519
64d7e9a4 520static int pit_initfn(ISADevice *dev)
d7d02e3c 521{
64d7e9a4 522 PITState *pit = DO_UPCAST(PITState, dev, dev);
d7d02e3c
FB
523 PITChannelState *s;
524
525 s = &pit->channels[0];
526 /* the timer 0 is connected to an IRQ */
74475455 527 s->irq_timer = qemu_new_timer_ns(vm_clock, pit_irq_timer, s);
ee951a37 528 s->irq = isa_get_irq(pit->irq);
80cabfad 529
60ea6aa8
RH
530 memory_region_init_io(&pit->ioports, &pit_ioport_ops, pit, "pit", 4);
531 isa_register_ioport(dev, &pit->ioports, pit->iobase);
d7d02e3c 532
ca22a3a3
JK
533 qdev_set_legacy_instance_id(&dev->qdev, pit->iobase, 2);
534
64d7e9a4
BS
535 return 0;
536}
537
538static ISADeviceInfo pit_info = {
539 .qdev.name = "isa-pit",
540 .qdev.size = sizeof(PITState),
541 .qdev.vmsd = &vmstate_pit,
542 .qdev.reset = pit_reset,
543 .qdev.no_user = 1,
544 .init = pit_initfn,
545 .qdev.props = (Property[]) {
546 DEFINE_PROP_UINT32("irq", PITState, irq, -1),
547 DEFINE_PROP_HEX32("iobase", PITState, iobase, -1),
548 DEFINE_PROP_END_OF_LIST(),
549 },
550};
551
552static void pit_register(void)
553{
554 isa_qdev_register(&pit_info);
80cabfad 555}
64d7e9a4 556device_init(pit_register)