From: David Hildenbrand <david@redhat.com>
To: qemu-devel@nongnu.org
Cc: "Jason J . Herne" <jjherne@linux.ibm.com>,
Thomas Huth <thuth@redhat.com>,
Janosch Frank <frankja@linux.ibm.com>,
David Hildenbrand <david@redhat.com>,
Cornelia Huck <cohuck@redhat.com>,
Richard Henderson <richard.henderson@linaro.org>,
Halil Pasic <pasic@linux.ibm.com>,
Christian Borntraeger <borntraeger@de.ibm.com>,
qemu-s390x@nongnu.org, Claudio Imbrenda <imbrenda@linux.ibm.com>
Subject: [PATCH v1 12/12] hw/s390x/s390-skeys: lazy storage key enablement under TCG
Date: Thu, 5 Aug 2021 17:28:04 +0200 [thread overview]
Message-ID: <20210805152804.100333-13-david@redhat.com> (raw)
In-Reply-To: <20210805152804.100333-1-david@redhat.com>
Let's enable storage keys lazily under TCG, just as we do under KVM.
Only fairly old Linux versions actually make use of storage keys, so it
can be kind of wasteful to allocate quite some memory and track
changes and references if nobody cares.
We have to make sure to flush the TLB when enabling storage keys after
the VM was already running: otherwise it might happen that we don't
catch references or modifications afterwards.
Add proper documentation to all callbacks.
The kvm-unit-tests skey tests keeps on working with this change.
Signed-off-by: David Hildenbrand <david@redhat.com>
---
hw/s390x/s390-skeys.c | 51 +++++++++++++++++++++-----
include/hw/s390x/storage-keys.h | 63 +++++++++++++++++++++++++++++++++
target/s390x/mmu_helper.c | 8 +++++
target/s390x/tcg/mem_helper.c | 9 +++++
4 files changed, 123 insertions(+), 8 deletions(-)
diff --git a/hw/s390x/s390-skeys.c b/hw/s390x/s390-skeys.c
index 53e16f1b9c..579bdf1d8a 100644
--- a/hw/s390x/s390-skeys.c
+++ b/hw/s390x/s390-skeys.c
@@ -190,18 +190,45 @@ out:
fclose(f);
}
-static void qemu_s390_skeys_init(Object *obj)
+static int qemu_s390_skeys_enabled(S390SKeysState *ss)
{
- QEMUS390SKeysState *skeys = QEMU_S390_SKEYS(obj);
- MachineState *machine = MACHINE(qdev_get_machine());
+ QEMUS390SKeysState *skeys = QEMU_S390_SKEYS(ss);
- skeys->key_count = machine->ram_size / TARGET_PAGE_SIZE;
- skeys->keydata = g_malloc0(skeys->key_count);
+ /* Lockless check is sufficient. */
+ return !!skeys->keydata;
}
-static int qemu_s390_skeys_enabled(S390SKeysState *ss)
+static int qemu_s390_skeys_enable(S390SKeysState *ss)
{
- return 1;
+ QEMUS390SKeysState *skeys = QEMU_S390_SKEYS(ss);
+ static gsize initialized;
+
+ if (likely(skeys->keydata)) {
+ return 1;
+ }
+
+ /*
+ * TODO: Modern Linux doesn't use storage keys unless running KVM guests
+ * that use storage keys. Therefore, we keep it simple for now.
+ *
+ * 1) We should initialize to "referenced+changed" for an initial
+ * over-indication. Let's avoid touching megabytes of data for now and
+ * assume that any sane user will issue a storage key instruction before
+ * actually relying on this data.
+ * 2) Relying on ram_size and allocating a big array is ugly. We should
+ * allocate and manage storage key data per RAMBlock or optimally using
+ * some sparse data structure.
+ * 3) We only ever have a single S390SKeysState, so relying on
+ * g_once_init_enter() is good enough.
+ */
+ if (g_once_init_enter(&initialized)) {
+ MachineState *machine = MACHINE(qdev_get_machine());
+
+ skeys->key_count = machine->ram_size / TARGET_PAGE_SIZE;
+ skeys->keydata = g_malloc0(skeys->key_count);
+ g_once_init_leave(&initialized, 1);
+ }
+ return 0;
}
static int qemu_s390_skeys_set(S390SKeysState *ss, uint64_t start_gfn,
@@ -250,6 +277,7 @@ static void qemu_s390_skeys_class_init(ObjectClass *oc, void *data)
DeviceClass *dc = DEVICE_CLASS(oc);
skeyclass->skeys_enabled = qemu_s390_skeys_enabled;
+ skeyclass->skeys_enable = qemu_s390_skeys_enable;
skeyclass->get_skeys = qemu_s390_skeys_get;
skeyclass->set_skeys = qemu_s390_skeys_set;
@@ -260,7 +288,6 @@ static void qemu_s390_skeys_class_init(ObjectClass *oc, void *data)
static const TypeInfo qemu_s390_skeys_info = {
.name = TYPE_QEMU_S390_SKEYS,
.parent = TYPE_S390_SKEYS,
- .instance_init = qemu_s390_skeys_init,
.instance_size = sizeof(QEMUS390SKeysState),
.class_init = qemu_s390_skeys_class_init,
.class_size = sizeof(S390SKeysClass),
@@ -340,6 +367,14 @@ static int s390_storage_keys_load(QEMUFile *f, void *opaque, int version_id)
S390SKeysClass *skeyclass = S390_SKEYS_GET_CLASS(ss);
int ret = 0;
+ /*
+ * Make sure to lazy-enable if required to be done explicitly. No need to
+ * flush any TLB as the VM is not running yet.
+ */
+ if (skeyclass->skeys_enable) {
+ skeyclass->skeys_enable(ss);
+ }
+
while (!ret) {
ram_addr_t addr;
int flags;
diff --git a/include/hw/s390x/storage-keys.h b/include/hw/s390x/storage-keys.h
index 2888d42d0b..8b15809716 100644
--- a/include/hw/s390x/storage-keys.h
+++ b/include/hw/s390x/storage-keys.h
@@ -28,9 +28,72 @@ struct S390SKeysState {
struct S390SKeysClass {
DeviceClass parent_class;
+
+ /**
+ * @skeys_enabled:
+ *
+ * Check whether storage keys are enabled. If not enabled, they were not
+ * enabled lazily either by the guest via a storage key instruction or
+ * by the host during migration.
+ *
+ * If disabled, everything not explicitly triggered by the guest,
+ * such as outgoing migration or dirty/change tracking, should not touch
+ * storage keys and should not lazily enable it.
+ *
+ * @ks: the #S390SKeysState
+ *
+ * Returns 0 if not enabled and 1 if enabled.
+ */
int (*skeys_enabled)(S390SKeysState *ks);
+
+ /**
+ * @skeys_enable:
+ *
+ * Lazily enable storage keys. If this function is not implemented,
+ * setting a storage key will lazily enable storage keys implicitly
+ * instead. TCG guests have to make sure to flush the TLB of all CPUs
+ * if storage keys were not enabled before this call.
+ *
+ * @ks: the #S390SKeysState
+ *
+ * Returns 0 if storage keys were not enabled before this call and 1 if
+ * they were already enabled.
+ */
+ int (*skeys_enable)(S390SKeysState *ks);
+
+ /**
+ * @get_skeys:
+ *
+ * Get storage keys for the given PFN range. This call will fail if
+ * storage keys have not been lazily enabled yet.
+ *
+ * Callers have to validate that a GFN is valid before this call.
+ *
+ * @ks: the #S390SKeysState
+ * @start_gfn: the start GFN to get storage keys for
+ * @count: the number of storage keys to get
+ * @keys: the byte array where storage keys will be stored to
+ *
+ * Returns 0 on success, returns an error if getting a storage key failed.
+ */
int (*get_skeys)(S390SKeysState *ks, uint64_t start_gfn, uint64_t count,
uint8_t *keys);
+ /**
+ * @set_skeys:
+ *
+ * Set storage keys for the given PFN range. This call will fail if
+ * storage keys have not been lazily enabled yet and implicit
+ * enablement is not supported.
+ *
+ * Callers have to validate that a GFN is valid before this call.
+ *
+ * @ks: the #S390SKeysState
+ * @start_gfn: the start GFN to set storage keys for
+ * @count: the number of storage keys to set
+ * @keys: the byte array where storage keys will be read from
+ *
+ * Returns 0 on success, returns an error if setting a storage key failed.
+ */
int (*set_skeys)(S390SKeysState *ks, uint64_t start_gfn, uint64_t count,
uint8_t *keys);
};
diff --git a/target/s390x/mmu_helper.c b/target/s390x/mmu_helper.c
index 0c2c39a970..41bb256ea8 100644
--- a/target/s390x/mmu_helper.c
+++ b/target/s390x/mmu_helper.c
@@ -313,6 +313,14 @@ static void mmu_handle_skey(target_ulong addr, int rw, int *flags)
skeyclass = S390_SKEYS_GET_CLASS(ss);
}
+ /*
+ * Don't enable storage keys if they are still disabled, i.e., no actual
+ * storage key instruction was issued yet.
+ */
+ if (!skeyclass->skeys_enabled(ss)) {
+ return;
+ }
+
/*
* Whenever we create a new TLB entry, we set the storage key reference
* bit. In case we allow write accesses, we set the storage key change
diff --git a/target/s390x/tcg/mem_helper.c b/target/s390x/tcg/mem_helper.c
index 9c1b9c7d06..0b318c6178 100644
--- a/target/s390x/tcg/mem_helper.c
+++ b/target/s390x/tcg/mem_helper.c
@@ -2186,6 +2186,9 @@ uint64_t HELPER(iske)(CPUS390XState *env, uint64_t r2)
if (unlikely(!ss)) {
ss = s390_get_skeys_device();
skeyclass = S390_SKEYS_GET_CLASS(ss);
+ if (skeyclass->skeys_enable && !skeyclass->skeys_enable(ss)) {
+ tlb_flush_all_cpus_synced(env_cpu(env));
+ }
}
rc = skeyclass->get_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key);
@@ -2213,6 +2216,9 @@ void HELPER(sske)(CPUS390XState *env, uint64_t r1, uint64_t r2)
if (unlikely(!ss)) {
ss = s390_get_skeys_device();
skeyclass = S390_SKEYS_GET_CLASS(ss);
+ if (skeyclass->skeys_enable && !skeyclass->skeys_enable(ss)) {
+ tlb_flush_all_cpus_synced(env_cpu(env));
+ }
}
key = r1 & 0xfe;
@@ -2245,6 +2251,9 @@ uint32_t HELPER(rrbe)(CPUS390XState *env, uint64_t r2)
if (unlikely(!ss)) {
ss = s390_get_skeys_device();
skeyclass = S390_SKEYS_GET_CLASS(ss);
+ if (skeyclass->skeys_enable && !skeyclass->skeys_enable(ss)) {
+ tlb_flush_all_cpus_synced(env_cpu(env));
+ }
}
rc = skeyclass->get_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key);
--
2.31.1
next prev parent reply other threads:[~2021-08-05 15:38 UTC|newest]
Thread overview: 46+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-08-05 15:27 [PATCH v1 00/12] s390x: skey related fixes, cleanups, and memory device preparations David Hildenbrand
2021-08-05 15:27 ` [PATCH v1 01/12] s390x/tcg: wrap address for RRBE David Hildenbrand
2021-08-06 5:39 ` Thomas Huth
2021-08-05 15:27 ` [PATCH v1 02/12] s390x/tcg: fix ignoring bit 63 when setting the storage key in SSKE David Hildenbrand
2021-08-06 6:19 ` Thomas Huth
2021-08-06 6:25 ` Thomas Huth
2021-08-06 6:31 ` David Hildenbrand
2021-08-05 15:27 ` [PATCH v1 03/12] s390x/tcg: convert real to absolute address for RRBE, SSKE and ISKE David Hildenbrand
2021-08-06 6:50 ` Thomas Huth
2021-08-06 6:52 ` David Hildenbrand
2021-08-06 7:11 ` Thomas Huth
2021-08-06 7:17 ` David Hildenbrand
2021-08-06 11:25 ` Cornelia Huck
2021-08-06 11:32 ` David Hildenbrand
2021-08-05 15:27 ` [PATCH v1 04/12] s390x/tcg: check for addressing exceptions for " David Hildenbrand
2021-08-05 17:33 ` David Hildenbrand
2021-08-05 15:27 ` [PATCH v1 05/12] s390x/mmu_helper: no need to pass access type to mmu_translate_asce() David Hildenbrand
2021-08-06 7:30 ` Thomas Huth
2021-08-06 7:34 ` David Hildenbrand
2021-08-06 7:36 ` Thomas Huth
2021-08-06 7:36 ` David Hildenbrand
2021-08-05 15:27 ` [PATCH v1 06/12] s390x/mmu_helper: fixup mmu_translate() documentation David Hildenbrand
2021-08-06 7:32 ` Thomas Huth
2021-08-05 15:27 ` [PATCH v1 07/12] s390x/mmu_helper: move address validation into mmu_translate*() David Hildenbrand
2021-08-06 8:18 ` Thomas Huth
2021-08-06 8:20 ` David Hildenbrand
2021-08-06 8:22 ` Thomas Huth
2021-08-06 8:23 ` David Hildenbrand
2021-08-06 8:24 ` Thomas Huth
2021-08-06 8:20 ` Thomas Huth
2021-08-05 15:28 ` [PATCH v1 08/12] s390x/mmu_helper: avoid setting the storage key if nothing changed David Hildenbrand
2021-08-06 8:24 ` Thomas Huth
2021-08-05 15:28 ` [PATCH v1 09/12] hw/s390x/s390-skeys: use memory mapping to detect which storage keys to migrate David Hildenbrand
2021-08-06 8:47 ` Thomas Huth
2021-08-05 15:28 ` [PATCH v1 10/12] hw/s390x/s390-skeys: use memory mapping to detect which storage keys to dump David Hildenbrand
2021-08-06 8:51 ` Thomas Huth
2021-08-05 15:28 ` [PATCH v1 11/12] hw/s390x/s390-skeys: check if an address is valid before dumping the key David Hildenbrand
2021-08-06 8:53 ` Thomas Huth
2021-08-06 8:54 ` David Hildenbrand
2021-08-05 15:28 ` David Hildenbrand [this message]
2021-08-06 9:42 ` [PATCH v1 12/12] hw/s390x/s390-skeys: lazy storage key enablement under TCG Thomas Huth
2021-08-06 13:18 ` David Hildenbrand
2021-08-06 13:52 ` Thomas Huth
2021-08-11 8:43 ` David Hildenbrand
2021-08-06 14:13 ` Cornelia Huck
2021-08-06 14:17 ` Thomas Huth
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20210805152804.100333-13-david@redhat.com \
--to=david@redhat.com \
--cc=borntraeger@de.ibm.com \
--cc=cohuck@redhat.com \
--cc=frankja@linux.ibm.com \
--cc=imbrenda@linux.ibm.com \
--cc=jjherne@linux.ibm.com \
--cc=pasic@linux.ibm.com \
--cc=qemu-devel@nongnu.org \
--cc=qemu-s390x@nongnu.org \
--cc=richard.henderson@linaro.org \
--cc=thuth@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).