debuggers.hg

view xen/arch/x86/hvm/i8254.c @ 0:7d21f7218375

Exact replica of unstable on 051908 + README-this
author Mukesh Rathor
date Mon May 19 15:34:57 2008 -0700 (2008-05-19)
parents
children 5c0bf00e371d
line source
1 /*
2 * QEMU 8253/8254 interval timer emulation
3 *
4 * Copyright (c) 2003-2004 Fabrice Bellard
5 * Copyright (c) 2006 Intel Corperation
6 * Copyright (c) 2007 Keir Fraser, XenSource Inc.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to
10 * deal in the Software without restriction, including without limitation the
11 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
12 * sell copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24 * IN THE SOFTWARE.
25 */
27 #include <xen/config.h>
28 #include <xen/types.h>
29 #include <xen/mm.h>
30 #include <xen/xmalloc.h>
31 #include <xen/lib.h>
32 #include <xen/errno.h>
33 #include <xen/sched.h>
34 #include <asm/hvm/hvm.h>
35 #include <asm/hvm/io.h>
36 #include <asm/hvm/support.h>
37 #include <asm/hvm/vpt.h>
38 #include <asm/current.h>
40 #define domain_vpit(d) (&(d)->arch.hvm_domain.pl_time.vpit)
41 #define vcpu_vpit(vcpu) (domain_vpit((vcpu)->domain))
42 #define vpit_domain(pit) (container_of((pit), struct domain, \
43 arch.hvm_domain.pl_time.vpit))
44 #define vpit_vcpu(pit) (vpit_domain(pit)->vcpu[0])
46 #define RW_STATE_LSB 1
47 #define RW_STATE_MSB 2
48 #define RW_STATE_WORD0 3
49 #define RW_STATE_WORD1 4
51 static int handle_pit_io(
52 int dir, uint32_t port, uint32_t bytes, uint32_t *val);
53 static int handle_speaker_io(
54 int dir, uint32_t port, uint32_t bytes, uint32_t *val);
56 /* Compute with 96 bit intermediate result: (a*b)/c */
57 static uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c)
58 {
59 union {
60 uint64_t ll;
61 struct {
62 #ifdef WORDS_BIGENDIAN
63 uint32_t high, low;
64 #else
65 uint32_t low, high;
66 #endif
67 } l;
68 } u, res;
69 uint64_t rl, rh;
71 u.ll = a;
72 rl = (uint64_t)u.l.low * (uint64_t)b;
73 rh = (uint64_t)u.l.high * (uint64_t)b;
74 rh += (rl >> 32);
75 res.l.high = rh / c;
76 res.l.low = (((rh % c) << 32) + (rl & 0xffffffff)) / c;
77 return res.ll;
78 }
80 static int pit_get_count(PITState *pit, int channel)
81 {
82 uint64_t d;
83 int counter;
84 struct hvm_hw_pit_channel *c = &pit->hw.channels[channel];
85 struct vcpu *v = vpit_vcpu(pit);
87 ASSERT(spin_is_locked(&pit->lock));
89 d = muldiv64(hvm_get_guest_time(v) - pit->count_load_time[channel],
90 PIT_FREQ, ticks_per_sec(v));
92 switch ( c->mode )
93 {
94 case 0:
95 case 1:
96 case 4:
97 case 5:
98 counter = (c->count - d) & 0xffff;
99 break;
100 case 3:
101 /* XXX: may be incorrect for odd counts */
102 counter = c->count - ((2 * d) % c->count);
103 break;
104 default:
105 counter = c->count - (d % c->count);
106 break;
107 }
108 return counter;
109 }
111 static int pit_get_out(PITState *pit, int channel)
112 {
113 struct hvm_hw_pit_channel *s = &pit->hw.channels[channel];
114 uint64_t d;
115 int out;
116 struct vcpu *v = vpit_vcpu(pit);
118 ASSERT(spin_is_locked(&pit->lock));
120 d = muldiv64(hvm_get_guest_time(v) - pit->count_load_time[channel],
121 PIT_FREQ, ticks_per_sec(v));
123 switch ( s->mode )
124 {
125 default:
126 case 0:
127 out = (d >= s->count);
128 break;
129 case 1:
130 out = (d < s->count);
131 break;
132 case 2:
133 out = (((d % s->count) == 0) && (d != 0));
134 break;
135 case 3:
136 out = ((d % s->count) < ((s->count + 1) >> 1));
137 break;
138 case 4:
139 case 5:
140 out = (d == s->count);
141 break;
142 }
144 return out;
145 }
147 static void pit_set_gate(PITState *pit, int channel, int val)
148 {
149 struct hvm_hw_pit_channel *s = &pit->hw.channels[channel];
150 struct vcpu *v = vpit_vcpu(pit);
152 ASSERT(spin_is_locked(&pit->lock));
154 switch ( s->mode )
155 {
156 default:
157 case 0:
158 case 4:
159 /* XXX: just disable/enable counting */
160 break;
161 case 1:
162 case 5:
163 case 2:
164 case 3:
165 /* Restart counting on rising edge. */
166 if ( s->gate < val )
167 pit->count_load_time[channel] = hvm_get_guest_time(v);
168 break;
169 }
171 s->gate = val;
172 }
174 int pit_get_gate(PITState *pit, int channel)
175 {
176 ASSERT(spin_is_locked(&pit->lock));
177 return pit->hw.channels[channel].gate;
178 }
180 static void pit_time_fired(struct vcpu *v, void *priv)
181 {
182 uint64_t *count_load_time = priv;
183 *count_load_time = hvm_get_guest_time(v);
184 }
186 static void pit_load_count(PITState *pit, int channel, int val)
187 {
188 u32 period;
189 struct hvm_hw_pit_channel *s = &pit->hw.channels[channel];
190 struct vcpu *v = vpit_vcpu(pit);
192 ASSERT(spin_is_locked(&pit->lock));
194 if ( val == 0 )
195 val = 0x10000;
197 if ( v == NULL )
198 rdtscll(pit->count_load_time[channel]);
199 else
200 pit->count_load_time[channel] = hvm_get_guest_time(v);
201 s->count = val;
202 period = DIV_ROUND((val * 1000000000ULL), PIT_FREQ);
204 if ( (v == NULL) || !is_hvm_vcpu(v) || (channel != 0) )
205 return;
207 switch ( s->mode )
208 {
209 case 2:
210 case 3:
211 /* Periodic timer. */
212 create_periodic_time(v, &pit->pt0, period, 0, 0, pit_time_fired,
213 &pit->count_load_time[channel]);
214 break;
215 case 1:
216 case 4:
217 /* One-shot timer. */
218 create_periodic_time(v, &pit->pt0, period, 0, 1, pit_time_fired,
219 &pit->count_load_time[channel]);
220 break;
221 default:
222 destroy_periodic_time(&pit->pt0);
223 break;
224 }
225 }
227 static void pit_latch_count(PITState *pit, int channel)
228 {
229 struct hvm_hw_pit_channel *c = &pit->hw.channels[channel];
231 ASSERT(spin_is_locked(&pit->lock));
233 if ( !c->count_latched )
234 {
235 c->latched_count = pit_get_count(pit, channel);
236 c->count_latched = c->rw_mode;
237 }
238 }
240 static void pit_latch_status(PITState *pit, int channel)
241 {
242 struct hvm_hw_pit_channel *c = &pit->hw.channels[channel];
244 ASSERT(spin_is_locked(&pit->lock));
246 if ( !c->status_latched )
247 {
248 /* TODO: Return NULL COUNT (bit 6). */
249 c->status = ((pit_get_out(pit, channel) << 7) |
250 (c->rw_mode << 4) |
251 (c->mode << 1) |
252 c->bcd);
253 c->status_latched = 1;
254 }
255 }
257 static void pit_ioport_write(struct PITState *pit, uint32_t addr, uint32_t val)
258 {
259 int channel, access;
260 struct hvm_hw_pit_channel *s;
262 val &= 0xff;
263 addr &= 3;
265 spin_lock(&pit->lock);
267 if ( addr == 3 )
268 {
269 channel = val >> 6;
270 if ( channel == 3 )
271 {
272 /* Read-Back Command. */
273 for ( channel = 0; channel < 3; channel++ )
274 {
275 s = &pit->hw.channels[channel];
276 if ( val & (2 << channel) )
277 {
278 if ( !(val & 0x20) )
279 pit_latch_count(pit, channel);
280 if ( !(val & 0x10) )
281 pit_latch_status(pit, channel);
282 }
283 }
284 }
285 else
286 {
287 /* Select Counter <channel>. */
288 s = &pit->hw.channels[channel];
289 access = (val >> 4) & 3;
290 if ( access == 0 )
291 {
292 pit_latch_count(pit, channel);
293 }
294 else
295 {
296 s->rw_mode = access;
297 s->read_state = access;
298 s->write_state = access;
299 s->mode = (val >> 1) & 7;
300 if ( s->mode > 5 )
301 s->mode -= 4;
302 s->bcd = val & 1;
303 /* XXX: update irq timer ? */
304 }
305 }
306 }
307 else
308 {
309 /* Write Count. */
310 s = &pit->hw.channels[addr];
311 switch ( s->write_state )
312 {
313 default:
314 case RW_STATE_LSB:
315 pit_load_count(pit, addr, val);
316 break;
317 case RW_STATE_MSB:
318 pit_load_count(pit, addr, val << 8);
319 break;
320 case RW_STATE_WORD0:
321 s->write_latch = val;
322 s->write_state = RW_STATE_WORD1;
323 break;
324 case RW_STATE_WORD1:
325 pit_load_count(pit, addr, s->write_latch | (val << 8));
326 s->write_state = RW_STATE_WORD0;
327 break;
328 }
329 }
331 spin_unlock(&pit->lock);
332 }
334 static uint32_t pit_ioport_read(struct PITState *pit, uint32_t addr)
335 {
336 int ret, count;
337 struct hvm_hw_pit_channel *s;
339 addr &= 3;
340 s = &pit->hw.channels[addr];
342 spin_lock(&pit->lock);
344 if ( s->status_latched )
345 {
346 s->status_latched = 0;
347 ret = s->status;
348 }
349 else if ( s->count_latched )
350 {
351 switch ( s->count_latched )
352 {
353 default:
354 case RW_STATE_LSB:
355 ret = s->latched_count & 0xff;
356 s->count_latched = 0;
357 break;
358 case RW_STATE_MSB:
359 ret = s->latched_count >> 8;
360 s->count_latched = 0;
361 break;
362 case RW_STATE_WORD0:
363 ret = s->latched_count & 0xff;
364 s->count_latched = RW_STATE_MSB;
365 break;
366 }
367 }
368 else
369 {
370 switch ( s->read_state )
371 {
372 default:
373 case RW_STATE_LSB:
374 count = pit_get_count(pit, addr);
375 ret = count & 0xff;
376 break;
377 case RW_STATE_MSB:
378 count = pit_get_count(pit, addr);
379 ret = (count >> 8) & 0xff;
380 break;
381 case RW_STATE_WORD0:
382 count = pit_get_count(pit, addr);
383 ret = count & 0xff;
384 s->read_state = RW_STATE_WORD1;
385 break;
386 case RW_STATE_WORD1:
387 count = pit_get_count(pit, addr);
388 ret = (count >> 8) & 0xff;
389 s->read_state = RW_STATE_WORD0;
390 break;
391 }
392 }
394 spin_unlock(&pit->lock);
396 return ret;
397 }
399 void pit_stop_channel0_irq(PITState *pit)
400 {
401 spin_lock(&pit->lock);
402 destroy_periodic_time(&pit->pt0);
403 spin_unlock(&pit->lock);
404 }
406 static int pit_save(struct domain *d, hvm_domain_context_t *h)
407 {
408 PITState *pit = domain_vpit(d);
409 int rc;
411 spin_lock(&pit->lock);
413 rc = hvm_save_entry(PIT, 0, h, &pit->hw);
415 spin_unlock(&pit->lock);
417 return rc;
418 }
420 static int pit_load(struct domain *d, hvm_domain_context_t *h)
421 {
422 PITState *pit = domain_vpit(d);
423 int i;
425 spin_lock(&pit->lock);
427 if ( hvm_load_entry(PIT, h, &pit->hw) )
428 {
429 spin_unlock(&pit->lock);
430 return 1;
431 }
433 /*
434 * Recreate platform timers from hardware state. There will be some
435 * time jitter here, but the wall-clock will have jumped massively, so
436 * we hope the guest can handle it.
437 */
438 pit->pt0.last_plt_gtime = hvm_get_guest_time(d->vcpu[0]);
439 for ( i = 0; i < 3; i++ )
440 pit_load_count(pit, i, pit->hw.channels[i].count);
442 spin_unlock(&pit->lock);
444 return 0;
445 }
447 HVM_REGISTER_SAVE_RESTORE(PIT, pit_save, pit_load, 1, HVMSR_PER_DOM);
449 void pit_init(struct vcpu *v, unsigned long cpu_khz)
450 {
451 PITState *pit = vcpu_vpit(v);
452 struct hvm_hw_pit_channel *s;
453 int i;
455 spin_lock_init(&pit->lock);
457 /* Some sub-functions assert that they are called with the lock held. */
458 spin_lock(&pit->lock);
460 pit->pt0.source = PTSRC_isa;
462 register_portio_handler(v->domain, PIT_BASE, 4, handle_pit_io);
463 register_portio_handler(v->domain, 0x61, 1, handle_speaker_io);
464 ticks_per_sec(v) = cpu_khz * (int64_t)1000;
466 for ( i = 0; i < 3; i++ )
467 {
468 s = &pit->hw.channels[i];
469 s->mode = 0xff; /* the init mode */
470 s->gate = (i != 2);
471 pit_load_count(pit, i, 0);
472 }
474 spin_unlock(&pit->lock);
475 }
477 void pit_deinit(struct domain *d)
478 {
479 PITState *pit = domain_vpit(d);
480 destroy_periodic_time(&pit->pt0);
481 }
483 /* the intercept action for PIT DM retval:0--not handled; 1--handled */
484 static int handle_pit_io(
485 int dir, uint32_t port, uint32_t bytes, uint32_t *val)
486 {
487 struct PITState *vpit = vcpu_vpit(current);
489 if ( bytes != 1 )
490 {
491 gdprintk(XENLOG_WARNING, "PIT bad access\n");
492 return X86EMUL_OKAY;
493 }
495 if ( dir == IOREQ_WRITE )
496 {
497 pit_ioport_write(vpit, port, *val);
498 }
499 else
500 {
501 if ( (port & 3) != 3 )
502 *val = pit_ioport_read(vpit, port);
503 else
504 gdprintk(XENLOG_WARNING, "PIT: read A1:A0=3!\n");
505 }
507 return X86EMUL_OKAY;
508 }
510 static void speaker_ioport_write(
511 struct PITState *pit, uint32_t addr, uint32_t val)
512 {
513 pit->hw.speaker_data_on = (val >> 1) & 1;
514 pit_set_gate(pit, 2, val & 1);
515 }
517 static uint32_t speaker_ioport_read(
518 struct PITState *pit, uint32_t addr)
519 {
520 /* Refresh clock toggles at about 15us. We approximate as 2^14ns. */
521 unsigned int refresh_clock = ((unsigned int)NOW() >> 14) & 1;
522 return ((pit->hw.speaker_data_on << 1) | pit_get_gate(pit, 2) |
523 (pit_get_out(pit, 2) << 5) | (refresh_clock << 4));
524 }
526 static int handle_speaker_io(
527 int dir, uint32_t port, uint32_t bytes, uint32_t *val)
528 {
529 struct PITState *vpit = vcpu_vpit(current);
531 BUG_ON(bytes != 1);
533 spin_lock(&vpit->lock);
535 if ( dir == IOREQ_WRITE )
536 speaker_ioport_write(vpit, port, *val);
537 else
538 *val = speaker_ioport_read(vpit, port);
540 spin_unlock(&vpit->lock);
542 return X86EMUL_OKAY;
543 }
545 int pv_pit_handler(int port, int data, int write)
546 {
547 ioreq_t ioreq = {
548 .size = 1,
549 .type = IOREQ_TYPE_PIO,
550 .addr = port,
551 .dir = write ? IOREQ_WRITE : IOREQ_READ,
552 .data = data
553 };
555 if ( (current->domain->domain_id == 0) && dom0_pit_access(&ioreq) )
556 {
557 /* nothing to do */;
558 }
559 else
560 {
561 uint32_t val = data;
562 if ( port == 0x61 )
563 handle_speaker_io(ioreq.dir, port, 1, &val);
564 else
565 handle_pit_io(ioreq.dir, port, 1, &val);
566 ioreq.data = val;
567 }
569 return !write ? ioreq.data : 0;
570 }