@@ -191,18 +191,45 @@ void qmp_dump_skeys(const char *filename, Error **errp)
191
191
fclose (f );
192
192
}
193
193
194
- static void qemu_s390_skeys_init ( Object * obj )
194
+ static bool qemu_s390_skeys_are_enabled ( S390SKeysState * ss )
195
195
{
196
- QEMUS390SKeysState * skeys = QEMU_S390_SKEYS (obj );
197
- MachineState * machine = MACHINE (qdev_get_machine ());
196
+ QEMUS390SKeysState * skeys = QEMU_S390_SKEYS (ss );
198
197
199
- skeys -> key_count = machine -> ram_size / TARGET_PAGE_SIZE ;
200
- skeys -> keydata = g_malloc0 ( skeys -> key_count ) ;
198
+ /* Lockless check is sufficient. */
199
+ return !! skeys -> keydata ;
201
200
}
202
201
203
- static bool qemu_s390_skeys_are_enabled (S390SKeysState * ss )
202
+ static bool qemu_s390_enable_skeys (S390SKeysState * ss )
204
203
{
205
- return true;
204
+ QEMUS390SKeysState * skeys = QEMU_S390_SKEYS (ss );
205
+ static gsize initialized ;
206
+
207
+ if (likely (skeys -> keydata )) {
208
+ return true;
209
+ }
210
+
211
+ /*
212
+ * TODO: Modern Linux doesn't use storage keys unless running KVM guests
213
+ * that use storage keys. Therefore, we keep it simple for now.
214
+ *
215
+ * 1) We should initialize to "referenced+changed" for an initial
216
+ * over-indication. Let's avoid touching megabytes of data for now and
217
+ * assume that any sane user will issue a storage key instruction before
218
+ * actually relying on this data.
219
+ * 2) Relying on ram_size and allocating a big array is ugly. We should
220
+ * allocate and manage storage key data per RAMBlock or optimally using
221
+ * some sparse data structure.
222
+ * 3) We only ever have a single S390SKeysState, so relying on
223
+ * g_once_init_enter() is good enough.
224
+ */
225
+ if (g_once_init_enter (& initialized )) {
226
+ MachineState * machine = MACHINE (qdev_get_machine ());
227
+
228
+ skeys -> key_count = machine -> ram_size / TARGET_PAGE_SIZE ;
229
+ skeys -> keydata = g_malloc0 (skeys -> key_count );
230
+ g_once_init_leave (& initialized , 1 );
231
+ }
232
+ return false;
206
233
}
207
234
208
235
static int qemu_s390_skeys_set (S390SKeysState * ss , uint64_t start_gfn ,
@@ -212,9 +239,10 @@ static int qemu_s390_skeys_set(S390SKeysState *ss, uint64_t start_gfn,
212
239
int i ;
213
240
214
241
/* Check for uint64 overflow and access beyond end of key data */
215
- if (start_gfn + count > skeydev -> key_count || start_gfn + count < count ) {
216
- error_report ("Error: Setting storage keys for page beyond the end "
217
- "of memory: gfn=%" PRIx64 " count=%" PRId64 ,
242
+ if (unlikely (!skeydev -> keydata || start_gfn + count > skeydev -> key_count ||
243
+ start_gfn + count < count )) {
244
+ error_report ("Error: Setting storage keys for pages with unallocated "
245
+ "storage key memory: gfn=%" PRIx64 " count=%" PRId64 ,
218
246
start_gfn , count );
219
247
return - EINVAL ;
220
248
}
@@ -232,9 +260,10 @@ static int qemu_s390_skeys_get(S390SKeysState *ss, uint64_t start_gfn,
232
260
int i ;
233
261
234
262
/* Check for uint64 overflow and access beyond end of key data */
235
- if (start_gfn + count > skeydev -> key_count || start_gfn + count < count ) {
236
- error_report ("Error: Getting storage keys for page beyond the end "
237
- "of memory: gfn=%" PRIx64 " count=%" PRId64 ,
263
+ if (unlikely (!skeydev -> keydata || start_gfn + count > skeydev -> key_count ||
264
+ start_gfn + count < count )) {
265
+ error_report ("Error: Getting storage keys for pages with unallocated "
266
+ "storage key memory: gfn=%" PRIx64 " count=%" PRId64 ,
238
267
start_gfn , count );
239
268
return - EINVAL ;
240
269
}
@@ -251,6 +280,7 @@ static void qemu_s390_skeys_class_init(ObjectClass *oc, void *data)
251
280
DeviceClass * dc = DEVICE_CLASS (oc );
252
281
253
282
skeyclass -> skeys_are_enabled = qemu_s390_skeys_are_enabled ;
283
+ skeyclass -> enable_skeys = qemu_s390_enable_skeys ;
254
284
skeyclass -> get_skeys = qemu_s390_skeys_get ;
255
285
skeyclass -> set_skeys = qemu_s390_skeys_set ;
256
286
@@ -261,7 +291,6 @@ static void qemu_s390_skeys_class_init(ObjectClass *oc, void *data)
261
291
static const TypeInfo qemu_s390_skeys_info = {
262
292
.name = TYPE_QEMU_S390_SKEYS ,
263
293
.parent = TYPE_S390_SKEYS ,
264
- .instance_init = qemu_s390_skeys_init ,
265
294
.instance_size = sizeof (QEMUS390SKeysState ),
266
295
.class_init = qemu_s390_skeys_class_init ,
267
296
.class_size = sizeof (S390SKeysClass ),
@@ -341,6 +370,14 @@ static int s390_storage_keys_load(QEMUFile *f, void *opaque, int version_id)
341
370
S390SKeysClass * skeyclass = S390_SKEYS_GET_CLASS (ss );
342
371
int ret = 0 ;
343
372
373
+ /*
374
+ * Make sure to lazy-enable if required to be done explicitly. No need to
375
+ * flush any TLB as the VM is not running yet.
376
+ */
377
+ if (skeyclass -> enable_skeys ) {
378
+ skeyclass -> enable_skeys (ss );
379
+ }
380
+
344
381
while (!ret ) {
345
382
ram_addr_t addr ;
346
383
int flags ;
0 commit comments