aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorGerd Hoffmann <kraxel@redhat.com>2015-05-06 10:58:30 +0200
committerPaolo Bonzini <pbonzini@redhat.com>2015-06-05 19:45:13 +0200
commit11e66a15a084cb0820dba13f4ea3b15b0512fd39 (patch)
tree8735fe3061fe96f8e5c6fc36a12162e783051e76 /hw
parentbafc90bdc594a4d04db846bd8712bdcec59678a8 (diff)
ich9: implement SMI_LOCK
Add write mask for the smi enable register, so we can disable write access to certain bits. Open all bits on reset. Disable write access to GBL_SMI_EN when SMI_LOCK (in ich9 lpc pci config space) is set. Write access to SMI_LOCK itself is disabled too. Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> Acked-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'hw')
-rw-r--r--hw/acpi/ich9.c4
-rw-r--r--hw/isa/lpc_ich9.c19
2 files changed, 22 insertions, 1 deletions
diff --git a/hw/acpi/ich9.c b/hw/acpi/ich9.c
index 799351ea44..25bc023882 100644
--- a/hw/acpi/ich9.c
+++ b/hw/acpi/ich9.c
@@ -94,7 +94,8 @@ static void ich9_smi_writel(void *opaque, hwaddr addr, uint64_t val,
ICH9LPCPMRegs *pm = opaque;
switch (addr) {
case 0:
- pm->smi_en = val;
+ pm->smi_en &= ~pm->smi_en_wmask;
+ pm->smi_en |= (val & pm->smi_en_wmask);
break;
}
}
@@ -198,6 +199,7 @@ static void pm_reset(void *opaque)
* support SMM mode. */
pm->smi_en |= ICH9_PMIO_SMI_EN_APMC_EN;
}
+ pm->smi_en_wmask = ~0;
acpi_update_sci(&pm->acpi_regs, pm->irq);
}
diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c
index 18718d772e..71a9f7a716 100644
--- a/hw/isa/lpc_ich9.c
+++ b/hw/isa/lpc_ich9.c
@@ -407,12 +407,28 @@ static void ich9_lpc_rcba_update(ICH9LPCState *lpc, uint32_t rbca_old)
}
}
+/* config:GEN_PMCON* */
+static void
+ich9_lpc_pmcon_update(ICH9LPCState *lpc)
+{
+ uint16_t gen_pmcon_1 = pci_get_word(lpc->d.config + ICH9_LPC_GEN_PMCON_1);
+ uint16_t wmask;
+
+ if (gen_pmcon_1 & ICH9_LPC_GEN_PMCON_1_SMI_LOCK) {
+ wmask = pci_get_word(lpc->d.wmask + ICH9_LPC_GEN_PMCON_1);
+ wmask &= ~ICH9_LPC_GEN_PMCON_1_SMI_LOCK;
+ pci_set_word(lpc->d.wmask + ICH9_LPC_GEN_PMCON_1, wmask);
+ lpc->pm.smi_en_wmask &= ~1;
+ }
+}
+
static int ich9_lpc_post_load(void *opaque, int version_id)
{
ICH9LPCState *lpc = opaque;
ich9_lpc_pmbase_update(lpc);
ich9_lpc_rcba_update(lpc, 0 /* disabled ICH9_LPC_RBCA_EN */);
+ ich9_lpc_pmcon_update(lpc);
return 0;
}
@@ -435,6 +451,9 @@ static void ich9_lpc_config_write(PCIDevice *d,
if (ranges_overlap(addr, len, ICH9_LPC_PIRQE_ROUT, 4)) {
pci_bus_fire_intx_routing_notifier(lpc->d.bus);
}
+ if (ranges_overlap(addr, len, ICH9_LPC_GEN_PMCON_1, 8)) {
+ ich9_lpc_pmcon_update(lpc);
+ }
}
static void ich9_lpc_reset(DeviceState *qdev)