aboutsummaryrefslogtreecommitdiff
path: root/hw/piix_pci.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/piix_pci.c')
-rw-r--r--hw/piix_pci.c76
1 files changed, 72 insertions, 4 deletions
diff --git a/hw/piix_pci.c b/hw/piix_pci.c
index ba1b3de..6c77e49 100644
--- a/hw/piix_pci.c
+++ b/hw/piix_pci.c
@@ -24,13 +24,14 @@
#include "hw.h"
#include "pc.h"
-#include "pci.h"
-#include "pci_host.h"
+#include "pci/pci.h"
+#include "pci/pci_host.h"
#include "isa.h"
#include "sysbus.h"
-#include "range.h"
+#include "qemu/range.h"
#include "xen.h"
#include "pam.h"
+#include "sysemu/sysemu.h"
/*
* I440FX chipset data sheet.
@@ -46,6 +47,12 @@ typedef struct I440FXState {
#define XEN_PIIX_NUM_PIRQS 128ULL
#define PIIX_PIRQC 0x60
+/*
+ * Reset Control Register: PCI-accessible ISA-Compatible Register at address
+ * 0xcf9, provided by the PCI/ISA bridge (PIIX3 PCI function 0, 8086:7000).
+ */
+#define RCR_IOPORT 0xcf9
+
typedef struct PIIX3State {
PCIDevice dev;
@@ -67,6 +74,12 @@ typedef struct PIIX3State {
/* This member isn't used. Just for save/load compatibility */
int32_t pci_irq_levels_vmstate[PIIX_NUM_PIRQS];
+
+ /* Reset Control Register contents */
+ uint8_t rcr;
+
+ /* IO memory region for Reset Control Register (RCR_IOPORT) */
+ MemoryRegion rcr_mem;
} PIIX3State;
struct PCII440FXState {
@@ -442,6 +455,7 @@ static void piix3_reset(void *opaque)
pci_conf[0xae] = 0x00;
d->pic_levels = 0;
+ d->rcr = 0;
}
static int piix3_post_load(void *opaque, int version_id)
@@ -462,6 +476,23 @@ static void piix3_pre_save(void *opaque)
}
}
+static bool piix3_rcr_needed(void *opaque)
+{
+ PIIX3State *piix3 = opaque;
+
+ return (piix3->rcr != 0);
+}
+
+static const VMStateDescription vmstate_piix3_rcr = {
+ .name = "PIIX3/rcr",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_UINT8(rcr, PIIX3State),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static const VMStateDescription vmstate_piix3 = {
.name = "PIIX3",
.version_id = 3,
@@ -469,12 +500,44 @@ static const VMStateDescription vmstate_piix3 = {
.minimum_version_id_old = 2,
.post_load = piix3_post_load,
.pre_save = piix3_pre_save,
- .fields = (VMStateField []) {
+ .fields = (VMStateField[]) {
VMSTATE_PCI_DEVICE(dev, PIIX3State),
VMSTATE_INT32_ARRAY_V(pci_irq_levels_vmstate, PIIX3State,
PIIX_NUM_PIRQS, 3),
VMSTATE_END_OF_LIST()
+ },
+ .subsections = (VMStateSubsection[]) {
+ {
+ .vmsd = &vmstate_piix3_rcr,
+ .needed = piix3_rcr_needed,
+ },
+ { 0 }
+ }
+};
+
+
+static void rcr_write(void *opaque, hwaddr addr, uint64_t val, unsigned len)
+{
+ PIIX3State *d = opaque;
+
+ if (val & 4) {
+ qemu_system_reset_request();
+ return;
}
+ d->rcr = val & 2; /* keep System Reset type only */
+}
+
+static uint64_t rcr_read(void *opaque, hwaddr addr, unsigned len)
+{
+ PIIX3State *d = opaque;
+
+ return d->rcr;
+}
+
+static const MemoryRegionOps rcr_ops = {
+ .read = rcr_read,
+ .write = rcr_write,
+ .endianness = DEVICE_LITTLE_ENDIAN
};
static int piix3_initfn(PCIDevice *dev)
@@ -482,6 +545,11 @@ static int piix3_initfn(PCIDevice *dev)
PIIX3State *d = DO_UPCAST(PIIX3State, dev, dev);
isa_bus_new(&d->dev.qdev, pci_address_space_io(dev));
+
+ memory_region_init_io(&d->rcr_mem, &rcr_ops, d, "piix3-reset-control", 1);
+ memory_region_add_subregion_overlap(pci_address_space_io(dev), RCR_IOPORT,
+ &d->rcr_mem, 1);
+
qemu_register_reset(piix3_reset, d);
return 0;
}