diff options
author | Gerd Hoffmann | 2015-05-06 10:58:30 +0200 |
---|---|---|
committer | Paolo Bonzini | 2015-06-05 19:45:13 +0200 |
commit | 11e66a15a084cb0820dba13f4ea3b15b0512fd39 (patch) | |
tree | 8735fe3061fe96f8e5c6fc36a12162e783051e76 /hw/isa | |
parent | q35: implement TSEG (diff) | |
download | qemu-11e66a15a084cb0820dba13f4ea3b15b0512fd39.tar.gz qemu-11e66a15a084cb0820dba13f4ea3b15b0512fd39.tar.xz qemu-11e66a15a084cb0820dba13f4ea3b15b0512fd39.zip |
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/isa')
-rw-r--r-- | hw/isa/lpc_ich9.c | 19 |
1 files changed, 19 insertions, 0 deletions
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) |