diff options
Diffstat (limited to 'hw')
-rw-r--r-- | hw/acpi/core.c | 18 | ||||
-rw-r--r-- | hw/acpi/ich9.c | 24 | ||||
-rw-r--r-- | hw/acpi/piix4.c | 27 | ||||
-rw-r--r-- | hw/core/qdev.c | 47 | ||||
-rw-r--r-- | hw/i386/acpi-dsdt-cpu-hotplug.dsl | 1 | ||||
-rw-r--r-- | hw/i386/pc_piix.c | 19 | ||||
-rw-r--r-- | hw/i386/pc_sysfw.c | 105 | ||||
-rw-r--r-- | hw/i386/q35-acpi-dsdt.dsl | 4 | ||||
-rw-r--r-- | hw/pci-host/piix.c | 11 | ||||
-rw-r--r-- | hw/pci/pci.c | 42 | ||||
-rw-r--r-- | hw/pci/pci_bridge.c | 2 | ||||
-rw-r--r-- | hw/s390x/virtio-ccw.c | 5 | ||||
-rw-r--r-- | hw/virtio/virtio.c | 2 |
13 files changed, 190 insertions, 117 deletions
diff --git a/hw/acpi/core.c b/hw/acpi/core.c index 58308a3406..79414b44c7 100644 --- a/hw/acpi/core.c +++ b/hw/acpi/core.c @@ -662,3 +662,21 @@ uint32_t acpi_gpe_ioport_readb(ACPIREGS *ar, uint32_t addr) return val; } + +void acpi_update_sci(ACPIREGS *regs, qemu_irq irq) +{ + int sci_level, pm1a_sts; + + pm1a_sts = acpi_pm1_evt_get_sts(regs); + + sci_level = ((pm1a_sts & + regs->pm1.evt.en & ACPI_BITMASK_PM1_COMMON_ENABLED) != 0) || + ((regs->gpe.sts[0] & regs->gpe.en[0]) != 0); + + qemu_set_irq(irq, sci_level); + + /* schedule a timer interruption if needed */ + acpi_pm_tmr_update(regs, + (regs->pm1.evt.en & ACPI_BITMASK_TIMER_ENABLE) && + !(pm1a_sts & ACPI_BITMASK_TIMER_STATUS)); +} diff --git a/hw/acpi/ich9.c b/hw/acpi/ich9.c index 7e0429e0f9..30f0df8713 100644 --- a/hw/acpi/ich9.c +++ b/hw/acpi/ich9.c @@ -44,29 +44,10 @@ do { printf("%s "fmt, __func__, ## __VA_ARGS__); } while (0) #define ICH9_DEBUG(fmt, ...) do { } while (0) #endif -static void pm_update_sci(ICH9LPCPMRegs *pm) -{ - int sci_level, pm1a_sts; - - pm1a_sts = acpi_pm1_evt_get_sts(&pm->acpi_regs); - - sci_level = (((pm1a_sts & pm->acpi_regs.pm1.evt.en) & - (ACPI_BITMASK_RT_CLOCK_ENABLE | - ACPI_BITMASK_POWER_BUTTON_ENABLE | - ACPI_BITMASK_GLOBAL_LOCK_ENABLE | - ACPI_BITMASK_TIMER_ENABLE)) != 0); - qemu_set_irq(pm->irq, sci_level); - - /* schedule a timer interruption if needed */ - acpi_pm_tmr_update(&pm->acpi_regs, - (pm->acpi_regs.pm1.evt.en & ACPI_BITMASK_TIMER_ENABLE) && - !(pm1a_sts & ACPI_BITMASK_TIMER_STATUS)); -} - static void ich9_pm_update_sci_fn(ACPIREGS *regs) { ICH9LPCPMRegs *pm = container_of(regs, ICH9LPCPMRegs, acpi_regs); - pm_update_sci(pm); + acpi_update_sci(&pm->acpi_regs, pm->irq); } static uint64_t ich9_gpe_readb(void *opaque, hwaddr addr, unsigned width) @@ -80,6 +61,7 @@ static void ich9_gpe_writeb(void *opaque, hwaddr addr, uint64_t val, { ICH9LPCPMRegs *pm = opaque; acpi_gpe_ioport_writeb(&pm->acpi_regs, addr, val); + acpi_update_sci(&pm->acpi_regs, pm->irq); } static const MemoryRegionOps ich9_gpe_ops = { @@ -193,7 +175,7 @@ static void pm_reset(void *opaque) pm->smi_en |= ICH9_PMIO_SMI_EN_APMC_EN; } - pm_update_sci(pm); + acpi_update_sci(&pm->acpi_regs, pm->irq); } static void pm_powerdown_req(Notifier *n, void *opaque) diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c index 9e8a89c233..20353b983e 100644 --- a/hw/acpi/piix4.c +++ b/hw/acpi/piix4.c @@ -112,29 +112,10 @@ static void piix4_acpi_system_hot_add_init(MemoryRegion *parent, #define ACPI_ENABLE 0xf1 #define ACPI_DISABLE 0xf0 -static void pm_update_sci(PIIX4PMState *s) -{ - int sci_level, pmsts; - - pmsts = acpi_pm1_evt_get_sts(&s->ar); - sci_level = (((pmsts & s->ar.pm1.evt.en) & - (ACPI_BITMASK_RT_CLOCK_ENABLE | - ACPI_BITMASK_POWER_BUTTON_ENABLE | - ACPI_BITMASK_GLOBAL_LOCK_ENABLE | - ACPI_BITMASK_TIMER_ENABLE)) != 0) || - (((s->ar.gpe.sts[0] & s->ar.gpe.en[0]) & - (PIIX4_PCI_HOTPLUG_STATUS | PIIX4_CPU_HOTPLUG_STATUS)) != 0); - - qemu_set_irq(s->irq, sci_level); - /* schedule a timer interruption if needed */ - acpi_pm_tmr_update(&s->ar, (s->ar.pm1.evt.en & ACPI_BITMASK_TIMER_ENABLE) && - !(pmsts & ACPI_BITMASK_TIMER_STATUS)); -} - static void pm_tmr_timer(ACPIREGS *ar) { PIIX4PMState *s = container_of(ar, PIIX4PMState, ar); - pm_update_sci(s); + acpi_update_sci(&s->ar, s->irq); } static void apm_ctrl_changed(uint32_t val, void *arg) @@ -582,7 +563,7 @@ static void gpe_writeb(void *opaque, hwaddr addr, uint64_t val, PIIX4PMState *s = opaque; acpi_gpe_ioport_writeb(&s->ar, addr, val); - pm_update_sci(s); + acpi_update_sci(&s->ar, s->irq); PIIX4_DPRINTF("gpe write %" HWADDR_PRIx " <== %" PRIu64 "\n", addr, val); } @@ -698,7 +679,7 @@ static void piix4_cpu_hotplug_req(PIIX4PMState *s, CPUState *cpu, } else { g->sts[cpu_id / 8] &= ~(1 << (cpu_id % 8)); } - pm_update_sci(s); + acpi_update_sci(&s->ar, s->irq); } static void piix4_cpu_added_req(Notifier *n, void *opaque) @@ -772,7 +753,7 @@ static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev, disable_device(s, slot); } - pm_update_sci(s); + acpi_update_sci(&s->ar, s->irq); return 0; } diff --git a/hw/core/qdev.c b/hw/core/qdev.c index bbd780aad1..d6df8864dd 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -233,19 +233,19 @@ static int qbus_reset_one(BusState *bus, void *opaque) { BusClass *bc = BUS_GET_CLASS(bus); if (bc->reset) { - return bc->reset(bus); + bc->reset(bus); } return 0; } void qdev_reset_all(DeviceState *dev) { - qdev_walk_children(dev, qdev_reset_one, qbus_reset_one, NULL); + qdev_walk_children(dev, NULL, NULL, qdev_reset_one, qbus_reset_one, NULL); } void qbus_reset_all(BusState *bus) { - qbus_walk_children(bus, qdev_reset_one, qbus_reset_one, NULL); + qbus_walk_children(bus, NULL, NULL, qdev_reset_one, qbus_reset_one, NULL); } void qbus_reset_all_fn(void *opaque) @@ -337,49 +337,70 @@ BusState *qdev_get_child_bus(DeviceState *dev, const char *name) return NULL; } -int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn, - qbus_walkerfn *busfn, void *opaque) +int qbus_walk_children(BusState *bus, + qdev_walkerfn *pre_devfn, qbus_walkerfn *pre_busfn, + qdev_walkerfn *post_devfn, qbus_walkerfn *post_busfn, + void *opaque) { BusChild *kid; int err; - if (busfn) { - err = busfn(bus, opaque); + if (pre_busfn) { + err = pre_busfn(bus, opaque); if (err) { return err; } } QTAILQ_FOREACH(kid, &bus->children, sibling) { - err = qdev_walk_children(kid->child, devfn, busfn, opaque); + err = qdev_walk_children(kid->child, + pre_devfn, pre_busfn, + post_devfn, post_busfn, opaque); if (err < 0) { return err; } } + if (post_busfn) { + err = post_busfn(bus, opaque); + if (err) { + return err; + } + } + return 0; } -int qdev_walk_children(DeviceState *dev, qdev_walkerfn *devfn, - qbus_walkerfn *busfn, void *opaque) +int qdev_walk_children(DeviceState *dev, + qdev_walkerfn *pre_devfn, qbus_walkerfn *pre_busfn, + qdev_walkerfn *post_devfn, qbus_walkerfn *post_busfn, + void *opaque) { BusState *bus; int err; - if (devfn) { - err = devfn(dev, opaque); + if (pre_devfn) { + err = pre_devfn(dev, opaque); if (err) { return err; } } QLIST_FOREACH(bus, &dev->child_bus, sibling) { - err = qbus_walk_children(bus, devfn, busfn, opaque); + err = qbus_walk_children(bus, pre_devfn, pre_busfn, + post_devfn, post_busfn, opaque); if (err < 0) { return err; } } + if (post_devfn) { + err = post_devfn(dev, opaque); + if (err) { + return err; + } + } + return 0; } diff --git a/hw/i386/acpi-dsdt-cpu-hotplug.dsl b/hw/i386/acpi-dsdt-cpu-hotplug.dsl index c96ac42a31..995b415bae 100644 --- a/hw/i386/acpi-dsdt-cpu-hotplug.dsl +++ b/hw/i386/acpi-dsdt-cpu-hotplug.dsl @@ -52,7 +52,6 @@ Scope(\_SB) { Sleep(200) } - /* CPU hotplug notify method */ OperationRegion(PRST, SystemIO, 0xaf00, 32) Field(PRST, ByteAcc, NoLock, Preserve) { PRS, 256 diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 4e0dae7981..276641436e 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -61,6 +61,11 @@ static const int ide_irq[MAX_IDE_BUS] = { 14, 15 }; static bool has_pci_info; static bool has_acpi_build = true; static bool smbios_type1_defaults = true; +/* Make sure that guest addresses aligned at 1Gbyte boundaries get mapped to + * host addresses aligned at 1Gbyte boundaries. This way we can use 1GByte + * pages in the host. + */ +static bool gigabyte_align = true; /* PC hardware initialisation */ static void pc_init1(QEMUMachineInitArgs *args, @@ -106,9 +111,17 @@ static void pc_init1(QEMUMachineInitArgs *args, kvmclock_create(); } + /* Check whether RAM fits below 4G (leaving 1/2 GByte for IO memory). + * If it doesn't, we need to split it in chunks below and above 4G. + * In any case, try to make sure that guest addresses aligned at + * 1G boundaries get mapped to host addresses aligned at 1G boundaries. + * For old machine types, use whatever split we used historically to avoid + * breaking migration. + */ if (args->ram_size >= 0xe0000000) { - above_4g_mem_size = args->ram_size - 0xe0000000; - below_4g_mem_size = 0xe0000000; + ram_addr_t lowmem = gigabyte_align ? 0xc0000000 : 0xe0000000; + above_4g_mem_size = args->ram_size - lowmem; + below_4g_mem_size = lowmem; } else { above_4g_mem_size = 0; below_4g_mem_size = args->ram_size; @@ -157,6 +170,7 @@ static void pc_init1(QEMUMachineInitArgs *args, if (pci_enabled) { pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, &isa_bus, gsi, system_memory, system_io, args->ram_size, + below_4g_mem_size, above_4g_mem_size, pci_memory, ram_memory); } else { @@ -245,6 +259,7 @@ static void pc_init_pci(QEMUMachineInitArgs *args) static void pc_compat_1_7(QEMUMachineInitArgs *args) { smbios_type1_defaults = false; + gigabyte_align = false; } static void pc_compat_1_6(QEMUMachineInitArgs *args) diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c index e917c83540..75a7ebbaa7 100644 --- a/hw/i386/pc_sysfw.c +++ b/hw/i386/pc_sysfw.c @@ -72,35 +72,102 @@ static void pc_isa_bios_init(MemoryRegion *rom_memory, memory_region_set_readonly(isa_bios, true); } -static void pc_system_flash_init(MemoryRegion *rom_memory, - DriveInfo *pflash_drv) +#define FLASH_MAP_UNIT_MAX 2 + +/* We don't have a theoretically justifiable exact lower bound on the base + * address of any flash mapping. In practice, the IO-APIC MMIO range is + * [0xFEE00000..0xFEE01000[ -- see IO_APIC_DEFAULT_ADDRESS --, leaving free + * only 18MB-4KB below 4G. For now, restrict the cumulative mapping to 8MB in + * size. + */ +#define FLASH_MAP_BASE_MIN ((hwaddr)(0x100000000ULL - 8*1024*1024)) + +/* This function maps flash drives from 4G downward, in order of their unit + * numbers. The mapping starts at unit#0, with unit number increments of 1, and + * stops before the first missing flash drive, or before + * unit#FLASH_MAP_UNIT_MAX, whichever is reached first. + * + * Addressing within one flash drive is of course not reversed. + * + * An error message is printed and the process exits if: + * - the size of the backing file for a flash drive is non-positive, or not a + * multiple of the required sector size, or + * - the current mapping's base address would fall below FLASH_MAP_BASE_MIN. + * + * The drive with unit#0 (if available) is mapped at the highest address, and + * it is passed to pc_isa_bios_init(). Merging several drives for isa-bios is + * not supported. + */ +static void pc_system_flash_init(MemoryRegion *rom_memory) { + int unit; + DriveInfo *pflash_drv; BlockDriverState *bdrv; int64_t size; - hwaddr phys_addr; + char *fatal_errmsg = NULL; + hwaddr phys_addr = 0x100000000ULL; int sector_bits, sector_size; pflash_t *system_flash; MemoryRegion *flash_mem; + char name[64]; - 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); + for (unit = 0; + (unit < FLASH_MAP_UNIT_MAX && + (pflash_drv = drive_get(IF_PFLASH, 0, unit)) != NULL); + ++unit) { + bdrv = pflash_drv->bdrv; + size = bdrv_getlength(bdrv); + if (size < 0) { + fatal_errmsg = g_strdup_printf("failed to get backing file size"); + } else if (size == 0) { + fatal_errmsg = g_strdup_printf("PC system firmware (pflash) " + "cannot have zero size"); + } else if ((size % sector_size) != 0) { + fatal_errmsg = g_strdup_printf("PC system firmware (pflash) " + "must be a multiple of 0x%x", sector_size); + } else if (phys_addr < size || phys_addr - size < FLASH_MAP_BASE_MIN) { + fatal_errmsg = g_strdup_printf("oversized backing file, pflash " + "segments cannot be mapped under " + TARGET_FMT_plx, FLASH_MAP_BASE_MIN); + } + if (fatal_errmsg != NULL) { + Location loc; + + /* push a new, "none" location on the location stack; overwrite its + * contents with the location saved in the option; print the error + * (includes location); pop the top + */ + loc_push_none(&loc); + if (pflash_drv->opts != NULL) { + qemu_opts_loc_restore(pflash_drv->opts); + } + error_report("%s", fatal_errmsg); + loc_pop(&loc); + g_free(fatal_errmsg); + exit(1); + } + + phys_addr -= size; + + /* pflash_cfi01_register() creates a deep copy of the name */ + snprintf(name, sizeof name, "system.flash%d", unit); + system_flash = pflash_cfi01_register(phys_addr, NULL /* qdev */, name, + size, bdrv, sector_size, + size >> sector_bits, + 1 /* width */, + 0x0000 /* id0 */, + 0x0000 /* id1 */, + 0x0000 /* id2 */, + 0x0000 /* id3 */, + 0 /* be */); + if (unit == 0) { + flash_mem = pflash_cfi01_get_memory(system_flash); + pc_isa_bios_init(rom_memory, flash_mem, size); + } } - - 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) @@ -181,5 +248,5 @@ void pc_system_firmware_init(MemoryRegion *rom_memory, bool isapc_ram_fw) exit(1); } - pc_system_flash_init(rom_memory, pflash_drv); + pc_system_flash_init(rom_memory); } diff --git a/hw/i386/q35-acpi-dsdt.dsl b/hw/i386/q35-acpi-dsdt.dsl index 575c5d7376..7934a9ddfb 100644 --- a/hw/i386/q35-acpi-dsdt.dsl +++ b/hw/i386/q35-acpi-dsdt.dsl @@ -417,11 +417,11 @@ DefinitionBlock ( Method(_L00) { } Method(_L01) { + } + Method(_E02) { // CPU hotplug event \_SB.PRSC() } - Method(_L02) { - } Method(_L03) { } Method(_L04) { diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c index cc97150a90..e89d5c1dfa 100644 --- a/hw/pci-host/piix.c +++ b/hw/pci-host/piix.c @@ -311,6 +311,7 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, MemoryRegion *address_space_mem, MemoryRegion *address_space_io, ram_addr_t ram_size, + ram_addr_t below_4g_mem_size, ram_addr_t above_4g_mem_size, MemoryRegion *pci_address_space, MemoryRegion *ram_memory) @@ -340,15 +341,7 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, f->ram_memory = ram_memory; i440fx = I440FX_PCI_HOST_BRIDGE(dev); - /* 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) { - i440fx->pci_info.w32.begin = 0x80000000; - } else if (ram_size <= 0xc0000000) { - i440fx->pci_info.w32.begin = 0xc0000000; - } else { - i440fx->pci_info.w32.begin = 0xe0000000; - } + i440fx->pci_info.w32.begin = below_4g_mem_size; /* setup pci memory mapping */ pc_pci_as_mapping_init(OBJECT(f), f->system_memory, diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 82c11ecde4..aa2a395499 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -46,7 +46,7 @@ static void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent); static char *pcibus_get_dev_path(DeviceState *dev); static char *pcibus_get_fw_dev_path(DeviceState *dev); -static int pcibus_reset(BusState *qbus); +static void pcibus_reset(BusState *qbus); static void pci_bus_finalize(Object *obj); static Property pci_props[] = { @@ -167,16 +167,10 @@ void pci_device_deassert_intx(PCIDevice *dev) } } -/* - * This function is called on #RST and FLR. - * FLR if PCI_EXP_DEVCTL_BCR_FLR is set - */ -void pci_device_reset(PCIDevice *dev) +static void pci_do_device_reset(PCIDevice *dev) { int r; - qdev_reset_all(&dev->qdev); - dev->irq_state = 0; pci_update_irq_status(dev); pci_device_deassert_intx(dev); @@ -209,30 +203,34 @@ void pci_device_reset(PCIDevice *dev) } /* + * This function is called on #RST and FLR. + * FLR if PCI_EXP_DEVCTL_BCR_FLR is set + */ +void pci_device_reset(PCIDevice *dev) +{ + qdev_reset_all(&dev->qdev); + pci_do_device_reset(dev); +} + +/* * Trigger pci bus reset under a given bus. - * To be called on RST# assert. + * Called via qbus_reset_all on RST# assert, after the devices + * have been reset qdev_reset_all-ed already. */ -void pci_bus_reset(PCIBus *bus) +static void pcibus_reset(BusState *qbus) { + PCIBus *bus = DO_UPCAST(PCIBus, qbus, qbus); int i; - for (i = 0; i < bus->nirq; i++) { - bus->irq_count[i] = 0; - } for (i = 0; i < ARRAY_SIZE(bus->devices); ++i) { if (bus->devices[i]) { - pci_device_reset(bus->devices[i]); + pci_do_device_reset(bus->devices[i]); } } -} - -static int pcibus_reset(BusState *qbus) -{ - pci_bus_reset(DO_UPCAST(PCIBus, qbus, qbus)); - /* topology traverse is done by pci_bus_reset(). - Tell qbus/qdev walker not to traverse the tree */ - return 1; + for (i = 0; i < bus->nirq; i++) { + assert(bus->irq_count[i] == 0); + } } static void pci_host_bus_register(PCIBus *bus, DeviceState *parent) diff --git a/hw/pci/pci_bridge.c b/hw/pci/pci_bridge.c index 355c3e1b06..4becdc14b8 100644 --- a/hw/pci/pci_bridge.c +++ b/hw/pci/pci_bridge.c @@ -268,7 +268,7 @@ void pci_bridge_write_config(PCIDevice *d, newctl = pci_get_word(d->config + PCI_BRIDGE_CONTROL); if (~oldctl & newctl & PCI_BRIDGE_CTL_BUS_RESET) { /* Trigger hot reset on 0->1 transition. */ - pci_bus_reset(&s->sec_bus); + qbus_reset_all(&s->sec_bus.qbus); } } diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index 4b6250dda9..bc8871249d 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -30,13 +30,10 @@ static void virtio_ccw_bus_new(VirtioBusState *bus, size_t bus_size, VirtioCcwDevice *dev); -static int virtual_css_bus_reset(BusState *qbus) +static void virtual_css_bus_reset(BusState *qbus) { /* This should actually be modelled via the generic css */ css_reset(); - - /* we dont traverse ourself, return 0 */ - return 0; } diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 144b9ca2ef..a001e668c4 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -1172,6 +1172,8 @@ static void virtio_device_unrealize(DeviceState *dev, Error **errp) VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(dev); Error *err = NULL; + virtio_bus_device_unplugged(vdev); + if (vdc->unrealize != NULL) { vdc->unrealize(dev, &err); if (err != NULL) { |