aboutsummaryrefslogtreecommitdiff
path: root/hw/i386
diff options
context:
space:
mode:
Diffstat (limited to 'hw/i386')
-rw-r--r--hw/i386/Makefile.objs1
-rw-r--r--hw/i386/kvm/apic.c2
-rw-r--r--hw/i386/kvm/i8254.c6
-rw-r--r--hw/i386/kvm/ioapic.c4
-rw-r--r--hw/i386/kvm/pci-assign.c1
-rw-r--r--hw/i386/kvmvapic.c4
-rw-r--r--hw/i386/pc.c79
-rw-r--r--hw/i386/pc_piix.c166
-rw-r--r--hw/i386/pc_q35.c62
-rw-r--r--hw/i386/pc_sysfw.c188
-rw-r--r--hw/i386/xen_domainbuild.c6
11 files changed, 357 insertions, 162 deletions
diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs
index 205d22e4aa..45e61655e9 100644
--- a/hw/i386/Makefile.objs
+++ b/hw/i386/Makefile.objs
@@ -1,6 +1,7 @@
obj-$(CONFIG_KVM) += kvm/
obj-y += multiboot.o smbios.o
obj-y += pc.o pc_piix.o pc_q35.o
+obj-y += pc_sysfw.o
obj-$(CONFIG_XEN) += xen_domainbuild.o xen_machine_pv.o
obj-y += kvmvapic.o
diff --git a/hw/i386/kvm/apic.c b/hw/i386/kvm/apic.c
index 179b806d96..5609063120 100644
--- a/hw/i386/kvm/apic.c
+++ b/hw/i386/kvm/apic.c
@@ -79,7 +79,7 @@ void kvm_get_apic_state(DeviceState *d, struct kvm_lapic_state *kapic)
v = (s->divide_conf & 3) | ((s->divide_conf >> 1) & 4);
s->count_shift = (v + 1) & 7;
- s->initial_count_load_time = qemu_get_clock_ns(vm_clock);
+ s->initial_count_load_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
apic_next_timer(s, s->initial_count_load_time);
}
diff --git a/hw/i386/kvm/i8254.c b/hw/i386/kvm/i8254.c
index c1f40948f9..20b6457fbd 100644
--- a/hw/i386/kvm/i8254.c
+++ b/hw/i386/kvm/i8254.c
@@ -65,12 +65,12 @@ static void kvm_pit_update_clock_offset(KVMPITState *s)
/*
* Measure the delta between CLOCK_MONOTONIC, the base used for
- * kvm_pit_channel_state::count_load_time, and vm_clock. Take the
+ * kvm_pit_channel_state::count_load_time, and QEMU_CLOCK_VIRTUAL. Take the
* minimum of several samples to filter out scheduling noise.
*/
clock_offset = INT64_MAX;
for (i = 0; i < CALIBRATION_ROUNDS; i++) {
- offset = qemu_get_clock_ns(vm_clock);
+ offset = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
clock_gettime(CLOCK_MONOTONIC, &ts);
offset -= ts.tv_nsec;
offset -= (int64_t)ts.tv_sec * 1000000000;
@@ -194,7 +194,7 @@ static void kvm_pit_set_gate(PITCommonState *s, PITChannelState *sc, int val)
case 5:
if (sc->gate < val) {
/* restart counting on rising edge */
- sc->count_load_time = qemu_get_clock_ns(vm_clock);
+ sc->count_load_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
}
break;
}
diff --git a/hw/i386/kvm/ioapic.c b/hw/i386/kvm/ioapic.c
index 688cb5cab3..f11a540825 100644
--- a/hw/i386/kvm/ioapic.c
+++ b/hw/i386/kvm/ioapic.c
@@ -112,7 +112,7 @@ static void kvm_ioapic_put(IOAPICCommonState *s)
static void kvm_ioapic_reset(DeviceState *dev)
{
- IOAPICCommonState *s = DO_UPCAST(IOAPICCommonState, busdev.qdev, dev);
+ IOAPICCommonState *s = IOAPIC_COMMON(dev);
ioapic_reset_common(dev);
kvm_ioapic_put(s);
@@ -131,7 +131,7 @@ static void kvm_ioapic_init(IOAPICCommonState *s, int instance_no)
{
memory_region_init_reservation(&s->io_memory, NULL, "kvm-ioapic", 0x1000);
- qdev_init_gpio_in(&s->busdev.qdev, kvm_ioapic_set_irq, IOAPIC_NUM_PINS);
+ qdev_init_gpio_in(DEVICE(s), kvm_ioapic_set_irq, IOAPIC_NUM_PINS);
}
static Property kvm_ioapic_properties[] = {
diff --git a/hw/i386/kvm/pci-assign.c b/hw/i386/kvm/pci-assign.c
index 73941b2950..011764fbf6 100644
--- a/hw/i386/kvm/pci-assign.c
+++ b/hw/i386/kvm/pci-assign.c
@@ -1855,6 +1855,7 @@ static void assign_class_init(ObjectClass *klass, void *data)
dc->props = assigned_dev_properties;
dc->vmsd = &vmstate_assigned_device;
dc->reset = reset_assigned_device;
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
dc->desc = "KVM-based PCI passthrough";
}
diff --git a/hw/i386/kvmvapic.c b/hw/i386/kvmvapic.c
index a4506bcf42..15beb8044e 100644
--- a/hw/i386/kvmvapic.c
+++ b/hw/i386/kvmvapic.c
@@ -456,7 +456,7 @@ static void patch_instruction(VAPICROMState *s, X86CPU *cpu, target_ulong ip)
void vapic_report_tpr_access(DeviceState *dev, CPUState *cs, target_ulong ip,
TPRAccess access)
{
- VAPICROMState *s = DO_UPCAST(VAPICROMState, busdev.qdev, dev);
+ VAPICROMState *s = VAPIC(dev);
X86CPU *cpu = X86_CPU(cs);
CPUX86State *env = &cpu->env;
@@ -508,7 +508,7 @@ static void vapic_enable_tpr_reporting(bool enable)
static void vapic_reset(DeviceState *dev)
{
- VAPICROMState *s = DO_UPCAST(VAPICROMState, busdev.qdev, dev);
+ VAPICROMState *s = VAPIC(dev);
if (s->state == VAPIC_ACTIVE) {
s->state = VAPIC_STANDBY;
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 2a8756321b..3a620a1856 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -55,6 +55,7 @@
#include "hw/acpi/acpi.h"
#include "hw/cpu/icc_bus.h"
#include "hw/boards.h"
+#include "hw/pci/pci_host.h"
/* debug PC/ISA interrupts */
//#define DEBUG_IRQ
@@ -75,8 +76,6 @@
#define FW_CFG_E820_TABLE (FW_CFG_ARCH_LOCAL + 3)
#define FW_CFG_HPET (FW_CFG_ARCH_LOCAL + 4)
-#define IO_APIC_DEFAULT_ADDRESS 0xfec00000
-
#define E820_NR_ENTRIES 16
struct e820_entry {
@@ -913,20 +912,19 @@ static X86CPU *pc_new_cpu(const char *cpu_model, int64_t apic_id,
X86CPU *cpu;
Error *local_err = NULL;
- cpu = cpu_x86_create(cpu_model, icc_bridge, errp);
- if (!cpu) {
- return cpu;
+ cpu = cpu_x86_create(cpu_model, icc_bridge, &local_err);
+ if (local_err != NULL) {
+ error_propagate(errp, local_err);
+ return NULL;
}
object_property_set_int(OBJECT(cpu), apic_id, "apic-id", &local_err);
object_property_set_bool(OBJECT(cpu), true, "realized", &local_err);
if (local_err) {
- if (cpu != NULL) {
- object_unref(OBJECT(cpu));
- cpu = NULL;
- }
error_propagate(errp, local_err);
+ object_unref(OBJECT(cpu));
+ cpu = NULL;
}
return cpu;
}
@@ -980,7 +978,7 @@ void pc_cpus_init(const char *cpu_model, DeviceState *icc_bridge)
cpu = pc_new_cpu(cpu_model, x86_cpu_apic_id_from_index(i),
icc_bridge, &error);
if (error) {
- fprintf(stderr, "%s\n", error_get_pretty(error));
+ error_report("%s", error_get_pretty(error));
error_free(error);
exit(1);
}
@@ -1005,15 +1003,27 @@ typedef struct PcRomPciInfo {
static void pc_fw_cfg_guest_info(PcGuestInfo *guest_info)
{
PcRomPciInfo *info;
+ Object *pci_info;
+ bool ambiguous = false;
+
if (!guest_info->has_pci_info || !guest_info->fw_cfg) {
return;
}
+ pci_info = object_resolve_path_type("", TYPE_PCI_HOST_BRIDGE, &ambiguous);
+ g_assert(!ambiguous);
+ if (!pci_info) {
+ return;
+ }
info = g_malloc(sizeof *info);
- info->w32_min = cpu_to_le64(guest_info->pci_info.w32.begin);
- info->w32_max = cpu_to_le64(guest_info->pci_info.w32.end);
- info->w64_min = cpu_to_le64(guest_info->pci_info.w64.begin);
- info->w64_max = cpu_to_le64(guest_info->pci_info.w64.end);
+ info->w32_min = cpu_to_le64(object_property_get_int(pci_info,
+ PCI_HOST_PROP_PCI_HOLE_START, NULL));
+ info->w32_max = cpu_to_le64(object_property_get_int(pci_info,
+ PCI_HOST_PROP_PCI_HOLE_END, NULL));
+ info->w64_min = cpu_to_le64(object_property_get_int(pci_info,
+ PCI_HOST_PROP_PCI_HOLE64_START, NULL));
+ info->w64_max = cpu_to_le64(object_property_get_int(pci_info,
+ PCI_HOST_PROP_PCI_HOLE64_END, NULL));
/* Pass PCI hole info to guest via a side channel.
* Required so guest PCI enumeration does the right thing. */
fw_cfg_add_file(guest_info->fw_cfg, "etc/pci-info", info, sizeof *info);
@@ -1039,29 +1049,28 @@ PcGuestInfo *pc_guest_info_init(ram_addr_t below_4g_mem_size,
PcGuestInfoState *guest_info_state = g_malloc0(sizeof *guest_info_state);
PcGuestInfo *guest_info = &guest_info_state->info;
- guest_info->pci_info.w32.end = IO_APIC_DEFAULT_ADDRESS;
- if (sizeof(hwaddr) == 4) {
- guest_info->pci_info.w64.begin = 0;
- guest_info->pci_info.w64.end = 0;
- } else {
- /*
- * BIOS does not set MTRR entries for the 64 bit window, so no need to
- * align address to power of two. Align address at 1G, this makes sure
- * it can be exactly covered with a PAT entry even when using huge
- * pages.
- */
- guest_info->pci_info.w64.begin =
- ROUND_UP((0x1ULL << 32) + above_4g_mem_size, 0x1ULL << 30);
- guest_info->pci_info.w64.end = guest_info->pci_info.w64.begin +
- (0x1ULL << 62);
- assert(guest_info->pci_info.w64.begin <= guest_info->pci_info.w64.end);
- }
-
guest_info_state->machine_done.notify = pc_guest_info_machine_done;
qemu_add_machine_init_done_notifier(&guest_info_state->machine_done);
return guest_info;
}
+void pc_init_pci64_hole(PcPciInfo *pci_info, uint64_t pci_hole64_start,
+ uint64_t pci_hole64_size)
+{
+ if ((sizeof(hwaddr) == 4) || (!pci_hole64_size)) {
+ return;
+ }
+ /*
+ * BIOS does not set MTRR entries for the 64 bit window, so no need to
+ * align address to power of two. Align address at 1G, this makes sure
+ * it can be exactly covered with a PAT entry even when using huge
+ * pages.
+ */
+ pci_info->w64.begin = ROUND_UP(pci_hole64_start, 0x1ULL << 30);
+ pci_info->w64.end = pci_info->w64.begin + pci_hole64_size;
+ assert(pci_info->w64.begin <= pci_info->w64.end);
+}
+
void pc_acpi_init(const char *default_dsdt)
{
char *filename;
@@ -1087,8 +1096,8 @@ void pc_acpi_init(const char *default_dsdt)
acpi_table_add(opts, &err);
if (err) {
- fprintf(stderr, "WARNING: failed to load %s: %s\n", filename,
- error_get_pretty(err));
+ error_report("WARNING: failed to load %s: %s", filename,
+ error_get_pretty(err));
error_free(err);
}
g_free(arg);
@@ -1136,7 +1145,7 @@ FWCfgState *pc_memory_init(MemoryRegion *system_memory,
/* Initialize PC system firmware */
- pc_system_firmware_init(rom_memory);
+ pc_system_firmware_init(rom_memory, guest_info->isapc_ram_fw);
option_rom_mr = g_malloc(sizeof(*option_rom_mr));
memory_region_init_ram(option_rom_mr, NULL, "pc.rom", PC_ROM_SIZE);
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index b58c25596d..3c36a2a1c3 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -25,6 +25,7 @@
#include <glib.h>
#include "hw/hw.h"
+#include "hw/loader.h"
#include "hw/i386/pc.h"
#include "hw/i386/apic.h"
#include "hw/pci/pci.h"
@@ -56,21 +57,16 @@ 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 };
-static bool has_pvpanic = true;
+static bool has_pvpanic;
static bool has_pci_info = true;
/* PC hardware initialisation */
-static void pc_init1(MemoryRegion *system_memory,
- MemoryRegion *system_io,
- 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,
+static void pc_init1(QEMUMachineInitArgs *args,
int pci_enabled,
int kvmclock_enabled)
{
+ MemoryRegion *system_memory = get_system_memory();
+ MemoryRegion *system_io = get_system_io();
int i;
ram_addr_t below_4g_mem_size, above_4g_mem_size;
PCIBus *pci_bus;
@@ -102,19 +98,18 @@ static void pc_init1(MemoryRegion *system_memory,
object_property_add_child(qdev_get_machine(), "icc-bridge",
OBJECT(icc_bridge), NULL);
- pc_cpus_init(cpu_model, icc_bridge);
- pc_acpi_init("acpi-dsdt.aml");
+ pc_cpus_init(args->cpu_model, icc_bridge);
if (kvm_enabled() && kvmclock_enabled) {
kvmclock_create();
}
- if (ram_size >= 0xe0000000 ) {
- above_4g_mem_size = ram_size - 0xe0000000;
+ if (args->ram_size >= 0xe0000000) {
+ above_4g_mem_size = args->ram_size - 0xe0000000;
below_4g_mem_size = 0xe0000000;
} else {
above_4g_mem_size = 0;
- below_4g_mem_size = ram_size;
+ below_4g_mem_size = args->ram_size;
}
if (pci_enabled) {
@@ -128,20 +123,13 @@ static void pc_init1(MemoryRegion *system_memory,
guest_info = pc_guest_info_init(below_4g_mem_size, above_4g_mem_size);
guest_info->has_pci_info = has_pci_info;
-
- /* Set PCI window size the way seabios has always done it. */
- /* Power of 2 so bios can cover it with a single MTRR */
- if (ram_size <= 0x80000000)
- guest_info->pci_info.w32.begin = 0x80000000;
- else if (ram_size <= 0xc0000000)
- guest_info->pci_info.w32.begin = 0xc0000000;
- else
- guest_info->pci_info.w32.begin = 0xe0000000;
+ guest_info->isapc_ram_fw = !pci_enabled;
/* allocate ram and load rom/bios */
if (!xen_enabled()) {
fw_cfg = pc_memory_init(system_memory,
- kernel_filename, kernel_cmdline, initrd_filename,
+ args->kernel_filename, args->kernel_cmdline,
+ args->initrd_filename,
below_4g_mem_size, above_4g_mem_size,
rom_memory, &ram_memory, guest_info);
}
@@ -157,13 +145,10 @@ static void pc_init1(MemoryRegion *system_memory,
if (pci_enabled) {
pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, &isa_bus, gsi,
- system_memory, system_io, ram_size,
+ system_memory, system_io, args->ram_size,
below_4g_mem_size,
0x100000000ULL - below_4g_mem_size,
- 0x100000000ULL + above_4g_mem_size,
- (sizeof(hwaddr) == 4
- ? 0
- : ((uint64_t)1 << 62)),
+ above_4g_mem_size,
pci_memory, ram_memory);
} else {
pci_bus = NULL;
@@ -219,7 +204,7 @@ static void pc_init1(MemoryRegion *system_memory,
}
}
- pc_cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device,
+ pc_cmos_init(below_4g_mem_size, above_4g_mem_size, args->boot_device,
floppy, idebus[0], idebus[1], rtc_state);
if (pci_enabled && usb_enabled(false)) {
@@ -248,90 +233,91 @@ static void pc_init1(MemoryRegion *system_memory,
static void pc_init_pci(QEMUMachineInitArgs *args)
{
- ram_addr_t ram_size = args->ram_size;
- const char *cpu_model = args->cpu_model;
- const char *kernel_filename = args->kernel_filename;
- const char *kernel_cmdline = args->kernel_cmdline;
- const char *initrd_filename = args->initrd_filename;
- const char *boot_device = args->boot_device;
- pc_init1(get_system_memory(),
- get_system_io(),
- ram_size, boot_device,
- kernel_filename, kernel_cmdline,
- initrd_filename, cpu_model, 1, 1);
+ pc_init1(args, 1, 1);
}
-static void pc_init_pci_1_5(QEMUMachineInitArgs *args)
+static void pc_compat_1_6(QEMUMachineInitArgs *args)
{
has_pci_info = false;
- pc_init_pci(args);
+ rom_file_in_ram = false;
}
-static void pc_init_pci_1_4(QEMUMachineInitArgs *args)
+static void pc_compat_1_5(QEMUMachineInitArgs *args)
{
+ pc_compat_1_6(args);
+ has_pvpanic = true;
+}
+
+static void pc_compat_1_4(QEMUMachineInitArgs *args)
+{
+ pc_compat_1_5(args);
has_pvpanic = false;
x86_cpu_compat_set_features("n270", FEAT_1_ECX, 0, CPUID_EXT_MOVBE);
- pc_init_pci_1_5(args);
+ x86_cpu_compat_set_features("Westmere", FEAT_1_ECX, 0, CPUID_EXT_PCLMULQDQ);
}
-static void pc_init_pci_1_3(QEMUMachineInitArgs *args)
+static void pc_compat_1_3(QEMUMachineInitArgs *args)
{
+ pc_compat_1_4(args);
enable_compat_apic_id_mode();
- pc_init_pci_1_4(args);
}
-/* PC machine init function for pc-1.1 to pc-1.2 */
-static void pc_init_pci_1_2(QEMUMachineInitArgs *args)
+/* PC compat function for pc-0.14 to pc-1.2 */
+static void pc_compat_1_2(QEMUMachineInitArgs *args)
{
+ pc_compat_1_3(args);
disable_kvm_pv_eoi();
- pc_init_pci_1_3(args);
}
-/* PC machine init function for pc-0.14 to pc-1.0 */
-static void pc_init_pci_1_0(QEMUMachineInitArgs *args)
+static void pc_init_pci_1_6(QEMUMachineInitArgs *args)
+{
+ pc_compat_1_6(args);
+ pc_init_pci(args);
+}
+
+static void pc_init_pci_1_5(QEMUMachineInitArgs *args)
+{
+ pc_compat_1_5(args);
+ pc_init_pci(args);
+}
+
+static void pc_init_pci_1_4(QEMUMachineInitArgs *args)
+{
+ pc_compat_1_4(args);
+ pc_init_pci(args);
+}
+
+static void pc_init_pci_1_3(QEMUMachineInitArgs *args)
{
- pc_init_pci_1_2(args);
+ pc_compat_1_3(args);
+ pc_init_pci(args);
+}
+
+/* PC machine init function for pc-0.14 to pc-1.2 */
+static void pc_init_pci_1_2(QEMUMachineInitArgs *args)
+{
+ pc_compat_1_2(args);
+ pc_init_pci(args);
}
/* PC init function for pc-0.10 to pc-0.13, and reused by xenfv */
static void pc_init_pci_no_kvmclock(QEMUMachineInitArgs *args)
{
- ram_addr_t ram_size = args->ram_size;
- const char *cpu_model = args->cpu_model;
- const char *kernel_filename = args->kernel_filename;
- const char *kernel_cmdline = args->kernel_cmdline;
- const char *initrd_filename = args->initrd_filename;
- const char *boot_device = args->boot_device;
- has_pvpanic = false;
has_pci_info = false;
disable_kvm_pv_eoi();
enable_compat_apic_id_mode();
- pc_init1(get_system_memory(),
- get_system_io(),
- ram_size, boot_device,
- kernel_filename, kernel_cmdline,
- initrd_filename, cpu_model, 1, 0);
+ pc_init1(args, 1, 0);
}
static void pc_init_isa(QEMUMachineInitArgs *args)
{
- ram_addr_t ram_size = args->ram_size;
- const char *cpu_model = args->cpu_model;
- const char *kernel_filename = args->kernel_filename;
- const char *kernel_cmdline = args->kernel_cmdline;
- const char *initrd_filename = args->initrd_filename;
- const char *boot_device = args->boot_device;
- has_pvpanic = false;
has_pci_info = false;
- if (cpu_model == NULL)
- cpu_model = "486";
+ if (!args->cpu_model) {
+ args->cpu_model = "486";
+ }
disable_kvm_pv_eoi();
enable_compat_apic_id_mode();
- pc_init1(get_system_memory(),
- get_system_io(),
- ram_size, boot_device,
- kernel_filename, kernel_cmdline,
- initrd_filename, cpu_model, 0, 1);
+ pc_init1(args, 0, 1);
}
#ifdef CONFIG_XEN
@@ -352,7 +338,7 @@ static QEMUMachine pc_i440fx_machine_v1_6 = {
.name = "pc-i440fx-1.6",
.alias = "pc",
.desc = "Standard PC (i440FX + PIIX, 1996)",
- .init = pc_init_pci,
+ .init = pc_init_pci_1_6,
.hot_add_cpu = pc_hot_add_cpu,
.max_cpus = 255,
.is_default = 1,
@@ -503,10 +489,6 @@ static QEMUMachine pc_machine_v1_1 = {
#define PC_COMPAT_1_0 \
PC_COMPAT_1_1,\
{\
- .driver = "pc-sysfw",\
- .property = "rom_only",\
- .value = stringify(1),\
- }, {\
.driver = TYPE_ISA_FDC,\
.property = "check_media_rate",\
.value = "off",\
@@ -527,7 +509,7 @@ static QEMUMachine pc_machine_v1_1 = {
static QEMUMachine pc_machine_v1_0 = {
.name = "pc-1.0",
.desc = "Standard PC",
- .init = pc_init_pci_1_0,
+ .init = pc_init_pci_1_2,
.max_cpus = 255,
.compat_props = (GlobalProperty[]) {
PC_COMPAT_1_0,
@@ -543,7 +525,7 @@ static QEMUMachine pc_machine_v1_0 = {
static QEMUMachine pc_machine_v0_15 = {
.name = "pc-0.15",
.desc = "Standard PC",
- .init = pc_init_pci_1_0,
+ .init = pc_init_pci_1_2,
.max_cpus = 255,
.compat_props = (GlobalProperty[]) {
PC_COMPAT_0_15,
@@ -576,7 +558,7 @@ static QEMUMachine pc_machine_v0_15 = {
static QEMUMachine pc_machine_v0_14 = {
.name = "pc-0.14",
.desc = "Standard PC",
- .init = pc_init_pci_1_0,
+ .init = pc_init_pci_1_2,
.max_cpus = 255,
.compat_props = (GlobalProperty[]) {
PC_COMPAT_0_14,
@@ -753,16 +735,6 @@ static QEMUMachine isapc_machine = {
.init = pc_init_isa,
.max_cpus = 1,
.compat_props = (GlobalProperty[]) {
- {
- .driver = "pc-sysfw",
- .property = "rom_only",
- .value = stringify(1),
- },
- {
- .driver = "pc-sysfw",
- .property = "isapc_ram_fw",
- .value = stringify(1),
- },
{ /* end of list */ }
},
DEFAULT_MACHINE_OPTIONS,
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index 0b1d2e32f7..198c7851b3 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -28,6 +28,7 @@
* THE SOFTWARE.
*/
#include "hw/hw.h"
+#include "hw/loader.h"
#include "sysemu/arch_init.h"
#include "hw/i2c/smbus.h"
#include "hw/boards.h"
@@ -46,18 +47,12 @@
/* ICH9 AHCI has 6 ports */
#define MAX_SATA_PORTS 6
-static bool has_pvpanic = true;
+static bool has_pvpanic;
static bool has_pci_info = true;
/* PC hardware initialisation */
static void pc_q35_init(QEMUMachineInitArgs *args)
{
- ram_addr_t ram_size = args->ram_size;
- const char *cpu_model = args->cpu_model;
- const char *kernel_filename = args->kernel_filename;
- const char *kernel_cmdline = args->kernel_cmdline;
- const char *initrd_filename = args->initrd_filename;
- const char *boot_device = args->boot_device;
ram_addr_t below_4g_mem_size, above_4g_mem_size;
Q35PCIHost *q35_host;
PCIHostState *phb;
@@ -85,17 +80,17 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
object_property_add_child(qdev_get_machine(), "icc-bridge",
OBJECT(icc_bridge), NULL);
- pc_cpus_init(cpu_model, icc_bridge);
+ pc_cpus_init(args->cpu_model, icc_bridge);
pc_acpi_init("q35-acpi-dsdt.aml");
kvmclock_create();
- if (ram_size >= 0xb0000000) {
- above_4g_mem_size = ram_size - 0xb0000000;
+ if (args->ram_size >= 0xb0000000) {
+ above_4g_mem_size = args->ram_size - 0xb0000000;
below_4g_mem_size = 0xb0000000;
} else {
above_4g_mem_size = 0;
- below_4g_mem_size = ram_size;
+ below_4g_mem_size = args->ram_size;
}
/* pci enabled */
@@ -110,11 +105,14 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
guest_info = pc_guest_info_init(below_4g_mem_size, above_4g_mem_size);
guest_info->has_pci_info = has_pci_info;
+ guest_info->isapc_ram_fw = false;
/* allocate ram and load rom/bios */
if (!xen_enabled()) {
- pc_memory_init(get_system_memory(), kernel_filename, kernel_cmdline,
- initrd_filename, below_4g_mem_size, above_4g_mem_size,
+ pc_memory_init(get_system_memory(),
+ args->kernel_filename, args->kernel_cmdline,
+ args->initrd_filename,
+ below_4g_mem_size, above_4g_mem_size,
rom_memory, &ram_memory, guest_info);
}
@@ -131,6 +129,7 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
/* create pci host bus */
q35_host = Q35_HOST_DEVICE(qdev_create(NULL, TYPE_Q35_HOST_DEVICE));
+ object_property_add_child(qdev_get_machine(), "q35", OBJECT(q35_host), NULL);
q35_host->mch.ram_memory = ram_memory;
q35_host->mch.pci_address_space = pci_memory;
q35_host->mch.system_memory = get_system_memory();
@@ -201,7 +200,7 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
0xb100),
8, NULL, 0);
- pc_cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device,
+ pc_cmos_init(below_4g_mem_size, above_4g_mem_size, args->boot_device,
floppy, idebus[0], idebus[1], rtc_state);
/* the rest devices to which pci devfn is automatically assigned */
@@ -216,24 +215,49 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
}
}
-static void pc_q35_init_1_5(QEMUMachineInitArgs *args)
+static void pc_compat_1_6(QEMUMachineInitArgs *args)
{
has_pci_info = false;
- pc_q35_init(args);
+ rom_file_in_ram = false;
}
-static void pc_q35_init_1_4(QEMUMachineInitArgs *args)
+static void pc_compat_1_5(QEMUMachineInitArgs *args)
+{
+ pc_compat_1_6(args);
+ has_pvpanic = true;
+}
+
+static void pc_compat_1_4(QEMUMachineInitArgs *args)
{
+ pc_compat_1_5(args);
has_pvpanic = false;
x86_cpu_compat_set_features("n270", FEAT_1_ECX, 0, CPUID_EXT_MOVBE);
- pc_q35_init_1_5(args);
+ x86_cpu_compat_set_features("Westmere", FEAT_1_ECX, 0, CPUID_EXT_PCLMULQDQ);
+}
+
+static void pc_q35_init_1_6(QEMUMachineInitArgs *args)
+{
+ pc_compat_1_6(args);
+ pc_q35_init(args);
+}
+
+static void pc_q35_init_1_5(QEMUMachineInitArgs *args)
+{
+ pc_compat_1_5(args);
+ pc_q35_init(args);
+}
+
+static void pc_q35_init_1_4(QEMUMachineInitArgs *args)
+{
+ pc_compat_1_4(args);
+ pc_q35_init(args);
}
static QEMUMachine pc_q35_machine_v1_6 = {
.name = "pc-q35-1.6",
.alias = "q35",
.desc = "Standard PC (Q35 + ICH9, 2009)",
- .init = pc_q35_init,
+ .init = pc_q35_init_1_6,
.hot_add_cpu = pc_hot_add_cpu,
.max_cpus = 255,
DEFAULT_MACHINE_OPTIONS,
diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c
new file mode 100644
index 0000000000..8246a1bdd4
--- /dev/null
+++ b/hw/i386/pc_sysfw.c
@@ -0,0 +1,188 @@
+/*
+ * QEMU PC System Firmware
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * Copyright (c) 2011-2012 Intel Corporation
+ *
+ * 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.
+ */
+
+#include "sysemu/blockdev.h"
+#include "qemu/error-report.h"
+#include "hw/sysbus.h"
+#include "hw/hw.h"
+#include "hw/i386/pc.h"
+#include "hw/boards.h"
+#include "hw/loader.h"
+#include "sysemu/sysemu.h"
+#include "hw/block/flash.h"
+#include "sysemu/kvm.h"
+
+#define BIOS_FILENAME "bios.bin"
+
+typedef struct PcSysFwDevice {
+ SysBusDevice busdev;
+ uint8_t isapc_ram_fw;
+} PcSysFwDevice;
+
+static void pc_isa_bios_init(MemoryRegion *rom_memory,
+ MemoryRegion *flash_mem,
+ int ram_size)
+{
+ int isa_bios_size;
+ MemoryRegion *isa_bios;
+ uint64_t flash_size;
+ void *flash_ptr, *isa_bios_ptr;
+
+ flash_size = memory_region_size(flash_mem);
+
+ /* map the last 128KB of the BIOS in ISA space */
+ isa_bios_size = flash_size;
+ if (isa_bios_size > (128 * 1024)) {
+ isa_bios_size = 128 * 1024;
+ }
+ isa_bios = g_malloc(sizeof(*isa_bios));
+ memory_region_init_ram(isa_bios, NULL, "isa-bios", isa_bios_size);
+ vmstate_register_ram_global(isa_bios);
+ memory_region_add_subregion_overlap(rom_memory,
+ 0x100000 - isa_bios_size,
+ isa_bios,
+ 1);
+
+ /* copy ISA rom image from top of flash memory */
+ flash_ptr = memory_region_get_ram_ptr(flash_mem);
+ isa_bios_ptr = memory_region_get_ram_ptr(isa_bios);
+ memcpy(isa_bios_ptr,
+ ((uint8_t*)flash_ptr) + (flash_size - isa_bios_size),
+ isa_bios_size);
+
+ memory_region_set_readonly(isa_bios, true);
+}
+
+static void pc_system_flash_init(MemoryRegion *rom_memory,
+ DriveInfo *pflash_drv)
+{
+ BlockDriverState *bdrv;
+ int64_t size;
+ hwaddr phys_addr;
+ int sector_bits, sector_size;
+ pflash_t *system_flash;
+ MemoryRegion *flash_mem;
+
+ bdrv = pflash_drv->bdrv;
+ size = bdrv_getlength(pflash_drv->bdrv);
+ sector_bits = 12;
+ sector_size = 1 << sector_bits;
+
+ if ((size % sector_size) != 0) {
+ fprintf(stderr,
+ "qemu: PC system firmware (pflash) must be a multiple of 0x%x\n",
+ sector_size);
+ exit(1);
+ }
+
+ phys_addr = 0x100000000ULL - size;
+ system_flash = pflash_cfi01_register(phys_addr, NULL, "system.flash", size,
+ bdrv, sector_size, size >> sector_bits,
+ 1, 0x0000, 0x0000, 0x0000, 0x0000, 0);
+ flash_mem = pflash_cfi01_get_memory(system_flash);
+
+ pc_isa_bios_init(rom_memory, flash_mem, size);
+}
+
+static void old_pc_system_rom_init(MemoryRegion *rom_memory, bool isapc_ram_fw)
+{
+ char *filename;
+ MemoryRegion *bios, *isa_bios;
+ int bios_size, isa_bios_size;
+ int ret;
+
+ /* BIOS load */
+ if (bios_name == NULL) {
+ bios_name = BIOS_FILENAME;
+ }
+ filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+ if (filename) {
+ bios_size = get_image_size(filename);
+ } else {
+ bios_size = -1;
+ }
+ if (bios_size <= 0 ||
+ (bios_size % 65536) != 0) {
+ goto bios_error;
+ }
+ bios = g_malloc(sizeof(*bios));
+ memory_region_init_ram(bios, NULL, "pc.bios", bios_size);
+ vmstate_register_ram_global(bios);
+ if (!isapc_ram_fw) {
+ memory_region_set_readonly(bios, true);
+ }
+ 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);
+ exit(1);
+ }
+ if (filename) {
+ g_free(filename);
+ }
+
+ /* map the last 128KB of the BIOS in ISA space */
+ isa_bios_size = bios_size;
+ if (isa_bios_size > (128 * 1024)) {
+ isa_bios_size = 128 * 1024;
+ }
+ isa_bios = g_malloc(sizeof(*isa_bios));
+ memory_region_init_alias(isa_bios, NULL, "isa-bios", bios,
+ bios_size - isa_bios_size, isa_bios_size);
+ memory_region_add_subregion_overlap(rom_memory,
+ 0x100000 - isa_bios_size,
+ isa_bios,
+ 1);
+ if (!isapc_ram_fw) {
+ memory_region_set_readonly(isa_bios, true);
+ }
+
+ /* map all the bios at the top of memory */
+ memory_region_add_subregion(rom_memory,
+ (uint32_t)(-bios_size),
+ bios);
+}
+
+void pc_system_firmware_init(MemoryRegion *rom_memory, bool isapc_ram_fw)
+{
+ DriveInfo *pflash_drv;
+
+ pflash_drv = drive_get(IF_PFLASH, 0, 0);
+
+ if (isapc_ram_fw || pflash_drv == NULL) {
+ /* When a pflash drive is not found, use rom-mode */
+ old_pc_system_rom_init(rom_memory, isapc_ram_fw);
+ return;
+ }
+
+ if (kvm_enabled() && !kvm_readonly_mem_enabled()) {
+ /* Older KVM cannot execute from device memory. So, flash memory
+ * cannot be used unless the readonly memory kvm capability is present. */
+ fprintf(stderr, "qemu: pflash with kvm requires KVM readonly memory support\n");
+ exit(1);
+ }
+
+ pc_system_flash_init(rom_memory, pflash_drv);
+}
diff --git a/hw/i386/xen_domainbuild.c b/hw/i386/xen_domainbuild.c
index 4e2cf95ae5..c0ab7537df 100644
--- a/hw/i386/xen_domainbuild.c
+++ b/hw/i386/xen_domainbuild.c
@@ -148,7 +148,7 @@ static void xen_domain_poll(void *opaque)
goto quit;
}
- qemu_mod_timer(xen_poll, qemu_get_clock_ms(rt_clock) + 1000);
+ timer_mod(xen_poll, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1000);
return;
quit:
@@ -290,8 +290,8 @@ int xen_domain_build_pv(const char *kernel, const char *ramdisk,
goto err;
}
- xen_poll = qemu_new_timer_ms(rt_clock, xen_domain_poll, NULL);
- qemu_mod_timer(xen_poll, qemu_get_clock_ms(rt_clock) + 1000);
+ xen_poll = timer_new_ms(QEMU_CLOCK_REALTIME, xen_domain_poll, NULL);
+ timer_mod(xen_poll, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1000);
return 0;
err: