pc_piix.c 31.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
/*
 * QEMU PC System Emulator
 *
 * Copyright (c) 2003-2004 Fabrice Bellard
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

P
Peter Maydell 已提交
25
#include "qemu/osdep.h"
A
Avi Kivity 已提交
26 27
#include <glib.h>

28
#include "hw/hw.h"
29
#include "hw/loader.h"
P
Paolo Bonzini 已提交
30 31
#include "hw/i386/pc.h"
#include "hw/i386/apic.h"
32
#include "hw/smbios/smbios.h"
33 34 35
#include "hw/pci/pci.h"
#include "hw/pci/pci_ids.h"
#include "hw/usb.h"
P
Paolo Bonzini 已提交
36
#include "net/net.h"
37 38
#include "hw/boards.h"
#include "hw/ide.h"
39
#include "sysemu/kvm.h"
40
#include "hw/kvm/clock.h"
41
#include "sysemu/sysemu.h"
42
#include "hw/sysbus.h"
43
#include "sysemu/arch_init.h"
44
#include "sysemu/block-backend.h"
P
Paolo Bonzini 已提交
45 46
#include "hw/i2c/smbus.h"
#include "hw/xen/xen.h"
47 48
#include "exec/memory.h"
#include "exec/address-spaces.h"
49
#include "hw/acpi/acpi.h"
50
#include "cpu.h"
51
#include "qemu/error-report.h"
A
Anthony PERARD 已提交
52
#ifdef CONFIG_XEN
53 54
#include <xen/hvm/hvm_info_table.h>
#include "hw/xen/xen_pt.h"
A
Anthony PERARD 已提交
55
#endif
56
#include "migration/migration.h"
57
#include "kvm_i386.h"
58 59 60 61 62 63 64 65

#define MAX_IDE_BUS 2

static const int ide_iobase[MAX_IDE_BUS] = { 0x1f0, 0x170 };
static const int ide_iobase2[MAX_IDE_BUS] = { 0x3f6, 0x376 };
static const int ide_irq[MAX_IDE_BUS] = { 14, 15 };

/* PC hardware initialisation */
66 67
static void pc_init1(MachineState *machine,
                     const char *host_type, const char *pci_type)
68
{
69
    PCMachineState *pcms = PC_MACHINE(machine);
70
    PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms);
71 72
    MemoryRegion *system_memory = get_system_memory();
    MemoryRegion *system_io = get_system_io();
73 74
    int i;
    PCIBus *pci_bus;
75
    ISABus *isa_bus;
76 77
    PCII440FXState *i440fx_state;
    int piix3_devfn = -1;
J
Jan Kiszka 已提交
78
    qemu_irq *gsi;
79
    qemu_irq *i8259;
S
Shannon Zhao 已提交
80
    qemu_irq smi_irq;
J
Jan Kiszka 已提交
81
    GSIState *gsi_state;
82
    DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
83
    BusState *idebus[MAX_IDE_BUS];
84
    ISADevice *rtc_state;
A
Avi Kivity 已提交
85 86
    MemoryRegion *ram_memory;
    MemoryRegion *pci_memory;
87
    MemoryRegion *rom_memory;
88
    ram_addr_t lowmem;
89

90 91 92 93 94 95 96
    /* Check whether RAM fits below 4G (leaving 1/2 GByte for IO memory).
     * If it doesn't, we need to split it in chunks below and above 4G.
     * In any case, try to make sure that guest addresses aligned at
     * 1G boundaries get mapped to host addresses aligned at 1G boundaries.
     * For old machine types, use whatever split we used historically to avoid
     * breaking migration.
     */
97
    if (machine->ram_size >= 0xe0000000) {
98
        lowmem = pcmc->gigabyte_align ? 0xc0000000 : 0xe0000000;
99 100 101 102
    } else {
        lowmem = 0xe0000000;
    }

103
    /* Handle the machine opt max-ram-below-4g.  It is basically doing
104 105
     * min(qemu limit, user limit).
     */
106 107
    if (lowmem > pcms->max_ram_below_4g) {
        lowmem = pcms->max_ram_below_4g;
108 109 110 111
        if (machine->ram_size - lowmem > lowmem &&
            lowmem & ((1ULL << 30) - 1)) {
            error_report("Warning: Large machine and max_ram_below_4g(%"PRIu64
                         ") not a multiple of 1G; possible bad performance.",
112
                         pcms->max_ram_below_4g);
113 114 115 116
        }
    }

    if (machine->ram_size >= lowmem) {
117 118
        pcms->above_4g_mem_size = machine->ram_size - lowmem;
        pcms->below_4g_mem_size = lowmem;
119
    } else {
120 121
        pcms->above_4g_mem_size = 0;
        pcms->below_4g_mem_size = machine->ram_size;
122 123
    }

124 125
    if (xen_enabled()) {
        xen_hvm_init(pcms, &ram_memory);
126 127
    }

128
    pc_cpus_init(pcms);
129

130
    if (kvm_enabled() && pcmc->kvmclock_enabled) {
131 132 133
        kvmclock_create();
    }

134
    if (pcmc->pci_enabled) {
135
        pci_memory = g_new(MemoryRegion, 1);
P
Paolo Bonzini 已提交
136
        memory_region_init(pci_memory, NULL, "pci", UINT64_MAX);
137 138 139 140 141
        rom_memory = pci_memory;
    } else {
        pci_memory = NULL;
        rom_memory = system_memory;
    }
A
Avi Kivity 已提交
142

143
    pc_guest_info_init(pcms);
144

145
    if (pcmc->smbios_defaults) {
146
        MachineClass *mc = MACHINE_GET_CLASS(machine);
147
        /* These values are guest ABI, do not change */
148
        smbios_set_defaults("QEMU", "Standard PC (i440FX + PIIX, 1996)",
149 150
                            mc->name, pcmc->smbios_legacy_mode,
                            pcmc->smbios_uuid_encoded,
W
Wei Huang 已提交
151
                            SMBIOS_ENTRY_POINT_21);
152 153
    }

154
    /* allocate ram and load rom/bios */
A
Anthony PERARD 已提交
155
    if (!xen_enabled()) {
156
        pc_memory_init(pcms, system_memory,
157
                       rom_memory, &ram_memory);
158 159
    } else if (machine->kernel_filename != NULL) {
        /* For xen HVM direct kernel boot, load linux here */
160
        xen_load_linux(pcms);
A
Anthony PERARD 已提交
161
    }
162

J
Jan Kiszka 已提交
163
    gsi_state = g_malloc0(sizeof(*gsi_state));
164
    if (kvm_ioapic_in_kernel()) {
165
        kvm_pc_setup_irq_routing(pcmc->pci_enabled);
166
        gsi = qemu_allocate_irqs(kvm_pc_gsi_handler, gsi_state,
167 168 169 170
                                 GSI_NUM_PINS);
    } else {
        gsi = qemu_allocate_irqs(gsi_handler, gsi_state, GSI_NUM_PINS);
    }
171

172
    if (pcmc->pci_enabled) {
173 174
        pci_bus = i440fx_init(host_type,
                              pci_type,
175
                              &i440fx_state, &piix3_devfn, &isa_bus, gsi,
176
                              system_memory, system_io, machine->ram_size,
177 178
                              pcms->below_4g_mem_size,
                              pcms->above_4g_mem_size,
A
Avi Kivity 已提交
179
                              pci_memory, ram_memory);
180
        pcms->bus = pci_bus;
181 182
    } else {
        pci_bus = NULL;
I
Isaku Yamahata 已提交
183
        i440fx_state = NULL;
184 185
        isa_bus = isa_bus_new(NULL, get_system_memory(), system_io,
                              &error_abort);
J
Jan Kiszka 已提交
186
        no_hpet = 1;
187
    }
188
    isa_bus_irqs(isa_bus, gsi);
189

190
    if (kvm_pic_in_kernel()) {
191 192 193 194
        i8259 = kvm_i8259_init(isa_bus);
    } else if (xen_enabled()) {
        i8259 = xen_interrupt_controller_init();
    } else {
195
        i8259 = i8259_init(isa_bus, pc_allocate_cpu_irq());
196 197
    }

198 199 200
    for (i = 0; i < ISA_NUM_IRQS; i++) {
        gsi_state->i8259_irq[i] = i8259[i];
    }
S
Shannon Zhao 已提交
201
    g_free(i8259);
202
    if (pcmc->pci_enabled) {
203
        ioapic_init_gsi(gsi_state, "i440fx");
204 205
    }

J
Jan Kiszka 已提交
206
    pc_register_ferr_irq(gsi[13]);
207

208
    pc_vga_init(isa_bus, pcmc->pci_enabled ? pci_bus : NULL);
209

210
    assert(pcms->vmport != ON_OFF_AUTO__MAX);
211 212
    if (pcms->vmport == ON_OFF_AUTO_AUTO) {
        pcms->vmport = xen_enabled() ? ON_OFF_AUTO_OFF : ON_OFF_AUTO_ON;
213 214
    }

215
    /* init basic PC hardware */
216
    pc_basic_device_init(isa_bus, gsi, &rtc_state, true,
217
                         (pcms->vmport != ON_OFF_AUTO_ON), 0x4);
218

219
    pc_nic_init(isa_bus, pci_bus);
220

221
    ide_drive_get(hd, ARRAY_SIZE(hd));
222
    if (pcmc->pci_enabled) {
223
        PCIDevice *dev;
224 225 226 227 228
        if (xen_enabled()) {
            dev = pci_piix3_xen_ide_init(pci_bus, hd, piix3_devfn + 1);
        } else {
            dev = pci_piix3_ide_init(pci_bus, hd, piix3_devfn + 1);
        }
229 230
        idebus[0] = qdev_get_child_bus(&dev->qdev, "ide.0");
        idebus[1] = qdev_get_child_bus(&dev->qdev, "ide.1");
231 232
    } else {
        for(i = 0; i < MAX_IDE_BUS; i++) {
233
            ISADevice *dev;
234
            char busname[] = "ide.0";
235 236
            dev = isa_ide_init(isa_bus, ide_iobase[i], ide_iobase2[i],
                               ide_irq[i],
237
                               hd[MAX_IDE_DEVS * i], hd[MAX_IDE_DEVS * i + 1]);
238 239 240 241 242 243
            /*
             * The ide bus name is ide.0 for the first bus and ide.1 for the
             * second one.
             */
            busname[4] = '0' + i;
            idebus[i] = qdev_get_child_bus(DEVICE(dev), busname);
244 245 246
        }
    }

247
    pc_cmos_init(pcms, idebus[0], idebus[1], rtc_state);
248

249
    if (pcmc->pci_enabled && usb_enabled()) {
250
        pci_create_simple(pci_bus, piix3_devfn + 2, "piix3-usb-uhci");
251 252
    }

253
    if (pcmc->pci_enabled && acpi_enabled) {
254
        DeviceState *piix4_pm;
A
Andreas Färber 已提交
255
        I2CBus *smbus;
256

S
Shannon Zhao 已提交
257
        smi_irq = qemu_allocate_irq(pc_acpi_smi_interrupt, first_cpu, 0);
258 259
        /* TODO: Populate SPD eeprom data.  */
        smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100,
S
Shannon Zhao 已提交
260
                              gsi[9], smi_irq,
261
                              pc_machine_is_smm_enabled(pcms),
P
Paolo Bonzini 已提交
262
                              &piix4_pm);
263
        smbus_eeprom_init(smbus, 8, NULL, 0);
264 265 266

        object_property_add_link(OBJECT(machine), PC_MACHINE_ACPI_DEVICE_PROP,
                                 TYPE_HOTPLUG_HANDLER,
267
                                 (Object **)&pcms->acpi_dev,
268 269 270 271
                                 object_property_allow_set_link,
                                 OBJ_PROP_LINK_UNREF_ON_RELEASE, &error_abort);
        object_property_set_link(OBJECT(machine), OBJECT(piix4_pm),
                                 PC_MACHINE_ACPI_DEVICE_PROP, &error_abort);
272 273
    }

274
    if (pcmc->pci_enabled) {
275 276 277 278
        pc_pci_device_init(pci_bus);
    }
}

279 280 281 282 283 284 285
/* Looking for a pc_compat_2_4() function? It doesn't exist.
 * pc_compat_*() functions that run on machine-init time and
 * change global QEMU state are deprecated. Please don't create
 * one, and implement any pc-*-2.4 (and newer) compat code in
 * HW_COMPAT_*, PC_COMPAT_*, or * pc_*_machine_options().
 */

J
Jason Wang 已提交
286 287
static void pc_compat_2_3(MachineState *machine)
{
P
Paolo Bonzini 已提交
288
    PCMachineState *pcms = PC_MACHINE(machine);
289
    savevm_skip_section_footers();
P
Paolo Bonzini 已提交
290 291 292
    if (kvm_enabled()) {
        pcms->smm = ON_OFF_AUTO_OFF;
    }
293
    global_state_set_optional();
294
    savevm_skip_configuration();
J
Jason Wang 已提交
295 296
}

P
Paolo Bonzini 已提交
297 298
static void pc_compat_2_2(MachineState *machine)
{
J
Jason Wang 已提交
299
    pc_compat_2_3(machine);
300
    machine->suppress_vmdesc = true;
P
Paolo Bonzini 已提交
301 302
}

E
Eduardo Habkost 已提交
303 304
static void pc_compat_2_1(MachineState *machine)
{
P
Paolo Bonzini 已提交
305
    pc_compat_2_2(machine);
306
    x86_cpu_change_kvm_default("svm", NULL);
E
Eduardo Habkost 已提交
307 308
}

309
static void pc_compat_2_0(MachineState *machine)
M
Michael S. Tsirkin 已提交
310
{
E
Eduardo Habkost 已提交
311
    pc_compat_2_1(machine);
M
Michael S. Tsirkin 已提交
312 313
}

314
static void pc_compat_1_7(MachineState *machine)
315
{
316
    pc_compat_2_0(machine);
317
    x86_cpu_change_kvm_default("x2apic", NULL);
318 319
}

320
static void pc_compat_1_6(MachineState *machine)
321
{
322
    pc_compat_1_7(machine);
323 324
}

325
static void pc_compat_1_5(MachineState *machine)
326
{
327
    pc_compat_1_6(machine);
328 329
}

330
static void pc_compat_1_4(MachineState *machine)
331
{
332
    pc_compat_1_5(machine);
333 334
}

335
static void pc_compat_1_3(MachineState *machine)
336
{
337
    pc_compat_1_4(machine);
338
    enable_compat_apic_id_mode();
339 340 341
}

/* PC compat function for pc-0.14 to pc-1.2 */
342
static void pc_compat_1_2(MachineState *machine)
343
{
344
    pc_compat_1_3(machine);
345
    x86_cpu_change_kvm_default("kvm-pv-eoi", NULL);
346 347
}

348 349 350 351 352 353
/* PC compat function for pc-0.10 to pc-0.13 */
static void pc_compat_0_13(MachineState *machine)
{
    pc_compat_1_2(machine);
}

354
static void pc_init_isa(MachineState *machine)
355
{
356 357
    if (!machine->cpu_model) {
        machine->cpu_model = "486";
358
    }
359
    x86_cpu_change_kvm_default("kvm-pv-eoi", NULL);
360
    enable_compat_apic_id_mode();
361
    pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, TYPE_I440FX_PCI_DEVICE);
362 363
}

A
Anthony PERARD 已提交
364
#ifdef CONFIG_XEN
365 366 367 368 369 370 371 372 373 374
static void pc_xen_hvm_init_pci(MachineState *machine)
{
    const char *pci_type = has_igd_gfx_passthru ?
                TYPE_IGD_PASSTHROUGH_I440FX_PCI_DEVICE : TYPE_I440FX_PCI_DEVICE;

    pc_init1(machine,
             TYPE_I440FX_PCI_HOST_BRIDGE,
             pci_type);
}

375
static void pc_xen_hvm_init(MachineState *machine)
A
Anthony PERARD 已提交
376
{
377 378
    PCIBus *bus;

379 380 381 382 383
    if (!xen_enabled()) {
        error_report("xenfv machine requires the xen accelerator");
        exit(1);
    }

384
    pc_xen_hvm_init_pci(machine);
385

D
David Gibson 已提交
386
    bus = pci_find_primary_bus();
387 388 389
    if (bus != NULL) {
        pci_create_simple(bus, -1, "xen-platform");
    }
A
Anthony PERARD 已提交
390 391 392
}
#endif

393 394 395 396 397 398 399
#define DEFINE_I440FX_MACHINE(suffix, name, compatfn, optionfn) \
    static void pc_init_##suffix(MachineState *machine) \
    { \
        void (*compat)(MachineState *m) = (compatfn); \
        if (compat) { \
            compat(machine); \
        } \
400 401
        pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, \
                 TYPE_I440FX_PCI_DEVICE); \
402 403
    } \
    DEFINE_PC_MACHINE(suffix, name, pc_init_##suffix, optionfn)
404

405
static void pc_i440fx_machine_options(MachineClass *m)
406 407 408 409
{
    m->family = "pc_piix";
    m->desc = "Standard PC (i440FX + PIIX, 1996)";
    m->hot_add_cpu = pc_hot_add_cpu;
410 411
    m->default_machine_opts = "firmware=bios-256k.bin";
    m->default_display = "std";
412 413
}

E
Eduardo Habkost 已提交
414
static void pc_i440fx_2_6_machine_options(MachineClass *m)
415 416 417 418 419
{
    pc_i440fx_machine_options(m);
    m->alias = "pc";
    m->is_default = 1;
}
420

E
Eduardo Habkost 已提交
421 422 423 424 425 426
DEFINE_I440FX_MACHINE(v2_6, "pc-i440fx-2.6", NULL,
                      pc_i440fx_2_6_machine_options);


static void pc_i440fx_2_5_machine_options(MachineClass *m)
{
427
    PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
E
Eduardo Habkost 已提交
428 429 430
    pc_i440fx_2_6_machine_options(m);
    m->alias = NULL;
    m->is_default = 0;
431
    pcmc->save_tsc_khz = false;
E
Eduardo Habkost 已提交
432 433 434
    SET_MACHINE_COMPAT(m, PC_COMPAT_2_5);
}

435 436 437 438 439 440 441 442
DEFINE_I440FX_MACHINE(v2_5, "pc-i440fx-2.5", NULL,
                      pc_i440fx_2_5_machine_options);


static void pc_i440fx_2_4_machine_options(MachineClass *m)
{
    PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
    pc_i440fx_2_5_machine_options(m);
443
    m->hw_version = "2.4.0";
444 445 446 447
    pcmc->broken_reserved_end = true;
    SET_MACHINE_COMPAT(m, PC_COMPAT_2_4);
}

448 449
DEFINE_I440FX_MACHINE(v2_4, "pc-i440fx-2.4", NULL,
                      pc_i440fx_2_4_machine_options)
J
Jason Wang 已提交
450

J
Jan Kiszka 已提交
451

452
static void pc_i440fx_2_3_machine_options(MachineClass *m)
453
{
454
    pc_i440fx_2_4_machine_options(m);
455
    m->hw_version = "2.3.0";
456
    SET_MACHINE_COMPAT(m, PC_COMPAT_2_3);
457
}
J
Jason Wang 已提交
458

459 460
DEFINE_I440FX_MACHINE(v2_3, "pc-i440fx-2.3", pc_compat_2_3,
                      pc_i440fx_2_3_machine_options);
461

J
Jason Wang 已提交
462

463
static void pc_i440fx_2_2_machine_options(MachineClass *m)
464
{
465
    PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
466
    pc_i440fx_2_3_machine_options(m);
467
    m->hw_version = "2.2.0";
468
    SET_MACHINE_COMPAT(m, PC_COMPAT_2_2);
469
    pcmc->rsdp_in_ram = false;
470
}
P
Paolo Bonzini 已提交
471

472 473
DEFINE_I440FX_MACHINE(v2_2, "pc-i440fx-2.2", pc_compat_2_2,
                      pc_i440fx_2_2_machine_options);
474

P
Paolo Bonzini 已提交
475

476
static void pc_i440fx_2_1_machine_options(MachineClass *m)
477
{
478
    PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
479
    pc_i440fx_2_2_machine_options(m);
480
    m->hw_version = "2.1.0";
481
    m->default_display = NULL;
482
    SET_MACHINE_COMPAT(m, PC_COMPAT_2_1);
483
    pcmc->smbios_uuid_encoded = false;
484
    pcmc->enforce_aligned_dimm = false;
485
}
J
Jan Kiszka 已提交
486

487 488
DEFINE_I440FX_MACHINE(v2_1, "pc-i440fx-2.1", pc_compat_2_1,
                      pc_i440fx_2_1_machine_options);
489

490

491

492
static void pc_i440fx_2_0_machine_options(MachineClass *m)
493
{
494
    PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
495
    pc_i440fx_2_1_machine_options(m);
496
    m->hw_version = "2.0.0";
497
    SET_MACHINE_COMPAT(m, PC_COMPAT_2_0);
498 499
    pcmc->smbios_legacy_mode = true;
    pcmc->has_reserved_memory = false;
500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516
    /* This value depends on the actual DSDT and SSDT compiled into
     * the source QEMU; unfortunately it depends on the binary and
     * not on the machine type, so we cannot make pc-i440fx-1.7 work on
     * both QEMU 1.7 and QEMU 2.0.
     *
     * Large variations cause migration to fail for more than one
     * consecutive value of the "-smp" maxcpus option.
     *
     * For small variations of the kind caused by different iasl versions,
     * the 4k rounding usually leaves slack.  However, there could be still
     * one or two values that break.  For QEMU 1.7 and QEMU 2.0 the
     * slack is only ~10 bytes before one "-smp maxcpus" value breaks!
     *
     * 6652 is valid for QEMU 2.0, the right value for pc-i440fx-1.7 on
     * QEMU 1.7 it is 6414.  For RHEL/CentOS 7.0 it is 6418.
     */
    pcmc->legacy_acpi_table_size = 6652;
517
    pcmc->acpi_data_size = 0x10000;
518
}
M
Michael S. Tsirkin 已提交
519

520 521
DEFINE_I440FX_MACHINE(v2_0, "pc-i440fx-2.0", pc_compat_2_0,
                      pc_i440fx_2_0_machine_options);
522

M
Michael S. Tsirkin 已提交
523

524
static void pc_i440fx_1_7_machine_options(MachineClass *m)
525
{
526
    PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
527
    pc_i440fx_2_0_machine_options(m);
528
    m->hw_version = "1.7.0";
529
    m->default_machine_opts = NULL;
530
    m->option_rom_has_mr = true;
531
    SET_MACHINE_COMPAT(m, PC_COMPAT_1_7);
532 533
    pcmc->smbios_defaults = false;
    pcmc->gigabyte_align = false;
534
    pcmc->legacy_acpi_table_size = 6414;
535
}
536

537 538
DEFINE_I440FX_MACHINE(v1_7, "pc-i440fx-1.7", pc_compat_1_7,
                      pc_i440fx_1_7_machine_options);
539

540

541
static void pc_i440fx_1_6_machine_options(MachineClass *m)
542
{
543
    PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
544
    pc_i440fx_1_7_machine_options(m);
545
    m->hw_version = "1.6.0";
546
    m->rom_file_has_mr = false;
547
    SET_MACHINE_COMPAT(m, PC_COMPAT_1_6);
548
    pcmc->has_acpi_build = false;
549
}
550

551 552
DEFINE_I440FX_MACHINE(v1_6, "pc-i440fx-1.6", pc_compat_1_6,
                      pc_i440fx_1_6_machine_options);
553

554

555
static void pc_i440fx_1_5_machine_options(MachineClass *m)
556 557
{
    pc_i440fx_1_6_machine_options(m);
558
    m->hw_version = "1.5.0";
559
    SET_MACHINE_COMPAT(m, PC_COMPAT_1_5);
560
}
561

562 563
DEFINE_I440FX_MACHINE(v1_5, "pc-i440fx-1.5", pc_compat_1_5,
                      pc_i440fx_1_5_machine_options);
564

565

566
static void pc_i440fx_1_4_machine_options(MachineClass *m)
567 568
{
    pc_i440fx_1_5_machine_options(m);
569
    m->hw_version = "1.4.0";
570
    m->hot_add_cpu = NULL;
571
    SET_MACHINE_COMPAT(m, PC_COMPAT_1_4);
572
}
573

574 575
DEFINE_I440FX_MACHINE(v1_4, "pc-i440fx-1.4", pc_compat_1_4,
                      pc_i440fx_1_4_machine_options);
576

577

578
#define PC_COMPAT_1_3 \
579
        PC_COMPAT_1_4 \
580 581 582 583
        {\
            .driver   = "usb-tablet",\
            .property = "usb_version",\
            .value    = stringify(1),\
584 585 586 587
        },{\
            .driver   = "virtio-net-pci",\
            .property = "ctrl_mac_addr",\
            .value    = "off",      \
588 589 590 591
        },{ \
            .driver   = "virtio-net-pci", \
            .property = "mq", \
            .value    = "off", \
592 593 594 595
        }, {\
            .driver   = "e1000",\
            .property = "autonegotiation",\
            .value    = "off",\
596
        },
597

598

599
static void pc_i440fx_1_3_machine_options(MachineClass *m)
600 601
{
    pc_i440fx_1_4_machine_options(m);
602
    m->hw_version = "1.3.0";
603
    SET_MACHINE_COMPAT(m, PC_COMPAT_1_3);
604
}
605

606 607
DEFINE_I440FX_MACHINE(v1_3, "pc-1.3", pc_compat_1_3,
                      pc_i440fx_1_3_machine_options);
608

G
Gerd Hoffmann 已提交
609

610
#define PC_COMPAT_1_2 \
611
        PC_COMPAT_1_3 \
612 613 614 615 616 617 618 619
        {\
            .driver   = "nec-usb-xhci",\
            .property = "msi",\
            .value    = "off",\
        },{\
            .driver   = "nec-usb-xhci",\
            .property = "msix",\
            .value    = "off",\
G
Gerd Hoffmann 已提交
620 621 622 623
        },{\
            .driver   = "ivshmem",\
            .property = "use64",\
            .value    = "0",\
G
Gerd Hoffmann 已提交
624 625 626 627 628 629 630 631
        },{\
            .driver   = "qxl",\
            .property = "revision",\
            .value    = stringify(3),\
        },{\
            .driver   = "qxl-vga",\
            .property = "revision",\
            .value    = stringify(3),\
G
Gerd Hoffmann 已提交
632 633 634 635
        },{\
            .driver   = "VGA",\
            .property = "mmio",\
            .value    = "off",\
636
        },
637

638
static void pc_i440fx_1_2_machine_options(MachineClass *m)
639 640
{
    pc_i440fx_1_3_machine_options(m);
641
    m->hw_version = "1.2.0";
642
    SET_MACHINE_COMPAT(m, PC_COMPAT_1_2);
643
}
644

645 646
DEFINE_I440FX_MACHINE(v1_2, "pc-1.2", pc_compat_1_2,
                      pc_i440fx_1_2_machine_options);
647

G
Gerd Hoffmann 已提交
648

G
Gerd Hoffmann 已提交
649
#define PC_COMPAT_1_1 \
650
        PC_COMPAT_1_2 \
G
Gerd Hoffmann 已提交
651
        {\
652 653 654 655 656 657 658 659
            .driver   = "virtio-scsi-pci",\
            .property = "hotplug",\
            .value    = "off",\
        },{\
            .driver   = "virtio-scsi-pci",\
            .property = "param_change",\
            .value    = "off",\
        },{\
G
Gerd Hoffmann 已提交
660 661 662 663 664 665 666 667 668 669 670 671 672 673 674
            .driver   = "VGA",\
            .property = "vgamem_mb",\
            .value    = stringify(8),\
        },{\
            .driver   = "vmware-svga",\
            .property = "vgamem_mb",\
            .value    = stringify(8),\
        },{\
            .driver   = "qxl-vga",\
            .property = "vgamem_mb",\
            .value    = stringify(8),\
        },{\
            .driver   = "qxl",\
            .property = "vgamem_mb",\
            .value    = stringify(8),\
675 676 677 678
        },{\
            .driver   = "virtio-blk-pci",\
            .property = "config-wce",\
            .value    = "off",\
679
        },
G
Gerd Hoffmann 已提交
680

681
static void pc_i440fx_1_1_machine_options(MachineClass *m)
682 683
{
    pc_i440fx_1_2_machine_options(m);
684
    m->hw_version = "1.1.0";
685
    SET_MACHINE_COMPAT(m, PC_COMPAT_1_1);
686
}
687

688 689
DEFINE_I440FX_MACHINE(v1_1, "pc-1.1", pc_compat_1_2,
                      pc_i440fx_1_1_machine_options);
690

G
Gerd Hoffmann 已提交
691

692
#define PC_COMPAT_1_0 \
693
        PC_COMPAT_1_1 \
694
        {\
695
            .driver   = TYPE_ISA_FDC,\
696 697
            .property = "check_media_rate",\
            .value    = "off",\
698 699 700 701
        }, {\
            .driver   = "virtio-balloon-pci",\
            .property = "class",\
            .value    = stringify(PCI_CLASS_MEMORY_RAM),\
702
        },{\
703
            .driver   = "apic-common",\
704 705
            .property = "vapic",\
            .value    = "off",\
G
Gerd Hoffmann 已提交
706
        },{\
707
            .driver   = TYPE_USB_DEVICE,\
G
Gerd Hoffmann 已提交
708 709
            .property = "full-path",\
            .value    = "no",\
710
        },
711

712
static void pc_i440fx_1_0_machine_options(MachineClass *m)
713 714 715
{
    pc_i440fx_1_1_machine_options(m);
    m->hw_version = "1.0";
716
    SET_MACHINE_COMPAT(m, PC_COMPAT_1_0);
717
}
718

719 720
DEFINE_I440FX_MACHINE(v1_0, "pc-1.0", pc_compat_1_2,
                      pc_i440fx_1_0_machine_options);
721

J
Jordan Justen 已提交
722

723 724 725
#define PC_COMPAT_0_15 \
        PC_COMPAT_1_0

726
static void pc_i440fx_0_15_machine_options(MachineClass *m)
727 728 729
{
    pc_i440fx_1_0_machine_options(m);
    m->hw_version = "0.15";
730
    SET_MACHINE_COMPAT(m, PC_COMPAT_0_15);
731
}
732

733 734
DEFINE_I440FX_MACHINE(v0_15, "pc-0.15", pc_compat_1_2,
                      pc_i440fx_0_15_machine_options);
735

A
Anthony Liguori 已提交
736

737
#define PC_COMPAT_0_14 \
738
        PC_COMPAT_0_15 \
739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754
        {\
            .driver   = "virtio-blk-pci",\
            .property = "event_idx",\
            .value    = "off",\
        },{\
            .driver   = "virtio-serial-pci",\
            .property = "event_idx",\
            .value    = "off",\
        },{\
            .driver   = "virtio-net-pci",\
            .property = "event_idx",\
            .value    = "off",\
        },{\
            .driver   = "virtio-balloon-pci",\
            .property = "event_idx",\
            .value    = "off",\
755 756 757 758 759 760 761 762
        },{\
            .driver   = "qxl",\
            .property = "revision",\
            .value    = stringify(2),\
        },{\
            .driver   = "qxl-vga",\
            .property = "revision",\
            .value    = stringify(2),\
763
        },
764

765
static void pc_i440fx_0_14_machine_options(MachineClass *m)
766 767 768
{
    pc_i440fx_0_15_machine_options(m);
    m->hw_version = "0.14";
769
    SET_MACHINE_COMPAT(m, PC_COMPAT_0_14);
770
}
771

772 773
DEFINE_I440FX_MACHINE(v0_14, "pc-0.14", pc_compat_1_2,
                      pc_i440fx_0_14_machine_options);
774

G
Gerd Hoffmann 已提交
775

776
#define PC_COMPAT_0_13 \
777
        PC_COMPAT_0_14 \
778
        {\
779
            .driver   = TYPE_PCI_DEVICE,\
780 781 782 783 784 785
            .property = "command_serr_enable",\
            .value    = "off",\
        },{\
            .driver   = "AC97",\
            .property = "use_broken_id",\
            .value    = stringify(1),\
786 787 788 789
        },{\
            .driver   = "virtio-9p-pci",\
            .property = "vectors",\
            .value    = stringify(0),\
790 791 792 793 794 795 796 797
        },{\
            .driver   = "VGA",\
            .property = "rombar",\
            .value    = stringify(0),\
        },{\
            .driver   = "vmware-svga",\
            .property = "rombar",\
            .value    = stringify(0),\
798
        },
799

800
static void pc_i440fx_0_13_machine_options(MachineClass *m)
801
{
802
    PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
803 804
    pc_i440fx_0_14_machine_options(m);
    m->hw_version = "0.13";
805
    SET_MACHINE_COMPAT(m, PC_COMPAT_0_13);
806
    pcmc->kvmclock_enabled = false;
807
}
808

809 810
DEFINE_I440FX_MACHINE(v0_13, "pc-0.13", pc_compat_0_13,
                      pc_i440fx_0_13_machine_options);
811

G
Gerd Hoffmann 已提交
812

813
#define PC_COMPAT_0_12 \
814
        PC_COMPAT_0_13 \
815 816 817 818 819 820 821 822
        {\
            .driver   = "virtio-serial-pci",\
            .property = "max_ports",\
            .value    = stringify(1),\
        },{\
            .driver   = "virtio-serial-pci",\
            .property = "vectors",\
            .value    = stringify(0),\
823 824 825 826 827 828 829 830 831 832 833 834
        },{\
            .driver   = "usb-mouse",\
            .property = "serial",\
            .value    = "1",\
        },{\
            .driver   = "usb-tablet",\
            .property = "serial",\
            .value    = "1",\
        },{\
            .driver   = "usb-kbd",\
            .property = "serial",\
            .value    = "1",\
835
        },
836

837
static void pc_i440fx_0_12_machine_options(MachineClass *m)
838 839 840
{
    pc_i440fx_0_13_machine_options(m);
    m->hw_version = "0.12";
841
    SET_MACHINE_COMPAT(m, PC_COMPAT_0_12);
842
}
843

844 845
DEFINE_I440FX_MACHINE(v0_12, "pc-0.12", pc_compat_0_13,
                      pc_i440fx_0_12_machine_options);
846

847

848
#define PC_COMPAT_0_11 \
849
        PC_COMPAT_0_12 \
850 851 852 853
        {\
            .driver   = "virtio-blk-pci",\
            .property = "vectors",\
            .value    = stringify(0),\
854
        },{\
855
            .driver   = TYPE_PCI_DEVICE,\
856 857
            .property = "rombar",\
            .value    = stringify(0),\
858 859 860 861 862 863 864 865
        },{\
            .driver   = "ide-drive",\
            .property = "ver",\
            .value    = "0.11",\
        },{\
            .driver   = "scsi-disk",\
            .property = "ver",\
            .value    = "0.11",\
866
        },
867

868
static void pc_i440fx_0_11_machine_options(MachineClass *m)
869 870 871
{
    pc_i440fx_0_12_machine_options(m);
    m->hw_version = "0.11";
872
    SET_MACHINE_COMPAT(m, PC_COMPAT_0_11);
873
}
874

875 876
DEFINE_I440FX_MACHINE(v0_11, "pc-0.11", pc_compat_0_13,
                      pc_i440fx_0_11_machine_options);
877

878

E
Eduardo Habkost 已提交
879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902
#define PC_COMPAT_0_10 \
    PC_COMPAT_0_11 \
    {\
        .driver   = "virtio-blk-pci",\
        .property = "class",\
        .value    = stringify(PCI_CLASS_STORAGE_OTHER),\
    },{\
        .driver   = "virtio-serial-pci",\
        .property = "class",\
        .value    = stringify(PCI_CLASS_DISPLAY_OTHER),\
    },{\
        .driver   = "virtio-net-pci",\
        .property = "vectors",\
        .value    = stringify(0),\
    },{\
        .driver   = "ide-drive",\
        .property = "ver",\
        .value    = "0.10",\
    },{\
        .driver   = "scsi-disk",\
        .property = "ver",\
        .value    = "0.10",\
    },

903
static void pc_i440fx_0_10_machine_options(MachineClass *m)
904 905 906
{
    pc_i440fx_0_11_machine_options(m);
    m->hw_version = "0.10";
907
    SET_MACHINE_COMPAT(m, PC_COMPAT_0_10);
908
}
909

910 911
DEFINE_I440FX_MACHINE(v0_10, "pc-0.10", pc_compat_0_13,
                      pc_i440fx_0_10_machine_options);
912

913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024
typedef struct {
    uint16_t gpu_device_id;
    uint16_t pch_device_id;
    uint8_t pch_revision_id;
} IGDDeviceIDInfo;

/* In real world different GPU should have different PCH. But actually
 * the different PCH DIDs likely map to different PCH SKUs. We do the
 * same thing for the GPU. For PCH, the different SKUs are going to be
 * all the same silicon design and implementation, just different
 * features turn on and off with fuses. The SW interfaces should be
 * consistent across all SKUs in a given family (eg LPT). But just same
 * features may not be supported.
 *
 * Most of these different PCH features probably don't matter to the
 * Gfx driver, but obviously any difference in display port connections
 * will so it should be fine with any PCH in case of passthrough.
 *
 * So currently use one PCH version, 0x8c4e, to cover all HSW(Haswell)
 * scenarios, 0x9cc3 for BDW(Broadwell).
 */
static const IGDDeviceIDInfo igd_combo_id_infos[] = {
    /* HSW Classic */
    {0x0402, 0x8c4e, 0x04}, /* HSWGT1D, HSWD_w7 */
    {0x0406, 0x8c4e, 0x04}, /* HSWGT1M, HSWM_w7 */
    {0x0412, 0x8c4e, 0x04}, /* HSWGT2D, HSWD_w7 */
    {0x0416, 0x8c4e, 0x04}, /* HSWGT2M, HSWM_w7 */
    {0x041E, 0x8c4e, 0x04}, /* HSWGT15D, HSWD_w7 */
    /* HSW ULT */
    {0x0A06, 0x8c4e, 0x04}, /* HSWGT1UT, HSWM_w7 */
    {0x0A16, 0x8c4e, 0x04}, /* HSWGT2UT, HSWM_w7 */
    {0x0A26, 0x8c4e, 0x06}, /* HSWGT3UT, HSWM_w7 */
    {0x0A2E, 0x8c4e, 0x04}, /* HSWGT3UT28W, HSWM_w7 */
    {0x0A1E, 0x8c4e, 0x04}, /* HSWGT2UX, HSWM_w7 */
    {0x0A0E, 0x8c4e, 0x04}, /* HSWGT1ULX, HSWM_w7 */
    /* HSW CRW */
    {0x0D26, 0x8c4e, 0x04}, /* HSWGT3CW, HSWM_w7 */
    {0x0D22, 0x8c4e, 0x04}, /* HSWGT3CWDT, HSWD_w7 */
    /* HSW Server */
    {0x041A, 0x8c4e, 0x04}, /* HSWSVGT2, HSWD_w7 */
    /* HSW SRVR */
    {0x040A, 0x8c4e, 0x04}, /* HSWSVGT1, HSWD_w7 */
    /* BSW */
    {0x1606, 0x9cc3, 0x03}, /* BDWULTGT1, BDWM_w7 */
    {0x1616, 0x9cc3, 0x03}, /* BDWULTGT2, BDWM_w7 */
    {0x1626, 0x9cc3, 0x03}, /* BDWULTGT3, BDWM_w7 */
    {0x160E, 0x9cc3, 0x03}, /* BDWULXGT1, BDWM_w7 */
    {0x161E, 0x9cc3, 0x03}, /* BDWULXGT2, BDWM_w7 */
    {0x1602, 0x9cc3, 0x03}, /* BDWHALOGT1, BDWM_w7 */
    {0x1612, 0x9cc3, 0x03}, /* BDWHALOGT2, BDWM_w7 */
    {0x1622, 0x9cc3, 0x03}, /* BDWHALOGT3, BDWM_w7 */
    {0x162B, 0x9cc3, 0x03}, /* BDWHALO28W, BDWM_w7 */
    {0x162A, 0x9cc3, 0x03}, /* BDWGT3WRKS, BDWM_w7 */
    {0x162D, 0x9cc3, 0x03}, /* BDWGT3SRVR, BDWM_w7 */
};

static void isa_bridge_class_init(ObjectClass *klass, void *data)
{
    DeviceClass *dc = DEVICE_CLASS(klass);
    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);

    dc->desc        = "ISA bridge faked to support IGD PT";
    k->vendor_id    = PCI_VENDOR_ID_INTEL;
    k->class_id     = PCI_CLASS_BRIDGE_ISA;
};

static TypeInfo isa_bridge_info = {
    .name          = "igd-passthrough-isa-bridge",
    .parent        = TYPE_PCI_DEVICE,
    .instance_size = sizeof(PCIDevice),
    .class_init = isa_bridge_class_init,
};

static void pt_graphics_register_types(void)
{
    type_register_static(&isa_bridge_info);
}
type_init(pt_graphics_register_types)

void igd_passthrough_isa_bridge_create(PCIBus *bus, uint16_t gpu_dev_id)
{
    struct PCIDevice *bridge_dev;
    int i, num;
    uint16_t pch_dev_id = 0xffff;
    uint8_t pch_rev_id;

    num = ARRAY_SIZE(igd_combo_id_infos);
    for (i = 0; i < num; i++) {
        if (gpu_dev_id == igd_combo_id_infos[i].gpu_device_id) {
            pch_dev_id = igd_combo_id_infos[i].pch_device_id;
            pch_rev_id = igd_combo_id_infos[i].pch_revision_id;
        }
    }

    if (pch_dev_id == 0xffff) {
        return;
    }

    /* Currently IGD drivers always need to access PCH by 1f.0. */
    bridge_dev = pci_create_simple(bus, PCI_DEVFN(0x1f, 0),
                                   "igd-passthrough-isa-bridge");

    /*
     * Note that vendor id is always PCI_VENDOR_ID_INTEL.
     */
    if (!bridge_dev) {
        fprintf(stderr, "set igd-passthrough-isa-bridge failed!\n");
        return;
    }
    pci_config_set_device_id(bridge_dev->config, pch_dev_id);
    pci_config_set_revision(bridge_dev->config, pch_rev_id);
}
1025

1026
static void isapc_machine_options(MachineClass *m)
1027
{
1028
    PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
1029 1030
    m->desc = "ISA-only PC";
    m->max_cpus = 1;
1031 1032
    m->option_rom_has_mr = true;
    m->rom_file_has_mr = false;
1033 1034 1035 1036 1037 1038
    pcmc->pci_enabled = false;
    pcmc->has_acpi_build = false;
    pcmc->smbios_defaults = false;
    pcmc->gigabyte_align = false;
    pcmc->smbios_legacy_mode = true;
    pcmc->has_reserved_memory = false;
1039
}
1040

1041
DEFINE_PC_MACHINE(isapc, "isapc", pc_init_isa,
1042
                  isapc_machine_options);
1043

1044

A
Anthony PERARD 已提交
1045
#ifdef CONFIG_XEN
1046
static void xenfv_machine_options(MachineClass *m)
1047 1048 1049 1050 1051 1052
{
    m->desc = "Xen Fully-virtualized PC";
    m->max_cpus = HVM_MAX_VCPUS;
    m->default_machine_opts = "accel=xen";
    m->hot_add_cpu = pc_hot_add_cpu;
}
1053

1054
DEFINE_PC_MACHINE(xenfv, "xenfv", pc_xen_hvm_init,
1055
                  xenfv_machine_options);
A
Anthony PERARD 已提交
1056
#endif