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 */
26
27 #include <xen/types.h>
28 #include <xen/mm.h>
29 #include <xen/xmalloc.h>
30 #include <xen/lib.h>
31 #include <xen/errno.h>
32 #include <xen/sched.h>
33 #include <xen/trace.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>
40
41 #define domain_vpit(x) (&(x)->arch.vpit)
42 #define vcpu_vpit(x) (domain_vpit((x)->domain))
43 #define vpit_domain(x) (container_of((x), struct domain, arch.vpit))
44 #define vpit_vcpu(x) (pt_global_vcpu_target(vpit_domain(x)))
45
46 #define RW_STATE_LSB 1
47 #define RW_STATE_MSB 2
48 #define RW_STATE_WORD0 3
49 #define RW_STATE_WORD1 4
50
51 static int handle_pit_io(
52 int dir, unsigned int port, unsigned int bytes, uint32_t *val);
53 static int handle_speaker_io(
54 int dir, unsigned int port, unsigned int bytes, uint32_t *val);
55
56 #define get_guest_time(v) \
57 (is_hvm_vcpu(v) ? hvm_get_guest_time(v) : (u64)get_s_time())
58
pit_get_count(PITState * pit,int channel)59 static int pit_get_count(PITState *pit, int channel)
60 {
61 uint64_t d;
62 int counter;
63 struct hvm_hw_pit_channel *c = &pit->hw.channels[channel];
64 struct vcpu *v = vpit_vcpu(pit);
65
66 ASSERT(spin_is_locked(&pit->lock));
67
68 d = muldiv64(get_guest_time(v) - pit->count_load_time[channel],
69 PIT_FREQ, SYSTEM_TIME_HZ);
70
71 switch ( c->mode )
72 {
73 case 0:
74 case 1:
75 case 4:
76 case 5:
77 counter = (c->count - d) & 0xffff;
78 break;
79 case 3:
80 /* XXX: may be incorrect for odd counts */
81 counter = c->count - ((2 * d) % c->count);
82 break;
83 default:
84 counter = c->count - (d % c->count);
85 break;
86 }
87 return counter;
88 }
89
pit_get_out(PITState * pit,int channel)90 static int pit_get_out(PITState *pit, int channel)
91 {
92 struct hvm_hw_pit_channel *s = &pit->hw.channels[channel];
93 uint64_t d;
94 int out;
95 struct vcpu *v = vpit_vcpu(pit);
96
97 ASSERT(spin_is_locked(&pit->lock));
98
99 d = muldiv64(get_guest_time(v) - pit->count_load_time[channel],
100 PIT_FREQ, SYSTEM_TIME_HZ);
101
102 switch ( s->mode )
103 {
104 default:
105 case 0:
106 out = (d >= s->count);
107 break;
108 case 1:
109 out = (d < s->count);
110 break;
111 case 2:
112 out = (((d % s->count) == 0) && (d != 0));
113 break;
114 case 3:
115 out = ((d % s->count) < ((s->count + 1) >> 1));
116 break;
117 case 4:
118 case 5:
119 out = (d == s->count);
120 break;
121 }
122
123 return out;
124 }
125
pit_set_gate(PITState * pit,int channel,int val)126 static void pit_set_gate(PITState *pit, int channel, int val)
127 {
128 struct hvm_hw_pit_channel *s = &pit->hw.channels[channel];
129 struct vcpu *v = vpit_vcpu(pit);
130
131 ASSERT(spin_is_locked(&pit->lock));
132
133 switch ( s->mode )
134 {
135 default:
136 case 0:
137 case 4:
138 /* XXX: just disable/enable counting */
139 break;
140 case 1:
141 case 5:
142 case 2:
143 case 3:
144 /* Restart counting on rising edge. */
145 if ( s->gate < val )
146 pit->count_load_time[channel] = get_guest_time(v);
147 break;
148 }
149
150 s->gate = val;
151 }
152
pit_get_gate(PITState * pit,int channel)153 static int pit_get_gate(PITState *pit, int channel)
154 {
155 ASSERT(spin_is_locked(&pit->lock));
156 return pit->hw.channels[channel].gate;
157 }
158
pit_time_fired(struct vcpu * v,void * priv)159 static void pit_time_fired(struct vcpu *v, void *priv)
160 {
161 uint64_t *count_load_time = priv;
162 TRACE_0D(TRC_HVM_EMUL_PIT_TIMER_CB);
163 *count_load_time = get_guest_time(v);
164 }
165
pit_load_count(PITState * pit,int channel,int val)166 static void pit_load_count(PITState *pit, int channel, int val)
167 {
168 u32 period;
169 struct hvm_hw_pit_channel *s = &pit->hw.channels[channel];
170 struct vcpu *v = vpit_vcpu(pit);
171
172 ASSERT(spin_is_locked(&pit->lock));
173
174 if ( val == 0 )
175 val = 0x10000;
176
177 if ( v == NULL )
178 pit->count_load_time[channel] = 0;
179 else
180 pit->count_load_time[channel] = get_guest_time(v);
181 s->count = val;
182 period = DIV_ROUND(val * SYSTEM_TIME_HZ, PIT_FREQ);
183
184 if ( (v == NULL) || !is_hvm_vcpu(v) || (channel != 0) )
185 return;
186
187 switch ( s->mode )
188 {
189 case 2:
190 case 3:
191 /* Periodic timer. */
192 TRACE_2D(TRC_HVM_EMUL_PIT_START_TIMER, period, period);
193 create_periodic_time(v, &pit->pt0, period, period, 0, pit_time_fired,
194 &pit->count_load_time[channel], false);
195 break;
196 case 1:
197 case 4:
198 /* One-shot timer. */
199 TRACE_2D(TRC_HVM_EMUL_PIT_START_TIMER, period, 0);
200 create_periodic_time(v, &pit->pt0, period, 0, 0, pit_time_fired,
201 &pit->count_load_time[channel], false);
202 break;
203 default:
204 TRACE_0D(TRC_HVM_EMUL_PIT_STOP_TIMER);
205 destroy_periodic_time(&pit->pt0);
206 break;
207 }
208 }
209
pit_latch_count(PITState * pit,int channel)210 static void pit_latch_count(PITState *pit, int channel)
211 {
212 struct hvm_hw_pit_channel *c = &pit->hw.channels[channel];
213
214 ASSERT(spin_is_locked(&pit->lock));
215
216 if ( !c->count_latched )
217 {
218 c->latched_count = pit_get_count(pit, channel);
219 c->count_latched = c->rw_mode;
220 }
221 }
222
pit_latch_status(PITState * pit,int channel)223 static void pit_latch_status(PITState *pit, int channel)
224 {
225 struct hvm_hw_pit_channel *c = &pit->hw.channels[channel];
226
227 ASSERT(spin_is_locked(&pit->lock));
228
229 if ( !c->status_latched )
230 {
231 /* TODO: Return NULL COUNT (bit 6). */
232 c->status = ((pit_get_out(pit, channel) << 7) |
233 (c->rw_mode << 4) |
234 (c->mode << 1) |
235 c->bcd);
236 c->status_latched = 1;
237 }
238 }
239
pit_ioport_write(struct PITState * pit,uint32_t addr,uint32_t val)240 static void pit_ioport_write(struct PITState *pit, uint32_t addr, uint32_t val)
241 {
242 int channel, access;
243 struct hvm_hw_pit_channel *s;
244
245 val &= 0xff;
246 addr &= 3;
247
248 spin_lock(&pit->lock);
249
250 if ( addr == 3 )
251 {
252 channel = val >> 6;
253 if ( channel == 3 )
254 {
255 /* Read-Back Command. */
256 for ( channel = 0; channel < 3; channel++ )
257 {
258 s = &pit->hw.channels[channel];
259 if ( val & (2 << channel) )
260 {
261 if ( !(val & 0x20) )
262 pit_latch_count(pit, channel);
263 if ( !(val & 0x10) )
264 pit_latch_status(pit, channel);
265 }
266 }
267 }
268 else
269 {
270 /* Select Counter <channel>. */
271 s = &pit->hw.channels[channel];
272 access = (val >> 4) & 3;
273 if ( access == 0 )
274 {
275 pit_latch_count(pit, channel);
276 }
277 else
278 {
279 s->rw_mode = access;
280 s->read_state = access;
281 s->write_state = access;
282 s->mode = (val >> 1) & 7;
283 if ( s->mode > 5 )
284 s->mode -= 4;
285 s->bcd = val & 1;
286 /* XXX: update irq timer ? */
287 }
288 }
289 }
290 else
291 {
292 /* Write Count. */
293 s = &pit->hw.channels[addr];
294 switch ( s->write_state )
295 {
296 default:
297 case RW_STATE_LSB:
298 pit_load_count(pit, addr, val);
299 break;
300 case RW_STATE_MSB:
301 pit_load_count(pit, addr, val << 8);
302 break;
303 case RW_STATE_WORD0:
304 s->write_latch = val;
305 s->write_state = RW_STATE_WORD1;
306 break;
307 case RW_STATE_WORD1:
308 pit_load_count(pit, addr, s->write_latch | (val << 8));
309 s->write_state = RW_STATE_WORD0;
310 break;
311 }
312 }
313
314 spin_unlock(&pit->lock);
315 }
316
pit_ioport_read(struct PITState * pit,uint32_t addr)317 static uint32_t pit_ioport_read(struct PITState *pit, uint32_t addr)
318 {
319 int ret, count;
320 struct hvm_hw_pit_channel *s;
321
322 addr &= 3;
323 s = &pit->hw.channels[addr];
324
325 spin_lock(&pit->lock);
326
327 if ( s->status_latched )
328 {
329 s->status_latched = 0;
330 ret = s->status;
331 }
332 else if ( s->count_latched )
333 {
334 switch ( s->count_latched )
335 {
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 }
351 else
352 {
353 switch ( s->read_state )
354 {
355 default:
356 case RW_STATE_LSB:
357 count = pit_get_count(pit, addr);
358 ret = count & 0xff;
359 break;
360 case RW_STATE_MSB:
361 count = pit_get_count(pit, addr);
362 ret = (count >> 8) & 0xff;
363 break;
364 case RW_STATE_WORD0:
365 count = pit_get_count(pit, addr);
366 ret = count & 0xff;
367 s->read_state = RW_STATE_WORD1;
368 break;
369 case RW_STATE_WORD1:
370 count = pit_get_count(pit, addr);
371 ret = (count >> 8) & 0xff;
372 s->read_state = RW_STATE_WORD0;
373 break;
374 }
375 }
376
377 spin_unlock(&pit->lock);
378
379 return ret;
380 }
381
382 #ifdef CONFIG_HVM
pit_stop_channel0_irq(PITState * pit)383 void pit_stop_channel0_irq(PITState *pit)
384 {
385 if ( !has_vpit(current->domain) )
386 return;
387
388 TRACE_0D(TRC_HVM_EMUL_PIT_STOP_TIMER);
389 spin_lock(&pit->lock);
390 destroy_periodic_time(&pit->pt0);
391 spin_unlock(&pit->lock);
392 }
393
pit_save(struct vcpu * v,hvm_domain_context_t * h)394 static int pit_save(struct vcpu *v, hvm_domain_context_t *h)
395 {
396 struct domain *d = v->domain;
397 PITState *pit = domain_vpit(d);
398 int rc;
399
400 if ( !has_vpit(d) )
401 return 0;
402
403 spin_lock(&pit->lock);
404
405 rc = hvm_save_entry(PIT, 0, h, &pit->hw);
406
407 spin_unlock(&pit->lock);
408
409 return rc;
410 }
411
pit_load(struct domain * d,hvm_domain_context_t * h)412 static int pit_load(struct domain *d, hvm_domain_context_t *h)
413 {
414 PITState *pit = domain_vpit(d);
415 int i;
416
417 if ( !has_vpit(d) )
418 return -ENODEV;
419
420 spin_lock(&pit->lock);
421
422 if ( hvm_load_entry(PIT, h, &pit->hw) )
423 {
424 spin_unlock(&pit->lock);
425 return 1;
426 }
427
428 /*
429 * Recreate platform timers from hardware state. There will be some
430 * time jitter here, but the wall-clock will have jumped massively, so
431 * we hope the guest can handle it.
432 */
433 pit->pt0.last_plt_gtime = get_guest_time(d->vcpu[0]);
434 for ( i = 0; i < 3; i++ )
435 pit_load_count(pit, i, pit->hw.channels[i].count);
436
437 spin_unlock(&pit->lock);
438
439 return 0;
440 }
441
442 HVM_REGISTER_SAVE_RESTORE(PIT, pit_save, pit_load, 1, HVMSR_PER_DOM);
443 #endif
444
pit_reset(struct domain * d)445 void pit_reset(struct domain *d)
446 {
447 PITState *pit = domain_vpit(d);
448 struct hvm_hw_pit_channel *s;
449 int i;
450
451 if ( !has_vpit(d) )
452 return;
453
454 if ( is_hvm_domain(d) )
455 {
456 TRACE_0D(TRC_HVM_EMUL_PIT_STOP_TIMER);
457 destroy_periodic_time(&pit->pt0);
458 pit->pt0.source = PTSRC_isa;
459 }
460
461 spin_lock(&pit->lock);
462
463 for ( i = 0; i < 3; i++ )
464 {
465 s = &pit->hw.channels[i];
466 s->mode = 0xff; /* the init mode */
467 s->gate = (i != 2);
468 pit_load_count(pit, i, 0);
469 }
470
471 spin_unlock(&pit->lock);
472 }
473
pit_init(struct domain * d,unsigned long cpu_khz)474 void pit_init(struct domain *d, unsigned long cpu_khz)
475 {
476 PITState *pit = domain_vpit(d);
477
478 if ( !has_vpit(d) )
479 return;
480
481 spin_lock_init(&pit->lock);
482
483 if ( is_hvm_domain(d) )
484 {
485 register_portio_handler(d, PIT_BASE, 4, handle_pit_io);
486 register_portio_handler(d, 0x61, 1, handle_speaker_io);
487 }
488
489 pit_reset(d);
490 }
491
pit_deinit(struct domain * d)492 void pit_deinit(struct domain *d)
493 {
494 PITState *pit = domain_vpit(d);
495
496 if ( !has_vpit(d) )
497 return;
498
499 if ( is_hvm_domain(d) )
500 {
501 TRACE_0D(TRC_HVM_EMUL_PIT_STOP_TIMER);
502 destroy_periodic_time(&pit->pt0);
503 }
504 }
505
506 /* the intercept action for PIT DM retval:0--not handled; 1--handled */
handle_pit_io(int dir,unsigned int port,unsigned int bytes,uint32_t * val)507 static int handle_pit_io(
508 int dir, unsigned int port, unsigned int bytes, uint32_t *val)
509 {
510 struct PITState *vpit = vcpu_vpit(current);
511
512 if ( bytes != 1 )
513 {
514 gdprintk(XENLOG_WARNING, "PIT bad access\n");
515 *val = ~0;
516 return X86EMUL_OKAY;
517 }
518
519 if ( dir == IOREQ_WRITE )
520 {
521 pit_ioport_write(vpit, port, *val);
522 }
523 else
524 {
525 if ( (port & 3) != 3 )
526 *val = pit_ioport_read(vpit, port);
527 else
528 gdprintk(XENLOG_WARNING, "PIT: read A1:A0=3!\n");
529 }
530
531 return X86EMUL_OKAY;
532 }
533
speaker_ioport_write(struct PITState * pit,uint32_t addr,uint32_t val)534 static void speaker_ioport_write(
535 struct PITState *pit, uint32_t addr, uint32_t val)
536 {
537 pit->hw.speaker_data_on = (val >> 1) & 1;
538 pit_set_gate(pit, 2, val & 1);
539 }
540
speaker_ioport_read(struct PITState * pit,uint32_t addr)541 static uint32_t speaker_ioport_read(
542 struct PITState *pit, uint32_t addr)
543 {
544 /* Refresh clock toggles at about 15us. We approximate as 2^14ns. */
545 unsigned int refresh_clock = ((unsigned int)NOW() >> 14) & 1;
546 return ((pit->hw.speaker_data_on << 1) | pit_get_gate(pit, 2) |
547 (pit_get_out(pit, 2) << 5) | (refresh_clock << 4));
548 }
549
handle_speaker_io(int dir,unsigned int port,uint32_t bytes,uint32_t * val)550 static int handle_speaker_io(
551 int dir, unsigned int port, uint32_t bytes, uint32_t *val)
552 {
553 struct PITState *vpit = vcpu_vpit(current);
554
555 BUG_ON(bytes != 1);
556
557 spin_lock(&vpit->lock);
558
559 if ( dir == IOREQ_WRITE )
560 speaker_ioport_write(vpit, port, *val);
561 else
562 *val = speaker_ioport_read(vpit, port);
563
564 spin_unlock(&vpit->lock);
565
566 return X86EMUL_OKAY;
567 }
568
pv_pit_handler(int port,int data,int write)569 int pv_pit_handler(int port, int data, int write)
570 {
571 ioreq_t ioreq = {
572 .size = 1,
573 .type = IOREQ_TYPE_PIO,
574 .addr = port,
575 .dir = write ? IOREQ_WRITE : IOREQ_READ,
576 .data = data
577 };
578
579 if ( !has_vpit(current->domain) )
580 return ~0;
581
582 if ( is_hardware_domain(current->domain) && hwdom_pit_access(&ioreq) )
583 {
584 /* nothing to do */;
585 }
586 else
587 {
588 uint32_t val = data;
589 if ( port == 0x61 )
590 handle_speaker_io(ioreq.dir, port, 1, &val);
591 else
592 handle_pit_io(ioreq.dir, port, 1, &val);
593 ioreq.data = val;
594 }
595
596 return !write ? ioreq.data : 0;
597 }
598
599 /*
600 * Local variables:
601 * mode: C
602 * c-file-style: "BSD"
603 * c-basic-offset: 4
604 * indent-tabs-mode: nil
605 * End:
606 */
607