[PATCH] q35: lpc: allow to lock down 128K RAM at default SMBASE address


Igor Mammedov <imammedo@...>
 

lpc already has SMI negotiation feature, extend it by adding
optin ICH9_LPC_SMI_F_LOCKED_SMBASE_BIT to supported features.

Writing this bit into "etc/smi/requested-features" fw_cfg file,
tells QEMU to alias 0x30000,128K RAM range into SMRAM address
space and mask this region from normal RAM address space
(reads return 0xff and writes are ignored, i.e. guest code
should be able to deal with not usable 0x30000,128K RAM range
once ICH9_LPC_SMI_F_LOCKED_SMBASE_BIT is activated).

To make negotiated change effective, guest should read
"etc/smi/features-ok" fw_cfg file, which activates negotiated
features and locks down negotiating capabilities until hard reset.

Flow for initializing SMI handler on guest side:
1. set SMI handler entry point at default SMBASE location
2. check that host supports ICH9_LPC_SMI_F_LOCKED_SMBASE_BIT
in "etc/smi/supported-features" and set if supported set
it in "etc/smi/requested-features"
3. read "etc/smi/features-ok", if returned value is 1
negotiated at step 2 features are activated successfully.

Signed-off-by: Igor Mammedov <imammedo@redhat.com>
---
include/hw/i386/ich9.h | 11 ++++++--
hw/i386/pc.c | 4 ++-
hw/i386/pc_q35.c | 3 ++-
hw/isa/lpc_ich9.c | 58 +++++++++++++++++++++++++++++++++++++++++-
4 files changed, 71 insertions(+), 5 deletions(-)

diff --git a/include/hw/i386/ich9.h b/include/hw/i386/ich9.h
index 72e803f6e2..c28685b753 100644
--- a/include/hw/i386/ich9.h
+++ b/include/hw/i386/ich9.h
@@ -12,11 +12,14 @@
#include "hw/acpi/acpi.h"
#include "hw/acpi/ich9.h"
#include "hw/pci/pci_bus.h"
+#include "qemu/units.h"

void ich9_lpc_set_irq(void *opaque, int irq_num, int level);
int ich9_lpc_map_irq(PCIDevice *pci_dev, int intx);
PCIINTxRoute ich9_route_intx_pin_to_irq(void *opaque, int pirq_pin);
-void ich9_lpc_pm_init(PCIDevice *pci_lpc, bool smm_enabled);
+void ich9_lpc_pm_init(PCIDevice *pci_lpc, bool smm_enabled,
+ MemoryRegion *system_memory, MemoryRegion *ram,
+ MemoryRegion *smram);
I2CBus *ich9_smb_init(PCIBus *bus, int devfn, uint32_t smb_io_base);

void ich9_generate_smi(void);
@@ -71,6 +74,8 @@ typedef struct ICH9LPCState {
uint8_t smi_features_ok; /* guest-visible, read-only; selecting it
* triggers feature lockdown */
uint64_t smi_negotiated_features; /* guest-invisible, host endian */
+ MemoryRegion smbase_blackhole;
+ MemoryRegion smbase_window;

/* isa bus */
ISABus *isa_bus;
@@ -248,5 +253,7 @@ typedef struct ICH9LPCState {

/* bit positions used in fw_cfg SMI feature negotiation */
#define ICH9_LPC_SMI_F_BROADCAST_BIT 0
-
+#define ICH9_LPC_SMI_F_LOCKED_SMBASE_BIT 1
+#define ICH9_LPC_SMBASE_ADDR 0x30000
+#define ICH9_LPC_SMBASE_RAM_SIZE (128 * KiB)
#endif /* HW_ICH9_H */
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index c14ed86439..99a98303eb 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -119,7 +119,9 @@ struct hpet_fw_config hpet_cfg = {.count = UINT8_MAX};
/* Physical Address of PVH entry point read from kernel ELF NOTE */
static size_t pvh_start_addr;

-GlobalProperty pc_compat_4_1[] = {};
+GlobalProperty pc_compat_4_1[] = {
+ { "ICH9-LPC", "x-smi-locked-smbase", "off" },
+};
const size_t pc_compat_4_1_len = G_N_ELEMENTS(pc_compat_4_1);

GlobalProperty pc_compat_4_0[] = {};
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index d4e8a1cb9f..50462686a0 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -292,7 +292,8 @@ static void pc_q35_init(MachineState *machine)
0xff0104);

/* connect pm stuff to lpc */
- ich9_lpc_pm_init(lpc, pc_machine_is_smm_enabled(pcms));
+ ich9_lpc_pm_init(lpc, pc_machine_is_smm_enabled(pcms), get_system_memory(),
+ ram_memory, MEMORY_REGION(object_resolve_path("/machine/smram", NULL)));

if (pcms->sata_enabled) {
/* ahci and SATA device, for q35 1 ahci controller is built-in */
diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c
index 17c292e306..17a8cd1b51 100644
--- a/hw/isa/lpc_ich9.c
+++ b/hw/isa/lpc_ich9.c
@@ -359,6 +359,38 @@ static void ich9_set_sci(void *opaque, int irq_num, int level)
}
}

+static uint64_t smbase_blackhole_read(void *ptr, hwaddr reg, unsigned size)
+{
+ return 0xffffffff;
+}
+
+static void smbase_blackhole_write(void *opaque, hwaddr addr, uint64_t val,
+ unsigned width)
+{
+ /* nothing */
+}
+
+static const MemoryRegionOps smbase_blackhole_ops = {
+ .read = smbase_blackhole_read,
+ .write = smbase_blackhole_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .valid.min_access_size = 1,
+ .valid.max_access_size = 4,
+ .impl.min_access_size = 4,
+ .impl.max_access_size = 4,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void ich9_lpc_smbase_locked_update(ICH9LPCState *lpc)
+{
+ bool en = lpc->smi_negotiated_features & ICH9_LPC_SMI_F_LOCKED_SMBASE_BIT;
+
+ memory_region_transaction_begin();
+ memory_region_set_enabled(&lpc->smbase_blackhole, en);
+ memory_region_set_enabled(&lpc->smbase_window, en);
+ memory_region_transaction_commit();
+}
+
static void smi_features_ok_callback(void *opaque)
{
ICH9LPCState *lpc = opaque;
@@ -379,9 +411,13 @@ static void smi_features_ok_callback(void *opaque)
/* valid feature subset requested, lock it down, report success */
lpc->smi_negotiated_features = guest_features;
lpc->smi_features_ok = 1;
+
+ ich9_lpc_smbase_locked_update(lpc);
}

-void ich9_lpc_pm_init(PCIDevice *lpc_pci, bool smm_enabled)
+void ich9_lpc_pm_init(PCIDevice *lpc_pci, bool smm_enabled,
+ MemoryRegion *system_memory, MemoryRegion *ram,
+ MemoryRegion *smram)
{
ICH9LPCState *lpc = ICH9_LPC_DEVICE(lpc_pci);
qemu_irq sci_irq;
@@ -413,6 +449,20 @@ void ich9_lpc_pm_init(PCIDevice *lpc_pci, bool smm_enabled)
&lpc->smi_features_ok,
sizeof lpc->smi_features_ok,
true);
+
+ memory_region_init_io(&lpc->smbase_blackhole, OBJECT(lpc),
+ &smbase_blackhole_ops, NULL,
+ "smbase-blackhole", ICH9_LPC_SMBASE_RAM_SIZE);
+ memory_region_set_enabled(&lpc->smbase_blackhole, false);
+ memory_region_add_subregion_overlap(system_memory, ICH9_LPC_SMBASE_ADDR,
+ &lpc->smbase_blackhole, 1);
+
+
+ memory_region_init_alias(&lpc->smbase_window, OBJECT(lpc),
+ "smbase-window", ram,
+ ICH9_LPC_SMBASE_ADDR, ICH9_LPC_SMBASE_RAM_SIZE);
+ memory_region_set_enabled(&lpc->smbase_window, false);
+ memory_region_add_subregion(smram, 0x30000, &lpc->smbase_window);
}

ich9_lpc_reset(DEVICE(lpc));
@@ -508,6 +558,7 @@ static int ich9_lpc_post_load(void *opaque, int version_id)
ich9_lpc_pmbase_sci_update(lpc);
ich9_lpc_rcba_update(lpc, 0 /* disabled ICH9_LPC_RCBA_EN */);
ich9_lpc_pmcon_update(lpc);
+ ich9_lpc_smbase_locked_update(lpc);
return 0;
}

@@ -567,6 +618,8 @@ static void ich9_lpc_reset(DeviceState *qdev)
memset(lpc->smi_guest_features_le, 0, sizeof lpc->smi_guest_features_le);
lpc->smi_features_ok = 0;
lpc->smi_negotiated_features = 0;
+
+ ich9_lpc_smbase_locked_update(lpc);
}

/* root complex register block is mapped into memory space */
@@ -697,6 +750,7 @@ static void ich9_lpc_realize(PCIDevice *d, Error **errp)
qdev_init_gpio_out_named(dev, lpc->gsi, ICH9_GPIO_GSI, GSI_NUM_PINS);

isa_bus_irqs(isa_bus, lpc->gsi);
+
}

static bool ich9_rst_cnt_needed(void *opaque)
@@ -764,6 +818,8 @@ static Property ich9_lpc_properties[] = {
DEFINE_PROP_BOOL("noreboot", ICH9LPCState, pin_strap.spkr_hi, true),
DEFINE_PROP_BIT64("x-smi-broadcast", ICH9LPCState, smi_host_features,
ICH9_LPC_SMI_F_BROADCAST_BIT, true),
+ DEFINE_PROP_BIT64("x-smi-locked-smbase", ICH9LPCState, smi_host_features,
+ ICH9_LPC_SMI_F_LOCKED_SMBASE_BIT, true),
DEFINE_PROP_END_OF_LIST(),
};

--
2.18.1

Join rfc@edk2.groups.io to automatically receive all group messages.