acpi,pci,pc,fedora,virtio fixes and enhancements

This includes some Preparatory patches for cpu hotplug for q25 and memory
 hotplug by Igor, tests and memory mapping change
 by Laszlo and pci reset cleanup by Paolo.
 There are also some fixes for fedora and virtio:
 included here since they are test blockers for me.
 
 Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.15 (GNU/Linux)
 
 iQEcBAABAgAGBQJSuF+2AAoJECgfDbjSjVRpTz0IAJhNCC8L2GVt+pm1RAt6lbqZ
 u9bCrqfThDORN2mUTEuLu4ZpZC0DYc7d0Jjr5NPesC5G/Afzi5/to6+l7nNZneU3
 OdBPglXCCfU/cRaLu7JG2akpha0GVU0tsSCoWIYa6mwlWA4/DXVMgeKg/bh/EgfM
 B1w4fE2RgRM9bEqWmX4+tZw8dgk7uVJhu95HCDnb5eikaKlFzwuOlvexrDV3KbPc
 bkJe35zbGrKOws93tiSeoqcDx2dcYSzecPoJ0jiCY0KXJ17PBWAvuLTtYqkwwe9J
 2FEnTslQJ3Rc8jTFiOPWx2pGaejG4y7Tnk6uuzW6fbbSLOQDPJy3KgmutJFMt1A=
 =ShCj
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'mst/tags/for_anthony' into staging

acpi,pci,pc,fedora,virtio fixes and enhancements

This includes some Preparatory patches for cpu hotplug for q25 and memory
hotplug by Igor, tests and memory mapping change
by Laszlo and pci reset cleanup by Paolo.
There are also some fixes for fedora and virtio:
included here since they are test blockers for me.

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>

# gpg: Signature made Mon 23 Dec 2013 08:07:18 AM PST using RSA key ID D28D5469
# gpg: Can't check signature: public key not found

* mst/tags/for_anthony:
  target-arm: fix build with gcc 4.8.2
  virtio: add back call to virtio_bus_device_unplugged
  piix: fix 32bit pci hole
  qdev: switch reset to post-order
  qdev: allow both pre- and post-order vists in qdev walking functions
  pci: clean up resetting of IRQs
  pci: do not export pci_bus_reset
  ACPI/DSDT-CPU: cleanup bogus comment
  ACPI: Q35 DSDT: fix CPU hotplug GPE0.2 handler
  acpi: ich9: allow guest to clear SCI rised by GPE
  acpi: factor out common pm_update_sci() into acpi core
  acpi: piix4: remove not needed GPE0 mask
  i440fx-test: verify firmware under 4G and 1M, both -bios and -pflash
  i440fx-test: generate temporary firmware blob
  i440fx-test: give each GTest case its own qtest
  i440fx-test: qtest_start() should be paired with qtest_end()
  hw/i386/pc_sysfw: support two flash drives
  pc_piix: document gigabyte_align
  piix: gigabyte alignment for ram

Message-id: 1387815007-1272-1-git-send-email-mst@redhat.com
Signed-off-by: Anthony Liguori <aliguori@amazon.com>
This commit is contained in:
Anthony Liguori 2014-01-10 11:04:48 -08:00
commit d1819762fc
18 changed files with 363 additions and 144 deletions

View File

@ -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));
}

View File

@ -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)

View File

@ -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;
}

View File

@ -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;
}

View File

@ -52,7 +52,6 @@ Scope(\_SB) {
Sleep(200)
}
/* CPU hotplug notify method */
OperationRegion(PRST, SystemIO, 0xaf00, 32)
Field(PRST, ByteAcc, NoLock, Preserve) {
PRS, 256

View File

@ -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)

View File

@ -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);
}

View File

@ -417,11 +417,11 @@ DefinitionBlock (
Method(_L00) {
}
Method(_L01) {
}
Method(_E02) {
// CPU hotplug event
\_SB.PRSC()
}
Method(_L02) {
}
Method(_L03) {
}
Method(_L04) {

View File

@ -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,

View File

@ -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)
}
/*
* Trigger pci bus reset under a given bus.
* To be called on RST# assert.
* This function is called on #RST and FLR.
* FLR if PCI_EXP_DEVCTL_BCR_FLR is set
*/
void pci_bus_reset(PCIBus *bus)
void pci_device_reset(PCIDevice *dev)
{
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]);
}
}
qdev_reset_all(&dev->qdev);
pci_do_device_reset(dev);
}
static int pcibus_reset(BusState *qbus)
/*
* Trigger pci bus reset under a given bus.
* Called via qbus_reset_all on RST# assert, after the devices
* have been reset qdev_reset_all-ed already.
*/
static void pcibus_reset(BusState *qbus)
{
pci_bus_reset(DO_UPCAST(PCIBus, qbus, qbus));
PCIBus *bus = DO_UPCAST(PCIBus, qbus, qbus);
int i;
/* topology traverse is done by pci_bus_reset().
Tell qbus/qdev walker not to traverse the tree */
return 1;
for (i = 0; i < ARRAY_SIZE(bus->devices); ++i) {
if (bus->devices[i]) {
pci_do_device_reset(bus->devices[i]);
}
}
for (i = 0; i < bus->nirq; i++) {
assert(bus->irq_count[i] == 0);
}
}
static void pci_host_bus_register(PCIBus *bus, DeviceState *parent)

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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) {

View File

@ -69,6 +69,12 @@
#define ACPI_BITMASK_RT_CLOCK_ENABLE 0x0400
#define ACPI_BITMASK_PCIEXP_WAKE_DISABLE 0x4000 /* ACPI 3.0 */
#define ACPI_BITMASK_PM1_COMMON_ENABLED ( \
ACPI_BITMASK_RT_CLOCK_ENABLE | \
ACPI_BITMASK_POWER_BUTTON_ENABLE | \
ACPI_BITMASK_GLOBAL_LOCK_ENABLE | \
ACPI_BITMASK_TIMER_ENABLE)
/* PM1x_CNT */
#define ACPI_BITMASK_SCI_ENABLE 0x0001
#define ACPI_BITMASK_BUS_MASTER_RLD 0x0002
@ -160,6 +166,8 @@ void acpi_gpe_reset(ACPIREGS *ar);
void acpi_gpe_ioport_writeb(ACPIREGS *ar, uint32_t addr, uint32_t val);
uint32_t acpi_gpe_ioport_readb(ACPIREGS *ar, uint32_t addr);
void acpi_update_sci(ACPIREGS *acpi_regs, qemu_irq irq);
/* acpi.c */
extern int acpi_enabled;
extern char unsigned *acpi_tables;

View File

@ -182,6 +182,7 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix_devfn,
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_memory,
MemoryRegion *ram_memory);

View File

@ -373,7 +373,6 @@ void pci_bus_fire_intx_routing_notifier(PCIBus *bus);
void pci_device_set_intx_routing_notifier(PCIDevice *dev,
PCIINTxRoutingNotifier notifier);
void pci_device_reset(PCIDevice *dev);
void pci_bus_reset(PCIBus *bus);
PCIDevice *pci_nic_init(NICInfo *nd, PCIBus *rootbus,
const char *default_model,

View File

@ -169,7 +169,7 @@ struct BusClass {
* bindings can be found at http://playground.sun.com/1275/bindings/.
*/
char *(*get_fw_dev_path)(DeviceState *dev);
int (*reset)(BusState *bus);
void (*reset)(BusState *bus);
/* maximum devices allowed on the bus, 0: no limit. */
int max_dev;
};
@ -264,10 +264,15 @@ BusState *qbus_create(const char *typename, DeviceState *parent, const char *nam
/* Returns > 0 if either devfn or busfn skip walk somewhere in cursion,
* < 0 if either devfn or busfn terminate walk somewhere in cursion,
* 0 otherwise. */
int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn,
qbus_walkerfn *busfn, void *opaque);
int qdev_walk_children(DeviceState *dev, 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);
int qdev_walk_children(DeviceState *dev,
qdev_walkerfn *pre_devfn, qbus_walkerfn *pre_busfn,
qdev_walkerfn *post_devfn, qbus_walkerfn *post_busfn,
void *opaque);
void qdev_reset_all(DeviceState *dev);
/**

View File

@ -2,9 +2,11 @@
* qtest I440FX test case
*
* Copyright IBM, Corp. 2012-2013
* Copyright Red Hat, Inc. 2013
*
* Authors:
* Anthony Liguori <aliguori@us.ibm.com>
* Laszlo Ersek <lersek@redhat.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
@ -18,6 +20,11 @@
#include <glib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/mman.h>
#include <stdlib.h>
#define BROKEN 1
@ -26,16 +33,32 @@
typedef struct TestData
{
int num_cpus;
QPCIBus *bus;
} TestData;
typedef struct FirmwareTestFixture {
/* decides whether we're testing -bios or -pflash */
bool is_bios;
} FirmwareTestFixture;
static QPCIBus *test_start_get_bus(const TestData *s)
{
char *cmdline;
cmdline = g_strdup_printf("-smp %d", s->num_cpus);
qtest_start(cmdline);
g_free(cmdline);
return qpci_init_pc();
}
static void test_i440fx_defaults(gconstpointer opaque)
{
const TestData *s = opaque;
QPCIBus *bus;
QPCIDevice *dev;
uint32_t value;
dev = qpci_device_find(s->bus, QPCI_DEVFN(0, 0));
bus = test_start_get_bus(s);
dev = qpci_device_find(bus, QPCI_DEVFN(0, 0));
g_assert(dev != NULL);
/* 3.2.2 */
@ -119,6 +142,8 @@ static void test_i440fx_defaults(gconstpointer opaque)
g_assert_cmpint(qpci_config_readb(dev, 0x91), ==, 0x00); /* ERRSTS */
/* 3.2.26 */
g_assert_cmpint(qpci_config_readb(dev, 0x93), ==, 0x00); /* TRC */
qtest_end();
}
#define PAM_RE 1
@ -177,6 +202,7 @@ static void write_area(uint32_t start, uint32_t end, uint8_t value)
static void test_i440fx_pam(gconstpointer opaque)
{
const TestData *s = opaque;
QPCIBus *bus;
QPCIDevice *dev;
int i;
static struct {
@ -199,7 +225,8 @@ static void test_i440fx_pam(gconstpointer opaque)
{ 0xEC000, 0xEFFFF }, /* BIOS Extension */
};
dev = qpci_device_find(s->bus, QPCI_DEVFN(0, 0));
bus = test_start_get_bus(s);
dev = qpci_device_find(bus, QPCI_DEVFN(0, 0));
g_assert(dev != NULL);
for (i = 0; i < ARRAY_SIZE(pam_area); i++) {
@ -252,34 +279,140 @@ static void test_i440fx_pam(gconstpointer opaque)
/* Verify the area is not our new mask */
g_assert(!verify_area(pam_area[i].start, pam_area[i].end, 0x82));
}
qtest_end();
}
#define BLOB_SIZE ((size_t)65536)
#define ISA_BIOS_MAXSZ ((size_t)(128 * 1024))
/* Create a blob file, and return its absolute pathname as a dynamically
* allocated string.
* The file is closed before the function returns.
* In case of error, NULL is returned. The function prints the error message.
*/
static char *create_blob_file(void)
{
int ret, fd;
char *pathname;
GError *error = NULL;
ret = -1;
fd = g_file_open_tmp("blob_XXXXXX", &pathname, &error);
if (fd == -1) {
fprintf(stderr, "unable to create blob file: %s\n", error->message);
g_error_free(error);
} else {
if (ftruncate(fd, BLOB_SIZE) == -1) {
fprintf(stderr, "ftruncate(\"%s\", %zu): %s\n", pathname,
BLOB_SIZE, strerror(errno));
} else {
void *buf;
buf = mmap(NULL, BLOB_SIZE, PROT_WRITE, MAP_SHARED, fd, 0);
if (buf == MAP_FAILED) {
fprintf(stderr, "mmap(\"%s\", %zu): %s\n", pathname, BLOB_SIZE,
strerror(errno));
} else {
size_t i;
for (i = 0; i < BLOB_SIZE; ++i) {
((uint8_t *)buf)[i] = i;
}
munmap(buf, BLOB_SIZE);
ret = 0;
}
}
close(fd);
if (ret == -1) {
unlink(pathname);
g_free(pathname);
}
}
return ret == -1 ? NULL : pathname;
}
static void test_i440fx_firmware(FirmwareTestFixture *fixture,
gconstpointer user_data)
{
char *fw_pathname, *cmdline;
uint8_t *buf;
size_t i, isa_bios_size;
fw_pathname = create_blob_file();
g_assert(fw_pathname != NULL);
/* Better hope the user didn't put metacharacters in TMPDIR and co. */
cmdline = g_strdup_printf("-S %s %s",
fixture->is_bios ? "-bios" : "-pflash",
fw_pathname);
g_test_message("qemu cmdline: %s", cmdline);
qtest_start(cmdline);
g_free(cmdline);
/* Qemu has loaded the firmware (because qtest_start() only returns after
* the QMP handshake completes). We must unlink the firmware blob right
* here, because any assertion firing below would leak it in the
* filesystem. This is also the reason why we recreate the blob every time
* this function is invoked.
*/
unlink(fw_pathname);
g_free(fw_pathname);
/* check below 4G */
buf = g_malloc0(BLOB_SIZE);
memread(0x100000000ULL - BLOB_SIZE, buf, BLOB_SIZE);
for (i = 0; i < BLOB_SIZE; ++i) {
g_assert_cmphex(buf[i], ==, (uint8_t)i);
}
/* check in ISA space too */
memset(buf, 0, BLOB_SIZE);
isa_bios_size = ISA_BIOS_MAXSZ < BLOB_SIZE ? ISA_BIOS_MAXSZ : BLOB_SIZE;
memread(0x100000 - isa_bios_size, buf, isa_bios_size);
for (i = 0; i < isa_bios_size; ++i) {
g_assert_cmphex(buf[i], ==,
(uint8_t)((BLOB_SIZE - isa_bios_size) + i));
}
g_free(buf);
qtest_end();
}
static void add_firmware_test(const char *testpath,
void (*setup_fixture)(FirmwareTestFixture *f,
gconstpointer test_data))
{
g_test_add(testpath, FirmwareTestFixture, NULL, setup_fixture,
test_i440fx_firmware, NULL);
}
static void request_bios(FirmwareTestFixture *fixture,
gconstpointer user_data)
{
fixture->is_bios = true;
}
static void request_pflash(FirmwareTestFixture *fixture,
gconstpointer user_data)
{
fixture->is_bios = false;
}
int main(int argc, char **argv)
{
QTestState *s;
TestData data;
char *cmdline;
int ret;
g_test_init(&argc, &argv, NULL);
data.num_cpus = 1;
cmdline = g_strdup_printf("-smp %d", data.num_cpus);
s = qtest_start(cmdline);
g_free(cmdline);
data.bus = qpci_init_pc();
g_test_add_data_func("/i440fx/defaults", &data, test_i440fx_defaults);
g_test_add_data_func("/i440fx/pam", &data, test_i440fx_pam);
add_firmware_test("/i440fx/firmware/bios", request_bios);
add_firmware_test("/i440fx/firmware/pflash", request_pflash);
ret = g_test_run();
if (s) {
qtest_quit(s);
}
return ret;
}