Coverage Report

Created: 2017-10-25 09:10

/root/src/xen/xen/arch/x86/hvm/vioapic.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 *  Copyright (C) 2001  MandrakeSoft S.A.
3
 *
4
 *    MandrakeSoft S.A.
5
 *    43, rue d'Aboukir
6
 *    75002 Paris - France
7
 *    http://www.linux-mandrake.com/
8
 *    http://www.mandrakesoft.com/
9
 *
10
 *  This library is free software; you can redistribute it and/or
11
 *  modify it under the terms of the GNU Lesser General Public
12
 *  License as published by the Free Software Foundation; either
13
 *  version 2 of the License, or (at your option) any later version.
14
 *
15
 *  This library is distributed in the hope that it will be useful,
16
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18
 *  Lesser General Public License for more details.
19
 *
20
 *  You should have received a copy of the GNU Lesser General Public
21
 *  License along with this library; If not, see <http://www.gnu.org/licenses/>.
22
 *
23
 *  Yunhong Jiang <yunhong.jiang@intel.com>
24
 *  Ported to xen by using virtual IRQ line.
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 <public/hvm/ioreq.h>
34
#include <asm/hvm/io.h>
35
#include <asm/hvm/vpic.h>
36
#include <asm/hvm/vlapic.h>
37
#include <asm/hvm/support.h>
38
#include <asm/current.h>
39
#include <asm/event.h>
40
#include <asm/io_apic.h>
41
42
/* HACK: Route IRQ0 only to VCPU0 to prevent time jumps. */
43
#define IRQ0_SPECIAL_ROUTING 1
44
45
static void vioapic_deliver(struct hvm_vioapic *vioapic, unsigned int irq);
46
47
static struct hvm_vioapic *addr_vioapic(const struct domain *d,
48
                                        unsigned long addr)
49
487k
{
50
487k
    unsigned int i;
51
487k
52
1.45M
    for ( i = 0; i < d->arch.hvm_domain.nr_vioapics; i++ )
53
970k
    {
54
970k
        struct hvm_vioapic *vioapic = domain_vioapic(d, i);
55
970k
56
970k
        if ( addr >= vioapic->base_address &&
57
26.4k
             addr < vioapic->base_address + VIOAPIC_MEM_LENGTH )
58
6.36k
            return vioapic;
59
970k
    }
60
487k
61
481k
    return NULL;
62
487k
}
63
64
static struct hvm_vioapic *gsi_vioapic(const struct domain *d,
65
                                       unsigned int gsi, unsigned int *pin)
66
309
{
67
309
    unsigned int i;
68
309
69
309
    for ( i = 0; i < d->arch.hvm_domain.nr_vioapics; i++ )
70
309
    {
71
309
        struct hvm_vioapic *vioapic = domain_vioapic(d, i);
72
309
73
309
        if ( gsi >= vioapic->base_gsi &&
74
309
             gsi < vioapic->base_gsi + vioapic->nr_pins )
75
309
        {
76
309
            *pin = gsi - vioapic->base_gsi;
77
309
            return vioapic;
78
309
        }
79
309
    }
80
309
81
0
    return NULL;
82
309
}
83
84
static uint32_t vioapic_read_indirect(const struct hvm_vioapic *vioapic)
85
118
{
86
118
    uint32_t result = 0;
87
118
88
118
    switch ( vioapic->ioregsel )
89
118
    {
90
4
    case VIOAPIC_REG_VERSION:
91
4
        result = ((union IO_APIC_reg_01){
92
4
                  .bits = { .version = VIOAPIC_VERSION_ID,
93
4
                            .entries = vioapic->nr_pins - 1 }
94
4
                  }).raw;
95
4
        break;
96
4
97
2
    case VIOAPIC_REG_APIC_ID:
98
2
        /*
99
2
         * Using union IO_APIC_reg_02 for the ID register too, as
100
2
         * union IO_APIC_reg_00's ID field is 8 bits wide for some reason.
101
2
         */
102
2
    case VIOAPIC_REG_ARB_ID:
103
2
        result = ((union IO_APIC_reg_02){
104
2
                  .bits = { .arbitration = vioapic->id }
105
2
                  }).raw;
106
2
        break;
107
2
108
112
    default:
109
112
    {
110
112
        uint32_t redir_index = (vioapic->ioregsel - VIOAPIC_REG_RTE0) >> 1;
111
112
        uint64_t redir_content;
112
112
113
112
        if ( redir_index >= vioapic->nr_pins )
114
0
        {
115
0
            gdprintk(XENLOG_WARNING, "apic_mem_readl:undefined ioregsel %x\n",
116
0
                     vioapic->ioregsel);
117
0
            break;
118
0
        }
119
112
120
112
        redir_content = vioapic->redirtbl[redir_index].bits;
121
17
        result = (vioapic->ioregsel & 1) ? (redir_content >> 32)
122
95
                                         : redir_content;
123
112
        break;
124
112
    }
125
118
    }
126
118
127
118
    return result;
128
118
}
129
130
static int vioapic_read(
131
    struct vcpu *v, unsigned long addr,
132
    unsigned int length, unsigned long *pval)
133
118
{
134
118
    const struct hvm_vioapic *vioapic;
135
118
    uint32_t result;
136
118
137
118
    HVM_DBG_LOG(DBG_LEVEL_IOAPIC, "addr %lx", addr);
138
118
139
118
    vioapic = addr_vioapic(v->domain, addr);
140
118
    ASSERT(vioapic);
141
118
142
118
    switch ( addr & 0xff )
143
118
    {
144
0
    case VIOAPIC_REG_SELECT:
145
0
        result = vioapic->ioregsel;
146
0
        break;
147
0
148
118
    case VIOAPIC_REG_WINDOW:
149
118
        result = vioapic_read_indirect(vioapic);
150
118
        break;
151
0
152
0
    default:
153
0
        result = 0;
154
0
        break;
155
118
    }
156
118
157
118
    *pval = result;
158
118
    return X86EMUL_OKAY;
159
118
}
160
161
static int vioapic_hwdom_map_gsi(unsigned int gsi, unsigned int trig,
162
                                 unsigned int pol)
163
301
{
164
301
    struct domain *currd = current->domain;
165
301
    struct xen_domctl_bind_pt_irq pt_irq_bind = {
166
301
        .irq_type = PT_IRQ_TYPE_PCI,
167
301
        .machine_irq = gsi,
168
301
    };
169
301
    int ret, pirq = gsi;
170
301
171
301
    ASSERT(is_hardware_domain(currd));
172
301
173
301
    /* Interrupt has been unmasked, bind it now. */
174
301
    ret = mp_register_gsi(gsi, trig, pol);
175
301
    if ( ret == -EEXIST )
176
295
        return 0;
177
6
    if ( ret )
178
0
    {
179
0
        gprintk(XENLOG_WARNING, "vioapic: error registering GSI %u: %d\n",
180
0
                 gsi, ret);
181
0
        return ret;
182
0
    }
183
6
184
6
    ret = allocate_and_map_gsi_pirq(currd, pirq, &pirq);
185
6
    if ( ret )
186
0
    {
187
0
        gprintk(XENLOG_WARNING, "vioapic: error mapping GSI %u: %d\n",
188
0
                 gsi, ret);
189
0
        return ret;
190
0
    }
191
6
192
6
    pcidevs_lock();
193
6
    ret = pt_irq_create_bind(currd, &pt_irq_bind);
194
6
    if ( ret )
195
0
    {
196
0
        gprintk(XENLOG_WARNING, "vioapic: error binding GSI %u: %d\n",
197
0
                gsi, ret);
198
0
        spin_lock(&currd->event_lock);
199
0
        unmap_domain_pirq(currd, pirq);
200
0
        spin_unlock(&currd->event_lock);
201
0
    }
202
6
    pcidevs_unlock();
203
6
204
6
    return ret;
205
6
}
206
207
static void vioapic_write_redirent(
208
    struct hvm_vioapic *vioapic, unsigned int idx,
209
    int top_word, uint32_t val)
210
678
{
211
678
    struct domain *d = vioapic_domain(vioapic);
212
678
    struct hvm_irq *hvm_irq = hvm_domain_irq(d);
213
678
    union vioapic_redir_entry *pent, ent;
214
678
    int unmasked = 0;
215
678
    unsigned int gsi = vioapic->base_gsi + idx;
216
678
217
678
    spin_lock(&d->arch.hvm_domain.irq_lock);
218
678
219
678
    pent = &vioapic->redirtbl[idx];
220
678
    ent  = *pent;
221
678
222
678
    if ( top_word )
223
17
    {
224
17
        /* Contains only the dest_id. */
225
17
        ent.bits = (uint32_t)ent.bits | ((uint64_t)val << 32);
226
17
    }
227
678
    else
228
661
    {
229
661
        unmasked = ent.fields.mask;
230
661
        /* Remote IRR and Delivery Status are read-only. */
231
661
        ent.bits = ((ent.bits >> 32) << 32) | val;
232
661
        ent.fields.delivery_status = 0;
233
661
        ent.fields.remote_irr = pent->fields.remote_irr;
234
357
        unmasked = unmasked && !ent.fields.mask;
235
661
    }
236
678
237
678
    *pent = ent;
238
678
239
678
    if ( is_hardware_domain(d) && unmasked )
240
301
    {
241
301
        int ret;
242
301
243
301
        ret = vioapic_hwdom_map_gsi(gsi, ent.fields.trig_mode,
244
301
                                    ent.fields.polarity);
245
301
        if ( ret )
246
0
        {
247
0
            /* Mask the entry again. */
248
0
            pent->fields.mask = 1;
249
0
            unmasked = 0;
250
0
        }
251
301
    }
252
678
253
678
    if ( gsi == 0 )
254
3
    {
255
3
        vlapic_adjust_i8259_target(d);
256
3
    }
257
675
    else if ( ent.fields.trig_mode == VIOAPIC_EDGE_TRIG )
258
77
        pent->fields.remote_irr = 0;
259
598
    else if ( !ent.fields.mask &&
260
299
              !ent.fields.remote_irr &&
261
299
              hvm_irq->gsi_assert_count[idx] )
262
0
    {
263
0
        pent->fields.remote_irr = 1;
264
0
        vioapic_deliver(vioapic, idx);
265
0
    }
266
678
267
678
    spin_unlock(&d->arch.hvm_domain.irq_lock);
268
678
269
678
    if ( gsi == 0 || unmasked )
270
304
        pt_may_unmask_irq(d, NULL);
271
678
}
272
273
static void vioapic_write_indirect(
274
    struct hvm_vioapic *vioapic, uint32_t val)
275
678
{
276
678
    switch ( vioapic->ioregsel )
277
678
    {
278
0
    case VIOAPIC_REG_VERSION:
279
0
        /* Writes are ignored. */
280
0
        break;
281
0
282
0
    case VIOAPIC_REG_APIC_ID:
283
0
        /*
284
0
         * Presumably because we emulate an Intel IOAPIC which only has a
285
0
         * 4 bit ID field (compared to 8 for AMD), using union IO_APIC_reg_02
286
0
         * for the ID register (union IO_APIC_reg_00's ID field is 8 bits).
287
0
         */
288
0
        vioapic->id = ((union IO_APIC_reg_02){ .raw = val }).bits.arbitration;
289
0
        break;
290
0
291
0
    case VIOAPIC_REG_ARB_ID:
292
0
        break;
293
0
294
678
    default:
295
678
    {
296
678
        uint32_t redir_index = (vioapic->ioregsel - VIOAPIC_REG_RTE0) >> 1;
297
678
298
678
        HVM_DBG_LOG(DBG_LEVEL_IOAPIC, "rte[%02x].%s = %08x",
299
678
                    redir_index, vioapic->ioregsel & 1 ? "hi" : "lo", val);
300
678
301
678
        if ( redir_index >= vioapic->nr_pins )
302
0
        {
303
0
            gdprintk(XENLOG_WARNING, "vioapic_write_indirect "
304
0
                     "error register %x\n", vioapic->ioregsel);
305
0
            break;
306
0
        }
307
678
308
678
        vioapic_write_redirent(
309
678
            vioapic, redir_index, vioapic->ioregsel&1, val);
310
678
        break;
311
678
    }
312
678
    }
313
678
}
314
315
static int vioapic_write(
316
    struct vcpu *v, unsigned long addr,
317
    unsigned int length, unsigned long val)
318
1.47k
{
319
1.47k
    struct hvm_vioapic *vioapic;
320
1.47k
321
1.47k
    vioapic = addr_vioapic(v->domain, addr);
322
1.47k
    ASSERT(vioapic);
323
1.47k
324
1.47k
    switch ( addr & 0xff )
325
1.47k
    {
326
796
    case VIOAPIC_REG_SELECT:
327
796
        vioapic->ioregsel = val;
328
796
        break;
329
796
330
678
    case VIOAPIC_REG_WINDOW:
331
678
        vioapic_write_indirect(vioapic, val);
332
678
        break;
333
796
334
796
#if VIOAPIC_VERSION_ID >= 0x20
335
    case VIOAPIC_REG_EOI:
336
        vioapic_update_EOI(v->domain, val);
337
        break;
338
#endif
339
796
340
0
    default:
341
0
        break;
342
1.47k
    }
343
1.47k
344
1.47k
    return X86EMUL_OKAY;
345
1.47k
}
346
347
static int vioapic_range(struct vcpu *v, unsigned long addr)
348
486k
{
349
486k
    return !!addr_vioapic(v->domain, addr);
350
486k
}
351
352
static const struct hvm_mmio_ops vioapic_mmio_ops = {
353
    .check = vioapic_range,
354
    .read = vioapic_read,
355
    .write = vioapic_write
356
};
357
358
static void ioapic_inj_irq(
359
    struct hvm_vioapic *vioapic,
360
    struct vlapic *target,
361
    uint8_t vector,
362
    uint8_t trig_mode,
363
    uint8_t delivery_mode)
364
297
{
365
297
    HVM_DBG_LOG(DBG_LEVEL_IOAPIC, "irq %d trig %d deliv %d",
366
297
                vector, trig_mode, delivery_mode);
367
297
368
297
    ASSERT((delivery_mode == dest_Fixed) ||
369
297
           (delivery_mode == dest_LowestPrio));
370
297
371
297
    vlapic_set_irq(target, vector, trig_mode);
372
297
}
373
374
static inline int pit_channel0_enabled(void)
375
0
{
376
0
    return pt_active(&current->domain->arch.vpit.pt0);
377
0
}
378
379
static void vioapic_deliver(struct hvm_vioapic *vioapic, unsigned int pin)
380
297
{
381
297
    uint16_t dest = vioapic->redirtbl[pin].fields.dest_id;
382
297
    uint8_t dest_mode = vioapic->redirtbl[pin].fields.dest_mode;
383
297
    uint8_t delivery_mode = vioapic->redirtbl[pin].fields.delivery_mode;
384
297
    uint8_t vector = vioapic->redirtbl[pin].fields.vector;
385
297
    uint8_t trig_mode = vioapic->redirtbl[pin].fields.trig_mode;
386
297
    struct domain *d = vioapic_domain(vioapic);
387
297
    struct vlapic *target;
388
297
    struct vcpu *v;
389
297
    unsigned int irq = vioapic->base_gsi + pin;
390
297
391
297
    ASSERT(spin_is_locked(&d->arch.hvm_domain.irq_lock));
392
297
393
297
    HVM_DBG_LOG(DBG_LEVEL_IOAPIC,
394
297
                "dest=%x dest_mode=%x delivery_mode=%x "
395
297
                "vector=%x trig_mode=%x",
396
297
                dest, dest_mode, delivery_mode, vector, trig_mode);
397
297
398
297
    switch ( delivery_mode )
399
297
    {
400
0
    case dest_LowestPrio:
401
0
    {
402
0
#ifdef IRQ0_SPECIAL_ROUTING
403
0
        /* Force round-robin to pick VCPU 0 */
404
0
        if ( (irq == hvm_isa_irq_to_gsi(0)) && pit_channel0_enabled() )
405
0
        {
406
0
            v = d->vcpu ? d->vcpu[0] : NULL;
407
0
            target = v ? vcpu_vlapic(v) : NULL;
408
0
        }
409
0
        else
410
0
#endif
411
0
            target = vlapic_lowest_prio(d, NULL, 0, dest, dest_mode);
412
0
        if ( target != NULL )
413
0
        {
414
0
            ioapic_inj_irq(vioapic, target, vector, trig_mode, delivery_mode);
415
0
        }
416
0
        else
417
0
        {
418
0
            HVM_DBG_LOG(DBG_LEVEL_IOAPIC, "null round robin: "
419
0
                        "vector=%x delivery_mode=%x",
420
0
                        vector, dest_LowestPrio);
421
0
        }
422
0
        break;
423
0
    }
424
0
425
297
    case dest_Fixed:
426
297
    {
427
297
#ifdef IRQ0_SPECIAL_ROUTING
428
297
        /* Do not deliver timer interrupts to VCPU != 0 */
429
297
        if ( (irq == hvm_isa_irq_to_gsi(0)) && pit_channel0_enabled() )
430
0
        {
431
0
            if ( (v = d->vcpu ? d->vcpu[0] : NULL) != NULL )
432
0
                ioapic_inj_irq(vioapic, vcpu_vlapic(v), vector,
433
0
                               trig_mode, delivery_mode);
434
0
        }
435
297
        else
436
297
#endif
437
297
        {
438
297
            for_each_vcpu ( d, v )
439
3.56k
                if ( vlapic_match_dest(vcpu_vlapic(v), NULL,
440
3.56k
                                       0, dest, dest_mode) )
441
297
                    ioapic_inj_irq(vioapic, vcpu_vlapic(v), vector,
442
297
                                   trig_mode, delivery_mode);
443
297
        }
444
297
        break;
445
0
    }
446
0
447
0
    case dest_NMI:
448
0
    {
449
0
        for_each_vcpu ( d, v )
450
0
            if ( vlapic_match_dest(vcpu_vlapic(v), NULL,
451
0
                                   0, dest, dest_mode) &&
452
0
                 !test_and_set_bool(v->nmi_pending) )
453
0
                vcpu_kick(v);
454
0
        break;
455
0
    }
456
0
457
0
    default:
458
0
        gdprintk(XENLOG_WARNING, "Unsupported delivery mode %d\n",
459
0
                 delivery_mode);
460
0
        break;
461
297
    }
462
297
}
463
464
void vioapic_irq_positive_edge(struct domain *d, unsigned int irq)
465
297
{
466
297
    unsigned int pin;
467
297
    struct hvm_vioapic *vioapic = gsi_vioapic(d, irq, &pin);
468
297
    union vioapic_redir_entry *ent;
469
297
470
297
    if ( !vioapic )
471
0
    {
472
0
        ASSERT_UNREACHABLE();
473
0
        return;
474
0
    }
475
297
476
297
    HVM_DBG_LOG(DBG_LEVEL_IOAPIC, "irq %x", irq);
477
297
478
297
    ASSERT(pin < vioapic->nr_pins);
479
297
    ASSERT(spin_is_locked(&d->arch.hvm_domain.irq_lock));
480
297
481
297
    ent = &vioapic->redirtbl[pin];
482
297
    if ( ent->fields.mask )
483
0
        return;
484
297
485
297
    if ( ent->fields.trig_mode == VIOAPIC_EDGE_TRIG )
486
1
    {
487
1
        vioapic_deliver(vioapic, pin);
488
1
    }
489
296
    else if ( !ent->fields.remote_irr )
490
296
    {
491
296
        ent->fields.remote_irr = 1;
492
296
        vioapic_deliver(vioapic, pin);
493
296
    }
494
297
}
495
496
void vioapic_update_EOI(struct domain *d, u8 vector)
497
296
{
498
296
    struct hvm_irq *hvm_irq = hvm_domain_irq(d);
499
296
    union vioapic_redir_entry *ent;
500
296
    unsigned int i;
501
296
502
296
    ASSERT(has_vioapic(d));
503
296
504
296
    spin_lock(&d->arch.hvm_domain.irq_lock);
505
296
506
888
    for ( i = 0; i < d->arch.hvm_domain.nr_vioapics; i++ )
507
592
    {
508
592
        struct hvm_vioapic *vioapic = domain_vioapic(d, i);
509
592
        unsigned int pin;
510
592
511
14.8k
        for ( pin = 0; pin < vioapic->nr_pins; pin++ )
512
14.2k
        {
513
14.2k
            ent = &vioapic->redirtbl[pin];
514
14.2k
            if ( ent->fields.vector != vector )
515
13.5k
                continue;
516
14.2k
517
650
            ent->fields.remote_irr = 0;
518
650
519
650
            if ( iommu_enabled )
520
650
            {
521
650
                spin_unlock(&d->arch.hvm_domain.irq_lock);
522
650
                hvm_dpci_eoi(d, vioapic->base_gsi + pin, ent);
523
650
                spin_lock(&d->arch.hvm_domain.irq_lock);
524
650
            }
525
650
526
650
            if ( (ent->fields.trig_mode == VIOAPIC_LEVEL_TRIG) &&
527
532
                 !ent->fields.mask &&
528
237
                 hvm_irq->gsi_assert_count[vioapic->base_gsi + pin] )
529
0
            {
530
0
                ent->fields.remote_irr = 1;
531
0
                vioapic_deliver(vioapic, pin);
532
0
            }
533
650
        }
534
592
    }
535
296
536
296
    spin_unlock(&d->arch.hvm_domain.irq_lock);
537
296
}
538
539
int vioapic_get_mask(const struct domain *d, unsigned int gsi)
540
6
{
541
6
    unsigned int pin;
542
6
    const struct hvm_vioapic *vioapic = gsi_vioapic(d, gsi, &pin);
543
6
544
6
    if ( !vioapic )
545
0
        return -EINVAL;
546
6
547
6
    return vioapic->redirtbl[pin].fields.mask;
548
6
}
549
550
int vioapic_get_vector(const struct domain *d, unsigned int gsi)
551
0
{
552
0
    unsigned int pin;
553
0
    const struct hvm_vioapic *vioapic = gsi_vioapic(d, gsi, &pin);
554
0
555
0
    if ( !vioapic )
556
0
        return -EINVAL;
557
0
558
0
    return vioapic->redirtbl[pin].fields.vector;
559
0
}
560
561
int vioapic_get_trigger_mode(const struct domain *d, unsigned int gsi)
562
6
{
563
6
    unsigned int pin;
564
6
    const struct hvm_vioapic *vioapic = gsi_vioapic(d, gsi, &pin);
565
6
566
6
    if ( !vioapic )
567
0
        return -EINVAL;
568
6
569
6
    return vioapic->redirtbl[pin].fields.trig_mode;
570
6
}
571
572
static int ioapic_save(struct domain *d, hvm_domain_context_t *h)
573
0
{
574
0
    struct hvm_vioapic *s;
575
0
576
0
    if ( !has_vioapic(d) )
577
0
        return 0;
578
0
579
0
    s = domain_vioapic(d, 0);
580
0
581
0
    if ( s->nr_pins != ARRAY_SIZE(s->domU.redirtbl) ||
582
0
         d->arch.hvm_domain.nr_vioapics != 1 )
583
0
        return -EOPNOTSUPP;
584
0
585
0
    return hvm_save_entry(IOAPIC, 0, h, &s->domU);
586
0
}
587
588
static int ioapic_load(struct domain *d, hvm_domain_context_t *h)
589
0
{
590
0
    struct hvm_vioapic *s;
591
0
592
0
    if ( !has_vioapic(d) )
593
0
        return -ENODEV;
594
0
595
0
    s = domain_vioapic(d, 0);
596
0
597
0
    if ( s->nr_pins != ARRAY_SIZE(s->domU.redirtbl) ||
598
0
         d->arch.hvm_domain.nr_vioapics != 1 )
599
0
        return -EOPNOTSUPP;
600
0
601
0
    return hvm_load_entry(IOAPIC, h, &s->domU);
602
0
}
603
604
HVM_REGISTER_SAVE_RESTORE(IOAPIC, ioapic_save, ioapic_load, 1, HVMSR_PER_DOM);
605
606
void vioapic_reset(struct domain *d)
607
1
{
608
1
    unsigned int i;
609
1
610
1
    if ( !has_vioapic(d) )
611
0
    {
612
0
        ASSERT(!d->arch.hvm_domain.nr_vioapics);
613
0
        return;
614
0
    }
615
1
616
3
    for ( i = 0; i < d->arch.hvm_domain.nr_vioapics; i++ )
617
2
    {
618
2
        struct hvm_vioapic *vioapic = domain_vioapic(d, i);
619
2
        unsigned int nr_pins = vioapic->nr_pins, base_gsi = vioapic->base_gsi;
620
2
        unsigned int pin;
621
2
622
2
        memset(vioapic, 0, hvm_vioapic_size(nr_pins));
623
50
        for ( pin = 0; pin < nr_pins; pin++ )
624
48
            vioapic->redirtbl[pin].fields.mask = 1;
625
2
626
2
        if ( !is_hardware_domain(d) )
627
0
        {
628
0
            ASSERT(!i && !base_gsi);
629
0
            vioapic->base_address = VIOAPIC_DEFAULT_BASE_ADDRESS;
630
0
            vioapic->id = 0;
631
0
        }
632
2
        else
633
2
        {
634
2
            vioapic->base_address = mp_ioapics[i].mpc_apicaddr;
635
2
            vioapic->id = mp_ioapics[i].mpc_apicid;
636
2
        }
637
2
        vioapic->base_gsi = base_gsi;
638
2
        vioapic->nr_pins = nr_pins;
639
2
        vioapic->domain = d;
640
2
    }
641
1
}
642
643
static void vioapic_free(const struct domain *d, unsigned int nr_vioapics)
644
0
{
645
0
    unsigned int i;
646
0
647
0
    for ( i = 0; i < nr_vioapics; i++)
648
0
        xfree(domain_vioapic(d, i));
649
0
    xfree(d->arch.hvm_domain.vioapic);
650
0
}
651
652
int vioapic_init(struct domain *d)
653
1
{
654
1
    unsigned int i, nr_vioapics, nr_gsis = 0;
655
1
656
1
    if ( !has_vioapic(d) )
657
0
    {
658
0
        ASSERT(!d->arch.hvm_domain.nr_vioapics);
659
0
        return 0;
660
0
    }
661
1
662
1
    nr_vioapics = is_hardware_domain(d) ? nr_ioapics : 1;
663
1
664
1
    if ( (d->arch.hvm_domain.vioapic == NULL) &&
665
1
         ((d->arch.hvm_domain.vioapic =
666
1
           xzalloc_array(struct hvm_vioapic *, nr_vioapics)) == NULL) )
667
0
        return -ENOMEM;
668
1
669
3
    for ( i = 0; i < nr_vioapics; i++ )
670
2
    {
671
2
        unsigned int nr_pins, base_gsi;
672
2
673
2
        if ( is_hardware_domain(d) )
674
2
        {
675
2
            nr_pins = nr_ioapic_entries[i];
676
2
            base_gsi = io_apic_gsi_base(i);
677
2
        }
678
2
        else
679
0
        {
680
0
            nr_pins = ARRAY_SIZE(domain_vioapic(d, 0)->domU.redirtbl);
681
0
            base_gsi = 0;
682
0
        }
683
2
684
2
        if ( (domain_vioapic(d, i) =
685
2
              xmalloc_bytes(hvm_vioapic_size(nr_pins))) == NULL )
686
0
        {
687
0
            vioapic_free(d, nr_vioapics);
688
0
            return -ENOMEM;
689
0
        }
690
2
        domain_vioapic(d, i)->nr_pins = nr_pins;
691
2
        domain_vioapic(d, i)->base_gsi = base_gsi;
692
2
        nr_gsis = max(nr_gsis, base_gsi + nr_pins);
693
2
    }
694
1
695
1
    /*
696
1
     * NB: hvm_domain_irq(d)->nr_gsis is actually the highest GSI + 1, but
697
1
     * there might be holes in this range (ie: GSIs that don't belong to any
698
1
     * vIO APIC).
699
1
     */
700
1
    ASSERT(hvm_domain_irq(d)->nr_gsis >= nr_gsis);
701
1
702
1
    d->arch.hvm_domain.nr_vioapics = nr_vioapics;
703
1
    vioapic_reset(d);
704
1
705
1
    register_mmio_handler(d, &vioapic_mmio_ops);
706
1
707
1
    return 0;
708
1
}
709
710
void vioapic_deinit(struct domain *d)
711
0
{
712
0
    if ( !has_vioapic(d) )
713
0
    {
714
0
        ASSERT(!d->arch.hvm_domain.nr_vioapics);
715
0
        return;
716
0
    }
717
0
718
0
    vioapic_free(d, d->arch.hvm_domain.nr_vioapics);
719
0
}