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

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

89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
    /*
     * Calculate ram split, for memory below and above 4G.  It's a bit
     * complicated for backward compatibility reasons ...
     *
     *  - Traditional split is 3.5G (lowmem = 0xe0000000).  This is the
     *    default value for max_ram_below_4g now.
     *
     *  - Then, to gigabyte align the memory, we move the split to 3G
     *    (lowmem = 0xc0000000).  But only in case we have to split in
     *    the first place, i.e. ram_size is larger than (traditional)
     *    lowmem.  And for new machine types (gigabyte_align = true)
     *    only, for live migration compatibility reasons.
     *
     *  - Next the max-ram-below-4g option was added, which allowed to
     *    reduce lowmem to a smaller value, to allow a larger PCI I/O
     *    window below 4G.  qemu doesn't enforce gigabyte alignment here,
     *    but prints a warning.
     *
     *  - Finally max-ram-below-4g got updated to also allow raising lowmem,
     *    so legacy non-PAE guests can get as much memory as possible in
     *    the 32bit address space below 4G.
     *
     * Examples:
     *    qemu -M pc-1.7 -m 4G    (old default)    -> 3584M low,  512M high
     *    qemu -M pc -m 4G        (new default)    -> 3072M low, 1024M high
     *    qemu -M pc,max-ram-below-4g=2G -m 4G     -> 2048M low, 2048M high
     *    qemu -M pc,max-ram-below-4g=4G -m 3968M  -> 3968M low (=4G-128M)
116
     */
117 118 119 120 121 122 123 124 125 126 127 128
    lowmem = pcms->max_ram_below_4g;
    if (machine->ram_size >= pcms->max_ram_below_4g) {
        if (pcmc->gigabyte_align) {
            if (lowmem > 0xc0000000) {
                lowmem = 0xc0000000;
            }
            if (lowmem & ((1ULL << 30) - 1)) {
                error_report("Warning: Large machine and max_ram_below_4g "
                             "(%" PRIu64 ") not a multiple of 1G; "
                             "possible bad performance.",
                             pcms->max_ram_below_4g);
            }
129 130 131 132
        }
    }

    if (machine->ram_size >= lowmem) {
133 134
        pcms->above_4g_mem_size = machine->ram_size - lowmem;
        pcms->below_4g_mem_size = lowmem;
135
    } else {
136 137
        pcms->above_4g_mem_size = 0;
        pcms->below_4g_mem_size = machine->ram_size;
138 139
    }

140 141
    if (xen_enabled()) {
        xen_hvm_init(pcms, &ram_memory);
142 143
    }

144
    pc_cpus_init(pcms);
145

146
    if (kvm_enabled() && pcmc->kvmclock_enabled) {
147 148 149
        kvmclock_create();
    }

150
    if (pcmc->pci_enabled) {
151
        pci_memory = g_new(MemoryRegion, 1);
P
Paolo Bonzini 已提交
152
        memory_region_init(pci_memory, NULL, "pci", UINT64_MAX);
153 154 155 156 157
        rom_memory = pci_memory;
    } else {
        pci_memory = NULL;
        rom_memory = system_memory;
    }
A
Avi Kivity 已提交
158

159
    pc_guest_info_init(pcms);
160

161
    if (pcmc->smbios_defaults) {
162
        MachineClass *mc = MACHINE_GET_CLASS(machine);
163
        /* These values are guest ABI, do not change */
164
        smbios_set_defaults("QEMU", "Standard PC (i440FX + PIIX, 1996)",
165 166
                            mc->name, pcmc->smbios_legacy_mode,
                            pcmc->smbios_uuid_encoded,
W
Wei Huang 已提交
167
                            SMBIOS_ENTRY_POINT_21);
168 169
    }

170
    /* allocate ram and load rom/bios */
A
Anthony PERARD 已提交
171
    if (!xen_enabled()) {
172
        pc_memory_init(pcms, system_memory,
173
                       rom_memory, &ram_memory);
174 175
    } else if (machine->kernel_filename != NULL) {
        /* For xen HVM direct kernel boot, load linux here */
176
        xen_load_linux(pcms);
A
Anthony PERARD 已提交
177
    }
178

J
Jan Kiszka 已提交
179
    gsi_state = g_malloc0(sizeof(*gsi_state));
180
    if (kvm_ioapic_in_kernel()) {
181
        kvm_pc_setup_irq_routing(pcmc->pci_enabled);
182
        gsi = qemu_allocate_irqs(kvm_pc_gsi_handler, gsi_state,
183 184 185 186
                                 GSI_NUM_PINS);
    } else {
        gsi = qemu_allocate_irqs(gsi_handler, gsi_state, GSI_NUM_PINS);
    }
187

188
    if (pcmc->pci_enabled) {
189 190
        pci_bus = i440fx_init(host_type,
                              pci_type,
191
                              &i440fx_state, &piix3_devfn, &isa_bus, gsi,
192
                              system_memory, system_io, machine->ram_size,
193 194
                              pcms->below_4g_mem_size,
                              pcms->above_4g_mem_size,
A
Avi Kivity 已提交
195
                              pci_memory, ram_memory);
196
        pcms->bus = pci_bus;
197 198
    } else {
        pci_bus = NULL;
I
Isaku Yamahata 已提交
199
        i440fx_state = NULL;
200 201
        isa_bus = isa_bus_new(NULL, get_system_memory(), system_io,
                              &error_abort);
J
Jan Kiszka 已提交
202
        no_hpet = 1;
203
    }
204
    isa_bus_irqs(isa_bus, gsi);
205

206
    if (kvm_pic_in_kernel()) {
207 208 209 210
        i8259 = kvm_i8259_init(isa_bus);
    } else if (xen_enabled()) {
        i8259 = xen_interrupt_controller_init();
    } else {
211
        i8259 = i8259_init(isa_bus, pc_allocate_cpu_irq());
212 213
    }

214 215 216
    for (i = 0; i < ISA_NUM_IRQS; i++) {
        gsi_state->i8259_irq[i] = i8259[i];
    }
S
Shannon Zhao 已提交
217
    g_free(i8259);
218
    if (pcmc->pci_enabled) {
219
        ioapic_init_gsi(gsi_state, "i440fx");
220 221
    }

J
Jan Kiszka 已提交
222
    pc_register_ferr_irq(gsi[13]);
223

224
    pc_vga_init(isa_bus, pcmc->pci_enabled ? pci_bus : NULL);
225

226
    assert(pcms->vmport != ON_OFF_AUTO__MAX);
227 228
    if (pcms->vmport == ON_OFF_AUTO_AUTO) {
        pcms->vmport = xen_enabled() ? ON_OFF_AUTO_OFF : ON_OFF_AUTO_ON;
229 230
    }

231
    /* init basic PC hardware */
232
    pc_basic_device_init(isa_bus, gsi, &rtc_state, true,
233
                         (pcms->vmport != ON_OFF_AUTO_ON), 0x4);
234

235
    pc_nic_init(isa_bus, pci_bus);
236

237
    ide_drive_get(hd, ARRAY_SIZE(hd));
238
    if (pcmc->pci_enabled) {
239
        PCIDevice *dev;
240 241 242 243 244
        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);
        }
245 246
        idebus[0] = qdev_get_child_bus(&dev->qdev, "ide.0");
        idebus[1] = qdev_get_child_bus(&dev->qdev, "ide.1");
247 248
    } else {
        for(i = 0; i < MAX_IDE_BUS; i++) {
249
            ISADevice *dev;
250
            char busname[] = "ide.0";
251 252
            dev = isa_ide_init(isa_bus, ide_iobase[i], ide_iobase2[i],
                               ide_irq[i],
253
                               hd[MAX_IDE_DEVS * i], hd[MAX_IDE_DEVS * i + 1]);
254 255 256 257 258 259
            /*
             * 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);
260 261 262
        }
    }

263
    pc_cmos_init(pcms, idebus[0], idebus[1], rtc_state);
264

E
Eduardo Habkost 已提交
265
    if (pcmc->pci_enabled && machine_usb(machine)) {
266
        pci_create_simple(pci_bus, piix3_devfn + 2, "piix3-usb-uhci");
267 268
    }

269
    if (pcmc->pci_enabled && acpi_enabled) {
270
        DeviceState *piix4_pm;
A
Andreas Färber 已提交
271
        I2CBus *smbus;
272

S
Shannon Zhao 已提交
273
        smi_irq = qemu_allocate_irq(pc_acpi_smi_interrupt, first_cpu, 0);
274 275
        /* TODO: Populate SPD eeprom data.  */
        smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100,
S
Shannon Zhao 已提交
276
                              gsi[9], smi_irq,
277
                              pc_machine_is_smm_enabled(pcms),
P
Paolo Bonzini 已提交
278
                              &piix4_pm);
279
        smbus_eeprom_init(smbus, 8, NULL, 0);
280 281 282

        object_property_add_link(OBJECT(machine), PC_MACHINE_ACPI_DEVICE_PROP,
                                 TYPE_HOTPLUG_HANDLER,
283
                                 (Object **)&pcms->acpi_dev,
284 285 286 287
                                 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);
288 289
    }

290
    if (pcmc->pci_enabled) {
291 292
        pc_pci_device_init(pci_bus);
    }
293 294 295 296 297

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

300 301 302 303 304 305 306
/* 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 已提交
307 308
static void pc_compat_2_3(MachineState *machine)
{
P
Paolo Bonzini 已提交
309
    PCMachineState *pcms = PC_MACHINE(machine);
310
    savevm_skip_section_footers();
P
Paolo Bonzini 已提交
311 312 313
    if (kvm_enabled()) {
        pcms->smm = ON_OFF_AUTO_OFF;
    }
314
    global_state_set_optional();
315
    savevm_skip_configuration();
J
Jason Wang 已提交
316 317
}

P
Paolo Bonzini 已提交
318 319
static void pc_compat_2_2(MachineState *machine)
{
J
Jason Wang 已提交
320
    pc_compat_2_3(machine);
321
    machine->suppress_vmdesc = true;
P
Paolo Bonzini 已提交
322 323
}

E
Eduardo Habkost 已提交
324 325
static void pc_compat_2_1(MachineState *machine)
{
P
Paolo Bonzini 已提交
326
    pc_compat_2_2(machine);
327
    x86_cpu_change_kvm_default("svm", NULL);
E
Eduardo Habkost 已提交
328 329
}

330
static void pc_compat_2_0(MachineState *machine)
M
Michael S. Tsirkin 已提交
331
{
E
Eduardo Habkost 已提交
332
    pc_compat_2_1(machine);
M
Michael S. Tsirkin 已提交
333 334
}

335
static void pc_compat_1_7(MachineState *machine)
336
{
337
    pc_compat_2_0(machine);
338
    x86_cpu_change_kvm_default("x2apic", NULL);
339 340
}

341
static void pc_compat_1_6(MachineState *machine)
342
{
343
    pc_compat_1_7(machine);
344 345
}

346
static void pc_compat_1_5(MachineState *machine)
347
{
348
    pc_compat_1_6(machine);
349 350
}

351
static void pc_compat_1_4(MachineState *machine)
352
{
353
    pc_compat_1_5(machine);
354 355
}

356
static void pc_compat_1_3(MachineState *machine)
357
{
358
    pc_compat_1_4(machine);
359
    enable_compat_apic_id_mode();
360 361 362
}

/* PC compat function for pc-0.14 to pc-1.2 */
363
static void pc_compat_1_2(MachineState *machine)
364
{
365
    pc_compat_1_3(machine);
366
    x86_cpu_change_kvm_default("kvm-pv-eoi", NULL);
367 368
}

369 370 371 372 373 374
/* PC compat function for pc-0.10 to pc-0.13 */
static void pc_compat_0_13(MachineState *machine)
{
    pc_compat_1_2(machine);
}

375
static void pc_init_isa(MachineState *machine)
376
{
377 378
    if (!machine->cpu_model) {
        machine->cpu_model = "486";
379
    }
380
    x86_cpu_change_kvm_default("kvm-pv-eoi", NULL);
381
    enable_compat_apic_id_mode();
382
    pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, TYPE_I440FX_PCI_DEVICE);
383 384
}

A
Anthony PERARD 已提交
385
#ifdef CONFIG_XEN
386 387 388 389 390 391 392 393 394 395
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);
}

396
static void pc_xen_hvm_init(MachineState *machine)
A
Anthony PERARD 已提交
397
{
398 399
    PCIBus *bus;

400 401 402 403 404
    if (!xen_enabled()) {
        error_report("xenfv machine requires the xen accelerator");
        exit(1);
    }

405
    pc_xen_hvm_init_pci(machine);
406

D
David Gibson 已提交
407
    bus = pci_find_primary_bus();
408 409 410
    if (bus != NULL) {
        pci_create_simple(bus, -1, "xen-platform");
    }
A
Anthony PERARD 已提交
411 412 413
}
#endif

414 415 416 417 418 419 420
#define DEFINE_I440FX_MACHINE(suffix, name, compatfn, optionfn) \
    static void pc_init_##suffix(MachineState *machine) \
    { \
        void (*compat)(MachineState *m) = (compatfn); \
        if (compat) { \
            compat(machine); \
        } \
421 422
        pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, \
                 TYPE_I440FX_PCI_DEVICE); \
423 424
    } \
    DEFINE_PC_MACHINE(suffix, name, pc_init_##suffix, optionfn)
425

426
static void pc_i440fx_machine_options(MachineClass *m)
427 428 429 430
{
    m->family = "pc_piix";
    m->desc = "Standard PC (i440FX + PIIX, 1996)";
    m->hot_add_cpu = pc_hot_add_cpu;
431 432
    m->default_machine_opts = "firmware=bios-256k.bin";
    m->default_display = "std";
433 434
}

I
Igor Mammedov 已提交
435
static void pc_i440fx_2_7_machine_options(MachineClass *m)
436 437 438 439 440
{
    pc_i440fx_machine_options(m);
    m->alias = "pc";
    m->is_default = 1;
}
441

I
Igor Mammedov 已提交
442 443 444 445 446 447 448 449 450 451 452 453
DEFINE_I440FX_MACHINE(v2_7, "pc-i440fx-2.7", NULL,
                      pc_i440fx_2_7_machine_options);


static void pc_i440fx_2_6_machine_options(MachineClass *m)
{
    pc_i440fx_2_7_machine_options(m);
    m->is_default = 0;
    m->alias = NULL;
    SET_MACHINE_COMPAT(m, PC_COMPAT_2_6);
}

E
Eduardo Habkost 已提交
454 455 456 457 458 459
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)
{
460
    PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
E
Eduardo Habkost 已提交
461
    pc_i440fx_2_6_machine_options(m);
462
    pcmc->save_tsc_khz = false;
G
Gerd Hoffmann 已提交
463
    m->legacy_fw_cfg_order = 1;
E
Eduardo Habkost 已提交
464 465 466
    SET_MACHINE_COMPAT(m, PC_COMPAT_2_5);
}

467 468 469 470 471 472 473 474
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);
475
    m->hw_version = "2.4.0";
476 477 478 479
    pcmc->broken_reserved_end = true;
    SET_MACHINE_COMPAT(m, PC_COMPAT_2_4);
}

480 481
DEFINE_I440FX_MACHINE(v2_4, "pc-i440fx-2.4", NULL,
                      pc_i440fx_2_4_machine_options)
J
Jason Wang 已提交
482

J
Jan Kiszka 已提交
483

484
static void pc_i440fx_2_3_machine_options(MachineClass *m)
485
{
486
    pc_i440fx_2_4_machine_options(m);
487
    m->hw_version = "2.3.0";
488
    SET_MACHINE_COMPAT(m, PC_COMPAT_2_3);
489
}
J
Jason Wang 已提交
490

491 492
DEFINE_I440FX_MACHINE(v2_3, "pc-i440fx-2.3", pc_compat_2_3,
                      pc_i440fx_2_3_machine_options);
493

J
Jason Wang 已提交
494

495
static void pc_i440fx_2_2_machine_options(MachineClass *m)
496
{
497
    PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
498
    pc_i440fx_2_3_machine_options(m);
499
    m->hw_version = "2.2.0";
500
    SET_MACHINE_COMPAT(m, PC_COMPAT_2_2);
501
    pcmc->rsdp_in_ram = false;
502
}
P
Paolo Bonzini 已提交
503

504 505
DEFINE_I440FX_MACHINE(v2_2, "pc-i440fx-2.2", pc_compat_2_2,
                      pc_i440fx_2_2_machine_options);
506

P
Paolo Bonzini 已提交
507

508
static void pc_i440fx_2_1_machine_options(MachineClass *m)
509
{
510
    PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
511
    pc_i440fx_2_2_machine_options(m);
512
    m->hw_version = "2.1.0";
513
    m->default_display = NULL;
514
    SET_MACHINE_COMPAT(m, PC_COMPAT_2_1);
515
    pcmc->smbios_uuid_encoded = false;
516
    pcmc->enforce_aligned_dimm = false;
517
}
J
Jan Kiszka 已提交
518

519 520
DEFINE_I440FX_MACHINE(v2_1, "pc-i440fx-2.1", pc_compat_2_1,
                      pc_i440fx_2_1_machine_options);
521

522

523

524
static void pc_i440fx_2_0_machine_options(MachineClass *m)
525
{
526
    PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
527
    pc_i440fx_2_1_machine_options(m);
528
    m->hw_version = "2.0.0";
529
    SET_MACHINE_COMPAT(m, PC_COMPAT_2_0);
530 531
    pcmc->smbios_legacy_mode = true;
    pcmc->has_reserved_memory = false;
532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548
    /* 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;
549
    pcmc->acpi_data_size = 0x10000;
550
}
M
Michael S. Tsirkin 已提交
551

552 553
DEFINE_I440FX_MACHINE(v2_0, "pc-i440fx-2.0", pc_compat_2_0,
                      pc_i440fx_2_0_machine_options);
554

M
Michael S. Tsirkin 已提交
555

556
static void pc_i440fx_1_7_machine_options(MachineClass *m)
557
{
558
    PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
559
    pc_i440fx_2_0_machine_options(m);
560
    m->hw_version = "1.7.0";
561
    m->default_machine_opts = NULL;
562
    m->option_rom_has_mr = true;
563
    SET_MACHINE_COMPAT(m, PC_COMPAT_1_7);
564 565
    pcmc->smbios_defaults = false;
    pcmc->gigabyte_align = false;
566
    pcmc->legacy_acpi_table_size = 6414;
567
}
568

569 570
DEFINE_I440FX_MACHINE(v1_7, "pc-i440fx-1.7", pc_compat_1_7,
                      pc_i440fx_1_7_machine_options);
571

572

573
static void pc_i440fx_1_6_machine_options(MachineClass *m)
574
{
575
    PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
576
    pc_i440fx_1_7_machine_options(m);
577
    m->hw_version = "1.6.0";
578
    m->rom_file_has_mr = false;
579
    SET_MACHINE_COMPAT(m, PC_COMPAT_1_6);
580
    pcmc->has_acpi_build = false;
581
}
582

583 584
DEFINE_I440FX_MACHINE(v1_6, "pc-i440fx-1.6", pc_compat_1_6,
                      pc_i440fx_1_6_machine_options);
585

586

587
static void pc_i440fx_1_5_machine_options(MachineClass *m)
588 589
{
    pc_i440fx_1_6_machine_options(m);
590
    m->hw_version = "1.5.0";
591
    SET_MACHINE_COMPAT(m, PC_COMPAT_1_5);
592
}
593

594 595
DEFINE_I440FX_MACHINE(v1_5, "pc-i440fx-1.5", pc_compat_1_5,
                      pc_i440fx_1_5_machine_options);
596

597

598
static void pc_i440fx_1_4_machine_options(MachineClass *m)
599 600
{
    pc_i440fx_1_5_machine_options(m);
601
    m->hw_version = "1.4.0";
602
    m->hot_add_cpu = NULL;
603
    SET_MACHINE_COMPAT(m, PC_COMPAT_1_4);
604
}
605

606 607
DEFINE_I440FX_MACHINE(v1_4, "pc-i440fx-1.4", pc_compat_1_4,
                      pc_i440fx_1_4_machine_options);
608

609

610
#define PC_COMPAT_1_3 \
611
        PC_CPU_MODEL_IDS("1.3.0") \
612 613 614 615
        {\
            .driver   = "usb-tablet",\
            .property = "usb_version",\
            .value    = stringify(1),\
616 617 618 619
        },{\
            .driver   = "virtio-net-pci",\
            .property = "ctrl_mac_addr",\
            .value    = "off",      \
620 621 622 623
        },{ \
            .driver   = "virtio-net-pci", \
            .property = "mq", \
            .value    = "off", \
624 625 626 627
        }, {\
            .driver   = "e1000",\
            .property = "autonegotiation",\
            .value    = "off",\
628
        },
629

630

631
static void pc_i440fx_1_3_machine_options(MachineClass *m)
632 633
{
    pc_i440fx_1_4_machine_options(m);
634
    m->hw_version = "1.3.0";
635
    SET_MACHINE_COMPAT(m, PC_COMPAT_1_3);
636
}
637

638 639
DEFINE_I440FX_MACHINE(v1_3, "pc-1.3", pc_compat_1_3,
                      pc_i440fx_1_3_machine_options);
640

G
Gerd Hoffmann 已提交
641

642
#define PC_COMPAT_1_2 \
643
        PC_CPU_MODEL_IDS("1.2.0") \
644 645 646 647 648 649 650 651
        {\
            .driver   = "nec-usb-xhci",\
            .property = "msi",\
            .value    = "off",\
        },{\
            .driver   = "nec-usb-xhci",\
            .property = "msix",\
            .value    = "off",\
G
Gerd Hoffmann 已提交
652 653 654 655
        },{\
            .driver   = "ivshmem",\
            .property = "use64",\
            .value    = "0",\
G
Gerd Hoffmann 已提交
656 657 658 659 660 661 662 663
        },{\
            .driver   = "qxl",\
            .property = "revision",\
            .value    = stringify(3),\
        },{\
            .driver   = "qxl-vga",\
            .property = "revision",\
            .value    = stringify(3),\
G
Gerd Hoffmann 已提交
664 665 666 667
        },{\
            .driver   = "VGA",\
            .property = "mmio",\
            .value    = "off",\
668
        },
669

670
static void pc_i440fx_1_2_machine_options(MachineClass *m)
671 672
{
    pc_i440fx_1_3_machine_options(m);
673
    m->hw_version = "1.2.0";
674
    SET_MACHINE_COMPAT(m, PC_COMPAT_1_2);
675
}
676

677 678
DEFINE_I440FX_MACHINE(v1_2, "pc-1.2", pc_compat_1_2,
                      pc_i440fx_1_2_machine_options);
679

G
Gerd Hoffmann 已提交
680

G
Gerd Hoffmann 已提交
681
#define PC_COMPAT_1_1 \
682
        PC_CPU_MODEL_IDS("1.1.0") \
G
Gerd Hoffmann 已提交
683
        {\
684 685 686 687 688 689 690 691
            .driver   = "virtio-scsi-pci",\
            .property = "hotplug",\
            .value    = "off",\
        },{\
            .driver   = "virtio-scsi-pci",\
            .property = "param_change",\
            .value    = "off",\
        },{\
G
Gerd Hoffmann 已提交
692 693 694 695 696 697 698 699 700 701 702 703 704 705 706
            .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),\
707 708 709 710
        },{\
            .driver   = "virtio-blk-pci",\
            .property = "config-wce",\
            .value    = "off",\
711
        },
G
Gerd Hoffmann 已提交
712

713
static void pc_i440fx_1_1_machine_options(MachineClass *m)
714 715
{
    pc_i440fx_1_2_machine_options(m);
716
    m->hw_version = "1.1.0";
717
    SET_MACHINE_COMPAT(m, PC_COMPAT_1_1);
718
}
719

720 721
DEFINE_I440FX_MACHINE(v1_1, "pc-1.1", pc_compat_1_2,
                      pc_i440fx_1_1_machine_options);
722

G
Gerd Hoffmann 已提交
723

724
#define PC_COMPAT_1_0 \
725
        PC_CPU_MODEL_IDS("1.0") \
726
        {\
727
            .driver   = TYPE_ISA_FDC,\
728 729
            .property = "check_media_rate",\
            .value    = "off",\
730 731 732 733
        }, {\
            .driver   = "virtio-balloon-pci",\
            .property = "class",\
            .value    = stringify(PCI_CLASS_MEMORY_RAM),\
734
        },{\
735
            .driver   = "apic-common",\
736 737
            .property = "vapic",\
            .value    = "off",\
G
Gerd Hoffmann 已提交
738
        },{\
739
            .driver   = TYPE_USB_DEVICE,\
G
Gerd Hoffmann 已提交
740 741
            .property = "full-path",\
            .value    = "no",\
742
        },
743

744
static void pc_i440fx_1_0_machine_options(MachineClass *m)
745 746 747
{
    pc_i440fx_1_1_machine_options(m);
    m->hw_version = "1.0";
748
    SET_MACHINE_COMPAT(m, PC_COMPAT_1_0);
749
}
750

751 752
DEFINE_I440FX_MACHINE(v1_0, "pc-1.0", pc_compat_1_2,
                      pc_i440fx_1_0_machine_options);
753

J
Jordan Justen 已提交
754

755 756 757
#define PC_COMPAT_0_15 \
        PC_CPU_MODEL_IDS("0.15")

758
static void pc_i440fx_0_15_machine_options(MachineClass *m)
759 760 761
{
    pc_i440fx_1_0_machine_options(m);
    m->hw_version = "0.15";
762
    SET_MACHINE_COMPAT(m, PC_COMPAT_0_15);
763
}
764

765 766
DEFINE_I440FX_MACHINE(v0_15, "pc-0.15", pc_compat_1_2,
                      pc_i440fx_0_15_machine_options);
767

A
Anthony Liguori 已提交
768

769
#define PC_COMPAT_0_14 \
770
        PC_CPU_MODEL_IDS("0.14") \
771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786
        {\
            .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",\
787 788 789 790 791 792 793 794
        },{\
            .driver   = "qxl",\
            .property = "revision",\
            .value    = stringify(2),\
        },{\
            .driver   = "qxl-vga",\
            .property = "revision",\
            .value    = stringify(2),\
795
        },
796

797
static void pc_i440fx_0_14_machine_options(MachineClass *m)
798 799 800
{
    pc_i440fx_0_15_machine_options(m);
    m->hw_version = "0.14";
801
    SET_MACHINE_COMPAT(m, PC_COMPAT_0_14);
802
}
803

804 805
DEFINE_I440FX_MACHINE(v0_14, "pc-0.14", pc_compat_1_2,
                      pc_i440fx_0_14_machine_options);
806

G
Gerd Hoffmann 已提交
807

808
#define PC_COMPAT_0_13 \
809
        PC_CPU_MODEL_IDS("0.13") \
810
        {\
811
            .driver   = TYPE_PCI_DEVICE,\
812 813 814 815 816 817
            .property = "command_serr_enable",\
            .value    = "off",\
        },{\
            .driver   = "AC97",\
            .property = "use_broken_id",\
            .value    = stringify(1),\
818 819 820 821
        },{\
            .driver   = "virtio-9p-pci",\
            .property = "vectors",\
            .value    = stringify(0),\
822 823 824 825 826 827 828 829
        },{\
            .driver   = "VGA",\
            .property = "rombar",\
            .value    = stringify(0),\
        },{\
            .driver   = "vmware-svga",\
            .property = "rombar",\
            .value    = stringify(0),\
830
        },
831

832
static void pc_i440fx_0_13_machine_options(MachineClass *m)
833
{
834
    PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
835 836
    pc_i440fx_0_14_machine_options(m);
    m->hw_version = "0.13";
837
    SET_MACHINE_COMPAT(m, PC_COMPAT_0_13);
838
    pcmc->kvmclock_enabled = false;
839
}
840

841 842
DEFINE_I440FX_MACHINE(v0_13, "pc-0.13", pc_compat_0_13,
                      pc_i440fx_0_13_machine_options);
843

G
Gerd Hoffmann 已提交
844

845
#define PC_COMPAT_0_12 \
846
        PC_CPU_MODEL_IDS("0.12") \
847 848 849 850 851 852 853 854
        {\
            .driver   = "virtio-serial-pci",\
            .property = "max_ports",\
            .value    = stringify(1),\
        },{\
            .driver   = "virtio-serial-pci",\
            .property = "vectors",\
            .value    = stringify(0),\
855 856 857 858 859 860 861 862 863 864 865 866
        },{\
            .driver   = "usb-mouse",\
            .property = "serial",\
            .value    = "1",\
        },{\
            .driver   = "usb-tablet",\
            .property = "serial",\
            .value    = "1",\
        },{\
            .driver   = "usb-kbd",\
            .property = "serial",\
            .value    = "1",\
867
        },
868

869
static void pc_i440fx_0_12_machine_options(MachineClass *m)
870 871 872
{
    pc_i440fx_0_13_machine_options(m);
    m->hw_version = "0.12";
873
    SET_MACHINE_COMPAT(m, PC_COMPAT_0_12);
874
}
875

876 877
DEFINE_I440FX_MACHINE(v0_12, "pc-0.12", pc_compat_0_13,
                      pc_i440fx_0_12_machine_options);
878

879

880
#define PC_COMPAT_0_11 \
881
        PC_CPU_MODEL_IDS("0.11") \
882 883 884 885
        {\
            .driver   = "virtio-blk-pci",\
            .property = "vectors",\
            .value    = stringify(0),\
886
        },{\
887
            .driver   = TYPE_PCI_DEVICE,\
888 889
            .property = "rombar",\
            .value    = stringify(0),\
890 891 892 893 894 895 896 897
        },{\
            .driver   = "ide-drive",\
            .property = "ver",\
            .value    = "0.11",\
        },{\
            .driver   = "scsi-disk",\
            .property = "ver",\
            .value    = "0.11",\
898
        },
899

900
static void pc_i440fx_0_11_machine_options(MachineClass *m)
901 902 903
{
    pc_i440fx_0_12_machine_options(m);
    m->hw_version = "0.11";
904
    SET_MACHINE_COMPAT(m, PC_COMPAT_0_11);
905
}
906

907 908
DEFINE_I440FX_MACHINE(v0_11, "pc-0.11", pc_compat_0_13,
                      pc_i440fx_0_11_machine_options);
909

910

E
Eduardo Habkost 已提交
911
#define PC_COMPAT_0_10 \
912
    PC_CPU_MODEL_IDS("0.10") \
E
Eduardo Habkost 已提交
913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934
    {\
        .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",\
    },

935
static void pc_i440fx_0_10_machine_options(MachineClass *m)
936 937 938
{
    pc_i440fx_0_11_machine_options(m);
    m->hw_version = "0.10";
939
    SET_MACHINE_COMPAT(m, PC_COMPAT_0_10);
940
}
941

942 943
DEFINE_I440FX_MACHINE(v0_10, "pc-0.10", pc_compat_0_13,
                      pc_i440fx_0_10_machine_options);
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 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056
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);
}
1057

1058
static void isapc_machine_options(MachineClass *m)
1059
{
1060
    PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
1061 1062
    m->desc = "ISA-only PC";
    m->max_cpus = 1;
1063 1064
    m->option_rom_has_mr = true;
    m->rom_file_has_mr = false;
1065 1066 1067 1068 1069 1070
    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;
1071
}
1072

1073
DEFINE_PC_MACHINE(isapc, "isapc", pc_init_isa,
1074
                  isapc_machine_options);
1075

1076

A
Anthony PERARD 已提交
1077
#ifdef CONFIG_XEN
1078
static void xenfv_machine_options(MachineClass *m)
1079 1080 1081 1082 1083 1084
{
    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;
}
1085

1086
DEFINE_PC_MACHINE(xenfv, "xenfv", pc_xen_hvm_init,
1087
                  xenfv_machine_options);
A
Anthony PERARD 已提交
1088
#endif