Coverage Report

Created: 2017-10-25 09:10

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