pc.c 31.0 KB
Newer Older
B
bellard 已提交
1 2
/*
 * QEMU PC System Emulator
3
 *
B
bellard 已提交
4
 * Copyright (c) 2003-2004 Fabrice Bellard
5
 *
B
bellard 已提交
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 * 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
pbrook 已提交
24 25
#include "hw.h"
#include "pc.h"
G
Gerd Hoffmann 已提交
26
#include "serial.h"
27
#include "apic.h"
P
pbrook 已提交
28
#include "fdc.h"
29
#include "ide.h"
30
#include "pci/pci.h"
31
#include "monitor/monitor.h"
32
#include "fw_cfg.h"
A
aliguori 已提交
33
#include "hpet_emul.h"
34
#include "smbios.h"
B
Blue Swirl 已提交
35 36
#include "loader.h"
#include "elf.h"
37
#include "multiboot.h"
38
#include "mc146818rtc.h"
J
Jan Kiszka 已提交
39
#include "i8254.h"
J
Jan Kiszka 已提交
40
#include "pcspk.h"
41
#include "pci/msi.h"
J
Jan Kiszka 已提交
42
#include "sysbus.h"
43 44
#include "sysemu/sysemu.h"
#include "sysemu/kvm.h"
45
#include "kvm_i386.h"
46
#include "xen.h"
47
#include "sysemu/blockdev.h"
48
#include "hw/block-common.h"
G
Gerd Hoffmann 已提交
49
#include "ui/qemu-spice.h"
50 51
#include "exec/memory.h"
#include "exec/address-spaces.h"
52
#include "sysemu/arch_init.h"
53
#include "qemu/bitmap.h"
B
bellard 已提交
54

B
Blue Swirl 已提交
55 56 57 58 59 60 61 62 63 64
/* debug PC/ISA interrupts */
//#define DEBUG_IRQ

#ifdef DEBUG_IRQ
#define DPRINTF(fmt, ...)                                       \
    do { printf("CPUIRQ: " fmt , ## __VA_ARGS__); } while (0)
#else
#define DPRINTF(fmt, ...)
#endif

65 66
/* Leave a chunk of memory at the top of RAM for the BIOS ACPI tables.  */
#define ACPI_DATA_SIZE       0x10000
67
#define BIOS_CFG_IOPORT 0x510
68
#define FW_CFG_ACPI_TABLES (FW_CFG_ARCH_LOCAL + 0)
69
#define FW_CFG_SMBIOS_ENTRIES (FW_CFG_ARCH_LOCAL + 1)
J
Jes Sorensen 已提交
70
#define FW_CFG_IRQ0_OVERRIDE (FW_CFG_ARCH_LOCAL + 2)
J
Jes Sorensen 已提交
71
#define FW_CFG_E820_TABLE (FW_CFG_ARCH_LOCAL + 3)
72
#define FW_CFG_HPET (FW_CFG_ARCH_LOCAL + 4)
B
bellard 已提交
73

J
Jes Sorensen 已提交
74 75 76 77 78 79
#define E820_NR_ENTRIES		16

struct e820_entry {
    uint64_t address;
    uint64_t length;
    uint32_t type;
80
} QEMU_PACKED __attribute((__aligned__(4)));
J
Jes Sorensen 已提交
81 82 83 84

struct e820_table {
    uint32_t count;
    struct e820_entry entry[E820_NR_ENTRIES];
85
} QEMU_PACKED __attribute((__aligned__(4)));
J
Jes Sorensen 已提交
86 87

static struct e820_table e820_table;
B
Blue Swirl 已提交
88
struct hpet_fw_config hpet_cfg = {.count = UINT8_MAX};
J
Jes Sorensen 已提交
89

J
Jan Kiszka 已提交
90
void gsi_handler(void *opaque, int n, int level)
91
{
J
Jan Kiszka 已提交
92
    GSIState *s = opaque;
93

J
Jan Kiszka 已提交
94 95 96
    DPRINTF("pc: %s GSI %d\n", level ? "raising" : "lowering", n);
    if (n < ISA_NUM_IRQS) {
        qemu_set_irq(s->i8259_irq[n], level);
A
Avi Kivity 已提交
97
    }
J
Jan Kiszka 已提交
98
    qemu_set_irq(s->ioapic_irq[n], level);
99
}
100

J
Julien Grall 已提交
101 102
static void ioport80_write(void *opaque, hwaddr addr, uint64_t data,
                           unsigned size)
B
bellard 已提交
103 104 105
{
}

106 107
static uint64_t ioport80_read(void *opaque, hwaddr addr, unsigned size)
{
108
    return 0xffffffffffffffffULL;
109 110
}

111
/* MSDOS compatibility mode FPU exception support */
P
pbrook 已提交
112
static qemu_irq ferr_irq;
113 114 115 116 117 118

void pc_register_ferr_irq(qemu_irq irq)
{
    ferr_irq = irq;
}

119 120 121
/* XXX: add IGNNE support */
void cpu_set_ferr(CPUX86State *s)
{
P
pbrook 已提交
122
    qemu_irq_raise(ferr_irq);
123 124
}

J
Julien Grall 已提交
125 126
static void ioportF0_write(void *opaque, hwaddr addr, uint64_t data,
                           unsigned size)
127
{
P
pbrook 已提交
128
    qemu_irq_lower(ferr_irq);
129 130
}

131 132
static uint64_t ioportF0_read(void *opaque, hwaddr addr, unsigned size)
{
133
    return 0xffffffffffffffffULL;
134 135
}

B
bellard 已提交
136 137 138
/* TSC handling */
uint64_t cpu_get_tsc(CPUX86State *env)
{
139
    return cpu_get_ticks();
B
bellard 已提交
140 141
}

B
bellard 已提交
142
/* SMM support */
143 144 145 146 147 148 149 150 151 152 153 154

static cpu_set_smm_t smm_set;
static void *smm_arg;

void cpu_smm_register(cpu_set_smm_t callback, void *arg)
{
    assert(smm_set == NULL);
    assert(smm_arg == NULL);
    smm_set = callback;
    smm_arg = arg;
}

A
Andreas Färber 已提交
155
void cpu_smm_update(CPUX86State *env)
B
bellard 已提交
156
{
157 158
    if (smm_set && smm_arg && env == first_cpu)
        smm_set(!!(env->hflags & HF_SMM_MASK), smm_arg);
B
bellard 已提交
159 160 161
}


B
bellard 已提交
162
/* IRQ handling */
A
Andreas Färber 已提交
163
int cpu_get_pic_interrupt(CPUX86State *env)
B
bellard 已提交
164 165 166
{
    int intno;

167
    intno = apic_get_interrupt(env->apic_state);
B
bellard 已提交
168 169 170 171
    if (intno >= 0) {
        return intno;
    }
    /* read the irq from the PIC */
172
    if (!apic_accept_pic_intr(env->apic_state)) {
173
        return -1;
174
    }
175

B
bellard 已提交
176 177 178 179
    intno = pic_read_irq(isa_pic);
    return intno;
}

P
pbrook 已提交
180
static void pic_irq_request(void *opaque, int irq, int level)
B
bellard 已提交
181
{
A
Andreas Färber 已提交
182
    CPUX86State *env = first_cpu;
183

B
Blue Swirl 已提交
184
    DPRINTF("pic_irqs: %s irq %d\n", level? "raise" : "lower", irq);
A
aurel32 已提交
185 186
    if (env->apic_state) {
        while (env) {
187 188 189
            if (apic_accept_pic_intr(env->apic_state)) {
                apic_deliver_pic_intr(env->apic_state, level);
            }
A
aurel32 已提交
190 191 192
            env = env->next_cpu;
        }
    } else {
A
aurel32 已提交
193 194 195 196
        if (level)
            cpu_interrupt(env, CPU_INTERRUPT_HARD);
        else
            cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
197
    }
B
bellard 已提交
198 199
}

B
bellard 已提交
200 201
/* PC cmos mappings */

B
bellard 已提交
202 203
#define REG_EQUIPMENT_BYTE          0x14

204
static int cmos_get_fd_drive_type(FDriveType fd0)
205 206 207 208
{
    int val;

    switch (fd0) {
209
    case FDRIVE_DRV_144:
210 211 212
        /* 1.44 Mb 3"5 drive */
        val = 4;
        break;
213
    case FDRIVE_DRV_288:
214 215 216
        /* 2.88 Mb 3"5 drive */
        val = 5;
        break;
217
    case FDRIVE_DRV_120:
218 219 220
        /* 1.2 Mb 5"5 drive */
        val = 2;
        break;
221
    case FDRIVE_DRV_NONE:
222 223 224 225 226 227 228
    default:
        val = 0;
        break;
    }
    return val;
}

229 230
static void cmos_init_hd(ISADevice *s, int type_ofs, int info_ofs,
                         int16_t cylinders, int8_t heads, int8_t sectors)
B
bellard 已提交
231 232 233 234 235 236 237 238 239 240 241 242 243
{
    rtc_set_memory(s, type_ofs, 47);
    rtc_set_memory(s, info_ofs, cylinders);
    rtc_set_memory(s, info_ofs + 1, cylinders >> 8);
    rtc_set_memory(s, info_ofs + 2, heads);
    rtc_set_memory(s, info_ofs + 3, 0xff);
    rtc_set_memory(s, info_ofs + 4, 0xff);
    rtc_set_memory(s, info_ofs + 5, 0xc0 | ((heads > 8) << 3));
    rtc_set_memory(s, info_ofs + 6, cylinders);
    rtc_set_memory(s, info_ofs + 7, cylinders >> 8);
    rtc_set_memory(s, info_ofs + 8, sectors);
}

244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
/* convert boot_device letter to something recognizable by the bios */
static int boot_device2nibble(char boot_device)
{
    switch(boot_device) {
    case 'a':
    case 'b':
        return 0x01; /* floppy boot */
    case 'c':
        return 0x02; /* hard drive boot */
    case 'd':
        return 0x03; /* CD-ROM boot */
    case 'n':
        return 0x04; /* Network boot */
    }
    return 0;
}

261
static int set_boot_dev(ISADevice *s, const char *boot_device, int fd_bootchk)
262 263 264 265 266 267 268
{
#define PC_MAX_BOOT_DEVICES 3
    int nbds, bds[3] = { 0, };
    int i;

    nbds = strlen(boot_device);
    if (nbds > PC_MAX_BOOT_DEVICES) {
269
        error_report("Too many boot devices for PC");
270 271 272 273 274
        return(1);
    }
    for (i = 0; i < nbds; i++) {
        bds[i] = boot_device2nibble(boot_device[i]);
        if (bds[i] == 0) {
275 276
            error_report("Invalid boot device for PC: '%c'",
                         boot_device[i]);
277 278 279 280
            return(1);
        }
    }
    rtc_set_memory(s, 0x3d, (bds[1] << 4) | bds[0]);
281
    rtc_set_memory(s, 0x38, (bds[2] << 4) | (fd_bootchk ? 0x0 : 0x1));
282 283 284
    return(0);
}

285 286 287 288 289
static int pc_boot_set(void *opaque, const char *boot_device)
{
    return set_boot_dev(opaque, boot_device, 0);
}

290 291
typedef struct pc_cmos_init_late_arg {
    ISADevice *rtc_state;
292
    BusState *idebus[2];
293 294 295 296 297 298
} pc_cmos_init_late_arg;

static void pc_cmos_init_late(void *opaque)
{
    pc_cmos_init_late_arg *arg = opaque;
    ISADevice *s = arg->rtc_state;
299 300
    int16_t cylinders;
    int8_t heads, sectors;
301
    int val;
302
    int i, trans;
303

304 305 306 307 308 309 310 311 312 313 314 315
    val = 0;
    if (ide_get_geometry(arg->idebus[0], 0,
                         &cylinders, &heads, &sectors) >= 0) {
        cmos_init_hd(s, 0x19, 0x1b, cylinders, heads, sectors);
        val |= 0xf0;
    }
    if (ide_get_geometry(arg->idebus[0], 1,
                         &cylinders, &heads, &sectors) >= 0) {
        cmos_init_hd(s, 0x1a, 0x24, cylinders, heads, sectors);
        val |= 0x0f;
    }
    rtc_set_memory(s, 0x12, val);
316 317 318

    val = 0;
    for (i = 0; i < 4; i++) {
319 320 321 322 323 324
        /* NOTE: ide_get_geometry() returns the physical
           geometry.  It is always such that: 1 <= sects <= 63, 1
           <= heads <= 16, 1 <= cylinders <= 16383. The BIOS
           geometry can be different if a translation is done. */
        if (ide_get_geometry(arg->idebus[i / 2], i % 2,
                             &cylinders, &heads, &sectors) >= 0) {
325 326 327
            trans = ide_get_bios_chs_trans(arg->idebus[i / 2], i % 2) - 1;
            assert((trans & ~3) == 0);
            val |= trans << (i * 2);
328 329 330 331 332 333 334
        }
    }
    rtc_set_memory(s, 0x39, val);

    qemu_unregister_reset(pc_cmos_init_late, opaque);
}

335
void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
336
                  const char *boot_device,
K
Kevin Wolf 已提交
337
                  ISADevice *floppy, BusState *idebus0, BusState *idebus1,
B
Blue Swirl 已提交
338
                  ISADevice *s)
B
bellard 已提交
339
{
340
    int val, nb, i;
341
    FDriveType fd_type[2] = { FDRIVE_DRV_NONE, FDRIVE_DRV_NONE };
342
    static pc_cmos_init_late_arg arg;
B
bellard 已提交
343 344

    /* various important CMOS locations needed by PC/Bochs bios */
B
bellard 已提交
345 346

    /* memory size */
347 348
    /* base memory (first MiB) */
    val = MIN(ram_size / 1024, 640);
B
bellard 已提交
349 350
    rtc_set_memory(s, 0x15, val);
    rtc_set_memory(s, 0x16, val >> 8);
351 352 353 354 355 356
    /* extended memory (next 64MiB) */
    if (ram_size > 1024 * 1024) {
        val = (ram_size - 1024 * 1024) / 1024;
    } else {
        val = 0;
    }
B
bellard 已提交
357 358
    if (val > 65535)
        val = 65535;
B
bellard 已提交
359 360 361 362
    rtc_set_memory(s, 0x17, val);
    rtc_set_memory(s, 0x18, val >> 8);
    rtc_set_memory(s, 0x30, val);
    rtc_set_memory(s, 0x31, val >> 8);
363 364 365 366
    /* memory between 16MiB and 4GiB */
    if (ram_size > 16 * 1024 * 1024) {
        val = (ram_size - 16 * 1024 * 1024) / 65536;
    } else {
B
bellard 已提交
367
        val = 0;
368
    }
B
bellard 已提交
369 370
    if (val > 65535)
        val = 65535;
B
bellard 已提交
371 372
    rtc_set_memory(s, 0x34, val);
    rtc_set_memory(s, 0x35, val >> 8);
373 374 375 376 377
    /* memory above 4GiB */
    val = above_4g_mem_size / 65536;
    rtc_set_memory(s, 0x5b, val);
    rtc_set_memory(s, 0x5c, val >> 8);
    rtc_set_memory(s, 0x5d, val >> 16);
378

A
aurel32 已提交
379 380 381
    /* set the number of CPU */
    rtc_set_memory(s, 0x5f, smp_cpus - 1);

382
    /* set boot devices, and disable floppy signature check if requested */
383
    if (set_boot_dev(s, boot_device, fd_bootchk)) {
384 385
        exit(1);
    }
B
bellard 已提交
386

B
bellard 已提交
387
    /* floppy type */
K
Kevin Wolf 已提交
388 389
    if (floppy) {
        for (i = 0; i < 2; i++) {
390
            fd_type[i] = isa_fdc_get_drive_type(floppy, i);
B
Blue Swirl 已提交
391 392 393 394
        }
    }
    val = (cmos_get_fd_drive_type(fd_type[0]) << 4) |
        cmos_get_fd_drive_type(fd_type[1]);
B
bellard 已提交
395
    rtc_set_memory(s, 0x10, val);
396

B
bellard 已提交
397
    val = 0;
B
bellard 已提交
398
    nb = 0;
B
Blue Swirl 已提交
399
    if (fd_type[0] < FDRIVE_DRV_NONE) {
B
bellard 已提交
400
        nb++;
401
    }
B
Blue Swirl 已提交
402
    if (fd_type[1] < FDRIVE_DRV_NONE) {
B
bellard 已提交
403
        nb++;
404
    }
B
bellard 已提交
405 406 407 408
    switch (nb) {
    case 0:
        break;
    case 1:
B
bellard 已提交
409
        val |= 0x01; /* 1 drive, ready for boot */
B
bellard 已提交
410 411
        break;
    case 2:
B
bellard 已提交
412
        val |= 0x41; /* 2 drives, ready for boot */
B
bellard 已提交
413 414
        break;
    }
B
bellard 已提交
415 416 417 418
    val |= 0x02; /* FPU is there */
    val |= 0x04; /* PS/2 mouse installed */
    rtc_set_memory(s, REG_EQUIPMENT_BYTE, val);

B
bellard 已提交
419
    /* hard drives */
420
    arg.rtc_state = s;
421 422
    arg.idebus[0] = idebus0;
    arg.idebus[1] = idebus1;
423
    qemu_register_reset(pc_cmos_init_late, &arg);
B
bellard 已提交
424 425
}

426 427 428
/* port 92 stuff: could be split off */
typedef struct Port92State {
    ISADevice dev;
429
    MemoryRegion io;
430 431 432 433
    uint8_t outport;
    qemu_irq *a20_out;
} Port92State;

434 435
static void port92_write(void *opaque, hwaddr addr, uint64_t val,
                         unsigned size)
436 437 438 439 440 441 442 443 444 445 446
{
    Port92State *s = opaque;

    DPRINTF("port92: write 0x%02x\n", val);
    s->outport = val;
    qemu_set_irq(*s->a20_out, (val >> 1) & 1);
    if (val & 1) {
        qemu_system_reset_request();
    }
}

447 448
static uint64_t port92_read(void *opaque, hwaddr addr,
                            unsigned size)
449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482
{
    Port92State *s = opaque;
    uint32_t ret;

    ret = s->outport;
    DPRINTF("port92: read 0x%02x\n", ret);
    return ret;
}

static void port92_init(ISADevice *dev, qemu_irq *a20_out)
{
    Port92State *s = DO_UPCAST(Port92State, dev, dev);

    s->a20_out = a20_out;
}

static const VMStateDescription vmstate_port92_isa = {
    .name = "port92",
    .version_id = 1,
    .minimum_version_id = 1,
    .minimum_version_id_old = 1,
    .fields      = (VMStateField []) {
        VMSTATE_UINT8(outport, Port92State),
        VMSTATE_END_OF_LIST()
    }
};

static void port92_reset(DeviceState *d)
{
    Port92State *s = container_of(d, Port92State, dev.qdev);

    s->outport &= ~1;
}

483
static const MemoryRegionOps port92_ops = {
484 485 486 487 488 489 490
    .read = port92_read,
    .write = port92_write,
    .impl = {
        .min_access_size = 1,
        .max_access_size = 1,
    },
    .endianness = DEVICE_LITTLE_ENDIAN,
491 492
};

493 494 495 496
static int port92_initfn(ISADevice *dev)
{
    Port92State *s = DO_UPCAST(Port92State, dev, dev);

497 498 499
    memory_region_init_io(&s->io, &port92_ops, s, "port92", 1);
    isa_register_ioport(dev, &s->io, 0x92);

500 501 502 503
    s->outport = 0;
    return 0;
}

504 505
static void port92_class_initfn(ObjectClass *klass, void *data)
{
506
    DeviceClass *dc = DEVICE_CLASS(klass);
507 508
    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
    ic->init = port92_initfn;
509 510 511
    dc->no_user = 1;
    dc->reset = port92_reset;
    dc->vmsd = &vmstate_port92_isa;
512 513
}

514
static const TypeInfo port92_info = {
515 516 517 518
    .name          = "port92",
    .parent        = TYPE_ISA_DEVICE,
    .instance_size = sizeof(Port92State),
    .class_init    = port92_class_initfn,
519 520
};

A
Andreas Färber 已提交
521
static void port92_register_types(void)
522
{
523
    type_register_static(&port92_info);
524
}
A
Andreas Färber 已提交
525 526

type_init(port92_register_types)
527

B
Blue Swirl 已提交
528
static void handle_a20_line_change(void *opaque, int irq, int level)
529
{
A
Andreas Färber 已提交
530
    CPUX86State *cpu = opaque;
B
bellard 已提交
531

B
Blue Swirl 已提交
532
    /* XXX: send to all CPUs ? */
533
    /* XXX: add logic to handle multiple A20 line sources */
B
Blue Swirl 已提交
534
    cpu_x86_set_a20(cpu, level);
B
bellard 已提交
535 536
}

J
Jes Sorensen 已提交
537 538
int e820_add_entry(uint64_t address, uint64_t length, uint32_t type)
{
539
    int index = le32_to_cpu(e820_table.count);
J
Jes Sorensen 已提交
540 541 542 543
    struct e820_entry *entry;

    if (index >= E820_NR_ENTRIES)
        return -EBUSY;
544
    entry = &e820_table.entry[index++];
J
Jes Sorensen 已提交
545

546 547 548
    entry->address = cpu_to_le64(address);
    entry->length = cpu_to_le64(length);
    entry->type = cpu_to_le32(type);
J
Jes Sorensen 已提交
549

550 551
    e820_table.count = cpu_to_le32(index);
    return index;
J
Jes Sorensen 已提交
552 553
}

A
Alexander Graf 已提交
554
static void *bochs_bios_init(void)
B
bellard 已提交
555
{
556
    void *fw_cfg;
557 558
    uint8_t *smbios_table;
    size_t smbios_len;
559 560
    uint64_t *numa_fw_cfg;
    int i, j;
561 562

    fw_cfg = fw_cfg_init(BIOS_CFG_IOPORT, BIOS_CFG_IOPORT + 1, 0, 0);
A
Alexander Graf 已提交
563

564
    fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1);
565
    fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
566 567
    fw_cfg_add_bytes(fw_cfg, FW_CFG_ACPI_TABLES,
                     acpi_tables, acpi_tables_len);
568
    fw_cfg_add_i32(fw_cfg, FW_CFG_IRQ0_OVERRIDE, kvm_allows_irq0_override());
569 570 571 572 573

    smbios_table = smbios_get_table(&smbios_len);
    if (smbios_table)
        fw_cfg_add_bytes(fw_cfg, FW_CFG_SMBIOS_ENTRIES,
                         smbios_table, smbios_len);
574 575
    fw_cfg_add_bytes(fw_cfg, FW_CFG_E820_TABLE,
                     &e820_table, sizeof(e820_table));
576

577
    fw_cfg_add_bytes(fw_cfg, FW_CFG_HPET, &hpet_cfg, sizeof(hpet_cfg));
578 579 580 581
    /* allocate memory for the NUMA channel: one (64bit) word for the number
     * of nodes, one word for each VCPU->node and one word for each node to
     * hold the amount of memory.
     */
582
    numa_fw_cfg = g_new0(uint64_t, 1 + max_cpus + nb_numa_nodes);
583
    numa_fw_cfg[0] = cpu_to_le64(nb_numa_nodes);
584
    for (i = 0; i < max_cpus; i++) {
585
        for (j = 0; j < nb_numa_nodes; j++) {
586
            if (test_bit(i, node_cpumask[j])) {
587 588 589 590 591 592
                numa_fw_cfg[i + 1] = cpu_to_le64(j);
                break;
            }
        }
    }
    for (i = 0; i < nb_numa_nodes; i++) {
593
        numa_fw_cfg[max_cpus + 1 + i] = cpu_to_le64(node_mem[i]);
594
    }
595
    fw_cfg_add_bytes(fw_cfg, FW_CFG_NUMA, numa_fw_cfg,
596
                     (1 + max_cpus + nb_numa_nodes) * sizeof(*numa_fw_cfg));
A
Alexander Graf 已提交
597 598

    return fw_cfg;
B
bellard 已提交
599 600
}

T
ths 已提交
601 602 603 604 605 606 607 608 609 610 611 612 613 614
static long get_file_size(FILE *f)
{
    long where, size;

    /* XXX: on Unix systems, using fstat() probably makes more sense */

    where = ftell(f);
    fseek(f, 0, SEEK_END);
    size = ftell(f);
    fseek(f, where, SEEK_SET);

    return size;
}

A
Alexander Graf 已提交
615
static void load_linux(void *fw_cfg,
616
                       const char *kernel_filename,
T
ths 已提交
617
		       const char *initrd_filename,
G
Glauber Costa 已提交
618
		       const char *kernel_cmdline,
A
Avi Kivity 已提交
619
                       hwaddr max_ram_size)
T
ths 已提交
620 621
{
    uint16_t protocol;
P
Paul Brook 已提交
622
    int setup_size, kernel_size, initrd_size = 0, cmdline_size;
T
ths 已提交
623
    uint32_t initrd_max;
624
    uint8_t header[8192], *setup, *kernel, *initrd_data;
A
Avi Kivity 已提交
625
    hwaddr real_addr, prot_addr, cmdline_addr, initrd_addr = 0;
626
    FILE *f;
P
Pascal Terjan 已提交
627
    char *vmode;
T
ths 已提交
628 629 630 631 632 633 634

    /* Align to 16 bytes as a paranoia measure */
    cmdline_size = (strlen(kernel_cmdline)+16) & ~15;

    /* load the kernel header */
    f = fopen(kernel_filename, "rb");
    if (!f || !(kernel_size = get_file_size(f)) ||
A
Alexander Graf 已提交
635 636
	fread(header, 1, MIN(ARRAY_SIZE(header), kernel_size), f) !=
	MIN(ARRAY_SIZE(header), kernel_size)) {
637 638
	fprintf(stderr, "qemu: could not load kernel '%s': %s\n",
		kernel_filename, strerror(errno));
T
ths 已提交
639 640 641 642
	exit(1);
    }

    /* kernel protocol version */
B
bellard 已提交
643
#if 0
T
ths 已提交
644
    fprintf(stderr, "header magic: %#x\n", ldl_p(header+0x202));
B
bellard 已提交
645
#endif
T
ths 已提交
646 647
    if (ldl_p(header+0x202) == 0x53726448)
	protocol = lduw_p(header+0x206);
A
Alexander Graf 已提交
648 649 650
    else {
	/* This looks like a multiboot kernel. If it is, let's stop
	   treating it like a Linux kernel. */
651 652
        if (load_multiboot(fw_cfg, f, kernel_filename, initrd_filename,
                           kernel_cmdline, kernel_size, header))
B
Blue Swirl 已提交
653
            return;
T
ths 已提交
654
	protocol = 0;
A
Alexander Graf 已提交
655
    }
T
ths 已提交
656 657 658

    if (protocol < 0x200 || !(header[0x211] & 0x01)) {
	/* Low kernel */
659 660 661
	real_addr    = 0x90000;
	cmdline_addr = 0x9a000 - cmdline_size;
	prot_addr    = 0x10000;
T
ths 已提交
662 663
    } else if (protocol < 0x202) {
	/* High but ancient kernel */
664 665 666
	real_addr    = 0x90000;
	cmdline_addr = 0x9a000 - cmdline_size;
	prot_addr    = 0x100000;
T
ths 已提交
667 668
    } else {
	/* High and recent kernel */
669 670 671
	real_addr    = 0x10000;
	cmdline_addr = 0x20000;
	prot_addr    = 0x100000;
T
ths 已提交
672 673
    }

B
bellard 已提交
674
#if 0
T
ths 已提交
675
    fprintf(stderr,
676 677 678
	    "qemu: real_addr     = 0x" TARGET_FMT_plx "\n"
	    "qemu: cmdline_addr  = 0x" TARGET_FMT_plx "\n"
	    "qemu: prot_addr     = 0x" TARGET_FMT_plx "\n",
679 680 681
	    real_addr,
	    cmdline_addr,
	    prot_addr);
B
bellard 已提交
682
#endif
T
ths 已提交
683 684 685 686 687 688 689

    /* highest address for loading the initrd */
    if (protocol >= 0x203)
	initrd_max = ldl_p(header+0x22c);
    else
	initrd_max = 0x37ffffff;

G
Glauber Costa 已提交
690 691
    if (initrd_max >= max_ram_size-ACPI_DATA_SIZE)
    	initrd_max = max_ram_size-ACPI_DATA_SIZE-1;
T
ths 已提交
692

693 694
    fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_ADDR, cmdline_addr);
    fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, strlen(kernel_cmdline)+1);
695
    fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, kernel_cmdline);
T
ths 已提交
696 697

    if (protocol >= 0x202) {
698
	stl_p(header+0x228, cmdline_addr);
T
ths 已提交
699 700 701 702 703
    } else {
	stw_p(header+0x20, 0xA33F);
	stw_p(header+0x22, cmdline_addr-real_addr);
    }

P
Pascal Terjan 已提交
704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721
    /* handle vga= parameter */
    vmode = strstr(kernel_cmdline, "vga=");
    if (vmode) {
        unsigned int video_mode;
        /* skip "vga=" */
        vmode += 4;
        if (!strncmp(vmode, "normal", 6)) {
            video_mode = 0xffff;
        } else if (!strncmp(vmode, "ext", 3)) {
            video_mode = 0xfffe;
        } else if (!strncmp(vmode, "ask", 3)) {
            video_mode = 0xfffd;
        } else {
            video_mode = strtol(vmode, NULL, 0);
        }
        stw_p(header+0x1fa, video_mode);
    }

T
ths 已提交
722
    /* loader type */
S
Stefan Weil 已提交
723
    /* High nybble = B reserved for QEMU; low nybble is revision number.
T
ths 已提交
724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741
       If this code is substantially changed, you may want to consider
       incrementing the revision. */
    if (protocol >= 0x200)
	header[0x210] = 0xB0;

    /* heap */
    if (protocol >= 0x201) {
	header[0x211] |= 0x80;	/* CAN_USE_HEAP */
	stw_p(header+0x224, cmdline_addr-real_addr-0x200);
    }

    /* load initrd */
    if (initrd_filename) {
	if (protocol < 0x200) {
	    fprintf(stderr, "qemu: linux kernel too old to load a ram disk\n");
	    exit(1);
	}

742
	initrd_size = get_image_size(initrd_filename);
M
M. Mohan Kumar 已提交
743 744 745 746 747 748
        if (initrd_size < 0) {
            fprintf(stderr, "qemu: error reading initrd %s\n",
                    initrd_filename);
            exit(1);
        }

749
        initrd_addr = (initrd_max-initrd_size) & ~4095;
750

751
        initrd_data = g_malloc(initrd_size);
752 753 754 755 756
        load_image(initrd_filename, initrd_data);

        fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, initrd_addr);
        fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size);
        fw_cfg_add_bytes(fw_cfg, FW_CFG_INITRD_DATA, initrd_data, initrd_size);
T
ths 已提交
757

758
	stl_p(header+0x218, initrd_addr);
T
ths 已提交
759 760 761
	stl_p(header+0x21c, initrd_size);
    }

762
    /* load kernel and setup */
T
ths 已提交
763 764 765 766
    setup_size = header[0x1f1];
    if (setup_size == 0)
	setup_size = 4;
    setup_size = (setup_size+1)*512;
767
    kernel_size -= setup_size;
T
ths 已提交
768

769 770
    setup  = g_malloc(setup_size);
    kernel = g_malloc(kernel_size);
771
    fseek(f, 0, SEEK_SET);
772 773 774 775 776 777 778 779
    if (fread(setup, 1, setup_size, f) != setup_size) {
        fprintf(stderr, "fread() failed\n");
        exit(1);
    }
    if (fread(kernel, 1, kernel_size, f) != kernel_size) {
        fprintf(stderr, "fread() failed\n");
        exit(1);
    }
T
ths 已提交
780
    fclose(f);
781
    memcpy(setup, header, MIN(sizeof(header), setup_size));
782 783 784 785 786 787 788 789 790

    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, prot_addr);
    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
    fw_cfg_add_bytes(fw_cfg, FW_CFG_KERNEL_DATA, kernel, kernel_size);

    fw_cfg_add_i32(fw_cfg, FW_CFG_SETUP_ADDR, real_addr);
    fw_cfg_add_i32(fw_cfg, FW_CFG_SETUP_SIZE, setup_size);
    fw_cfg_add_bytes(fw_cfg, FW_CFG_SETUP_DATA, setup, setup_size);

G
Gleb Natapov 已提交
791 792
    option_rom[nb_option_roms].name = "linuxboot.bin";
    option_rom[nb_option_roms].bootindex = 0;
793
    nb_option_roms++;
T
ths 已提交
794 795
}

B
bellard 已提交
796 797
#define NE2000_NB_MAX 6

B
Blue Swirl 已提交
798 799 800
static const int ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340, 0x360,
                                              0x280, 0x380 };
static const int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 };
B
bellard 已提交
801

B
Blue Swirl 已提交
802 803
static const int parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc };
static const int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 };
804

805
void pc_init_ne2k_isa(ISABus *bus, NICInfo *nd)
806 807 808 809 810
{
    static int nb_ne2k = 0;

    if (nb_ne2k == NE2000_NB_MAX)
        return;
811
    isa_ne2000_init(bus, ne2000_io[nb_ne2k],
G
Gerd Hoffmann 已提交
812
                    ne2000_irq[nb_ne2k], nd);
813 814 815
    nb_ne2k++;
}

B
Blue Swirl 已提交
816
DeviceState *cpu_get_current_apic(void)
817 818 819 820 821 822 823 824
{
    if (cpu_single_env) {
        return cpu_single_env->apic_state;
    } else {
        return NULL;
    }
}

825
void pc_acpi_smi_interrupt(void *opaque, int irq, int level)
B
Blue Swirl 已提交
826
{
A
Andreas Färber 已提交
827
    CPUX86State *s = opaque;
B
Blue Swirl 已提交
828 829 830 831 832 833

    if (level) {
        cpu_interrupt(s, CPU_INTERRUPT_SMI);
    }
}

834
void pc_cpus_init(const char *cpu_model)
835 836 837 838 839 840 841 842 843 844 845 846
{
    int i;

    /* init CPUs */
    if (cpu_model == NULL) {
#ifdef TARGET_X86_64
        cpu_model = "qemu64";
#else
        cpu_model = "qemu32";
#endif
    }

847 848 849 850 851
    for (i = 0; i < smp_cpus; i++) {
        if (!cpu_x86_init(cpu_model)) {
            fprintf(stderr, "Unable to find x86 CPU definition\n");
            exit(1);
        }
852 853 854
    }
}

G
Gerd Hoffmann 已提交
855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877
void pc_acpi_init(const char *default_dsdt)
{
    char *filename = NULL, *arg = NULL;

    if (acpi_tables != NULL) {
        /* manually set via -acpitable, leave it alone */
        return;
    }

    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, default_dsdt);
    if (filename == NULL) {
        fprintf(stderr, "WARNING: failed to find %s\n", default_dsdt);
        return;
    }

    arg = g_strdup_printf("file=%s", filename);
    if (acpi_table_add(arg) != 0) {
        fprintf(stderr, "WARNING: failed to load %s\n", filename);
    }
    g_free(arg);
    g_free(filename);
}

878
void *pc_memory_init(MemoryRegion *system_memory,
A
Avi Kivity 已提交
879
                    const char *kernel_filename,
880 881
                    const char *kernel_cmdline,
                    const char *initrd_filename,
882
                    ram_addr_t below_4g_mem_size,
A
Avi Kivity 已提交
883
                    ram_addr_t above_4g_mem_size,
884
                    MemoryRegion *rom_memory,
A
Avi Kivity 已提交
885
                    MemoryRegion **ram_memory)
B
bellard 已提交
886
{
887 888
    int linux_boot, i;
    MemoryRegion *ram, *option_rom_mr;
889
    MemoryRegion *ram_below_4g, *ram_above_4g;
890
    void *fw_cfg;
891

B
bellard 已提交
892 893
    linux_boot = (kernel_filename != NULL);

894
    /* Allocate RAM.  We allocate it as a single memory region and use
D
Dong Xu Wang 已提交
895
     * aliases to address portions of it, mostly for backwards compatibility
896 897
     * with older qemus that used qemu_ram_alloc().
     */
898
    ram = g_malloc(sizeof(*ram));
899
    memory_region_init_ram(ram, "pc.ram",
900
                           below_4g_mem_size + above_4g_mem_size);
901
    vmstate_register_ram_global(ram);
A
Avi Kivity 已提交
902
    *ram_memory = ram;
903
    ram_below_4g = g_malloc(sizeof(*ram_below_4g));
904 905 906
    memory_region_init_alias(ram_below_4g, "ram-below-4g", ram,
                             0, below_4g_mem_size);
    memory_region_add_subregion(system_memory, 0, ram_below_4g);
907
    if (above_4g_mem_size > 0) {
908
        ram_above_4g = g_malloc(sizeof(*ram_above_4g));
909 910 911 912
        memory_region_init_alias(ram_above_4g, "ram-above-4g", ram,
                                 below_4g_mem_size, above_4g_mem_size);
        memory_region_add_subregion(system_memory, 0x100000000ULL,
                                    ram_above_4g);
913
    }
914

915 916 917

    /* Initialize PC system firmware */
    pc_system_firmware_init(rom_memory);
918

919
    option_rom_mr = g_malloc(sizeof(*option_rom_mr));
920 921
    memory_region_init_ram(option_rom_mr, "pc.rom", PC_ROM_SIZE);
    vmstate_register_ram_global(option_rom_mr);
922
    memory_region_add_subregion_overlap(rom_memory,
923 924 925
                                        PC_ROM_MIN_VGA,
                                        option_rom_mr,
                                        1);
926

A
Alexander Graf 已提交
927
    fw_cfg = bochs_bios_init();
G
Gerd Hoffmann 已提交
928
    rom_set_fw(fw_cfg);
A
Alexander Graf 已提交
929

930
    if (linux_boot) {
931
        load_linux(fw_cfg, kernel_filename, initrd_filename, kernel_cmdline, below_4g_mem_size);
932 933 934
    }

    for (i = 0; i < nb_option_roms; i++) {
G
Gleb Natapov 已提交
935
        rom_add_option(option_rom[i].name, option_rom[i].bootindex);
936
    }
937
    return fw_cfg;
938 939
}

940 941 942 943 944
qemu_irq *pc_allocate_cpu_irq(void)
{
    return qemu_allocate_irqs(pic_irq_request, NULL, 1);
}

945
DeviceState *pc_vga_init(ISABus *isa_bus, PCIBus *pci_bus)
946
{
947 948
    DeviceState *dev = NULL;

949 950 951 952 953 954
    if (pci_bus) {
        PCIDevice *pcidev = pci_vga_init(pci_bus);
        dev = pcidev ? &pcidev->qdev : NULL;
    } else if (isa_bus) {
        ISADevice *isadev = isa_vga_init(isa_bus);
        dev = isadev ? &isadev->qdev : NULL;
955
    }
956
    return dev;
957 958
}

B
Blue Swirl 已提交
959 960
static void cpu_request_exit(void *opaque, int irq, int level)
{
A
Andreas Färber 已提交
961
    CPUX86State *env = cpu_single_env;
B
Blue Swirl 已提交
962 963 964 965 966 967

    if (env && level) {
        cpu_exit(env);
    }
}

J
Julien Grall 已提交
968 969
static const MemoryRegionOps ioport80_io_ops = {
    .write = ioport80_write,
970
    .read = ioport80_read,
J
Julien Grall 已提交
971 972 973 974 975 976 977 978 979
    .endianness = DEVICE_NATIVE_ENDIAN,
    .impl = {
        .min_access_size = 1,
        .max_access_size = 1,
    },
};

static const MemoryRegionOps ioportF0_io_ops = {
    .write = ioportF0_write,
980
    .read = ioportF0_read,
J
Julien Grall 已提交
981 982 983 984 985 986 987
    .endianness = DEVICE_NATIVE_ENDIAN,
    .impl = {
        .min_access_size = 1,
        .max_access_size = 1,
    },
};

988
void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
989
                          ISADevice **rtc_state,
K
Kevin Wolf 已提交
990
                          ISADevice **floppy,
991
                          bool no_vmport)
992 993 994
{
    int i;
    DriveInfo *fd[MAX_FD];
995 996 997
    DeviceState *hpet = NULL;
    int pit_isa_irq = 0;
    qemu_irq pit_alt_irq = NULL;
998
    qemu_irq rtc_irq = NULL;
B
Blue Swirl 已提交
999
    qemu_irq *a20_line;
1000
    ISADevice *i8042, *port92, *vmmouse, *pit = NULL;
B
Blue Swirl 已提交
1001
    qemu_irq *cpu_exit_irq;
J
Julien Grall 已提交
1002 1003
    MemoryRegion *ioport80_io = g_new(MemoryRegion, 1);
    MemoryRegion *ioportF0_io = g_new(MemoryRegion, 1);
1004

J
Julien Grall 已提交
1005 1006
    memory_region_init_io(ioport80_io, &ioport80_io_ops, NULL, "ioport80", 1);
    memory_region_add_subregion(isa_bus->address_space_io, 0x80, ioport80_io);
1007

J
Julien Grall 已提交
1008 1009
    memory_region_init_io(ioportF0_io, &ioportF0_io_ops, NULL, "ioportF0", 1);
    memory_region_add_subregion(isa_bus->address_space_io, 0xf0, ioportF0_io);
1010

1011 1012 1013 1014 1015 1016 1017
    /*
     * Check if an HPET shall be created.
     *
     * Without KVM_CAP_PIT_STATE2, we cannot switch off the in-kernel PIT
     * when the HPET wants to take over. Thus we have to disable the latter.
     */
    if (!no_hpet && (!kvm_irqchip_in_kernel() || kvm_has_pit_state2())) {
1018
        hpet = sysbus_try_create_simple("hpet", HPET_BASE, NULL);
J
Jan Kiszka 已提交
1019

B
Blue Swirl 已提交
1020
        if (hpet) {
J
Jan Kiszka 已提交
1021 1022
            for (i = 0; i < GSI_NUM_PINS; i++) {
                sysbus_connect_irq(sysbus_from_qdev(hpet), i, gsi[i]);
B
Blue Swirl 已提交
1023
            }
1024 1025 1026
            pit_isa_irq = -1;
            pit_alt_irq = qdev_get_gpio_in(hpet, HPET_LEGACY_PIT_INT);
            rtc_irq = qdev_get_gpio_in(hpet, HPET_LEGACY_RTC_INT);
J
Jan Kiszka 已提交
1027
        }
1028
    }
1029
    *rtc_state = rtc_init(isa_bus, 2000, rtc_irq);
1030 1031 1032

    qemu_register_boot_set(pc_boot_set, *rtc_state);

1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043
    if (!xen_enabled()) {
        if (kvm_irqchip_in_kernel()) {
            pit = kvm_pit_init(isa_bus, 0x40);
        } else {
            pit = pit_init(isa_bus, 0x40, pit_isa_irq, pit_alt_irq);
        }
        if (hpet) {
            /* connect PIT to output control line of the HPET */
            qdev_connect_gpio_out(hpet, 0, qdev_get_gpio_in(&pit->qdev, 0));
        }
        pcspk_init(isa_bus, pit);
1044
    }
1045 1046 1047

    for(i = 0; i < MAX_SERIAL_PORTS; i++) {
        if (serial_hds[i]) {
1048
            serial_isa_init(isa_bus, i, serial_hds[i]);
1049 1050 1051 1052 1053
        }
    }

    for(i = 0; i < MAX_PARALLEL_PORTS; i++) {
        if (parallel_hds[i]) {
1054
            parallel_init(isa_bus, i, parallel_hds[i]);
1055 1056 1057
        }
    }

1058
    a20_line = qemu_allocate_irqs(handle_a20_line_change, first_cpu, 2);
1059
    i8042 = isa_create_simple(isa_bus, "i8042");
1060
    i8042_setup_a20_line(i8042, &a20_line[0]);
1061
    if (!no_vmport) {
1062 1063
        vmport_init(isa_bus);
        vmmouse = isa_try_create(isa_bus, "vmmouse");
1064 1065 1066
    } else {
        vmmouse = NULL;
    }
B
Blue Swirl 已提交
1067 1068
    if (vmmouse) {
        qdev_prop_set_ptr(&vmmouse->qdev, "ps2_mouse", i8042);
J
Jan Kiszka 已提交
1069
        qdev_init_nofail(&vmmouse->qdev);
B
Blue Swirl 已提交
1070
    }
1071
    port92 = isa_create_simple(isa_bus, "port92");
1072
    port92_init(port92, &a20_line[1]);
B
Blue Swirl 已提交
1073

B
Blue Swirl 已提交
1074 1075
    cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1);
    DMA_init(0, cpu_exit_irq);
1076 1077 1078 1079

    for(i = 0; i < MAX_FD; i++) {
        fd[i] = drive_get(IF_FLOPPY, 0, i);
    }
1080
    *floppy = fdctrl_init_isa(isa_bus, fd);
1081 1082
}

1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097
void pc_nic_init(ISABus *isa_bus, PCIBus *pci_bus)
{
    int i;

    for (i = 0; i < nb_nics; i++) {
        NICInfo *nd = &nd_table[i];

        if (!pci_bus || (nd->model && strcmp(nd->model, "ne2k_isa") == 0)) {
            pc_init_ne2k_isa(isa_bus, nd);
        } else {
            pci_nic_init_nofail(nd, "e1000", NULL);
        }
    }
}

1098
void pc_pci_device_init(PCIBus *pci_bus)
1099 1100 1101 1102 1103 1104 1105 1106 1107
{
    int max_bus;
    int bus;

    max_bus = drive_get_max_bus(IF_SCSI);
    for (bus = 0; bus <= max_bus; bus++) {
        pci_create_simple(pci_bus, -1, "lsi53c895a");
    }
}
1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131

void ioapic_init_gsi(GSIState *gsi_state, const char *parent_name)
{
    DeviceState *dev;
    SysBusDevice *d;
    unsigned int i;

    if (kvm_irqchip_in_kernel()) {
        dev = qdev_create(NULL, "kvm-ioapic");
    } else {
        dev = qdev_create(NULL, "ioapic");
    }
    if (parent_name) {
        object_property_add_child(object_resolve_path(parent_name, NULL),
                                  "ioapic", OBJECT(dev), NULL);
    }
    qdev_init_nofail(dev);
    d = sysbus_from_qdev(dev);
    sysbus_mmio_map(d, 0, 0xfec00000);

    for (i = 0; i < IOAPIC_NUM_PINS; i++) {
        gsi_state->ioapic_irq[i] = qdev_get_gpio_in(dev, i);
    }
}