Add access control support to qemu bridge helper
[qemu.git] / hw / i8254.c
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 typedef struct PITState {
57 ISADevice dev;
58 MemoryRegion ioports;
59 uint32_t irq;
60 uint32_t iobase;
61 PITChannelState channels[3];
62 } PITState;
63
64 static PITState pit_state;
65
66 static void pit_irq_timer_update(PITChannelState *s, int64_t current_time);
67
68 static int pit_get_count(PITChannelState *s)
69 {
70 uint64_t d;
71 int counter;
72
73 d = muldiv64(qemu_get_clock_ns(vm_clock) - s->count_load_time, PIT_FREQ,
74 get_ticks_per_sec());
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 */
94 static int pit_get_out1(PITChannelState *s, int64_t current_time)
95 {
96 uint64_t d;
97 int out;
98
99 d = muldiv64(current_time - s->count_load_time, PIT_FREQ,
100 get_ticks_per_sec());
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
126 int pit_get_out(ISADevice *dev, int channel, int64_t current_time)
127 {
128 PITState *pit = DO_UPCAST(PITState, dev, dev);
129 PITChannelState *s = &pit->channels[channel];
130 return pit_get_out1(s, current_time);
131 }
132
133 /* return -1 if no transition will occur. */
134 static int64_t pit_get_next_transition_time(PITChannelState *s,
135 int64_t current_time)
136 {
137 uint64_t d, next_time, base;
138 int period2;
139
140 d = muldiv64(current_time - s->count_load_time, PIT_FREQ,
141 get_ticks_per_sec());
142 switch(s->mode) {
143 default:
144 case 0:
145 case 1:
146 if (d < s->count)
147 next_time = s->count;
148 else
149 return -1;
150 break;
151 case 2:
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;
157 break;
158 case 3:
159 base = (d / s->count) * s->count;
160 period2 = ((s->count + 1) >> 1);
161 if ((d - base) < period2)
162 next_time = base + period2;
163 else
164 next_time = base + s->count;
165 break;
166 case 4:
167 case 5:
168 if (d < s->count)
169 next_time = s->count;
170 else if (d == s->count)
171 next_time = s->count + 1;
172 else
173 return -1;
174 break;
175 }
176 /* convert to timer units */
177 next_time = s->count_load_time + muldiv64(next_time, get_ticks_per_sec(),
178 PIT_FREQ);
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;
183 return next_time;
184 }
185
186 /* val must be 0 or 1 */
187 void pit_set_gate(ISADevice *dev, int channel, int val)
188 {
189 PITState *pit = DO_UPCAST(PITState, dev, dev);
190 PITChannelState *s = &pit->channels[channel];
191
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 */
202 s->count_load_time = qemu_get_clock_ns(vm_clock);
203 pit_irq_timer_update(s, s->count_load_time);
204 }
205 break;
206 case 2:
207 case 3:
208 if (s->gate < val) {
209 /* restart counting on rising edge */
210 s->count_load_time = qemu_get_clock_ns(vm_clock);
211 pit_irq_timer_update(s, s->count_load_time);
212 }
213 /* XXX: disable/enable counting */
214 break;
215 }
216 s->gate = val;
217 }
218
219 int pit_get_gate(ISADevice *dev, int channel)
220 {
221 PITState *pit = DO_UPCAST(PITState, dev, dev);
222 PITChannelState *s = &pit->channels[channel];
223 return s->gate;
224 }
225
226 int pit_get_initial_count(ISADevice *dev, int channel)
227 {
228 PITState *pit = DO_UPCAST(PITState, dev, dev);
229 PITChannelState *s = &pit->channels[channel];
230 return s->count;
231 }
232
233 int pit_get_mode(ISADevice *dev, int channel)
234 {
235 PITState *pit = DO_UPCAST(PITState, dev, dev);
236 PITChannelState *s = &pit->channels[channel];
237 return s->mode;
238 }
239
240 static inline void pit_load_count(PITChannelState *s, int val)
241 {
242 if (val == 0)
243 val = 0x10000;
244 s->count_load_time = qemu_get_clock_ns(vm_clock);
245 s->count = val;
246 pit_irq_timer_update(s, s->count_load_time);
247 }
248
249 /* if already latched, do not latch again */
250 static 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
258 static void pit_ioport_write(void *opaque, uint32_t addr, uint32_t val)
259 {
260 PITState *pit = opaque;
261 int channel, access;
262 PITChannelState *s;
263
264 addr &= 3;
265 if (addr == 3) {
266 channel = val >> 6;
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 */
278 s->status = (pit_get_out1(s, qemu_get_clock_ns(vm_clock)) << 7) |
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 }
300 }
301 } else {
302 s = &pit->channels[addr];
303 switch(s->write_state) {
304 default:
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:
312 s->write_latch = val;
313 s->write_state = RW_STATE_WORD1;
314 break;
315 case RW_STATE_WORD1:
316 pit_load_count(s, s->write_latch | (val << 8));
317 s->write_state = RW_STATE_WORD0;
318 break;
319 }
320 }
321 }
322
323 static uint32_t pit_ioport_read(void *opaque, uint32_t addr)
324 {
325 PITState *pit = opaque;
326 int ret, count;
327 PITChannelState *s;
328
329 addr &= 3;
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:
342 ret = s->latched_count >> 8;
343 s->count_latched = 0;
344 break;
345 case RW_STATE_WORD0:
346 ret = s->latched_count & 0xff;
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 }
372 }
373 return ret;
374 }
375
376 static 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);
384 irq_level = pit_get_out1(s, current_time);
385 qemu_set_irq(s->irq, irq_level);
386 #ifdef DEBUG_PIT
387 printf("irq_level=%d next_delay=%f\n",
388 irq_level,
389 (double)(expire_time - current_time) / get_ticks_per_sec());
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
398 static void pit_irq_timer(void *opaque)
399 {
400 PITChannelState *s = opaque;
401
402 pit_irq_timer_update(s, s->next_transition_time);
403 }
404
405 static 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()
426 }
427 };
428
429 static int pit_load_old(QEMUFile *f, void *opaque, int version_id)
430 {
431 PITState *pit = opaque;
432 PITChannelState *s;
433 int i;
434
435 if (version_id != 1)
436 return -EINVAL;
437
438 for(i = 0; i < 3; i++) {
439 s = &pit->channels[i];
440 s->count=qemu_get_be32(f);
441 qemu_get_be16s(f, &s->latched_count);
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);
449 qemu_get_8s(f, &s->mode);
450 qemu_get_8s(f, &s->bcd);
451 qemu_get_8s(f, &s->gate);
452 s->count_load_time=qemu_get_be64(f);
453 if (s->irq_timer) {
454 s->next_transition_time=qemu_get_be64(f);
455 qemu_get_timer(f, s->irq_timer);
456 }
457 }
458 return 0;
459 }
460
461 static 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
474 static void pit_reset(DeviceState *dev)
475 {
476 PITState *pit = container_of(dev, PITState, dev.qdev);
477 PITChannelState *s;
478 int i;
479
480 for(i = 0;i < 3; i++) {
481 s = &pit->channels[i];
482 s->mode = 3;
483 s->gate = (i != 2);
484 pit_load_count(s, 0);
485 }
486 }
487
488 /* When HPET is operating in legacy mode, i8254 timer0 is disabled */
489 void hpet_pit_disable(void) {
490 PITChannelState *s;
491 s = &pit_state.channels[0];
492 if (s->irq_timer)
493 qemu_del_timer(s->irq_timer);
494 }
495
496 /* When HPET is reset or leaving legacy mode, it must reenable i8254
497 * timer 0
498 */
499
500 void 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
510 static 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
516 static const MemoryRegionOps pit_ioport_ops = {
517 .old_portio = pit_portio
518 };
519
520 static int pit_initfn(ISADevice *dev)
521 {
522 PITState *pit = DO_UPCAST(PITState, dev, dev);
523 PITChannelState *s;
524
525 s = &pit->channels[0];
526 /* the timer 0 is connected to an IRQ */
527 s->irq_timer = qemu_new_timer_ns(vm_clock, pit_irq_timer, s);
528 s->irq = isa_get_irq(dev, pit->irq);
529
530 memory_region_init_io(&pit->ioports, &pit_ioport_ops, pit, "pit", 4);
531 isa_register_ioport(dev, &pit->ioports, pit->iobase);
532
533 qdev_set_legacy_instance_id(&dev->qdev, pit->iobase, 2);
534
535 return 0;
536 }
537
538 static void pit_class_initfn(ObjectClass *klass, void *data)
539 {
540 ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
541 ic->init = pit_initfn;
542 }
543
544 static DeviceInfo pit_info = {
545 .name = "isa-pit",
546 .size = sizeof(PITState),
547 .vmsd = &vmstate_pit,
548 .reset = pit_reset,
549 .no_user = 1,
550 .class_init = pit_class_initfn,
551 .props = (Property[]) {
552 DEFINE_PROP_UINT32("irq", PITState, irq, -1),
553 DEFINE_PROP_HEX32("iobase", PITState, iobase, -1),
554 DEFINE_PROP_END_OF_LIST(),
555 },
556 };
557
558 static void pit_register(void)
559 {
560 isa_qdev_register(&pit_info);
561 }
562 device_init(pit_register)