pc_piix.c 31.6 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
        pc_pci_device_init(pci_bus);
    }
277 278 279 280 281

    if (pcms->acpi_nvdimm_state.is_enabled) {
        nvdimm_init_acpi_state(&pcms->acpi_nvdimm_state, system_io,
                               pcms->fw_cfg, OBJECT(pcms));
    }
282 283
}

284 285 286 287 288 289 290
/* 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 已提交
291 292
static void pc_compat_2_3(MachineState *machine)
{
P
Paolo Bonzini 已提交
293
    PCMachineState *pcms = PC_MACHINE(machine);
294
    savevm_skip_section_footers();
P
Paolo Bonzini 已提交
295 296 297
    if (kvm_enabled()) {
        pcms->smm = ON_OFF_AUTO_OFF;
    }
298
    global_state_set_optional();
299
    savevm_skip_configuration();
J
Jason Wang 已提交
300 301
}

P
Paolo Bonzini 已提交
302 303
static void pc_compat_2_2(MachineState *machine)
{
J
Jason Wang 已提交
304
    pc_compat_2_3(machine);
305
    machine->suppress_vmdesc = true;
P
Paolo Bonzini 已提交
306 307
}

E
Eduardo Habkost 已提交
308 309
static void pc_compat_2_1(MachineState *machine)
{
P
Paolo Bonzini 已提交
310
    pc_compat_2_2(machine);
311
    x86_cpu_change_kvm_default("svm", NULL);
E
Eduardo Habkost 已提交
312 313
}

314
static void pc_compat_2_0(MachineState *machine)
M
Michael S. Tsirkin 已提交
315
{
E
Eduardo Habkost 已提交
316
    pc_compat_2_1(machine);
M
Michael S. Tsirkin 已提交
317 318
}

319
static void pc_compat_1_7(MachineState *machine)
320
{
321
    pc_compat_2_0(machine);
322
    x86_cpu_change_kvm_default("x2apic", NULL);
323 324
}

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

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

335
static void pc_compat_1_4(MachineState *machine)
336
{
337
    pc_compat_1_5(machine);
338 339
}

340
static void pc_compat_1_3(MachineState *machine)
341
{
342
    pc_compat_1_4(machine);
343
    enable_compat_apic_id_mode();
344 345 346
}

/* PC compat function for pc-0.14 to pc-1.2 */
347
static void pc_compat_1_2(MachineState *machine)
348
{
349
    pc_compat_1_3(machine);
350
    x86_cpu_change_kvm_default("kvm-pv-eoi", NULL);
351 352
}

353 354 355 356 357 358
/* PC compat function for pc-0.10 to pc-0.13 */
static void pc_compat_0_13(MachineState *machine)
{
    pc_compat_1_2(machine);
}

359
static void pc_init_isa(MachineState *machine)
360
{
361 362
    if (!machine->cpu_model) {
        machine->cpu_model = "486";
363
    }
364
    x86_cpu_change_kvm_default("kvm-pv-eoi", NULL);
365
    enable_compat_apic_id_mode();
366
    pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, TYPE_I440FX_PCI_DEVICE);
367 368
}

A
Anthony PERARD 已提交
369
#ifdef CONFIG_XEN
370 371 372 373 374 375 376 377 378 379
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);
}

380
static void pc_xen_hvm_init(MachineState *machine)
A
Anthony PERARD 已提交
381
{
382 383
    PCIBus *bus;

384 385 386 387 388
    if (!xen_enabled()) {
        error_report("xenfv machine requires the xen accelerator");
        exit(1);
    }

389
    pc_xen_hvm_init_pci(machine);
390

D
David Gibson 已提交
391
    bus = pci_find_primary_bus();
392 393 394
    if (bus != NULL) {
        pci_create_simple(bus, -1, "xen-platform");
    }
A
Anthony PERARD 已提交
395 396 397
}
#endif

398 399 400 401 402 403 404
#define DEFINE_I440FX_MACHINE(suffix, name, compatfn, optionfn) \
    static void pc_init_##suffix(MachineState *machine) \
    { \
        void (*compat)(MachineState *m) = (compatfn); \
        if (compat) { \
            compat(machine); \
        } \
405 406
        pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, \
                 TYPE_I440FX_PCI_DEVICE); \
407 408
    } \
    DEFINE_PC_MACHINE(suffix, name, pc_init_##suffix, optionfn)
409

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

E
Eduardo Habkost 已提交
419
static void pc_i440fx_2_6_machine_options(MachineClass *m)
420 421 422 423 424
{
    pc_i440fx_machine_options(m);
    m->alias = "pc";
    m->is_default = 1;
}
425

E
Eduardo Habkost 已提交
426 427 428 429 430 431
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)
{
432
    PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
E
Eduardo Habkost 已提交
433 434 435
    pc_i440fx_2_6_machine_options(m);
    m->alias = NULL;
    m->is_default = 0;
436
    pcmc->save_tsc_khz = false;
G
Gerd Hoffmann 已提交
437
    m->legacy_fw_cfg_order = 1;
E
Eduardo Habkost 已提交
438 439 440
    SET_MACHINE_COMPAT(m, PC_COMPAT_2_5);
}

441 442 443 444 445 446 447 448
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);
449
    m->hw_version = "2.4.0";
450 451 452 453
    pcmc->broken_reserved_end = true;
    SET_MACHINE_COMPAT(m, PC_COMPAT_2_4);
}

454 455
DEFINE_I440FX_MACHINE(v2_4, "pc-i440fx-2.4", NULL,
                      pc_i440fx_2_4_machine_options)
J
Jason Wang 已提交
456

J
Jan Kiszka 已提交
457

458
static void pc_i440fx_2_3_machine_options(MachineClass *m)
459
{
460
    pc_i440fx_2_4_machine_options(m);
461
    m->hw_version = "2.3.0";
462
    SET_MACHINE_COMPAT(m, PC_COMPAT_2_3);
463
}
J
Jason Wang 已提交
464

465 466
DEFINE_I440FX_MACHINE(v2_3, "pc-i440fx-2.3", pc_compat_2_3,
                      pc_i440fx_2_3_machine_options);
467

J
Jason Wang 已提交
468

469
static void pc_i440fx_2_2_machine_options(MachineClass *m)
470
{
471
    PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
472
    pc_i440fx_2_3_machine_options(m);
473
    m->hw_version = "2.2.0";
474
    SET_MACHINE_COMPAT(m, PC_COMPAT_2_2);
475
    pcmc->rsdp_in_ram = false;
476
}
P
Paolo Bonzini 已提交
477

478 479
DEFINE_I440FX_MACHINE(v2_2, "pc-i440fx-2.2", pc_compat_2_2,
                      pc_i440fx_2_2_machine_options);
480

P
Paolo Bonzini 已提交
481

482
static void pc_i440fx_2_1_machine_options(MachineClass *m)
483
{
484
    PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
485
    pc_i440fx_2_2_machine_options(m);
486
    m->hw_version = "2.1.0";
487
    m->default_display = NULL;
488
    SET_MACHINE_COMPAT(m, PC_COMPAT_2_1);
489
    pcmc->smbios_uuid_encoded = false;
490
    pcmc->enforce_aligned_dimm = false;
491
}
J
Jan Kiszka 已提交
492

493 494
DEFINE_I440FX_MACHINE(v2_1, "pc-i440fx-2.1", pc_compat_2_1,
                      pc_i440fx_2_1_machine_options);
495

496

497

498
static void pc_i440fx_2_0_machine_options(MachineClass *m)
499
{
500
    PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
501
    pc_i440fx_2_1_machine_options(m);
502
    m->hw_version = "2.0.0";
503
    SET_MACHINE_COMPAT(m, PC_COMPAT_2_0);
504 505
    pcmc->smbios_legacy_mode = true;
    pcmc->has_reserved_memory = false;
506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522
    /* 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;
523
    pcmc->acpi_data_size = 0x10000;
524
}
M
Michael S. Tsirkin 已提交
525

526 527
DEFINE_I440FX_MACHINE(v2_0, "pc-i440fx-2.0", pc_compat_2_0,
                      pc_i440fx_2_0_machine_options);
528

M
Michael S. Tsirkin 已提交
529

530
static void pc_i440fx_1_7_machine_options(MachineClass *m)
531
{
532
    PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
533
    pc_i440fx_2_0_machine_options(m);
534
    m->hw_version = "1.7.0";
535
    m->default_machine_opts = NULL;
536
    m->option_rom_has_mr = true;
537
    SET_MACHINE_COMPAT(m, PC_COMPAT_1_7);
538 539
    pcmc->smbios_defaults = false;
    pcmc->gigabyte_align = false;
540
    pcmc->legacy_acpi_table_size = 6414;
541
}
542

543 544
DEFINE_I440FX_MACHINE(v1_7, "pc-i440fx-1.7", pc_compat_1_7,
                      pc_i440fx_1_7_machine_options);
545

546

547
static void pc_i440fx_1_6_machine_options(MachineClass *m)
548
{
549
    PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
550
    pc_i440fx_1_7_machine_options(m);
551
    m->hw_version = "1.6.0";
552
    m->rom_file_has_mr = false;
553
    SET_MACHINE_COMPAT(m, PC_COMPAT_1_6);
554
    pcmc->has_acpi_build = false;
555
}
556

557 558
DEFINE_I440FX_MACHINE(v1_6, "pc-i440fx-1.6", pc_compat_1_6,
                      pc_i440fx_1_6_machine_options);
559

560

561
static void pc_i440fx_1_5_machine_options(MachineClass *m)
562 563
{
    pc_i440fx_1_6_machine_options(m);
564
    m->hw_version = "1.5.0";
565
    SET_MACHINE_COMPAT(m, PC_COMPAT_1_5);
566
}
567

568 569
DEFINE_I440FX_MACHINE(v1_5, "pc-i440fx-1.5", pc_compat_1_5,
                      pc_i440fx_1_5_machine_options);
570

571

572
static void pc_i440fx_1_4_machine_options(MachineClass *m)
573 574
{
    pc_i440fx_1_5_machine_options(m);
575
    m->hw_version = "1.4.0";
576
    m->hot_add_cpu = NULL;
577
    SET_MACHINE_COMPAT(m, PC_COMPAT_1_4);
578
}
579

580 581
DEFINE_I440FX_MACHINE(v1_4, "pc-i440fx-1.4", pc_compat_1_4,
                      pc_i440fx_1_4_machine_options);
582

583

584
#define PC_COMPAT_1_3 \
585
        PC_CPU_MODEL_IDS("1.3.0") \
586 587 588 589
        {\
            .driver   = "usb-tablet",\
            .property = "usb_version",\
            .value    = stringify(1),\
590 591 592 593
        },{\
            .driver   = "virtio-net-pci",\
            .property = "ctrl_mac_addr",\
            .value    = "off",      \
594 595 596 597
        },{ \
            .driver   = "virtio-net-pci", \
            .property = "mq", \
            .value    = "off", \
598 599 600 601
        }, {\
            .driver   = "e1000",\
            .property = "autonegotiation",\
            .value    = "off",\
602
        },
603

604

605
static void pc_i440fx_1_3_machine_options(MachineClass *m)
606 607
{
    pc_i440fx_1_4_machine_options(m);
608
    m->hw_version = "1.3.0";
609
    SET_MACHINE_COMPAT(m, PC_COMPAT_1_3);
610
}
611

612 613
DEFINE_I440FX_MACHINE(v1_3, "pc-1.3", pc_compat_1_3,
                      pc_i440fx_1_3_machine_options);
614

G
Gerd Hoffmann 已提交
615

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

644
static void pc_i440fx_1_2_machine_options(MachineClass *m)
645 646
{
    pc_i440fx_1_3_machine_options(m);
647
    m->hw_version = "1.2.0";
648
    SET_MACHINE_COMPAT(m, PC_COMPAT_1_2);
649
}
650

651 652
DEFINE_I440FX_MACHINE(v1_2, "pc-1.2", pc_compat_1_2,
                      pc_i440fx_1_2_machine_options);
653

G
Gerd Hoffmann 已提交
654

G
Gerd Hoffmann 已提交
655
#define PC_COMPAT_1_1 \
656
        PC_CPU_MODEL_IDS("1.1.0") \
G
Gerd Hoffmann 已提交
657
        {\
658 659 660 661 662 663 664 665
            .driver   = "virtio-scsi-pci",\
            .property = "hotplug",\
            .value    = "off",\
        },{\
            .driver   = "virtio-scsi-pci",\
            .property = "param_change",\
            .value    = "off",\
        },{\
G
Gerd Hoffmann 已提交
666 667 668 669 670 671 672 673 674 675 676 677 678 679 680
            .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),\
681 682 683 684
        },{\
            .driver   = "virtio-blk-pci",\
            .property = "config-wce",\
            .value    = "off",\
685
        },
G
Gerd Hoffmann 已提交
686

687
static void pc_i440fx_1_1_machine_options(MachineClass *m)
688 689
{
    pc_i440fx_1_2_machine_options(m);
690
    m->hw_version = "1.1.0";
691
    SET_MACHINE_COMPAT(m, PC_COMPAT_1_1);
692
}
693

694 695
DEFINE_I440FX_MACHINE(v1_1, "pc-1.1", pc_compat_1_2,
                      pc_i440fx_1_1_machine_options);
696

G
Gerd Hoffmann 已提交
697

698
#define PC_COMPAT_1_0 \
699
        PC_CPU_MODEL_IDS("1.0") \
700
        {\
701
            .driver   = TYPE_ISA_FDC,\
702 703
            .property = "check_media_rate",\
            .value    = "off",\
704 705 706 707
        }, {\
            .driver   = "virtio-balloon-pci",\
            .property = "class",\
            .value    = stringify(PCI_CLASS_MEMORY_RAM),\
708
        },{\
709
            .driver   = "apic-common",\
710 711
            .property = "vapic",\
            .value    = "off",\
G
Gerd Hoffmann 已提交
712
        },{\
713
            .driver   = TYPE_USB_DEVICE,\
G
Gerd Hoffmann 已提交
714 715
            .property = "full-path",\
            .value    = "no",\
716
        },
717

718
static void pc_i440fx_1_0_machine_options(MachineClass *m)
719 720 721
{
    pc_i440fx_1_1_machine_options(m);
    m->hw_version = "1.0";
722
    SET_MACHINE_COMPAT(m, PC_COMPAT_1_0);
723
}
724

725 726
DEFINE_I440FX_MACHINE(v1_0, "pc-1.0", pc_compat_1_2,
                      pc_i440fx_1_0_machine_options);
727

J
Jordan Justen 已提交
728

729 730 731
#define PC_COMPAT_0_15 \
        PC_CPU_MODEL_IDS("0.15")

732
static void pc_i440fx_0_15_machine_options(MachineClass *m)
733 734 735
{
    pc_i440fx_1_0_machine_options(m);
    m->hw_version = "0.15";
736
    SET_MACHINE_COMPAT(m, PC_COMPAT_0_15);
737
}
738

739 740
DEFINE_I440FX_MACHINE(v0_15, "pc-0.15", pc_compat_1_2,
                      pc_i440fx_0_15_machine_options);
741

A
Anthony Liguori 已提交
742

743
#define PC_COMPAT_0_14 \
744
        PC_CPU_MODEL_IDS("0.14") \
745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760
        {\
            .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",\
761 762 763 764 765 766 767 768
        },{\
            .driver   = "qxl",\
            .property = "revision",\
            .value    = stringify(2),\
        },{\
            .driver   = "qxl-vga",\
            .property = "revision",\
            .value    = stringify(2),\
769
        },
770

771
static void pc_i440fx_0_14_machine_options(MachineClass *m)
772 773 774
{
    pc_i440fx_0_15_machine_options(m);
    m->hw_version = "0.14";
775
    SET_MACHINE_COMPAT(m, PC_COMPAT_0_14);
776
}
777

778 779
DEFINE_I440FX_MACHINE(v0_14, "pc-0.14", pc_compat_1_2,
                      pc_i440fx_0_14_machine_options);
780

G
Gerd Hoffmann 已提交
781

782
#define PC_COMPAT_0_13 \
783
        PC_CPU_MODEL_IDS("0.13") \
784
        {\
785
            .driver   = TYPE_PCI_DEVICE,\
786 787 788 789 790 791
            .property = "command_serr_enable",\
            .value    = "off",\
        },{\
            .driver   = "AC97",\
            .property = "use_broken_id",\
            .value    = stringify(1),\
792 793 794 795
        },{\
            .driver   = "virtio-9p-pci",\
            .property = "vectors",\
            .value    = stringify(0),\
796 797 798 799 800 801 802 803
        },{\
            .driver   = "VGA",\
            .property = "rombar",\
            .value    = stringify(0),\
        },{\
            .driver   = "vmware-svga",\
            .property = "rombar",\
            .value    = stringify(0),\
804
        },
805

806
static void pc_i440fx_0_13_machine_options(MachineClass *m)
807
{
808
    PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
809 810
    pc_i440fx_0_14_machine_options(m);
    m->hw_version = "0.13";
811
    SET_MACHINE_COMPAT(m, PC_COMPAT_0_13);
812
    pcmc->kvmclock_enabled = false;
813
}
814

815 816
DEFINE_I440FX_MACHINE(v0_13, "pc-0.13", pc_compat_0_13,
                      pc_i440fx_0_13_machine_options);
817

G
Gerd Hoffmann 已提交
818

819
#define PC_COMPAT_0_12 \
820
        PC_CPU_MODEL_IDS("0.12") \
821 822 823 824 825 826 827 828
        {\
            .driver   = "virtio-serial-pci",\
            .property = "max_ports",\
            .value    = stringify(1),\
        },{\
            .driver   = "virtio-serial-pci",\
            .property = "vectors",\
            .value    = stringify(0),\
829 830 831 832 833 834 835 836 837 838 839 840
        },{\
            .driver   = "usb-mouse",\
            .property = "serial",\
            .value    = "1",\
        },{\
            .driver   = "usb-tablet",\
            .property = "serial",\
            .value    = "1",\
        },{\
            .driver   = "usb-kbd",\
            .property = "serial",\
            .value    = "1",\
841
        },
842

843
static void pc_i440fx_0_12_machine_options(MachineClass *m)
844 845 846
{
    pc_i440fx_0_13_machine_options(m);
    m->hw_version = "0.12";
847
    SET_MACHINE_COMPAT(m, PC_COMPAT_0_12);
848
}
849

850 851
DEFINE_I440FX_MACHINE(v0_12, "pc-0.12", pc_compat_0_13,
                      pc_i440fx_0_12_machine_options);
852

853

854
#define PC_COMPAT_0_11 \
855
        PC_CPU_MODEL_IDS("0.11") \
856 857 858 859
        {\
            .driver   = "virtio-blk-pci",\
            .property = "vectors",\
            .value    = stringify(0),\
860
        },{\
861
            .driver   = TYPE_PCI_DEVICE,\
862 863
            .property = "rombar",\
            .value    = stringify(0),\
864 865 866 867 868 869 870 871
        },{\
            .driver   = "ide-drive",\
            .property = "ver",\
            .value    = "0.11",\
        },{\
            .driver   = "scsi-disk",\
            .property = "ver",\
            .value    = "0.11",\
872
        },
873

874
static void pc_i440fx_0_11_machine_options(MachineClass *m)
875 876 877
{
    pc_i440fx_0_12_machine_options(m);
    m->hw_version = "0.11";
878
    SET_MACHINE_COMPAT(m, PC_COMPAT_0_11);
879
}
880

881 882
DEFINE_I440FX_MACHINE(v0_11, "pc-0.11", pc_compat_0_13,
                      pc_i440fx_0_11_machine_options);
883

884

E
Eduardo Habkost 已提交
885
#define PC_COMPAT_0_10 \
886
    PC_CPU_MODEL_IDS("0.10") \
E
Eduardo Habkost 已提交
887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908
    {\
        .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",\
    },

909
static void pc_i440fx_0_10_machine_options(MachineClass *m)
910 911 912
{
    pc_i440fx_0_11_machine_options(m);
    m->hw_version = "0.10";
913
    SET_MACHINE_COMPAT(m, PC_COMPAT_0_10);
914
}
915

916 917
DEFINE_I440FX_MACHINE(v0_10, "pc-0.10", pc_compat_0_13,
                      pc_i440fx_0_10_machine_options);
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 1025 1026 1027 1028 1029 1030
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);
}
1031

1032
static void isapc_machine_options(MachineClass *m)
1033
{
1034
    PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
1035 1036
    m->desc = "ISA-only PC";
    m->max_cpus = 1;
1037 1038
    m->option_rom_has_mr = true;
    m->rom_file_has_mr = false;
1039 1040 1041 1042 1043 1044
    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;
1045
}
1046

1047
DEFINE_PC_MACHINE(isapc, "isapc", pc_init_isa,
1048
                  isapc_machine_options);
1049

1050

A
Anthony PERARD 已提交
1051
#ifdef CONFIG_XEN
1052
static void xenfv_machine_options(MachineClass *m)
1053 1054 1055 1056 1057 1058
{
    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;
}
1059

1060
DEFINE_PC_MACHINE(xenfv, "xenfv", pc_xen_hvm_init,
1061
                  xenfv_machine_options);
A
Anthony PERARD 已提交
1062
#endif