ia64/xen-unstable

view xen/arch/x86/hvm/i8254.c @ 19823:82bbce59b65d

save/restore : Save guest's preferred TSC frequency in image

For save/restore or live migration between two different frequency
platforms, guest's preferred TSC frequency is required to caculate
guest's TSC after resotre, so save it in the image header.

Signed-off-by: Xiantao Zhang <xiantao.zhang@intel.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Jun 24 10:48:21 2009 +0100 (2009-06-24)
parents 71c15dfaa12b
children 50634c215234
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/time.h>
35 #include <asm/hvm/hvm.h>
36 #include <asm/hvm/io.h>
37 #include <asm/hvm/support.h>
38 #include <asm/hvm/vpt.h>
39 #include <asm/current.h>
41 #define domain_vpit(d) (&(d)->arch.hvm_domain.pl_time.vpit)
42 #define vcpu_vpit(vcpu) (domain_vpit((vcpu)->domain))
43 #define vpit_domain(pit) (container_of((pit), struct domain, \
44 arch.hvm_domain.pl_time.vpit))
45 #define vpit_vcpu(pit) (vpit_domain(pit)->vcpu[0])
47 #define RW_STATE_LSB 1
48 #define RW_STATE_MSB 2
49 #define RW_STATE_WORD0 3
50 #define RW_STATE_WORD1 4
52 static int handle_pit_io(
53 int dir, uint32_t port, uint32_t bytes, uint32_t *val);
54 static int handle_speaker_io(
55 int dir, uint32_t port, uint32_t bytes, uint32_t *val);
57 #define get_guest_time(v) \
58 (is_hvm_vcpu(v) ? hvm_get_guest_time(v) : (u64)get_s_time())
60 /* Compute with 96 bit intermediate result: (a*b)/c */
61 static uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c)
62 {
63 union {
64 uint64_t ll;
65 struct {
66 #ifdef WORDS_BIGENDIAN
67 uint32_t high, low;
68 #else
69 uint32_t low, high;
70 #endif
71 } l;
72 } u, res;
73 uint64_t rl, rh;
75 u.ll = a;
76 rl = (uint64_t)u.l.low * (uint64_t)b;
77 rh = (uint64_t)u.l.high * (uint64_t)b;
78 rh += (rl >> 32);
79 res.l.high = rh / c;
80 res.l.low = (((rh % c) << 32) + (rl & 0xffffffff)) / c;
81 return res.ll;
82 }
84 static int pit_get_count(PITState *pit, int channel)
85 {
86 uint64_t d;
87 int counter;
88 struct hvm_hw_pit_channel *c = &pit->hw.channels[channel];
89 struct vcpu *v = vpit_vcpu(pit);
91 ASSERT(spin_is_locked(&pit->lock));
93 d = muldiv64(get_guest_time(v) - pit->count_load_time[channel],
94 PIT_FREQ, SYSTEM_TIME_HZ);
96 switch ( c->mode )
97 {
98 case 0:
99 case 1:
100 case 4:
101 case 5:
102 counter = (c->count - d) & 0xffff;
103 break;
104 case 3:
105 /* XXX: may be incorrect for odd counts */
106 counter = c->count - ((2 * d) % c->count);
107 break;
108 default:
109 counter = c->count - (d % c->count);
110 break;
111 }
112 return counter;
113 }
115 static int pit_get_out(PITState *pit, int channel)
116 {
117 struct hvm_hw_pit_channel *s = &pit->hw.channels[channel];
118 uint64_t d;
119 int out;
120 struct vcpu *v = vpit_vcpu(pit);
122 ASSERT(spin_is_locked(&pit->lock));
124 d = muldiv64(get_guest_time(v) - pit->count_load_time[channel],
125 PIT_FREQ, SYSTEM_TIME_HZ);
127 switch ( s->mode )
128 {
129 default:
130 case 0:
131 out = (d >= s->count);
132 break;
133 case 1:
134 out = (d < s->count);
135 break;
136 case 2:
137 out = (((d % s->count) == 0) && (d != 0));
138 break;
139 case 3:
140 out = ((d % s->count) < ((s->count + 1) >> 1));
141 break;
142 case 4:
143 case 5:
144 out = (d == s->count);
145 break;
146 }
148 return out;
149 }
151 static void pit_set_gate(PITState *pit, int channel, int val)
152 {
153 struct hvm_hw_pit_channel *s = &pit->hw.channels[channel];
154 struct vcpu *v = vpit_vcpu(pit);
156 ASSERT(spin_is_locked(&pit->lock));
158 switch ( s->mode )
159 {
160 default:
161 case 0:
162 case 4:
163 /* XXX: just disable/enable counting */
164 break;
165 case 1:
166 case 5:
167 case 2:
168 case 3:
169 /* Restart counting on rising edge. */
170 if ( s->gate < val )
171 pit->count_load_time[channel] = get_guest_time(v);
172 break;
173 }
175 s->gate = val;
176 }
178 int pit_get_gate(PITState *pit, int channel)
179 {
180 ASSERT(spin_is_locked(&pit->lock));
181 return pit->hw.channels[channel].gate;
182 }
184 static void pit_time_fired(struct vcpu *v, void *priv)
185 {
186 uint64_t *count_load_time = priv;
187 *count_load_time = get_guest_time(v);
188 }
190 static void pit_load_count(PITState *pit, int channel, int val)
191 {
192 u32 period;
193 struct hvm_hw_pit_channel *s = &pit->hw.channels[channel];
194 struct vcpu *v = vpit_vcpu(pit);
196 ASSERT(spin_is_locked(&pit->lock));
198 if ( val == 0 )
199 val = 0x10000;
201 if ( v == NULL )
202 pit->count_load_time[channel] = 0;
203 else
204 pit->count_load_time[channel] = get_guest_time(v);
205 s->count = val;
206 period = DIV_ROUND(val * SYSTEM_TIME_HZ, PIT_FREQ);
208 if ( (v == NULL) || !is_hvm_vcpu(v) || (channel != 0) )
209 return;
211 switch ( s->mode )
212 {
213 case 2:
214 case 3:
215 /* Periodic timer. */
216 create_periodic_time(v, &pit->pt0, period, period, 0, pit_time_fired,
217 &pit->count_load_time[channel]);
218 break;
219 case 1:
220 case 4:
221 /* One-shot timer. */
222 create_periodic_time(v, &pit->pt0, period, 0, 0, pit_time_fired,
223 &pit->count_load_time[channel]);
224 break;
225 default:
226 destroy_periodic_time(&pit->pt0);
227 break;
228 }
229 }
231 static void pit_latch_count(PITState *pit, int channel)
232 {
233 struct hvm_hw_pit_channel *c = &pit->hw.channels[channel];
235 ASSERT(spin_is_locked(&pit->lock));
237 if ( !c->count_latched )
238 {
239 c->latched_count = pit_get_count(pit, channel);
240 c->count_latched = c->rw_mode;
241 }
242 }
244 static void pit_latch_status(PITState *pit, int channel)
245 {
246 struct hvm_hw_pit_channel *c = &pit->hw.channels[channel];
248 ASSERT(spin_is_locked(&pit->lock));
250 if ( !c->status_latched )
251 {
252 /* TODO: Return NULL COUNT (bit 6). */
253 c->status = ((pit_get_out(pit, channel) << 7) |
254 (c->rw_mode << 4) |
255 (c->mode << 1) |
256 c->bcd);
257 c->status_latched = 1;
258 }
259 }
261 static void pit_ioport_write(struct PITState *pit, uint32_t addr, uint32_t val)
262 {
263 int channel, access;
264 struct hvm_hw_pit_channel *s;
266 val &= 0xff;
267 addr &= 3;
269 spin_lock(&pit->lock);
271 if ( addr == 3 )
272 {
273 channel = val >> 6;
274 if ( channel == 3 )
275 {
276 /* Read-Back Command. */
277 for ( channel = 0; channel < 3; channel++ )
278 {
279 s = &pit->hw.channels[channel];
280 if ( val & (2 << channel) )
281 {
282 if ( !(val & 0x20) )
283 pit_latch_count(pit, channel);
284 if ( !(val & 0x10) )
285 pit_latch_status(pit, channel);
286 }
287 }
288 }
289 else
290 {
291 /* Select Counter <channel>. */
292 s = &pit->hw.channels[channel];
293 access = (val >> 4) & 3;
294 if ( access == 0 )
295 {
296 pit_latch_count(pit, channel);
297 }
298 else
299 {
300 s->rw_mode = access;
301 s->read_state = access;
302 s->write_state = access;
303 s->mode = (val >> 1) & 7;
304 if ( s->mode > 5 )
305 s->mode -= 4;
306 s->bcd = val & 1;
307 /* XXX: update irq timer ? */
308 }
309 }
310 }
311 else
312 {
313 /* Write Count. */
314 s = &pit->hw.channels[addr];
315 switch ( s->write_state )
316 {
317 default:
318 case RW_STATE_LSB:
319 pit_load_count(pit, addr, val);
320 break;
321 case RW_STATE_MSB:
322 pit_load_count(pit, addr, val << 8);
323 break;
324 case RW_STATE_WORD0:
325 s->write_latch = val;
326 s->write_state = RW_STATE_WORD1;
327 break;
328 case RW_STATE_WORD1:
329 pit_load_count(pit, addr, s->write_latch | (val << 8));
330 s->write_state = RW_STATE_WORD0;
331 break;
332 }
333 }
335 spin_unlock(&pit->lock);
336 }
338 static uint32_t pit_ioport_read(struct PITState *pit, uint32_t addr)
339 {
340 int ret, count;
341 struct hvm_hw_pit_channel *s;
343 addr &= 3;
344 s = &pit->hw.channels[addr];
346 spin_lock(&pit->lock);
348 if ( s->status_latched )
349 {
350 s->status_latched = 0;
351 ret = s->status;
352 }
353 else if ( s->count_latched )
354 {
355 switch ( s->count_latched )
356 {
357 default:
358 case RW_STATE_LSB:
359 ret = s->latched_count & 0xff;
360 s->count_latched = 0;
361 break;
362 case RW_STATE_MSB:
363 ret = s->latched_count >> 8;
364 s->count_latched = 0;
365 break;
366 case RW_STATE_WORD0:
367 ret = s->latched_count & 0xff;
368 s->count_latched = RW_STATE_MSB;
369 break;
370 }
371 }
372 else
373 {
374 switch ( s->read_state )
375 {
376 default:
377 case RW_STATE_LSB:
378 count = pit_get_count(pit, addr);
379 ret = count & 0xff;
380 break;
381 case RW_STATE_MSB:
382 count = pit_get_count(pit, addr);
383 ret = (count >> 8) & 0xff;
384 break;
385 case RW_STATE_WORD0:
386 count = pit_get_count(pit, addr);
387 ret = count & 0xff;
388 s->read_state = RW_STATE_WORD1;
389 break;
390 case RW_STATE_WORD1:
391 count = pit_get_count(pit, addr);
392 ret = (count >> 8) & 0xff;
393 s->read_state = RW_STATE_WORD0;
394 break;
395 }
396 }
398 spin_unlock(&pit->lock);
400 return ret;
401 }
403 void pit_stop_channel0_irq(PITState *pit)
404 {
405 spin_lock(&pit->lock);
406 destroy_periodic_time(&pit->pt0);
407 spin_unlock(&pit->lock);
408 }
410 static int pit_save(struct domain *d, hvm_domain_context_t *h)
411 {
412 PITState *pit = domain_vpit(d);
413 int rc;
415 spin_lock(&pit->lock);
417 rc = hvm_save_entry(PIT, 0, h, &pit->hw);
419 spin_unlock(&pit->lock);
421 return rc;
422 }
424 static int pit_load(struct domain *d, hvm_domain_context_t *h)
425 {
426 PITState *pit = domain_vpit(d);
427 int i;
429 spin_lock(&pit->lock);
431 if ( hvm_load_entry(PIT, h, &pit->hw) )
432 {
433 spin_unlock(&pit->lock);
434 return 1;
435 }
437 /*
438 * Recreate platform timers from hardware state. There will be some
439 * time jitter here, but the wall-clock will have jumped massively, so
440 * we hope the guest can handle it.
441 */
442 pit->pt0.last_plt_gtime = get_guest_time(d->vcpu[0]);
443 for ( i = 0; i < 3; i++ )
444 pit_load_count(pit, i, pit->hw.channels[i].count);
446 spin_unlock(&pit->lock);
448 return 0;
449 }
451 HVM_REGISTER_SAVE_RESTORE(PIT, pit_save, pit_load, 1, HVMSR_PER_DOM);
453 void pit_reset(struct domain *d)
454 {
455 PITState *pit = domain_vpit(d);
456 struct hvm_hw_pit_channel *s;
457 int i;
459 destroy_periodic_time(&pit->pt0);
460 pit->pt0.source = PTSRC_isa;
462 spin_lock(&pit->lock);
464 for ( i = 0; i < 3; i++ )
465 {
466 s = &pit->hw.channels[i];
467 s->mode = 0xff; /* the init mode */
468 s->gate = (i != 2);
469 pit_load_count(pit, i, 0);
470 }
472 spin_unlock(&pit->lock);
473 }
475 void pit_init(struct vcpu *v, unsigned long cpu_khz)
476 {
477 PITState *pit = vcpu_vpit(v);
479 spin_lock_init(&pit->lock);
481 register_portio_handler(v->domain, PIT_BASE, 4, handle_pit_io);
482 register_portio_handler(v->domain, 0x61, 1, handle_speaker_io);
484 pit_reset(v->domain);
485 }
487 void pit_deinit(struct domain *d)
488 {
489 PITState *pit = domain_vpit(d);
490 destroy_periodic_time(&pit->pt0);
491 }
493 /* the intercept action for PIT DM retval:0--not handled; 1--handled */
494 static int handle_pit_io(
495 int dir, uint32_t port, uint32_t bytes, uint32_t *val)
496 {
497 struct PITState *vpit = vcpu_vpit(current);
499 if ( bytes != 1 )
500 {
501 gdprintk(XENLOG_WARNING, "PIT bad access\n");
502 return X86EMUL_OKAY;
503 }
505 if ( dir == IOREQ_WRITE )
506 {
507 pit_ioport_write(vpit, port, *val);
508 }
509 else
510 {
511 if ( (port & 3) != 3 )
512 *val = pit_ioport_read(vpit, port);
513 else
514 gdprintk(XENLOG_WARNING, "PIT: read A1:A0=3!\n");
515 }
517 return X86EMUL_OKAY;
518 }
520 static void speaker_ioport_write(
521 struct PITState *pit, uint32_t addr, uint32_t val)
522 {
523 pit->hw.speaker_data_on = (val >> 1) & 1;
524 pit_set_gate(pit, 2, val & 1);
525 }
527 static uint32_t speaker_ioport_read(
528 struct PITState *pit, uint32_t addr)
529 {
530 /* Refresh clock toggles at about 15us. We approximate as 2^14ns. */
531 unsigned int refresh_clock = ((unsigned int)NOW() >> 14) & 1;
532 return ((pit->hw.speaker_data_on << 1) | pit_get_gate(pit, 2) |
533 (pit_get_out(pit, 2) << 5) | (refresh_clock << 4));
534 }
536 static int handle_speaker_io(
537 int dir, uint32_t port, uint32_t bytes, uint32_t *val)
538 {
539 struct PITState *vpit = vcpu_vpit(current);
541 BUG_ON(bytes != 1);
543 spin_lock(&vpit->lock);
545 if ( dir == IOREQ_WRITE )
546 speaker_ioport_write(vpit, port, *val);
547 else
548 *val = speaker_ioport_read(vpit, port);
550 spin_unlock(&vpit->lock);
552 return X86EMUL_OKAY;
553 }
555 int pv_pit_handler(int port, int data, int write)
556 {
557 ioreq_t ioreq = {
558 .size = 1,
559 .type = IOREQ_TYPE_PIO,
560 .addr = port,
561 .dir = write ? IOREQ_WRITE : IOREQ_READ,
562 .data = data
563 };
565 if ( (current->domain->domain_id == 0) && dom0_pit_access(&ioreq) )
566 {
567 /* nothing to do */;
568 }
569 else
570 {
571 uint32_t val = data;
572 if ( port == 0x61 )
573 handle_speaker_io(ioreq.dir, port, 1, &val);
574 else
575 handle_pit_io(ioreq.dir, port, 1, &val);
576 ioreq.data = val;
577 }
579 return !write ? ioreq.data : 0;
580 }