On Mon, 2013-02-18 at 17:37 -0500, Kevin O'Connor wrote:
On Mon, Feb 18, 2013 at 09:12:46PM +0000, David Woodhouse wrote:
The i440fx data sheet (§3.0) appears to say that the default values are loaded on a *hard* reset, not a soft reset. And a reset invoked by the keyboard controller (as SeaBIOS does) is a *soft* reset. The only way to do a *hard* reset from software that's mentioned in the datasheet is the PMC turbo/reset control register (port 0x93). And that, presumably, is chipset-dependent and not something we can easily use from the reset vector without doing a bunch of hardware probing.
The ACPI v2 spec describes a "hard" reset register. SeaBIOS could extract it from the FADT and then use it. Of course, we'd probably want to update the QEMU ACPI tables to implement ACPI v2 then.
Yeah, that makes me somewhat happier about the SeaBIOS side of it being hardware-specific. That way the code at the reset vector only has to cope with a single 8-bit write to memory, IO or config space.
Laszlo has hooked up the RCR on the PIIX3 already, so something like this ought to make it reset the PAM setup *only* if reset via that...
diff --git a/hw/piix_pci.c b/hw/piix_pci.c index 6c77e49..f4420bd 100644 --- a/hw/piix_pci.c +++ b/hw/piix_pci.c @@ -77,6 +77,7 @@ typedef struct PIIX3State {
/* Reset Control Register contents */ uint8_t rcr; + uint8_t rcr_hard_reset;
/* IO memory region for Reset Control Register (RCR_IOPORT) */ MemoryRegion rcr_mem; @@ -84,6 +85,7 @@ typedef struct PIIX3State {
struct PCII440FXState { PCIDevice dev; + PIIX3State *piix3; MemoryRegion *system_memory; MemoryRegion *pci_address_space; MemoryRegion *ram_memory; @@ -171,6 +173,29 @@ static int i440fx_load_old(QEMUFile* f, void *opaque, int version_id) return 0; }
+static void i440fx_reset(DeviceState *ds) +{ + PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, ds); + PCII440FXState *d = DO_UPCAST(PCII440FXState, dev, dev); + uint8_t *pci_conf = d->dev.config; + + if (!d->piix3->rcr_hard_reset) + return; + + pci_conf[0x59] = 0x00; // Reset PAM setup + pci_conf[0x5a] = 0x00; + pci_conf[0x5b] = 0x00; + pci_conf[0x5c] = 0x00; + pci_conf[0x5d] = 0x00; + pci_conf[0x5e] = 0x00; + pci_conf[0x5f] = 0x00; + pci_conf[0x72] = 0x02; // And SMM + + i440fx_update_memory_mappings(d); + + d->piix3->rcr_hard_reset = 0; +} + static int i440fx_post_load(void *opaque, int version_id) { PCII440FXState *d = opaque; @@ -297,6 +322,7 @@ static PCIBus *i440fx_common_init(const char *device_name, pci_bus_set_route_irq_fn(b, piix3_route_intx_pin_to_irq); } piix3->pic = pic; + f->piix3 = piix3; *isa_bus = DO_UPCAST(ISABus, qbus, qdev_get_child_bus(&piix3->dev.qdev, "isa.0"));
@@ -521,6 +547,8 @@ static void rcr_write(void *opaque, hwaddr addr, uint64_t val, unsigned len) PIIX3State *d = opaque;
if (val & 4) { + if (val & 2) + d->rcr_hard_reset = 1; qemu_system_reset_request(); return; } @@ -615,6 +643,7 @@ static void i440fx_class_init(ObjectClass *klass, void *data) dc->desc = "Host bridge"; dc->no_user = 1; dc->vmsd = &vmstate_i440fx; + dc->reset = i440fx_reset; }
static const TypeInfo i440fx_info = {