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>
This commit is contained in:
Gerd Hoffmann 2015-05-06 10:58:30 +02:00 committed by Paolo Bonzini
parent bafc90bdc5
commit 11e66a15a0
4 changed files with 29 additions and 1 deletions

View File

@ -94,7 +94,8 @@ static void ich9_smi_writel(void *opaque, hwaddr addr, uint64_t val,
ICH9LPCPMRegs *pm = opaque; ICH9LPCPMRegs *pm = opaque;
switch (addr) { switch (addr) {
case 0: case 0:
pm->smi_en = val; pm->smi_en &= ~pm->smi_en_wmask;
pm->smi_en |= (val & pm->smi_en_wmask);
break; break;
} }
} }
@ -198,6 +199,7 @@ static void pm_reset(void *opaque)
* support SMM mode. */ * support SMM mode. */
pm->smi_en |= ICH9_PMIO_SMI_EN_APMC_EN; pm->smi_en |= ICH9_PMIO_SMI_EN_APMC_EN;
} }
pm->smi_en_wmask = ~0;
acpi_update_sci(&pm->acpi_regs, pm->irq); acpi_update_sci(&pm->acpi_regs, pm->irq);
} }

View File

@ -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) static int ich9_lpc_post_load(void *opaque, int version_id)
{ {
ICH9LPCState *lpc = opaque; ICH9LPCState *lpc = opaque;
ich9_lpc_pmbase_update(lpc); ich9_lpc_pmbase_update(lpc);
ich9_lpc_rcba_update(lpc, 0 /* disabled ICH9_LPC_RBCA_EN */); ich9_lpc_rcba_update(lpc, 0 /* disabled ICH9_LPC_RBCA_EN */);
ich9_lpc_pmcon_update(lpc);
return 0; return 0;
} }
@ -435,6 +451,9 @@ static void ich9_lpc_config_write(PCIDevice *d,
if (ranges_overlap(addr, len, ICH9_LPC_PIRQE_ROUT, 4)) { if (ranges_overlap(addr, len, ICH9_LPC_PIRQE_ROUT, 4)) {
pci_bus_fire_intx_routing_notifier(lpc->d.bus); 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) static void ich9_lpc_reset(DeviceState *qdev)

View File

@ -39,6 +39,7 @@ typedef struct ICH9LPCPMRegs {
MemoryRegion io_smi; MemoryRegion io_smi;
uint32_t smi_en; uint32_t smi_en;
uint32_t smi_en_wmask;
uint32_t smi_sts; uint32_t smi_sts;
qemu_irq irq; /* SCI */ qemu_irq irq; /* SCI */

View File

@ -152,6 +152,12 @@ Object *ich9_lpc_find(void);
#define ICH9_LPC_PIRQ_ROUT_MASK Q35_MASK(8, 3, 0) #define ICH9_LPC_PIRQ_ROUT_MASK Q35_MASK(8, 3, 0)
#define ICH9_LPC_PIRQ_ROUT_DEFAULT 0x80 #define ICH9_LPC_PIRQ_ROUT_DEFAULT 0x80
#define ICH9_LPC_GEN_PMCON_1 0xa0
#define ICH9_LPC_GEN_PMCON_1_SMI_LOCK (1 << 4)
#define ICH9_LPC_GEN_PMCON_2 0xa2
#define ICH9_LPC_GEN_PMCON_3 0xa4
#define ICH9_LPC_GEN_PMCON_LOCK 0xa6
#define ICH9_LPC_RCBA 0xf0 #define ICH9_LPC_RCBA 0xf0
#define ICH9_LPC_RCBA_BA_MASK Q35_MASK(32, 31, 14) #define ICH9_LPC_RCBA_BA_MASK Q35_MASK(32, 31, 14)
#define ICH9_LPC_RCBA_EN 0x1 #define ICH9_LPC_RCBA_EN 0x1