ia64/xen-unstable

view tools/ioemu/hw/i8254.c @ 6946:e703abaf6e3d

Add behaviour to the remove methods to remove the transaction's path itself. This allows us to write Remove(path) to remove the specified path rather than having to slice the path ourselves.
author emellor@ewan
date Sun Sep 18 14:42:13 2005 +0100 (2005-09-18)
parents 3233e7ecfa9f
children 06d84bf87159
line source
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 "vl.h"
25 #include "xenctrl.h"
26 #include <io/ioreq.h>
28 //#define DEBUG_PIT
30 #define RW_STATE_LSB 1
31 #define RW_STATE_MSB 2
32 #define RW_STATE_WORD0 3
33 #define RW_STATE_WORD1 4
35 typedef struct PITChannelState {
36 int count; /* can be 65536 */
37 uint16_t latched_count;
38 uint8_t count_latched;
39 uint8_t status_latched;
40 uint8_t status;
41 uint8_t read_state;
42 uint8_t write_state;
43 uint8_t write_latch;
44 uint8_t rw_mode;
45 uint8_t mode;
46 uint8_t bcd; /* not supported */
47 uint8_t gate; /* timer start */
48 int64_t count_load_time;
49 /* irq handling */
50 int64_t next_transition_time;
51 QEMUTimer *irq_timer;
52 int irq;
53 int vmx_channel; /* Is this accelerated by VMX ? */
54 } PITChannelState;
56 struct PITState {
57 PITChannelState channels[3];
58 };
60 static PITState pit_state;
62 static void pit_irq_timer_update(PITChannelState *s, int64_t current_time);
64 /* currently operate which channel for vmx use */
65 int vmx_channel = -1;
66 extern FILE *logfile;
67 static int pit_get_count(PITChannelState *s)
68 {
69 uint64_t d;
70 int counter;
72 d = muldiv64(qemu_get_clock(vm_clock) - s->count_load_time, PIT_FREQ, ticks_per_sec);
73 switch(s->mode) {
74 case 0:
75 case 1:
76 case 4:
77 case 5:
78 counter = (s->count - d) & 0xffff;
79 break;
80 case 3:
81 /* XXX: may be incorrect for odd counts */
82 counter = s->count - ((2 * d) % s->count);
83 break;
84 default:
85 counter = s->count - (d % s->count);
86 break;
87 }
88 return counter;
89 }
91 /* get pit output bit */
92 static int pit_get_out1(PITChannelState *s, int64_t current_time)
93 {
94 uint64_t d;
95 int out;
97 d = muldiv64(current_time - s->count_load_time, PIT_FREQ, ticks_per_sec);
98 switch(s->mode) {
99 default:
100 case 0:
101 out = (d >= s->count);
102 break;
103 case 1:
104 out = (d < s->count);
105 break;
106 case 2:
107 if ((d % s->count) == 0 && d != 0)
108 out = 1;
109 else
110 out = 0;
111 break;
112 case 3:
113 out = (d % s->count) < ((s->count + 1) >> 1);
114 break;
115 case 4:
116 case 5:
117 out = (d == s->count);
118 break;
119 }
120 return out;
121 }
123 int pit_get_out(PITState *pit, int channel, int64_t current_time)
124 {
125 PITChannelState *s = &pit->channels[channel];
126 return pit_get_out1(s, current_time);
127 }
129 /* return -1 if no transition will occur. */
130 static int64_t pit_get_next_transition_time(PITChannelState *s,
131 int64_t current_time)
132 {
133 uint64_t d, next_time, base;
134 int period2;
136 d = muldiv64(current_time - s->count_load_time, PIT_FREQ, ticks_per_sec);
137 switch(s->mode) {
138 default:
139 case 0:
140 case 1:
141 if (d < s->count)
142 next_time = s->count;
143 else
144 return -1;
145 break;
146 case 2:
147 base = (d / s->count) * s->count;
148 if ((d - base) == 0 && d != 0)
149 next_time = base + s->count;
150 else
151 next_time = base + s->count + 1;
152 break;
153 case 3:
154 base = (d / s->count) * s->count;
155 period2 = ((s->count + 1) >> 1);
156 if ((d - base) < period2)
157 next_time = base + period2;
158 else
159 next_time = base + s->count;
160 break;
161 case 4:
162 case 5:
163 if (d < s->count)
164 next_time = s->count;
165 else if (d == s->count)
166 next_time = s->count + 1;
167 else
168 return -1;
169 break;
170 }
171 /* convert to timer units */
172 next_time = s->count_load_time + muldiv64(next_time, ticks_per_sec, PIT_FREQ);
173 /* fix potential rounding problems */
174 /* XXX: better solution: use a clock at PIT_FREQ Hz */
175 if (next_time <= current_time)
176 next_time = current_time + 1;
177 return next_time;
178 }
180 /* val must be 0 or 1 */
181 void pit_set_gate(PITState *pit, int channel, int val)
182 {
183 PITChannelState *s = &pit->channels[channel];
185 switch(s->mode) {
186 default:
187 case 0:
188 case 4:
189 /* XXX: just disable/enable counting */
190 break;
191 case 1:
192 case 5:
193 if (s->gate < val) {
194 /* restart counting on rising edge */
195 s->count_load_time = qemu_get_clock(vm_clock);
196 pit_irq_timer_update(s, s->count_load_time);
197 }
198 break;
199 case 2:
200 case 3:
201 if (s->gate < val) {
202 /* restart counting on rising edge */
203 s->count_load_time = qemu_get_clock(vm_clock);
204 pit_irq_timer_update(s, s->count_load_time);
205 }
206 /* XXX: disable/enable counting */
207 break;
208 }
209 s->gate = val;
210 }
212 int pit_get_gate(PITState *pit, int channel)
213 {
214 PITChannelState *s = &pit->channels[channel];
215 return s->gate;
216 }
218 void pit_reset_vmx_vectors()
219 {
220 extern shared_iopage_t *shared_page;
221 ioreq_t *req;
222 int irq, i;
223 PITChannelState *s;
225 /* Assumes PIT is wired to IRQ0 and -1 is uninitialized irq base */
226 if ((irq = pic_irq2vec(0)) == -1)
227 return;
229 for(i = 0; i < 3; i++) {
230 if (pit_state.channels[i].vmx_channel)
231 break;
232 }
234 if (i == 3)
235 return;
237 /* Assumes just one VMX accelerated channel */
238 vmx_channel = i;
239 s = &pit_state.channels[vmx_channel];
240 fprintf(logfile,
241 "VMX_PIT:guest init pit channel %d!\n", vmx_channel);
242 req = &shared_page->vcpu_iodata[0].vp_ioreq;
244 req->state = STATE_IORESP_HOOK;
245 /*
246 * info passed to HV as following
247 * -- init count:16 bit, timer vec:8 bit,
248 * PIT channel(0~2):2 bit, rw mode:2 bit
249 */
250 req->u.data = s->count;
251 req->u.data |= (irq << 16);
252 req->u.data |= (vmx_channel << 24);
253 req->u.data |= ((s->rw_mode) << 26);
254 fprintf(logfile, "VMX_PIT:pass info 0x%llx to HV!\n", req->u.data);
255 }
257 static inline void pit_load_count(PITChannelState *s, int val)
258 {
259 if (val == 0)
260 val = 0x10000;
261 s->count_load_time = qemu_get_clock(vm_clock);
262 s->count = val;
264 /* guest init this pit channel for periodic mode. we do not update related
265 * timer so the channel never send intr from device model*/
266 if (vmx_channel != -1 && s->mode == 2) {
267 pit_reset_vmx_vectors();
268 vmx_channel = -1;
269 }
271 /* pit_irq_timer_update(s, s->count_load_time);*/
272 }
274 /* if already latched, do not latch again */
275 static void pit_latch_count(PITChannelState *s)
276 {
277 if (!s->count_latched) {
278 s->latched_count = pit_get_count(s);
279 s->count_latched = s->rw_mode;
280 }
281 }
283 static void pit_ioport_write(void *opaque, uint32_t addr, uint32_t val)
284 {
285 PITState *pit = opaque;
286 int channel, access;
287 PITChannelState *s;
289 addr &= 3;
290 if (addr == 3) {
291 channel = val >> 6;
292 if (channel == 3) {
293 /* read back command */
294 for(channel = 0; channel < 3; channel++) {
295 s = &pit->channels[channel];
296 if (val & (2 << channel)) {
297 if (!(val & 0x20)) {
298 pit_latch_count(s);
299 }
300 if (!(val & 0x10) && !s->status_latched) {
301 /* status latch */
302 /* XXX: add BCD and null count */
303 s->status = (pit_get_out1(s, qemu_get_clock(vm_clock)) << 7) |
304 (s->rw_mode << 4) |
305 (s->mode << 1) |
306 s->bcd;
307 s->status_latched = 1;
308 }
309 }
310 }
311 } else {
312 s = &pit->channels[channel];
313 access = (val >> 4) & 3;
314 if (access == 0) {
315 pit_latch_count(s);
316 } else {
317 s->rw_mode = access;
318 s->read_state = access;
319 s->write_state = access;
321 s->mode = (val >> 1) & 7;
322 s->bcd = val & 1;
323 /* XXX: update irq timer ? */
324 }
325 }
326 } else {
327 s = &pit->channels[addr];
328 s->vmx_channel = 1;
329 vmx_channel = addr;
330 switch(s->write_state) {
331 default:
332 case RW_STATE_LSB:
333 pit_load_count(s, val);
334 break;
335 case RW_STATE_MSB:
336 pit_load_count(s, val << 8);
337 break;
338 case RW_STATE_WORD0:
339 s->write_latch = val;
340 s->write_state = RW_STATE_WORD1;
341 break;
342 case RW_STATE_WORD1:
343 pit_load_count(s, s->write_latch | (val << 8));
344 s->write_state = RW_STATE_WORD0;
345 break;
346 }
347 }
348 }
350 static uint32_t pit_ioport_read(void *opaque, uint32_t addr)
351 {
352 PITState *pit = opaque;
353 int ret, count;
354 PITChannelState *s;
356 addr &= 3;
357 s = &pit->channels[addr];
358 if (s->status_latched) {
359 s->status_latched = 0;
360 ret = s->status;
361 } else if (s->count_latched) {
362 switch(s->count_latched) {
363 default:
364 case RW_STATE_LSB:
365 ret = s->latched_count & 0xff;
366 s->count_latched = 0;
367 break;
368 case RW_STATE_MSB:
369 ret = s->latched_count >> 8;
370 s->count_latched = 0;
371 break;
372 case RW_STATE_WORD0:
373 ret = s->latched_count & 0xff;
374 s->count_latched = RW_STATE_MSB;
375 break;
376 }
377 } else {
378 switch(s->read_state) {
379 default:
380 case RW_STATE_LSB:
381 count = pit_get_count(s);
382 ret = count & 0xff;
383 break;
384 case RW_STATE_MSB:
385 count = pit_get_count(s);
386 ret = (count >> 8) & 0xff;
387 break;
388 case RW_STATE_WORD0:
389 count = pit_get_count(s);
390 ret = count & 0xff;
391 s->read_state = RW_STATE_WORD1;
392 break;
393 case RW_STATE_WORD1:
394 count = pit_get_count(s);
395 ret = (count >> 8) & 0xff;
396 s->read_state = RW_STATE_WORD0;
397 break;
398 }
399 }
400 return ret;
401 }
403 static void pit_irq_timer_update(PITChannelState *s, int64_t current_time)
404 {
405 int64_t expire_time;
406 int irq_level;
408 if (!s->irq_timer)
409 return;
410 expire_time = pit_get_next_transition_time(s, current_time);
411 irq_level = pit_get_out1(s, current_time);
412 pic_set_irq(s->irq, irq_level);
413 #ifdef DEBUG_PIT
414 printf("irq_level=%d next_delay=%f\n",
415 irq_level,
416 (double)(expire_time - current_time) / ticks_per_sec);
417 #endif
418 s->next_transition_time = expire_time;
419 if (expire_time != -1)
420 qemu_mod_timer(s->irq_timer, expire_time);
421 else
422 qemu_del_timer(s->irq_timer);
423 }
425 static void pit_irq_timer(void *opaque)
426 {
427 PITChannelState *s = opaque;
429 pit_irq_timer_update(s, s->next_transition_time);
430 }
432 static void pit_save(QEMUFile *f, void *opaque)
433 {
434 PITState *pit = opaque;
435 PITChannelState *s;
436 int i;
438 for(i = 0; i < 3; i++) {
439 s = &pit->channels[i];
440 qemu_put_be32s(f, &s->count);
441 qemu_put_be16s(f, &s->latched_count);
442 qemu_put_8s(f, &s->count_latched);
443 qemu_put_8s(f, &s->status_latched);
444 qemu_put_8s(f, &s->status);
445 qemu_put_8s(f, &s->read_state);
446 qemu_put_8s(f, &s->write_state);
447 qemu_put_8s(f, &s->write_latch);
448 qemu_put_8s(f, &s->rw_mode);
449 qemu_put_8s(f, &s->mode);
450 qemu_put_8s(f, &s->bcd);
451 qemu_put_8s(f, &s->gate);
452 qemu_put_be64s(f, &s->count_load_time);
453 if (s->irq_timer) {
454 qemu_put_be64s(f, &s->next_transition_time);
455 qemu_put_timer(f, s->irq_timer);
456 }
457 }
458 }
460 static int pit_load(QEMUFile *f, void *opaque, int version_id)
461 {
462 PITState *pit = opaque;
463 PITChannelState *s;
464 int i;
466 if (version_id != 1)
467 return -EINVAL;
469 for(i = 0; i < 3; i++) {
470 s = &pit->channels[i];
471 qemu_get_be32s(f, &s->count);
472 qemu_get_be16s(f, &s->latched_count);
473 qemu_get_8s(f, &s->count_latched);
474 qemu_get_8s(f, &s->status_latched);
475 qemu_get_8s(f, &s->status);
476 qemu_get_8s(f, &s->read_state);
477 qemu_get_8s(f, &s->write_state);
478 qemu_get_8s(f, &s->write_latch);
479 qemu_get_8s(f, &s->rw_mode);
480 qemu_get_8s(f, &s->mode);
481 qemu_get_8s(f, &s->bcd);
482 qemu_get_8s(f, &s->gate);
483 qemu_get_be64s(f, &s->count_load_time);
484 if (s->irq_timer) {
485 qemu_get_be64s(f, &s->next_transition_time);
486 qemu_get_timer(f, s->irq_timer);
487 }
488 }
489 return 0;
490 }
492 static void pit_reset(void *opaque)
493 {
494 PITState *pit = opaque;
495 PITChannelState *s;
496 int i;
498 for(i = 0;i < 3; i++) {
499 s = &pit->channels[i];
500 s->mode = 3;
501 s->gate = (i != 2);
502 pit_load_count(s, 0);
503 }
504 }
506 PITState *pit_init(int base, int irq)
507 {
508 PITState *pit = &pit_state;
509 PITChannelState *s;
511 s = &pit->channels[0];
512 /* the timer 0 is connected to an IRQ */
513 s->irq_timer = qemu_new_timer(vm_clock, pit_irq_timer, s);
514 s->irq = irq;
516 register_savevm("i8254", base, 1, pit_save, pit_load, pit);
518 qemu_register_reset(pit_reset, pit);
519 register_ioport_write(base, 4, 1, pit_ioport_write, pit);
520 register_ioport_read(base, 3, 1, pit_ioport_read, pit);
522 pit_reset(pit);
524 return pit;
525 }