#include "pc.h"
#include "apic.h"
#include "fdc.h"
+#include "ide.h"
#include "pci.h"
#include "vmware_vga.h"
-#include "usb-uhci.h"
-#include "usb-ohci.h"
-#include "prep_pci.h"
-#include "apb_pci.h"
-#include "block.h"
-#include "sysemu.h"
-#include "audio/audio.h"
-#include "net.h"
-#include "smbus.h"
-#include "boards.h"
#include "monitor.h"
#include "fw_cfg.h"
#include "hpet_emul.h"
-#include "watchdog.h"
#include "smbios.h"
-#include "ide.h"
#include "loader.h"
#include "elf.h"
#include "multiboot.h"
-#include "kvm.h"
+#include "mc146818rtc.h"
+#include "msix.h"
+#include "sysbus.h"
+#include "sysemu.h"
+#include "blockdev.h"
+#include "ui/qemu-spice.h"
/* output Bochs bios info messages */
//#define DEBUG_BIOS
+/* 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
+
#define BIOS_FILENAME "bios.bin"
#define PC_MAX_BIOS_SIZE (4 * 1024 * 1024)
#define FW_CFG_SMBIOS_ENTRIES (FW_CFG_ARCH_LOCAL + 1)
#define FW_CFG_IRQ0_OVERRIDE (FW_CFG_ARCH_LOCAL + 2)
#define FW_CFG_E820_TABLE (FW_CFG_ARCH_LOCAL + 3)
+#define FW_CFG_HPET (FW_CFG_ARCH_LOCAL + 4)
-#define MAX_IDE_BUS 2
+#define MSI_ADDR_BASE 0xfee00000
#define E820_NR_ENTRIES 16
uint64_t address;
uint64_t length;
uint32_t type;
-};
+} __attribute((__packed__, __aligned__(4)));
struct e820_table {
uint32_t count;
struct e820_entry entry[E820_NR_ENTRIES];
-};
+} __attribute((__packed__, __aligned__(4)));
static struct e820_table e820_table;
+struct hpet_fw_config hpet_cfg = {.count = UINT8_MAX};
-typedef struct isa_irq_state {
- qemu_irq *i8259;
- qemu_irq *ioapic;
-} IsaIrqState;
-
-static void isa_irq_handler(void *opaque, int n, int level)
+void isa_irq_handler(void *opaque, int n, int level)
{
IsaIrqState *isa = (IsaIrqState *)opaque;
+ DPRINTF("isa_irqs: %s irq %d\n", level? "raise" : "lower", n);
if (n < 16) {
qemu_set_irq(isa->i8259[n], level);
}
{
int intno;
- intno = apic_get_interrupt(env);
+ intno = apic_get_interrupt(env->apic_state);
if (intno >= 0) {
/* set irq request if a PIC irq is still pending */
/* XXX: improve that */
return intno;
}
/* read the irq from the PIC */
- if (!apic_accept_pic_intr(env))
+ if (!apic_accept_pic_intr(env->apic_state)) {
return -1;
+ }
intno = pic_read_irq(isa_pic);
return intno;
{
CPUState *env = first_cpu;
+ DPRINTF("pic_irqs: %s irq %d\n", level? "raise" : "lower", irq);
if (env->apic_state) {
while (env) {
- if (apic_accept_pic_intr(env))
- apic_deliver_pic_intr(env, level);
+ if (apic_accept_pic_intr(env->apic_state)) {
+ apic_deliver_pic_intr(env->apic_state, level);
+ }
env = env->next_cpu;
}
} else {
#define REG_EQUIPMENT_BYTE 0x14
-static int cmos_get_fd_drive_type(int fd0)
+static int cmos_get_fd_drive_type(FDriveType fd0)
{
int val;
switch (fd0) {
- case 0:
+ case FDRIVE_DRV_144:
/* 1.44 Mb 3"5 drive */
val = 4;
break;
- case 1:
+ case FDRIVE_DRV_288:
/* 2.88 Mb 3"5 drive */
val = 5;
break;
- case 2:
+ case FDRIVE_DRV_120:
/* 1.2 Mb 5"5 drive */
val = 2;
break;
+ case FDRIVE_DRV_NONE:
default:
val = 0;
break;
}
static void cmos_init_hd(int type_ofs, int info_ofs, BlockDriverState *hd,
- RTCState *s)
+ ISADevice *s)
{
int cylinders, heads, sectors;
bdrv_get_geometry_hint(hd, &cylinders, &heads, §ors);
return 0;
}
-static int set_boot_dev(RTCState *s, const char *boot_device, int fd_bootchk)
+static int set_boot_dev(ISADevice *s, const char *boot_device, int fd_bootchk)
{
#define PC_MAX_BOOT_DEVICES 3
int nbds, bds[3] = { 0, };
return set_boot_dev(opaque, boot_device, 0);
}
-/* hd_table must contain 4 block drivers */
-static void cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
- const char *boot_device, DriveInfo **hd_table,
- FDCtrl *floppy_controller, RTCState *s)
+typedef struct pc_cmos_init_late_arg {
+ ISADevice *rtc_state;
+ BusState *idebus0, *idebus1;
+} 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;
int val;
- int fd0, fd1, nb;
+ BlockDriverState *hd_table[4];
int i;
+ ide_get_bs(hd_table, arg->idebus0);
+ ide_get_bs(hd_table + 2, arg->idebus1);
+
+ rtc_set_memory(s, 0x12, (hd_table[0] ? 0xf0 : 0) | (hd_table[1] ? 0x0f : 0));
+ if (hd_table[0])
+ cmos_init_hd(0x19, 0x1b, hd_table[0], s);
+ if (hd_table[1])
+ cmos_init_hd(0x1a, 0x24, hd_table[1], s);
+
+ val = 0;
+ for (i = 0; i < 4; i++) {
+ if (hd_table[i]) {
+ int cylinders, heads, sectors, translation;
+ /* NOTE: bdrv_get_geometry_hint() 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. */
+ translation = bdrv_get_translation_hint(hd_table[i]);
+ if (translation == BIOS_ATA_TRANSLATION_AUTO) {
+ bdrv_get_geometry_hint(hd_table[i], &cylinders, &heads, §ors);
+ if (cylinders <= 1024 && heads <= 16 && sectors <= 63) {
+ /* No translation. */
+ translation = 0;
+ } else {
+ /* LBA translation. */
+ translation = 1;
+ }
+ } else {
+ translation--;
+ }
+ val |= translation << (i * 2);
+ }
+ }
+ rtc_set_memory(s, 0x39, val);
+
+ qemu_unregister_reset(pc_cmos_init_late, opaque);
+}
+
+void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
+ const char *boot_device,
+ BusState *idebus0, BusState *idebus1,
+ ISADevice *s)
+{
+ int val, nb, nb_heads, max_track, last_sect, i;
+ FDriveType fd_type[2];
+ DriveInfo *fd[2];
+ static pc_cmos_init_late_arg arg;
+
/* various important CMOS locations needed by PC/Bochs bios */
/* memory size */
}
/* floppy type */
-
- fd0 = fdctrl_get_drive_type(floppy_controller, 0);
- fd1 = fdctrl_get_drive_type(floppy_controller, 1);
-
- val = (cmos_get_fd_drive_type(fd0) << 4) | cmos_get_fd_drive_type(fd1);
+ for (i = 0; i < 2; i++) {
+ fd[i] = drive_get(IF_FLOPPY, 0, i);
+ if (fd[i] && bdrv_is_inserted(fd[i]->bdrv)) {
+ bdrv_get_floppy_geometry_hint(fd[i]->bdrv, &nb_heads, &max_track,
+ &last_sect, FDRIVE_DRV_NONE,
+ &fd_type[i]);
+ } else {
+ fd_type[i] = FDRIVE_DRV_NONE;
+ }
+ }
+ val = (cmos_get_fd_drive_type(fd_type[0]) << 4) |
+ cmos_get_fd_drive_type(fd_type[1]);
rtc_set_memory(s, 0x10, val);
val = 0;
nb = 0;
- if (fd0 < 3)
+ if (fd_type[0] < FDRIVE_DRV_NONE) {
nb++;
- if (fd1 < 3)
+ }
+ if (fd_type[1] < FDRIVE_DRV_NONE) {
nb++;
+ }
switch (nb) {
case 0:
break;
rtc_set_memory(s, REG_EQUIPMENT_BYTE, val);
/* hard drives */
+ arg.rtc_state = s;
+ arg.idebus0 = idebus0;
+ arg.idebus1 = idebus1;
+ qemu_register_reset(pc_cmos_init_late, &arg);
+}
- rtc_set_memory(s, 0x12, (hd_table[0] ? 0xf0 : 0) | (hd_table[1] ? 0x0f : 0));
- if (hd_table[0])
- cmos_init_hd(0x19, 0x1b, hd_table[0]->bdrv, s);
- if (hd_table[1])
- cmos_init_hd(0x1a, 0x24, hd_table[1]->bdrv, s);
+/* port 92 stuff: could be split off */
+typedef struct Port92State {
+ ISADevice dev;
+ uint8_t outport;
+ qemu_irq *a20_out;
+} Port92State;
- val = 0;
- for (i = 0; i < 4; i++) {
- if (hd_table[i]) {
- int cylinders, heads, sectors, translation;
- /* NOTE: bdrv_get_geometry_hint() 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. */
- translation = bdrv_get_translation_hint(hd_table[i]->bdrv);
- if (translation == BIOS_ATA_TRANSLATION_AUTO) {
- bdrv_get_geometry_hint(hd_table[i]->bdrv, &cylinders, &heads, §ors);
- if (cylinders <= 1024 && heads <= 16 && sectors <= 63) {
- /* No translation. */
- translation = 0;
- } else {
- /* LBA translation. */
- translation = 1;
- }
- } else {
- translation--;
- }
- val |= translation << (i * 2);
- }
+static void port92_write(void *opaque, uint32_t addr, uint32_t val)
+{
+ 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();
}
- rtc_set_memory(s, 0x39, val);
}
-void ioport_set_a20(int enable)
+static uint32_t port92_read(void *opaque, uint32_t addr)
{
- /* XXX: send to all CPUs ? */
- cpu_x86_set_a20(first_cpu, enable);
+ 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;
}
-int ioport_get_a20(void)
+static int port92_initfn(ISADevice *dev)
{
- return ((first_cpu->a20_mask >> 20) & 1);
+ Port92State *s = DO_UPCAST(Port92State, dev, dev);
+
+ register_ioport_read(0x92, 1, 1, port92_read, s);
+ register_ioport_write(0x92, 1, 1, port92_write, s);
+ isa_init_ioport(dev, 0x92);
+ s->outport = 0;
+ return 0;
}
-static void ioport92_write(void *opaque, uint32_t addr, uint32_t val)
+static ISADeviceInfo port92_info = {
+ .qdev.name = "port92",
+ .qdev.size = sizeof(Port92State),
+ .qdev.vmsd = &vmstate_port92_isa,
+ .qdev.no_user = 1,
+ .qdev.reset = port92_reset,
+ .init = port92_initfn,
+};
+
+static void port92_register(void)
{
- ioport_set_a20((val >> 1) & 1);
- /* XXX: bit 0 is fast reset */
+ isa_qdev_register(&port92_info);
}
+device_init(port92_register)
-static uint32_t ioport92_read(void *opaque, uint32_t addr)
+static void handle_a20_line_change(void *opaque, int irq, int level)
{
- return ioport_get_a20() << 1;
+ CPUState *cpu = opaque;
+
+ /* XXX: send to all CPUs ? */
+ /* XXX: add logic to handle multiple A20 line sources */
+ cpu_x86_set_a20(cpu, level);
}
/***********************************************************/
/* Bochs BIOS messages */
case 0x400:
case 0x401:
- fprintf(stderr, "BIOS panic at rombios.c, line %d\n", val);
- exit(1);
+ /* used to be panic, now unused */
+ break;
case 0x402:
case 0x403:
#ifdef DEBUG_BIOS
int e820_add_entry(uint64_t address, uint64_t length, uint32_t type)
{
- int index = e820_table.count;
+ int index = le32_to_cpu(e820_table.count);
struct e820_entry *entry;
if (index >= E820_NR_ENTRIES)
return -EBUSY;
- entry = &e820_table.entry[index];
+ entry = &e820_table.entry[index++];
- entry->address = address;
- entry->length = length;
- entry->type = type;
+ entry->address = cpu_to_le64(address);
+ entry->length = cpu_to_le64(length);
+ entry->type = cpu_to_le32(type);
- e820_table.count++;
- return e820_table.count;
+ e820_table.count = cpu_to_le32(index);
+ return index;
}
static void *bochs_bios_init(void)
fw_cfg_add_bytes(fw_cfg, FW_CFG_E820_TABLE, (uint8_t *)&e820_table,
sizeof(struct e820_table));
+ fw_cfg_add_bytes(fw_cfg, FW_CFG_HPET, (uint8_t *)&hpet_cfg,
+ sizeof(struct hpet_fw_config));
/* 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.
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);
- option_rom[nb_option_roms] = "linuxboot.bin";
+ option_rom[nb_option_roms].name = "linuxboot.bin";
+ option_rom[nb_option_roms].bootindex = 0;
nb_option_roms++;
}
-static const int ide_iobase[2] = { 0x1f0, 0x170 };
-static const int ide_iobase2[2] = { 0x3f6, 0x376 };
-static const int ide_irq[2] = { 14, 15 };
-
#define NE2000_NB_MAX 6
static const int ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340, 0x360,
static const int parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc };
static const int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 };
-#ifdef HAS_AUDIO
-static void audio_init (PCIBus *pci_bus, qemu_irq *pic)
-{
- struct soundhw *c;
-
- for (c = soundhw; c->name; ++c) {
- if (c->enabled) {
- if (c->isa) {
- c->init.init_isa(pic);
- } else {
- if (pci_bus) {
- c->init.init_pci(pci_bus);
- }
- }
- }
- }
-}
-#endif
-
-static void pc_init_ne2k_isa(NICInfo *nd)
+void pc_init_ne2k_isa(NICInfo *nd)
{
static int nb_ne2k = 0;
return env->cpu_index == 0;
}
+DeviceState *cpu_get_current_apic(void)
+{
+ if (cpu_single_env) {
+ return cpu_single_env->apic_state;
+ } else {
+ return NULL;
+ }
+}
+
+static DeviceState *apic_init(void *env, uint8_t apic_id)
+{
+ DeviceState *dev;
+ SysBusDevice *d;
+ static int apic_mapped;
+
+ dev = qdev_create(NULL, "apic");
+ qdev_prop_set_uint8(dev, "id", apic_id);
+ qdev_prop_set_ptr(dev, "cpu_env", env);
+ qdev_init_nofail(dev);
+ d = sysbus_from_qdev(dev);
+
+ /* XXX: mapping more APICs at the same memory location */
+ if (apic_mapped == 0) {
+ /* NOTE: the APIC is directly connected to the CPU - it is not
+ on the global memory bus. */
+ /* XXX: what if the base changes? */
+ sysbus_mmio_map(d, 0, MSI_ADDR_BASE);
+ apic_mapped = 1;
+ }
+
+ msix_supported = 1;
+
+ return dev;
+}
+
/* set CMOS shutdown status register (index 0xF) as S3_resume(0xFE)
BIOS will read it and start S3 resume at POST Entry */
-static void cmos_set_s3_resume(void *opaque, int irq, int level)
+void pc_cmos_set_s3_resume(void *opaque, int irq, int level)
{
- RTCState *s = opaque;
+ ISADevice *s = opaque;
if (level) {
rtc_set_memory(s, 0xF, 0xFE);
}
}
-static void acpi_smi_interrupt(void *opaque, int irq, int level)
+void pc_acpi_smi_interrupt(void *opaque, int irq, int level)
{
CPUState *s = opaque;
}
}
+static void pc_cpu_reset(void *opaque)
+{
+ CPUState *env = opaque;
+
+ cpu_reset(env);
+ env->halted = !cpu_is_bsp(env);
+}
+
static CPUState *pc_new_cpu(const char *cpu_model)
{
CPUState *env;
}
if ((env->cpuid_features & CPUID_APIC) || smp_cpus > 1) {
env->cpuid_apic_id = env->cpu_index;
- /* APIC reset callback resets cpu */
- apic_init(env);
- } else {
- qemu_register_reset((QEMUResetHandler*)cpu_reset, env);
+ env->apic_state = apic_init(env, env->cpuid_apic_id);
}
+ qemu_register_reset(pc_cpu_reset, env);
+ pc_cpu_reset(env);
return env;
}
-static void pc_cpus_init(const char *cpu_model)
+void pc_cpus_init(const char *cpu_model)
{
int i;
}
}
-static qemu_irq *pc_allocate_cpu_irq(void)
-{
- return qemu_allocate_irqs(pic_irq_request, NULL, 1);
-}
-
-/* PC hardware initialisation */
-static void pc_init1(ram_addr_t ram_size,
- const char *boot_device,
- const char *kernel_filename,
- const char *kernel_cmdline,
- const char *initrd_filename,
- const char *cpu_model,
- int pci_enabled)
+void pc_memory_init(ram_addr_t ram_size,
+ const char *kernel_filename,
+ const char *kernel_cmdline,
+ const char *initrd_filename,
+ ram_addr_t *below_4g_mem_size_p,
+ ram_addr_t *above_4g_mem_size_p)
{
char *filename;
int ret, linux_boot, i;
ram_addr_t ram_addr, bios_offset, option_rom_offset;
ram_addr_t below_4g_mem_size, above_4g_mem_size = 0;
int bios_size, isa_bios_size;
- PCIBus *pci_bus;
- PCII440FXState *i440fx_state;
- int piix3_devfn = -1;
- qemu_irq *cpu_irq;
- qemu_irq *isa_irq;
- qemu_irq *i8259;
- qemu_irq *cmos_s3;
- qemu_irq *smi_irq;
- IsaIrqState *isa_irq_state;
- DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
- DriveInfo *fd[MAX_FD];
void *fw_cfg;
- FDCtrl *floppy_controller;
- RTCState *rtc_state;
- PITState *pit;
if (ram_size >= 0xe0000000 ) {
above_4g_mem_size = ram_size - 0xe0000000;
} else {
below_4g_mem_size = ram_size;
}
+ *above_4g_mem_size_p = above_4g_mem_size;
+ *below_4g_mem_size_p = below_4g_mem_size;
linux_boot = (kernel_filename != NULL);
- pc_cpus_init(cpu_model);
-
- vmport_init();
-
/* allocate RAM */
- ram_addr = qemu_ram_alloc(below_4g_mem_size);
+ ram_addr = qemu_ram_alloc(NULL, "pc.ram",
+ below_4g_mem_size + above_4g_mem_size);
cpu_register_physical_memory(0, 0xa0000, ram_addr);
cpu_register_physical_memory(0x100000,
below_4g_mem_size - 0x100000,
ram_addr + 0x100000);
-
- /* above 4giga memory allocation */
if (above_4g_mem_size > 0) {
-#if TARGET_PHYS_ADDR_BITS == 32
- hw_error("To much RAM for 32-bit physical address");
-#else
- ram_addr = qemu_ram_alloc(above_4g_mem_size);
- cpu_register_physical_memory(0x100000000ULL,
- above_4g_mem_size,
- ram_addr);
-#endif
+ cpu_register_physical_memory(0x100000000ULL, above_4g_mem_size,
+ ram_addr + below_4g_mem_size);
}
-
/* BIOS load */
if (bios_name == NULL)
bios_name = BIOS_FILENAME;
(bios_size % 65536) != 0) {
goto bios_error;
}
- bios_offset = qemu_ram_alloc(bios_size);
- ret = rom_add_file_fixed(bios_name, (uint32_t)(-bios_size));
+ bios_offset = qemu_ram_alloc(NULL, "pc.bios", bios_size);
+ ret = rom_add_file_fixed(bios_name, (uint32_t)(-bios_size), -1);
if (ret != 0) {
bios_error:
fprintf(stderr, "qemu: could not load PC BIOS '%s'\n", bios_name);
isa_bios_size,
(bios_offset + bios_size - isa_bios_size) | IO_MEM_ROM);
- option_rom_offset = qemu_ram_alloc(PC_ROM_SIZE);
+ option_rom_offset = qemu_ram_alloc(NULL, "pc.rom", PC_ROM_SIZE);
cpu_register_physical_memory(PC_ROM_MIN_VGA, PC_ROM_SIZE, option_rom_offset);
/* map all the bios at the top of memory */
}
for (i = 0; i < nb_option_roms; i++) {
- rom_add_option(option_rom[i]);
- }
-
- cpu_irq = pc_allocate_cpu_irq();
- i8259 = i8259_init(cpu_irq[0]);
- isa_irq_state = qemu_mallocz(sizeof(*isa_irq_state));
- isa_irq_state->i8259 = i8259;
- if (pci_enabled) {
- isa_irq_state->ioapic = ioapic_init();
- }
- isa_irq = qemu_allocate_irqs(isa_irq_handler, isa_irq_state, 24);
-
- if (pci_enabled) {
- pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, isa_irq, ram_size);
- } else {
- pci_bus = NULL;
- isa_bus_new(NULL);
+ rom_add_option(option_rom[i].name, option_rom[i].bootindex);
}
- isa_bus_irqs(isa_irq);
-
- pc_register_ferr_irq(isa_reserve_irq(13));
-
- /* init basic PC hardware */
- register_ioport_write(0x80, 1, 1, ioport80_write, NULL);
+}
- register_ioport_write(0xf0, 1, 1, ioportF0_write, NULL);
+qemu_irq *pc_allocate_cpu_irq(void)
+{
+ return qemu_allocate_irqs(pic_irq_request, NULL, 1);
+}
+void pc_vga_init(PCIBus *pci_bus)
+{
if (cirrus_vga_enabled) {
- if (pci_enabled) {
+ if (pci_bus) {
pci_cirrus_vga_init(pci_bus);
} else {
isa_cirrus_vga_init();
}
} else if (vmsvga_enabled) {
- if (pci_enabled)
- pci_vmsvga_init(pci_bus);
- else
+ if (pci_bus) {
+ if (!pci_vmsvga_init(pci_bus)) {
+ fprintf(stderr, "Warning: vmware_vga not available,"
+ " using standard VGA instead\n");
+ pci_vga_init(pci_bus);
+ }
+ } else {
fprintf(stderr, "%s: vmware_vga: no PCI bus\n", __FUNCTION__);
+ }
+#ifdef CONFIG_SPICE
+ } else if (qxl_enabled) {
+ if (pci_bus)
+ pci_create_simple(pci_bus, -1, "qxl-vga");
+ else
+ fprintf(stderr, "%s: qxl: no PCI bus\n", __FUNCTION__);
+#endif
} else if (std_vga_enabled) {
- if (pci_enabled) {
- pci_vga_init(pci_bus, 0, 0);
+ if (pci_bus) {
+ pci_vga_init(pci_bus);
} else {
isa_vga_init();
}
}
+}
- rtc_state = rtc_init(2000);
+static void cpu_request_exit(void *opaque, int irq, int level)
+{
+ CPUState *env = cpu_single_env;
- qemu_register_boot_set(pc_boot_set, rtc_state);
+ if (env && level) {
+ cpu_exit(env);
+ }
+}
- register_ioport_read(0x92, 1, 1, ioport92_read, NULL);
- register_ioport_write(0x92, 1, 1, ioport92_write, NULL);
+void pc_basic_device_init(qemu_irq *isa_irq,
+ ISADevice **rtc_state)
+{
+ int i;
+ DriveInfo *fd[MAX_FD];
+ qemu_irq rtc_irq = NULL;
+ qemu_irq *a20_line;
+ ISADevice *i8042, *port92, *vmmouse, *pit;
+ qemu_irq *cpu_exit_irq;
+
+ register_ioport_write(0x80, 1, 1, ioport80_write, NULL);
+
+ register_ioport_write(0xf0, 1, 1, ioportF0_write, NULL);
- pit = pit_init(0x40, isa_reserve_irq(0));
- pcspk_init(pit);
if (!no_hpet) {
- hpet_init(isa_irq);
+ DeviceState *hpet = sysbus_try_create_simple("hpet", HPET_BASE, NULL);
+
+ if (hpet) {
+ for (i = 0; i < 24; i++) {
+ sysbus_connect_irq(sysbus_from_qdev(hpet), i, isa_irq[i]);
+ }
+ rtc_irq = qdev_get_gpio_in(hpet, 0);
+ }
}
+ *rtc_state = rtc_init(2000, rtc_irq);
+
+ qemu_register_boot_set(pc_boot_set, *rtc_state);
+
+ pit = pit_init(0x40, 0);
+ pcspk_init(pit);
for(i = 0; i < MAX_SERIAL_PORTS; i++) {
if (serial_hds[i]) {
}
}
- for(i = 0; i < nb_nics; i++) {
- NICInfo *nd = &nd_table[i];
-
- if (!pci_enabled || (nd->model && strcmp(nd->model, "ne2k_isa") == 0))
- pc_init_ne2k_isa(nd);
- else
- pci_nic_init_nofail(nd, "e1000", NULL);
- }
-
- if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
- fprintf(stderr, "qemu: too many IDE bus\n");
- exit(1);
- }
-
- for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) {
- hd[i] = drive_get(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS);
- }
-
- if (pci_enabled) {
- pci_piix3_ide_init(pci_bus, hd, piix3_devfn + 1);
- } else {
- for(i = 0; i < MAX_IDE_BUS; i++) {
- isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i],
- hd[MAX_IDE_DEVS * i], hd[MAX_IDE_DEVS * i + 1]);
- }
+ a20_line = qemu_allocate_irqs(handle_a20_line_change, first_cpu, 2);
+ i8042 = isa_create_simple("i8042");
+ i8042_setup_a20_line(i8042, &a20_line[0]);
+ vmport_init();
+ vmmouse = isa_try_create("vmmouse");
+ if (vmmouse) {
+ qdev_prop_set_ptr(&vmmouse->qdev, "ps2_mouse", i8042);
+ qdev_init_nofail(&vmmouse->qdev);
}
+ port92 = isa_create_simple("port92");
+ port92_init(port92, &a20_line[1]);
- isa_create_simple("i8042");
- DMA_init(0);
-#ifdef HAS_AUDIO
- audio_init(pci_enabled ? pci_bus : NULL, isa_irq);
-#endif
+ cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1);
+ DMA_init(0, cpu_exit_irq);
for(i = 0; i < MAX_FD; i++) {
fd[i] = drive_get(IF_FLOPPY, 0, i);
}
- floppy_controller = fdctrl_init_isa(fd);
-
- cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device, hd,
- floppy_controller, rtc_state);
-
- if (pci_enabled && usb_enabled) {
- usb_uhci_piix3_init(pci_bus, piix3_devfn + 2);
- }
-
- if (pci_enabled && acpi_enabled) {
- uint8_t *eeprom_buf = qemu_mallocz(8 * 256); /* XXX: make this persistent */
- i2c_bus *smbus;
-
- cmos_s3 = qemu_allocate_irqs(cmos_set_s3_resume, rtc_state, 1);
- smi_irq = qemu_allocate_irqs(acpi_smi_interrupt, first_cpu, 1);
- /* TODO: Populate SPD eeprom data. */
- smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100,
- isa_reserve_irq(9), *cmos_s3, *smi_irq,
- kvm_enabled());
- for (i = 0; i < 8; i++) {
- DeviceState *eeprom;
- eeprom = qdev_create((BusState *)smbus, "smbus-eeprom");
- qdev_prop_set_uint8(eeprom, "address", 0x50 + i);
- qdev_prop_set_ptr(eeprom, "data", eeprom_buf + (i * 256));
- qdev_init_nofail(eeprom);
- }
- piix4_acpi_system_hot_add_init(pci_bus);
- }
-
- if (i440fx_state) {
- i440fx_init_memory_mappings(i440fx_state);
- }
-
- if (pci_enabled) {
- 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");
- }
- }
-}
-
-static void pc_init_pci(ram_addr_t ram_size,
- const char *boot_device,
- const char *kernel_filename,
- const char *kernel_cmdline,
- const char *initrd_filename,
- const char *cpu_model)
-{
- pc_init1(ram_size, boot_device,
- kernel_filename, kernel_cmdline,
- initrd_filename, cpu_model, 1);
+ fdctrl_init_isa(fd);
}
-static void pc_init_isa(ram_addr_t ram_size,
- const char *boot_device,
- const char *kernel_filename,
- const char *kernel_cmdline,
- const char *initrd_filename,
- const char *cpu_model)
+void pc_pci_device_init(PCIBus *pci_bus)
{
- if (cpu_model == NULL)
- cpu_model = "486";
- pc_init1(ram_size, boot_device,
- kernel_filename, kernel_cmdline,
- initrd_filename, cpu_model, 0);
-}
-
-static QEMUMachine pc_machine = {
- .name = "pc-0.13",
- .alias = "pc",
- .desc = "Standard PC",
- .init = pc_init_pci,
- .max_cpus = 255,
- .is_default = 1,
-};
+ int max_bus;
+ int bus;
-static QEMUMachine pc_machine_v0_12 = {
- .name = "pc-0.12",
- .desc = "Standard PC",
- .init = pc_init_pci,
- .max_cpus = 255,
- .compat_props = (GlobalProperty[]) {
- {
- .driver = "virtio-serial-pci",
- .property = "max_nr_ports",
- .value = stringify(1),
- },{
- .driver = "virtio-serial-pci",
- .property = "vectors",
- .value = stringify(0),
- },
- { /* end of list */ }
+ max_bus = drive_get_max_bus(IF_SCSI);
+ for (bus = 0; bus <= max_bus; bus++) {
+ pci_create_simple(pci_bus, -1, "lsi53c895a");
}
-};
-
-static QEMUMachine pc_machine_v0_11 = {
- .name = "pc-0.11",
- .desc = "Standard PC, qemu 0.11",
- .init = pc_init_pci,
- .max_cpus = 255,
- .compat_props = (GlobalProperty[]) {
- {
- .driver = "virtio-blk-pci",
- .property = "vectors",
- .value = stringify(0),
- },{
- .driver = "virtio-serial-pci",
- .property = "max_nr_ports",
- .value = stringify(1),
- },{
- .driver = "virtio-serial-pci",
- .property = "vectors",
- .value = stringify(0),
- },{
- .driver = "ide-drive",
- .property = "ver",
- .value = "0.11",
- },{
- .driver = "scsi-disk",
- .property = "ver",
- .value = "0.11",
- },{
- .driver = "PCI",
- .property = "rombar",
- .value = stringify(0),
- },
- { /* end of list */ }
- }
-};
-
-static QEMUMachine pc_machine_v0_10 = {
- .name = "pc-0.10",
- .desc = "Standard PC, qemu 0.10",
- .init = pc_init_pci,
- .max_cpus = 255,
- .compat_props = (GlobalProperty[]) {
- {
- .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-serial-pci",
- .property = "max_nr_ports",
- .value = stringify(1),
- },{
- .driver = "virtio-serial-pci",
- .property = "vectors",
- .value = stringify(0),
- },{
- .driver = "virtio-net-pci",
- .property = "vectors",
- .value = stringify(0),
- },{
- .driver = "virtio-blk-pci",
- .property = "vectors",
- .value = stringify(0),
- },{
- .driver = "ide-drive",
- .property = "ver",
- .value = "0.10",
- },{
- .driver = "scsi-disk",
- .property = "ver",
- .value = "0.10",
- },{
- .driver = "PCI",
- .property = "rombar",
- .value = stringify(0),
- },
- { /* end of list */ }
- },
-};
-
-static QEMUMachine isapc_machine = {
- .name = "isapc",
- .desc = "ISA-only PC",
- .init = pc_init_isa,
- .max_cpus = 1,
-};
-
-static void pc_machine_init(void)
-{
- qemu_register_machine(&pc_machine);
- qemu_register_machine(&pc_machine_v0_12);
- qemu_register_machine(&pc_machine_v0_11);
- qemu_register_machine(&pc_machine_v0_10);
- qemu_register_machine(&isapc_machine);
}
-
-machine_init(pc_machine_init);