~ubuntu-branches/ubuntu/wily/qemu-kvm-spice/wily

« back to all changes in this revision

Viewing changes to hw/piix_pci.c

  • Committer: Bazaar Package Importer
  • Author(s): Serge Hallyn
  • Date: 2011-10-19 10:44:56 UTC
  • Revision ID: james.westby@ubuntu.com-20111019104456-xgvskumk3sxi97f4
Tags: upstream-0.15.0+noroms
ImportĀ upstreamĀ versionĀ 0.15.0+noroms

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * QEMU i440FX/PIIX3 PCI Bridge Emulation
 
3
 *
 
4
 * Copyright (c) 2006 Fabrice Bellard
 
5
 *
 
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 
7
 * of this software and associated documentation files (the "Software"), to deal
 
8
 * in the Software without restriction, including without limitation the rights
 
9
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 
10
 * copies of the Software, and to permit persons to whom the Software is
 
11
 * furnished to do so, subject to the following conditions:
 
12
 *
 
13
 * The above copyright notice and this permission notice shall be included in
 
14
 * all copies or substantial portions of the Software.
 
15
 *
 
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 
19
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 
21
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 
22
 * THE SOFTWARE.
 
23
 */
 
24
 
 
25
#include "hw.h"
 
26
#include "pc.h"
 
27
#include "pci.h"
 
28
#include "pci_host.h"
 
29
#include "isa.h"
 
30
#include "sysbus.h"
 
31
#include "range.h"
 
32
#include "xen.h"
 
33
#include "kvm.h"
 
34
 
 
35
/*
 
36
 * I440FX chipset data sheet.
 
37
 * http://download.intel.com/design/chipsets/datashts/29054901.pdf
 
38
 */
 
39
 
 
40
typedef PCIHostState I440FXState;
 
41
 
 
42
#define PIIX_NUM_PIC_IRQS       16      /* i8259 * 2 */
 
43
#define PIIX_NUM_PIRQS          4ULL    /* PIRQ[A-D] */
 
44
#define XEN_PIIX_NUM_PIRQS      128ULL
 
45
#define PIIX_PIRQC              0x60
 
46
 
 
47
typedef struct PIIX3State {
 
48
    PCIDevice dev;
 
49
 
 
50
    /*
 
51
     * bitmap to track pic levels.
 
52
     * The pic level is the logical OR of all the PCI irqs mapped to it
 
53
     * So one PIC level is tracked by PIIX_NUM_PIRQS bits.
 
54
     *
 
55
     * PIRQ is mapped to PIC pins, we track it by
 
56
     * PIIX_NUM_PIRQS * PIIX_NUM_PIC_IRQS = 64 bits with
 
57
     * pic_irq * PIIX_NUM_PIRQS + pirq
 
58
     */
 
59
#if PIIX_NUM_PIC_IRQS * PIIX_NUM_PIRQS > 64
 
60
#error "unable to encode pic state in 64bit in pic_levels."
 
61
#endif
 
62
    uint64_t pic_levels;
 
63
 
 
64
    qemu_irq *pic;
 
65
 
 
66
    /* This member isn't used. Just for save/load compatibility */
 
67
    int32_t pci_irq_levels_vmstate[PIIX_NUM_PIRQS];
 
68
} PIIX3State;
 
69
 
 
70
struct PCII440FXState {
 
71
    PCIDevice dev;
 
72
    target_phys_addr_t isa_page_descs[384 / 4];
 
73
    uint8_t smm_enabled;
 
74
    PIIX3State *piix3;
 
75
};
 
76
 
 
77
 
 
78
#define I440FX_PAM      0x59
 
79
#define I440FX_PAM_SIZE 7
 
80
#define I440FX_SMRAM    0x72
 
81
 
 
82
static void piix3_set_irq(void *opaque, int pirq, int level);
 
83
static void piix3_write_config_xen(PCIDevice *dev,
 
84
                               uint32_t address, uint32_t val, int len);
 
85
 
 
86
/* return the global irq number corresponding to a given device irq
 
87
   pin. We could also use the bus number to have a more precise
 
88
   mapping. */
 
89
static int pci_slot_get_pirq(PCIDevice *pci_dev, int pci_intx)
 
90
{
 
91
    int slot_addend;
 
92
    slot_addend = (pci_dev->devfn >> 3) - 1;
 
93
    return (pci_intx + slot_addend) & 3;
 
94
}
 
95
 
 
96
static void update_pam(PCII440FXState *d, uint32_t start, uint32_t end, int r)
 
97
{
 
98
    uint32_t addr;
 
99
 
 
100
    //    printf("ISA mapping %08x-0x%08x: %d\n", start, end, r);
 
101
    switch(r) {
 
102
    case 3:
 
103
        /* RAM */
 
104
        cpu_register_physical_memory(start, end - start,
 
105
                                     start);
 
106
        break;
 
107
    case 1:
 
108
        /* ROM (XXX: not quite correct) */
 
109
        cpu_register_physical_memory(start, end - start,
 
110
                                     start | IO_MEM_ROM);
 
111
        break;
 
112
    case 2:
 
113
    case 0:
 
114
        /* XXX: should distinguish read/write cases */
 
115
        for(addr = start; addr < end; addr += 4096) {
 
116
            cpu_register_physical_memory(addr, 4096,
 
117
                                         d->isa_page_descs[(addr - 0xa0000) >> 12]);
 
118
        }
 
119
        break;
 
120
    }
 
121
}
 
122
 
 
123
static void i440fx_update_memory_mappings(PCII440FXState *d)
 
124
{
 
125
    int i, r;
 
126
    uint32_t smram, addr;
 
127
 
 
128
    update_pam(d, 0xf0000, 0x100000, (d->dev.config[I440FX_PAM] >> 4) & 3);
 
129
    for(i = 0; i < 12; i++) {
 
130
        r = (d->dev.config[(i >> 1) + (I440FX_PAM + 1)] >> ((i & 1) * 4)) & 3;
 
131
        update_pam(d, 0xc0000 + 0x4000 * i, 0xc0000 + 0x4000 * (i + 1), r);
 
132
    }
 
133
    smram = d->dev.config[I440FX_SMRAM];
 
134
    if ((d->smm_enabled && (smram & 0x08)) || (smram & 0x40)) {
 
135
        cpu_register_physical_memory(0xa0000, 0x20000, 0xa0000);
 
136
    } else {
 
137
        for(addr = 0xa0000; addr < 0xc0000; addr += 4096) {
 
138
            cpu_register_physical_memory(addr, 4096,
 
139
                                         d->isa_page_descs[(addr - 0xa0000) >> 12]);
 
140
        }
 
141
    }
 
142
}
 
143
 
 
144
static void i440fx_set_smm(int val, void *arg)
 
145
{
 
146
    PCII440FXState *d = arg;
 
147
 
 
148
    val = (val != 0);
 
149
    if (d->smm_enabled != val) {
 
150
        d->smm_enabled = val;
 
151
        i440fx_update_memory_mappings(d);
 
152
    }
 
153
}
 
154
 
 
155
 
 
156
/* XXX: suppress when better memory API. We make the assumption that
 
157
   no device (in particular the VGA) changes the memory mappings in
 
158
   the 0xa0000-0x100000 range */
 
159
void i440fx_init_memory_mappings(PCII440FXState *d)
 
160
{
 
161
    int i;
 
162
    for(i = 0; i < 96; i++) {
 
163
        d->isa_page_descs[i] = cpu_get_physical_page_desc(0xa0000 + i * 0x1000);
 
164
    }
 
165
}
 
166
 
 
167
static void i440fx_write_config(PCIDevice *dev,
 
168
                                uint32_t address, uint32_t val, int len)
 
169
{
 
170
    PCII440FXState *d = DO_UPCAST(PCII440FXState, dev, dev);
 
171
 
 
172
    /* XXX: implement SMRAM.D_LOCK */
 
173
    pci_default_write_config(dev, address, val, len);
 
174
    if (ranges_overlap(address, len, I440FX_PAM, I440FX_PAM_SIZE) ||
 
175
        range_covers_byte(address, len, I440FX_SMRAM)) {
 
176
        i440fx_update_memory_mappings(d);
 
177
    }
 
178
}
 
179
 
 
180
static int i440fx_load_old(QEMUFile* f, void *opaque, int version_id)
 
181
{
 
182
    PCII440FXState *d = opaque;
 
183
    int ret, i;
 
184
 
 
185
    ret = pci_device_load(&d->dev, f);
 
186
    if (ret < 0)
 
187
        return ret;
 
188
    i440fx_update_memory_mappings(d);
 
189
    qemu_get_8s(f, &d->smm_enabled);
 
190
 
 
191
    if (version_id == 2) {
 
192
        for (i = 0; i < PIIX_NUM_PIRQS; i++) {
 
193
            qemu_get_be32(f); /* dummy load for compatibility */
 
194
        }
 
195
    }
 
196
 
 
197
    return 0;
 
198
}
 
199
 
 
200
static int i440fx_post_load(void *opaque, int version_id)
 
201
{
 
202
    PCII440FXState *d = opaque;
 
203
 
 
204
    i440fx_update_memory_mappings(d);
 
205
    return 0;
 
206
}
 
207
 
 
208
static const VMStateDescription vmstate_i440fx = {
 
209
    .name = "I440FX",
 
210
    .version_id = 3,
 
211
    .minimum_version_id = 3,
 
212
    .minimum_version_id_old = 1,
 
213
    .load_state_old = i440fx_load_old,
 
214
    .post_load = i440fx_post_load,
 
215
    .fields      = (VMStateField []) {
 
216
        VMSTATE_PCI_DEVICE(dev, PCII440FXState),
 
217
        VMSTATE_UINT8(smm_enabled, PCII440FXState),
 
218
        VMSTATE_END_OF_LIST()
 
219
    }
 
220
};
 
221
 
 
222
static int i440fx_pcihost_initfn(SysBusDevice *dev)
 
223
{
 
224
    I440FXState *s = FROM_SYSBUS(I440FXState, dev);
 
225
 
 
226
    pci_host_conf_register_ioport(0xcf8, s);
 
227
 
 
228
    pci_host_data_register_ioport(0xcfc, s);
 
229
    return 0;
 
230
}
 
231
 
 
232
static int i440fx_initfn(PCIDevice *dev)
 
233
{
 
234
    PCII440FXState *d = DO_UPCAST(PCII440FXState, dev, dev);
 
235
 
 
236
    d->dev.config[I440FX_SMRAM] = 0x02;
 
237
 
 
238
    cpu_smm_register(&i440fx_set_smm, d);
 
239
    return 0;
 
240
}
 
241
 
 
242
static PIIX3State *piix3_dev;
 
243
 
 
244
static PCIBus *i440fx_common_init(const char *device_name,
 
245
                                  PCII440FXState **pi440fx_state,
 
246
                                  int *piix3_devfn,
 
247
                                  qemu_irq *pic, ram_addr_t ram_size)
 
248
{
 
249
    DeviceState *dev;
 
250
    PCIBus *b;
 
251
    PCIDevice *d;
 
252
    I440FXState *s;
 
253
    PIIX3State *piix3;
 
254
 
 
255
    dev = qdev_create(NULL, "i440FX-pcihost");
 
256
    s = FROM_SYSBUS(I440FXState, sysbus_from_qdev(dev));
 
257
    b = pci_bus_new(&s->busdev.qdev, NULL, 0);
 
258
    s->bus = b;
 
259
    qdev_init_nofail(dev);
 
260
 
 
261
    d = pci_create_simple(b, 0, device_name);
 
262
    *pi440fx_state = DO_UPCAST(PCII440FXState, dev, d);
 
263
 
 
264
    /* Xen supports additional interrupt routes from the PCI devices to
 
265
     * the IOAPIC: the four pins of each PCI device on the bus are also
 
266
     * connected to the IOAPIC directly.
 
267
     * These additional routes can be discovered through ACPI. */
 
268
    if (xen_enabled()) {
 
269
        piix3 = DO_UPCAST(PIIX3State, dev,
 
270
                pci_create_simple_multifunction(b, -1, true, "PIIX3-xen"));
 
271
        pci_bus_irqs(b, xen_piix3_set_irq, xen_pci_slot_get_pirq,
 
272
                piix3, XEN_PIIX_NUM_PIRQS);
 
273
    } else {
 
274
        piix3 = DO_UPCAST(PIIX3State, dev,
 
275
                pci_create_simple_multifunction(b, -1, true, "PIIX3"));
 
276
        pci_bus_irqs(b, piix3_set_irq, pci_slot_get_pirq, piix3,
 
277
                PIIX_NUM_PIRQS);
 
278
    }
 
279
    piix3->pic = pic;
 
280
 
 
281
    (*pi440fx_state)->piix3 = piix3;
 
282
 
 
283
    *piix3_devfn = piix3->dev.devfn;
 
284
 
 
285
    ram_size = ram_size / 8 / 1024 / 1024;
 
286
    if (ram_size > 255)
 
287
        ram_size = 255;
 
288
    (*pi440fx_state)->dev.config[0x57]=ram_size;
 
289
 
 
290
    piix3_dev = piix3;
 
291
 
 
292
    return b;
 
293
}
 
294
 
 
295
PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn,
 
296
                    qemu_irq *pic, ram_addr_t ram_size)
 
297
{
 
298
    PCIBus *b;
 
299
 
 
300
    b = i440fx_common_init("i440FX", pi440fx_state, piix3_devfn, pic, ram_size);
 
301
    return b;
 
302
}
 
303
 
 
304
/* PIIX3 PCI to ISA bridge */
 
305
static void piix3_set_irq_pic(PIIX3State *piix3, int pic_irq)
 
306
{
 
307
    qemu_set_irq(piix3->pic[pic_irq],
 
308
                 !!(piix3->pic_levels &
 
309
                    (((1ULL << PIIX_NUM_PIRQS) - 1) <<
 
310
                     (pic_irq * PIIX_NUM_PIRQS))));
 
311
}
 
312
 
 
313
static void piix3_set_irq_level(PIIX3State *piix3, int pirq, int level)
 
314
{
 
315
    int pic_irq;
 
316
    uint64_t mask;
 
317
 
 
318
    pic_irq = piix3->dev.config[PIIX_PIRQC + pirq];
 
319
    if (pic_irq >= PIIX_NUM_PIC_IRQS) {
 
320
        return;
 
321
    }
 
322
 
 
323
    mask = 1ULL << ((pic_irq * PIIX_NUM_PIRQS) + pirq);
 
324
    piix3->pic_levels &= ~mask;
 
325
    piix3->pic_levels |= mask * !!level;
 
326
 
 
327
    piix3_set_irq_pic(piix3, pic_irq);
 
328
}
 
329
 
 
330
static void piix3_set_irq(void *opaque, int pirq, int level)
 
331
{
 
332
    PIIX3State *piix3 = opaque;
 
333
    piix3_set_irq_level(piix3, pirq, level);
 
334
}
 
335
 
 
336
/* irq routing is changed. so rebuild bitmap */
 
337
static void piix3_update_irq_levels(PIIX3State *piix3)
 
338
{
 
339
    int pirq;
 
340
 
 
341
    piix3->pic_levels = 0;
 
342
    for (pirq = 0; pirq < PIIX_NUM_PIRQS; pirq++) {
 
343
        piix3_set_irq_level(piix3, pirq,
 
344
                            pci_bus_get_irq_level(piix3->dev.bus, pirq));
 
345
    }
 
346
}
 
347
 
 
348
static void piix3_write_config(PCIDevice *dev,
 
349
                               uint32_t address, uint32_t val, int len)
 
350
{
 
351
    pci_default_write_config(dev, address, val, len);
 
352
    if (ranges_overlap(address, len, PIIX_PIRQC, 4)) {
 
353
        PIIX3State *piix3 = DO_UPCAST(PIIX3State, dev, dev);
 
354
        int pic_irq;
 
355
        piix3_update_irq_levels(piix3);
 
356
        for (pic_irq = 0; pic_irq < PIIX_NUM_PIC_IRQS; pic_irq++) {
 
357
            piix3_set_irq_pic(piix3, pic_irq);
 
358
        }
 
359
    }
 
360
}
 
361
 
 
362
int piix_get_irq(int pin)
 
363
{
 
364
    if (piix3_dev)
 
365
        return piix3_dev->dev.config[0x60+pin];
 
366
    return 0;
 
367
}
 
368
 
 
369
static void piix3_write_config_xen(PCIDevice *dev,
 
370
                               uint32_t address, uint32_t val, int len)
 
371
{
 
372
    xen_piix_pci_write_config_client(address, val, len);
 
373
    piix3_write_config(dev, address, val, len);
 
374
}
 
375
 
 
376
static void piix3_reset(void *opaque)
 
377
{
 
378
    PIIX3State *d = opaque;
 
379
    uint8_t *pci_conf = d->dev.config;
 
380
 
 
381
    pci_conf[0x04] = 0x07; // master, memory and I/O
 
382
    pci_conf[0x05] = 0x00;
 
383
    pci_conf[0x06] = 0x00;
 
384
    pci_conf[0x07] = 0x02; // PCI_status_devsel_medium
 
385
    pci_conf[0x4c] = 0x4d;
 
386
    pci_conf[0x4e] = 0x03;
 
387
    pci_conf[0x4f] = 0x00;
 
388
    pci_conf[0x60] = 0x80;
 
389
    pci_conf[0x61] = 0x80;
 
390
    pci_conf[0x62] = 0x80;
 
391
    pci_conf[0x63] = 0x80;
 
392
    pci_conf[0x69] = 0x02;
 
393
    pci_conf[0x70] = 0x80;
 
394
    pci_conf[0x76] = 0x0c;
 
395
    pci_conf[0x77] = 0x0c;
 
396
    pci_conf[0x78] = 0x02;
 
397
    pci_conf[0x79] = 0x00;
 
398
    pci_conf[0x80] = 0x00;
 
399
    pci_conf[0x82] = 0x00;
 
400
    pci_conf[0xa0] = 0x08;
 
401
    pci_conf[0xa2] = 0x00;
 
402
    pci_conf[0xa3] = 0x00;
 
403
    pci_conf[0xa4] = 0x00;
 
404
    pci_conf[0xa5] = 0x00;
 
405
    pci_conf[0xa6] = 0x00;
 
406
    pci_conf[0xa7] = 0x00;
 
407
    pci_conf[0xa8] = 0x0f;
 
408
    pci_conf[0xaa] = 0x00;
 
409
    pci_conf[0xab] = 0x00;
 
410
    pci_conf[0xac] = 0x00;
 
411
    pci_conf[0xae] = 0x00;
 
412
 
 
413
    d->pic_levels = 0;
 
414
}
 
415
 
 
416
static int piix3_post_load(void *opaque, int version_id)
 
417
{
 
418
    PIIX3State *piix3 = opaque;
 
419
    piix3_update_irq_levels(piix3);
 
420
    return 0;
 
421
}
 
422
 
 
423
static void piix3_pre_save(void *opaque)
 
424
{
 
425
    int i;
 
426
    PIIX3State *piix3 = opaque;
 
427
 
 
428
    for (i = 0; i < ARRAY_SIZE(piix3->pci_irq_levels_vmstate); i++) {
 
429
        piix3->pci_irq_levels_vmstate[i] =
 
430
            pci_bus_get_irq_level(piix3->dev.bus, i);
 
431
    }
 
432
}
 
433
 
 
434
static const VMStateDescription vmstate_piix3 = {
 
435
    .name = "PIIX3",
 
436
    .version_id = 3,
 
437
    .minimum_version_id = 2,
 
438
    .minimum_version_id_old = 2,
 
439
    .post_load = piix3_post_load,
 
440
    .pre_save = piix3_pre_save,
 
441
    .fields      = (VMStateField []) {
 
442
        VMSTATE_PCI_DEVICE(dev, PIIX3State),
 
443
        VMSTATE_INT32_ARRAY_V(pci_irq_levels_vmstate, PIIX3State,
 
444
                              PIIX_NUM_PIRQS, 3),
 
445
        VMSTATE_END_OF_LIST()
 
446
    }
 
447
};
 
448
 
 
449
static int piix3_initfn(PCIDevice *dev)
 
450
{
 
451
    PIIX3State *d = DO_UPCAST(PIIX3State, dev, dev);
 
452
 
 
453
    isa_bus_new(&d->dev.qdev);
 
454
    qemu_register_reset(piix3_reset, d);
 
455
    return 0;
 
456
}
 
457
 
 
458
static PCIDeviceInfo i440fx_info[] = {
 
459
    {
 
460
        .qdev.name    = "i440FX",
 
461
        .qdev.desc    = "Host bridge",
 
462
        .qdev.size    = sizeof(PCII440FXState),
 
463
        .qdev.vmsd    = &vmstate_i440fx,
 
464
        .qdev.no_user = 1,
 
465
        .no_hotplug   = 1,
 
466
        .init         = i440fx_initfn,
 
467
        .config_write = i440fx_write_config,
 
468
        .vendor_id    = PCI_VENDOR_ID_INTEL,
 
469
        .device_id    = PCI_DEVICE_ID_INTEL_82441,
 
470
        .revision     = 0x02,
 
471
        .class_id     = PCI_CLASS_BRIDGE_HOST,
 
472
    },{
 
473
        .qdev.name    = "PIIX3",
 
474
        .qdev.desc    = "ISA bridge",
 
475
        .qdev.size    = sizeof(PIIX3State),
 
476
        .qdev.vmsd    = &vmstate_piix3,
 
477
        .qdev.no_user = 1,
 
478
        .no_hotplug   = 1,
 
479
        .init         = piix3_initfn,
 
480
        .config_write = piix3_write_config,
 
481
        .vendor_id    = PCI_VENDOR_ID_INTEL,
 
482
        .device_id    = PCI_DEVICE_ID_INTEL_82371SB_0, // 82371SB PIIX3 PCI-to-ISA bridge (Step A1)
 
483
        .class_id     = PCI_CLASS_BRIDGE_ISA,
 
484
    },{
 
485
        .qdev.name    = "PIIX3-xen",
 
486
        .qdev.desc    = "ISA bridge",
 
487
        .qdev.size    = sizeof(PIIX3State),
 
488
        .qdev.vmsd    = &vmstate_piix3,
 
489
        .qdev.no_user = 1,
 
490
        .no_hotplug   = 1,
 
491
        .init         = piix3_initfn,
 
492
        .config_write = piix3_write_config_xen,
 
493
        .vendor_id    = PCI_VENDOR_ID_INTEL,
 
494
        .device_id    = PCI_DEVICE_ID_INTEL_82371SB_0, // 82371SB PIIX3 PCI-to-ISA bridge (Step A1)
 
495
        .class_id     = PCI_CLASS_BRIDGE_ISA,
 
496
    },{
 
497
        /* end of list */
 
498
    }
 
499
};
 
500
 
 
501
static SysBusDeviceInfo i440fx_pcihost_info = {
 
502
    .init         = i440fx_pcihost_initfn,
 
503
    .qdev.name    = "i440FX-pcihost",
 
504
    .qdev.fw_name = "pci",
 
505
    .qdev.size    = sizeof(I440FXState),
 
506
    .qdev.no_user = 1,
 
507
};
 
508
 
 
509
static void i440fx_register(void)
 
510
{
 
511
    sysbus_register_withprop(&i440fx_pcihost_info);
 
512
    pci_qdev_register_many(i440fx_info);
 
513
}
 
514
device_init(i440fx_register);