mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-02 15:23:53 -06:00
Hi,
"Host Memory Backends" and "Memory devices" queue ("mem"): - Fixup handling of virtio-mem unplug during system resets, as preparation for s390x support (especially kdump in the Linux guest) - virtio-mem support for s390x -----BEGIN PGP SIGNATURE----- iQJFBAABCAAvFiEEG9nKrXNcTDpGDfzKTd4Q9wD/g1oFAmdnFD4RHGRhdmlkQHJl ZGhhdC5jb20ACgkQTd4Q9wD/g1rWBBAAp7WkYaNAjRy1PgpjNZ3z1gUJc/vk+skJ xVgGodA8txrJOFpNrbTyfhrdLs2TV4oWDvB/zrZRRtuxvur3O1EhFd9k6EqXuydr 0FunvLvVJwRHfEZycjN4aacQMRH3CJw07OaTzexeSl5UR/6w5PRofwUK4HX7W/Ka arqomGa3OJrs1+WgkV0Qcn4vh9HLRVv3iNC2Xo4W1wOCr1Du9zSPn9oC7zOQ0EO4 ZC//7QsdkNRjUX/yMXMkhlSXx3b/RmRg2DBrxo7BZXg27VwGu4uHxL4LRBZiB2A7 V9MqFOcVKzPMkXKTRjrgZ0vXQx1MPJ6WprEihMzMpYU6DrpA7KN/l8Ca8H24B2ln h7+bmkDsHVVcWovE9ii/9cMRfws6uWXXg3KoA8RQ8IbX1tU02lblw2uHhXEzcoge npqp/Z5LAiKVMetEnNnLH5thjut5PAEjuqD00cmZAMy4DNngLX2bGSdzMeVBkDMa 78ehLGRplm3t7ibUfaZaMKe6UD9tFrcD6XKsvUTXXHNbYO8ynbx58WOxSZmY98zU n3JNQRqtXYjBVlH3Dqm47vOTZHgOzFv3raa8BmSLpcBDeTXCTcUIl20s77dGw/vT r5YNCMN7O4YPFKUoRK9604QTgw6qlYaRTQlJD09usprGqVylb6gQtfZZuZkYDMp8 sEI77QHsePA= =HDxr -----END PGP SIGNATURE----- Merge tag 'mem-2024-12-21' of https://github.com/davidhildenbrand/qemu into staging Hi, "Host Memory Backends" and "Memory devices" queue ("mem"): - Fixup handling of virtio-mem unplug during system resets, as preparation for s390x support (especially kdump in the Linux guest) - virtio-mem support for s390x # -----BEGIN PGP SIGNATURE----- # # iQJFBAABCAAvFiEEG9nKrXNcTDpGDfzKTd4Q9wD/g1oFAmdnFD4RHGRhdmlkQHJl # ZGhhdC5jb20ACgkQTd4Q9wD/g1rWBBAAp7WkYaNAjRy1PgpjNZ3z1gUJc/vk+skJ # xVgGodA8txrJOFpNrbTyfhrdLs2TV4oWDvB/zrZRRtuxvur3O1EhFd9k6EqXuydr # 0FunvLvVJwRHfEZycjN4aacQMRH3CJw07OaTzexeSl5UR/6w5PRofwUK4HX7W/Ka # arqomGa3OJrs1+WgkV0Qcn4vh9HLRVv3iNC2Xo4W1wOCr1Du9zSPn9oC7zOQ0EO4 # ZC//7QsdkNRjUX/yMXMkhlSXx3b/RmRg2DBrxo7BZXg27VwGu4uHxL4LRBZiB2A7 # V9MqFOcVKzPMkXKTRjrgZ0vXQx1MPJ6WprEihMzMpYU6DrpA7KN/l8Ca8H24B2ln # h7+bmkDsHVVcWovE9ii/9cMRfws6uWXXg3KoA8RQ8IbX1tU02lblw2uHhXEzcoge # npqp/Z5LAiKVMetEnNnLH5thjut5PAEjuqD00cmZAMy4DNngLX2bGSdzMeVBkDMa # 78ehLGRplm3t7ibUfaZaMKe6UD9tFrcD6XKsvUTXXHNbYO8ynbx58WOxSZmY98zU # n3JNQRqtXYjBVlH3Dqm47vOTZHgOzFv3raa8BmSLpcBDeTXCTcUIl20s77dGw/vT # r5YNCMN7O4YPFKUoRK9604QTgw6qlYaRTQlJD09usprGqVylb6gQtfZZuZkYDMp8 # sEI77QHsePA= # =HDxr # -----END PGP SIGNATURE----- # gpg: Signature made Sat 21 Dec 2024 14:17:18 EST # gpg: using RSA key 1BD9CAAD735C4C3A460DFCCA4DDE10F700FF835A # gpg: issuer "david@redhat.com" # gpg: Good signature from "David Hildenbrand <david@redhat.com>" [unknown] # gpg: aka "David Hildenbrand <davidhildenbrand@gmail.com>" [full] # gpg: aka "David Hildenbrand <hildenbr@in.tum.de>" [unknown] # gpg: WARNING: The key's User ID is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 1BD9 CAAD 735C 4C3A 460D FCCA 4DDE 10F7 00FF 835A * tag 'mem-2024-12-21' of https://github.com/davidhildenbrand/qemu: s390x: virtio-mem support s390x/virtio-ccw: add support for virtio based memory devices s390x: remember the maximum page size s390x/pv: prepare for memory devices s390x/s390-virtio-ccw: prepare for memory devices s390x/s390-skeys: prepare for memory devices s390x/s390-stattrib-kvm: prepare for memory devices and sparse memory layouts s390x/s390-hypercall: introduce DIAG500 STORAGE_LIMIT s390x: introduce s390_get_memory_limit() s390x/s390-virtio-ccw: move setting the maximum guest size from sclp to machine code s390x: rename s390-virtio-hcall* to s390-hypercall* s390x/s390-virtio-hcall: prepare for more diag500 hypercalls s390x/s390-virtio-hcall: remove hypercall registration mechanism s390x/s390-virtio-ccw: don't crash on weird RAM sizes virtio-mem: unplug memory only during system resets, not device resets Conflicts: - hw/s390x/s390-stattrib-kvm.c sysemu/ -> system/ header rename conflict. - hw/s390x/virtio-ccw-mem.c Make Property array const and removed DEFINE_PROP_END_OF_LIST() to conform to the latest conventions. Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
commit
aa3a285b5b
25 changed files with 879 additions and 235 deletions
|
@ -2384,6 +2384,9 @@ F: include/hw/virtio/virtio-crypto.h
|
|||
virtio based memory device
|
||||
M: David Hildenbrand <david@redhat.com>
|
||||
S: Supported
|
||||
F: hw/s390x/virtio-ccw-md.c
|
||||
F: hw/s390x/virtio-ccw-md.h
|
||||
F: hw/s390x/virtio-ccw-md-stubs.c
|
||||
F: hw/virtio/virtio-md-pci.c
|
||||
F: include/hw/virtio/virtio-md-pci.h
|
||||
F: stubs/virtio-md-pci.c
|
||||
|
@ -2395,6 +2398,8 @@ W: https://virtio-mem.gitlab.io/
|
|||
F: hw/virtio/virtio-mem.c
|
||||
F: hw/virtio/virtio-mem-pci.h
|
||||
F: hw/virtio/virtio-mem-pci.c
|
||||
F: hw/s390x/virtio-ccw-mem.c
|
||||
F: hw/s390x/virtio-ccw-mem.h
|
||||
F: include/hw/virtio/virtio-mem.h
|
||||
|
||||
virtio-snd
|
||||
|
|
|
@ -16,3 +16,4 @@ config S390_CCW_VIRTIO
|
|||
select SCLPCONSOLE
|
||||
select VIRTIO_CCW
|
||||
select MSI_NONBROKEN
|
||||
select VIRTIO_MEM_SUPPORTED
|
||||
|
|
|
@ -12,7 +12,6 @@ s390x_ss.add(files(
|
|||
's390-pci-inst.c',
|
||||
's390-skeys.c',
|
||||
's390-stattrib.c',
|
||||
's390-virtio-hcall.c',
|
||||
'sclp.c',
|
||||
'sclpcpu.c',
|
||||
'sclpquiesce.c',
|
||||
|
@ -28,7 +27,10 @@ s390x_ss.add(when: 'CONFIG_KVM', if_true: files(
|
|||
s390x_ss.add(when: 'CONFIG_TCG', if_true: files(
|
||||
'tod-tcg.c',
|
||||
))
|
||||
s390x_ss.add(when: 'CONFIG_S390_CCW_VIRTIO', if_true: files('s390-virtio-ccw.c'))
|
||||
s390x_ss.add(when: 'CONFIG_S390_CCW_VIRTIO', if_true: files(
|
||||
's390-virtio-ccw.c',
|
||||
's390-hypercall.c',
|
||||
))
|
||||
s390x_ss.add(when: 'CONFIG_TERMINAL3270', if_true: files('3270-ccw.c'))
|
||||
s390x_ss.add(when: 'CONFIG_VFIO', if_true: files('s390-pci-vfio.c'))
|
||||
|
||||
|
@ -48,8 +50,12 @@ endif
|
|||
virtio_ss.add(when: 'CONFIG_VHOST_SCSI', if_true: files('vhost-scsi-ccw.c'))
|
||||
virtio_ss.add(when: 'CONFIG_VHOST_VSOCK', if_true: files('vhost-vsock-ccw.c'))
|
||||
virtio_ss.add(when: 'CONFIG_VHOST_USER_FS', if_true: files('vhost-user-fs-ccw.c'))
|
||||
virtio_ss.add(when: 'CONFIG_VIRTIO_MD', if_true: files('virtio-ccw-md.c'))
|
||||
virtio_ss.add(when: 'CONFIG_VIRTIO_MEM', if_true: files('virtio-ccw-mem.c'))
|
||||
s390x_ss.add_all(when: 'CONFIG_VIRTIO_CCW', if_true: virtio_ss)
|
||||
|
||||
s390x_ss.add(when: 'CONFIG_VIRTIO_MD', if_false: files('virtio-ccw-md-stubs.c'))
|
||||
|
||||
hw_arch += {'s390x': s390x_ss}
|
||||
|
||||
hw_s390x_modules = {}
|
||||
|
|
85
hw/s390x/s390-hypercall.c
Normal file
85
hw/s390x/s390-hypercall.c
Normal file
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Support for QEMU/KVM hypercalls on s390
|
||||
*
|
||||
* Copyright 2012 IBM Corp.
|
||||
* Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or (at
|
||||
* your option) any later version. See the COPYING file in the top-level
|
||||
* directory.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "hw/s390x/s390-virtio-ccw.h"
|
||||
#include "hw/s390x/s390-hypercall.h"
|
||||
#include "hw/s390x/ioinst.h"
|
||||
#include "hw/s390x/css.h"
|
||||
#include "virtio-ccw.h"
|
||||
|
||||
static int handle_virtio_notify(uint64_t mem)
|
||||
{
|
||||
MachineState *ms = MACHINE(qdev_get_machine());
|
||||
|
||||
if (mem < ms->ram_size) {
|
||||
/* Early printk */
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int handle_virtio_ccw_notify(uint64_t subch_id, uint64_t data)
|
||||
{
|
||||
SubchDev *sch;
|
||||
VirtIODevice *vdev;
|
||||
int cssid, ssid, schid, m;
|
||||
uint16_t vq_idx = data;
|
||||
|
||||
if (ioinst_disassemble_sch_ident(subch_id, &m, &cssid, &ssid, &schid)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
sch = css_find_subch(m, cssid, ssid, schid);
|
||||
if (!sch || !css_subch_visible(sch)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
vdev = virtio_ccw_get_vdev(sch);
|
||||
if (vq_idx >= VIRTIO_QUEUE_MAX || !virtio_queue_get_num(vdev, vq_idx)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (virtio_vdev_has_feature(vdev, VIRTIO_F_NOTIFICATION_DATA)) {
|
||||
virtio_queue_set_shadow_avail_idx(virtio_get_queue(vdev, vq_idx),
|
||||
(data >> 16) & 0xFFFF);
|
||||
}
|
||||
|
||||
virtio_queue_notify(vdev, vq_idx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint64_t handle_storage_limit(void)
|
||||
{
|
||||
S390CcwMachineState *s390ms = S390_CCW_MACHINE(qdev_get_machine());
|
||||
|
||||
return s390_get_memory_limit(s390ms) - 1;
|
||||
}
|
||||
|
||||
void handle_diag_500(S390CPU *cpu, uintptr_t ra)
|
||||
{
|
||||
CPUS390XState *env = &cpu->env;
|
||||
const uint64_t subcode = env->regs[1];
|
||||
|
||||
switch (subcode) {
|
||||
case DIAG500_VIRTIO_NOTIFY:
|
||||
env->regs[2] = handle_virtio_notify(env->regs[2]);
|
||||
break;
|
||||
case DIAG500_VIRTIO_CCW_NOTIFY:
|
||||
env->regs[2] = handle_virtio_ccw_notify(env->regs[2], env->regs[3]);
|
||||
break;
|
||||
case DIAG500_STORAGE_LIMIT:
|
||||
env->regs[2] = handle_storage_limit();
|
||||
break;
|
||||
default:
|
||||
s390_program_interrupt(env, PGM_SPECIFICATION, ra);
|
||||
}
|
||||
}
|
25
hw/s390x/s390-hypercall.h
Normal file
25
hw/s390x/s390-hypercall.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Support for QEMU/KVM hypercalls on s390x
|
||||
*
|
||||
* Copyright IBM Corp. 2012, 2017
|
||||
* Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or (at
|
||||
* your option) any later version. See the COPYING file in the top-level
|
||||
* directory.
|
||||
*/
|
||||
|
||||
#ifndef HW_S390_HYPERCALL_H
|
||||
#define HW_S390_HYPERCALL_H
|
||||
|
||||
#include "cpu.h"
|
||||
|
||||
#define DIAG500_VIRTIO_NOTIFY 0 /* legacy, implemented as a NOP */
|
||||
#define DIAG500_VIRTIO_RESET 1 /* legacy */
|
||||
#define DIAG500_VIRTIO_SET_STATUS 2 /* legacy */
|
||||
#define DIAG500_VIRTIO_CCW_NOTIFY 3 /* KVM_S390_VIRTIO_CCW_NOTIFY */
|
||||
#define DIAG500_STORAGE_LIMIT 4
|
||||
|
||||
void handle_diag_500(S390CPU *cpu, uintptr_t ra);
|
||||
|
||||
#endif /* HW_S390_HYPERCALL_H */
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/units.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/s390x/s390-virtio-ccw.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/s390x/storage-keys.h"
|
||||
#include "qapi/error.h"
|
||||
|
@ -251,9 +251,9 @@ static bool qemu_s390_enable_skeys(S390SKeysState *ss)
|
|||
* g_once_init_enter() is good enough.
|
||||
*/
|
||||
if (g_once_init_enter(&initialized)) {
|
||||
MachineState *machine = MACHINE(qdev_get_machine());
|
||||
S390CcwMachineState *s390ms = S390_CCW_MACHINE(qdev_get_machine());
|
||||
|
||||
skeys->key_count = machine->ram_size / TARGET_PAGE_SIZE;
|
||||
skeys->key_count = s390_get_memory_limit(s390ms) / TARGET_PAGE_SIZE;
|
||||
skeys->keydata = g_malloc0(skeys->key_count);
|
||||
g_once_init_leave(&initialized, 1);
|
||||
}
|
||||
|
|
|
@ -10,11 +10,12 @@
|
|||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/s390x/s390-virtio-ccw.h"
|
||||
#include "migration/qemu-file.h"
|
||||
#include "hw/s390x/storage-attributes.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "system/kvm.h"
|
||||
#include "system/memory_mapping.h"
|
||||
#include "exec/ram_addr.h"
|
||||
#include "kvm/kvm_s390x.h"
|
||||
#include "qapi/error.h"
|
||||
|
@ -84,8 +85,8 @@ static int kvm_s390_stattrib_set_stattr(S390StAttribState *sa,
|
|||
uint8_t *values)
|
||||
{
|
||||
KVMS390StAttribState *sas = KVM_S390_STATTRIB(sa);
|
||||
MachineState *machine = MACHINE(qdev_get_machine());
|
||||
unsigned long max = machine->ram_size / TARGET_PAGE_SIZE;
|
||||
S390CcwMachineState *s390ms = S390_CCW_MACHINE(qdev_get_machine());
|
||||
unsigned long max = s390_get_memory_limit(s390ms) / TARGET_PAGE_SIZE;
|
||||
|
||||
if (start_gfn + count > max) {
|
||||
error_report("Out of memory bounds when setting storage attributes");
|
||||
|
@ -103,39 +104,57 @@ static int kvm_s390_stattrib_set_stattr(S390StAttribState *sa,
|
|||
static void kvm_s390_stattrib_synchronize(S390StAttribState *sa)
|
||||
{
|
||||
KVMS390StAttribState *sas = KVM_S390_STATTRIB(sa);
|
||||
MachineState *machine = MACHINE(qdev_get_machine());
|
||||
unsigned long max = machine->ram_size / TARGET_PAGE_SIZE;
|
||||
/* We do not need to reach the maximum buffer size allowed */
|
||||
unsigned long cx, len = KVM_S390_SKEYS_MAX / 2;
|
||||
S390CcwMachineState *s390ms = S390_CCW_MACHINE(qdev_get_machine());
|
||||
unsigned long max = s390_get_memory_limit(s390ms) / TARGET_PAGE_SIZE;
|
||||
unsigned long start_gfn, end_gfn, pages;
|
||||
GuestPhysBlockList guest_phys_blocks;
|
||||
GuestPhysBlock *block;
|
||||
int r;
|
||||
struct kvm_s390_cmma_log clog = {
|
||||
.flags = 0,
|
||||
.mask = ~0ULL,
|
||||
};
|
||||
|
||||
if (sas->incoming_buffer) {
|
||||
for (cx = 0; cx + len <= max; cx += len) {
|
||||
clog.start_gfn = cx;
|
||||
clog.count = len;
|
||||
clog.values = (uint64_t)(sas->incoming_buffer + cx);
|
||||
r = kvm_vm_ioctl(kvm_state, KVM_S390_SET_CMMA_BITS, &clog);
|
||||
if (r) {
|
||||
error_report("KVM_S390_SET_CMMA_BITS failed: %s", strerror(-r));
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (cx < max) {
|
||||
clog.start_gfn = cx;
|
||||
clog.count = max - cx;
|
||||
clog.values = (uint64_t)(sas->incoming_buffer + cx);
|
||||
r = kvm_vm_ioctl(kvm_state, KVM_S390_SET_CMMA_BITS, &clog);
|
||||
if (r) {
|
||||
error_report("KVM_S390_SET_CMMA_BITS failed: %s", strerror(-r));
|
||||
}
|
||||
}
|
||||
g_free(sas->incoming_buffer);
|
||||
sas->incoming_buffer = NULL;
|
||||
if (!sas->incoming_buffer) {
|
||||
return;
|
||||
}
|
||||
guest_phys_blocks_init(&guest_phys_blocks);
|
||||
guest_phys_blocks_append(&guest_phys_blocks);
|
||||
|
||||
QTAILQ_FOREACH(block, &guest_phys_blocks.head, next) {
|
||||
assert(QEMU_IS_ALIGNED(block->target_start, TARGET_PAGE_SIZE));
|
||||
assert(QEMU_IS_ALIGNED(block->target_end, TARGET_PAGE_SIZE));
|
||||
|
||||
start_gfn = block->target_start / TARGET_PAGE_SIZE;
|
||||
end_gfn = block->target_end / TARGET_PAGE_SIZE;
|
||||
|
||||
while (start_gfn < end_gfn) {
|
||||
/* Don't exceed the maximum buffer size. */
|
||||
pages = MIN(end_gfn - start_gfn, KVM_S390_SKEYS_MAX / 2);
|
||||
|
||||
/*
|
||||
* If we ever get guest physical memory beyond the configured
|
||||
* memory limit, something went very wrong.
|
||||
*/
|
||||
assert(start_gfn + pages <= max);
|
||||
|
||||
clog.start_gfn = start_gfn;
|
||||
clog.count = pages;
|
||||
clog.values = (uint64_t)(sas->incoming_buffer + start_gfn);
|
||||
r = kvm_vm_ioctl(kvm_state, KVM_S390_SET_CMMA_BITS, &clog);
|
||||
if (r) {
|
||||
error_report("KVM_S390_SET_CMMA_BITS failed: %s", strerror(-r));
|
||||
goto out;
|
||||
}
|
||||
|
||||
start_gfn += pages;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
guest_phys_blocks_free(&guest_phys_blocks);
|
||||
g_free(sas->incoming_buffer);
|
||||
sas->incoming_buffer = NULL;
|
||||
}
|
||||
|
||||
static int kvm_s390_stattrib_set_migrationmode(S390StAttribState *sa, bool val,
|
||||
|
|
|
@ -16,11 +16,8 @@
|
|||
#include "exec/ram_addr.h"
|
||||
#include "system/confidential-guest-support.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/s390x/s390-virtio-hcall.h"
|
||||
#include "hw/s390x/sclp.h"
|
||||
#include "hw/s390x/s390_flic.h"
|
||||
#include "hw/s390x/ioinst.h"
|
||||
#include "hw/s390x/css.h"
|
||||
#include "virtio-ccw.h"
|
||||
#include "qemu/config-file.h"
|
||||
#include "qemu/ctype.h"
|
||||
|
@ -48,6 +45,9 @@
|
|||
#include "migration/blocker.h"
|
||||
#include "qapi/visitor.h"
|
||||
#include "hw/s390x/cpu-topology.h"
|
||||
#include "kvm/kvm_s390x.h"
|
||||
#include "hw/virtio/virtio-md-pci.h"
|
||||
#include "hw/s390x/virtio-ccw-md.h"
|
||||
#include CONFIG_DEVICES
|
||||
|
||||
static Error *pv_mig_blocker;
|
||||
|
@ -124,70 +124,86 @@ static void subsystem_reset(void)
|
|||
}
|
||||
}
|
||||
|
||||
static int virtio_ccw_hcall_notify(const uint64_t *args)
|
||||
static void s390_set_memory_limit(S390CcwMachineState *s390ms,
|
||||
uint64_t new_limit)
|
||||
{
|
||||
uint64_t subch_id = args[0];
|
||||
uint64_t data = args[1];
|
||||
SubchDev *sch;
|
||||
VirtIODevice *vdev;
|
||||
int cssid, ssid, schid, m;
|
||||
uint16_t vq_idx = data;
|
||||
uint64_t hw_limit = 0;
|
||||
int ret = 0;
|
||||
|
||||
if (ioinst_disassemble_sch_ident(subch_id, &m, &cssid, &ssid, &schid)) {
|
||||
return -EINVAL;
|
||||
assert(!s390ms->memory_limit && new_limit);
|
||||
if (kvm_enabled()) {
|
||||
ret = kvm_s390_set_mem_limit(new_limit, &hw_limit);
|
||||
}
|
||||
sch = css_find_subch(m, cssid, ssid, schid);
|
||||
if (!sch || !css_subch_visible(sch)) {
|
||||
return -EINVAL;
|
||||
if (ret == -E2BIG) {
|
||||
error_report("host supports a maximum of %" PRIu64 " GB",
|
||||
hw_limit / GiB);
|
||||
exit(EXIT_FAILURE);
|
||||
} else if (ret) {
|
||||
error_report("setting the guest size failed");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
vdev = virtio_ccw_get_vdev(sch);
|
||||
if (vq_idx >= VIRTIO_QUEUE_MAX || !virtio_queue_get_num(vdev, vq_idx)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (virtio_vdev_has_feature(vdev, VIRTIO_F_NOTIFICATION_DATA)) {
|
||||
virtio_queue_set_shadow_avail_idx(virtio_get_queue(vdev, vq_idx),
|
||||
(data >> 16) & 0xFFFF);
|
||||
}
|
||||
|
||||
virtio_queue_notify(vdev, vq_idx);
|
||||
return 0;
|
||||
s390ms->memory_limit = new_limit;
|
||||
}
|
||||
|
||||
static int virtio_ccw_hcall_early_printk(const uint64_t *args)
|
||||
static void s390_set_max_pagesize(S390CcwMachineState *s390ms,
|
||||
uint64_t pagesize)
|
||||
{
|
||||
uint64_t mem = args[0];
|
||||
MachineState *ms = MACHINE(qdev_get_machine());
|
||||
|
||||
if (mem < ms->ram_size) {
|
||||
/* Early printk */
|
||||
return 0;
|
||||
assert(!s390ms->max_pagesize && pagesize);
|
||||
if (kvm_enabled()) {
|
||||
kvm_s390_set_max_pagesize(pagesize, &error_fatal);
|
||||
}
|
||||
return -EINVAL;
|
||||
s390ms->max_pagesize = pagesize;
|
||||
}
|
||||
|
||||
static void virtio_ccw_register_hcalls(void)
|
||||
{
|
||||
s390_register_virtio_hypercall(KVM_S390_VIRTIO_CCW_NOTIFY,
|
||||
virtio_ccw_hcall_notify);
|
||||
/* Tolerate early printk. */
|
||||
s390_register_virtio_hypercall(KVM_S390_VIRTIO_NOTIFY,
|
||||
virtio_ccw_hcall_early_printk);
|
||||
}
|
||||
|
||||
static void s390_memory_init(MemoryRegion *ram)
|
||||
static void s390_memory_init(MachineState *machine)
|
||||
{
|
||||
S390CcwMachineState *s390ms = S390_CCW_MACHINE(machine);
|
||||
MemoryRegion *sysmem = get_system_memory();
|
||||
MemoryRegion *ram = machine->ram;
|
||||
uint64_t ram_size = memory_region_size(ram);
|
||||
uint64_t devmem_base, devmem_size;
|
||||
|
||||
/* allocate RAM for core */
|
||||
if (!QEMU_IS_ALIGNED(ram_size, 1 * MiB)) {
|
||||
/*
|
||||
* SCLP cannot possibly expose smaller granularity right now and KVM
|
||||
* cannot handle smaller granularity. As we don't support NUMA, the
|
||||
* region size directly corresponds to machine->ram_size, and the region
|
||||
* is a single RAM memory region.
|
||||
*/
|
||||
error_report("ram size must be multiples of 1 MiB");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
devmem_size = 0;
|
||||
devmem_base = ram_size;
|
||||
#ifdef CONFIG_MEM_DEVICE
|
||||
if (machine->ram_size < machine->maxram_size) {
|
||||
|
||||
/*
|
||||
* Make sure memory devices have a sane default alignment, even
|
||||
* when weird initial memory sizes are specified.
|
||||
*/
|
||||
devmem_base = QEMU_ALIGN_UP(devmem_base, 1 * GiB);
|
||||
devmem_size = machine->maxram_size - machine->ram_size;
|
||||
}
|
||||
#endif
|
||||
s390_set_memory_limit(s390ms, devmem_base + devmem_size);
|
||||
|
||||
/* Map the initial memory. Must happen after setting the memory limit. */
|
||||
memory_region_add_subregion(sysmem, 0, ram);
|
||||
|
||||
/* Initialize address space for memory devices. */
|
||||
#ifdef CONFIG_MEM_DEVICE
|
||||
if (devmem_size) {
|
||||
machine_memory_devices_init(machine, devmem_base, devmem_size);
|
||||
}
|
||||
#endif /* CONFIG_MEM_DEVICE */
|
||||
|
||||
/*
|
||||
* Configure the maximum page size. As no memory devices were created
|
||||
* yet, this is the page size of initial memory only.
|
||||
*/
|
||||
s390_set_max_pagesize(qemu_maxrampagesize(), &error_fatal);
|
||||
s390_set_max_pagesize(s390ms, qemu_maxrampagesize());
|
||||
/* Initialize storage key device */
|
||||
s390_skeys_init();
|
||||
/* Initialize storage attributes device */
|
||||
|
@ -255,7 +271,7 @@ static void ccw_init(MachineState *machine)
|
|||
qdev_realize_and_unref(DEVICE(ms->sclp), NULL, &error_fatal);
|
||||
|
||||
/* init memory + setup max page size. Required for the CPU model */
|
||||
s390_memory_init(machine->ram);
|
||||
s390_memory_init(machine);
|
||||
|
||||
/* init CPUs (incl. CPU model) early so s390_has_feature() works */
|
||||
s390_init_cpus(machine);
|
||||
|
@ -285,9 +301,6 @@ static void ccw_init(MachineState *machine)
|
|||
OBJECT(dev));
|
||||
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
||||
|
||||
/* register hypercalls */
|
||||
virtio_ccw_register_hcalls();
|
||||
|
||||
s390_enable_css_support(s390_cpu_addr2state(0));
|
||||
|
||||
ret = css_create_css_image(VIRTUAL_CSSID, true);
|
||||
|
@ -535,11 +548,39 @@ static void s390_machine_reset(MachineState *machine, ResetType type)
|
|||
s390_ipl_clear_reset_request();
|
||||
}
|
||||
|
||||
static void s390_machine_device_pre_plug(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_CCW)) {
|
||||
virtio_ccw_md_pre_plug(VIRTIO_MD_CCW(dev), MACHINE(hotplug_dev), errp);
|
||||
} else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_PCI)) {
|
||||
error_setg(errp,
|
||||
"PCI-attached virtio based memory devices not supported");
|
||||
}
|
||||
}
|
||||
|
||||
static void s390_machine_device_plug(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
S390CcwMachineState *s390ms = S390_CCW_MACHINE(hotplug_dev);
|
||||
|
||||
if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
|
||||
s390_cpu_plug(hotplug_dev, dev, errp);
|
||||
} else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_CCW)) {
|
||||
/*
|
||||
* At this point, the device is realized and set all memdevs mapped, so
|
||||
* qemu_maxrampagesize() will pick up the page sizes of these memdevs
|
||||
* as well. Before we plug the device and expose any RAM memory regions
|
||||
* to the system, make sure we don't exceed the previously set max page
|
||||
* size. While only relevant for KVM, there is not really any use case
|
||||
* for this with TCG, so we'll unconditionally reject it.
|
||||
*/
|
||||
if (qemu_maxrampagesize() != s390ms->max_pagesize) {
|
||||
error_setg(errp, "Memory device uses a bigger page size than"
|
||||
" initial memory");
|
||||
return;
|
||||
}
|
||||
virtio_ccw_md_plug(VIRTIO_MD_CCW(dev), MACHINE(hotplug_dev), errp);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -549,9 +590,20 @@ static void s390_machine_device_unplug_request(HotplugHandler *hotplug_dev,
|
|||
if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
|
||||
error_setg(errp, "CPU hot unplug not supported on this machine");
|
||||
return;
|
||||
} else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_CCW)) {
|
||||
virtio_ccw_md_unplug_request(VIRTIO_MD_CCW(dev), MACHINE(hotplug_dev),
|
||||
errp);
|
||||
}
|
||||
}
|
||||
|
||||
static void s390_machine_device_unplug(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_CCW)) {
|
||||
virtio_ccw_md_unplug(VIRTIO_MD_CCW(dev), MACHINE(hotplug_dev), errp);
|
||||
}
|
||||
}
|
||||
|
||||
static CpuInstanceProperties s390_cpu_index_to_props(MachineState *ms,
|
||||
unsigned cpu_index)
|
||||
{
|
||||
|
@ -598,7 +650,9 @@ static const CPUArchIdList *s390_possible_cpu_arch_ids(MachineState *ms)
|
|||
static HotplugHandler *s390_get_hotplug_handler(MachineState *machine,
|
||||
DeviceState *dev)
|
||||
{
|
||||
if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
|
||||
if (object_dynamic_cast(OBJECT(dev), TYPE_CPU) ||
|
||||
object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_CCW) ||
|
||||
object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_PCI)) {
|
||||
return HOTPLUG_HANDLER(machine);
|
||||
}
|
||||
return NULL;
|
||||
|
@ -758,8 +812,10 @@ static void ccw_machine_class_init(ObjectClass *oc, void *data)
|
|||
mc->possible_cpu_arch_ids = s390_possible_cpu_arch_ids;
|
||||
/* it is overridden with 'host' cpu *in kvm_arch_init* */
|
||||
mc->default_cpu_type = S390_CPU_TYPE_NAME("qemu");
|
||||
hc->pre_plug = s390_machine_device_pre_plug;
|
||||
hc->plug = s390_machine_device_plug;
|
||||
hc->unplug_request = s390_machine_device_unplug_request;
|
||||
hc->unplug = s390_machine_device_unplug;
|
||||
nc->nmi_monitor_handler = s390_nmi;
|
||||
mc->default_ram_id = "s390.ram";
|
||||
mc->default_nic = "virtio-net-ccw";
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
* Support for virtio hypercalls on s390
|
||||
*
|
||||
* Copyright 2012 IBM Corp.
|
||||
* Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or (at
|
||||
* your option) any later version. See the COPYING file in the top-level
|
||||
* directory.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "hw/s390x/s390-virtio-hcall.h"
|
||||
|
||||
#define MAX_DIAG_SUBCODES 255
|
||||
|
||||
static s390_virtio_fn s390_diag500_table[MAX_DIAG_SUBCODES];
|
||||
|
||||
void s390_register_virtio_hypercall(uint64_t code, s390_virtio_fn fn)
|
||||
{
|
||||
assert(code < MAX_DIAG_SUBCODES);
|
||||
assert(!s390_diag500_table[code]);
|
||||
|
||||
s390_diag500_table[code] = fn;
|
||||
}
|
||||
|
||||
int s390_virtio_hypercall(CPUS390XState *env)
|
||||
{
|
||||
s390_virtio_fn fn;
|
||||
|
||||
if (env->regs[1] < MAX_DIAG_SUBCODES) {
|
||||
fn = s390_diag500_table[env->regs[1]];
|
||||
if (fn) {
|
||||
env->regs[2] = fn(&env->regs[2]);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
/*
|
||||
* Support for virtio hypercalls on s390x
|
||||
*
|
||||
* Copyright IBM Corp. 2012, 2017
|
||||
* Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or (at
|
||||
* your option) any later version. See the COPYING file in the top-level
|
||||
* directory.
|
||||
*/
|
||||
|
||||
#ifndef HW_S390_VIRTIO_HCALL_H
|
||||
#define HW_S390_VIRTIO_HCALL_H
|
||||
|
||||
#include "standard-headers/asm-s390/virtio-ccw.h"
|
||||
#include "cpu.h"
|
||||
|
||||
/* The only thing that we need from the old kvm_virtio.h file */
|
||||
#define KVM_S390_VIRTIO_NOTIFY 0
|
||||
|
||||
typedef int (*s390_virtio_fn)(const uint64_t *args);
|
||||
void s390_register_virtio_hypercall(uint64_t code, s390_virtio_fn fn);
|
||||
int s390_virtio_hypercall(CPUS390XState *env);
|
||||
|
||||
#endif /* HW_S390_VIRTIO_HCALL_H */
|
|
@ -161,7 +161,11 @@ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb)
|
|||
read_info->rnsize2 = cpu_to_be32(rnsize);
|
||||
}
|
||||
|
||||
/* we don't support standby memory, maxram_size is never exposed */
|
||||
/*
|
||||
* We don't support standby memory. maxram_size is used for sizing the
|
||||
* memory device region, which is not exposed through SCLP but through
|
||||
* diag500.
|
||||
*/
|
||||
rnmax = machine->ram_size >> sclp->increment_size;
|
||||
if (rnmax < 0x10000) {
|
||||
read_info->rnmax = cpu_to_be16(rnmax);
|
||||
|
@ -376,10 +380,7 @@ void sclp_service_interrupt(uint32_t sccb)
|
|||
/* qemu object creation and initialization functions */
|
||||
static void sclp_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
MachineState *machine = MACHINE(qdev_get_machine());
|
||||
SCLPDevice *sclp = SCLP(dev);
|
||||
uint64_t hw_limit;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* qdev_device_add searches the sysbus for TYPE_SCLP_EVENTS_BUS. As long
|
||||
|
@ -389,14 +390,6 @@ static void sclp_realize(DeviceState *dev, Error **errp)
|
|||
if (!sysbus_realize(SYS_BUS_DEVICE(sclp->event_facility), errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ret = s390_set_memory_limit(machine->maxram_size, &hw_limit);
|
||||
if (ret == -E2BIG) {
|
||||
error_setg(errp, "host supports a maximum of %" PRIu64 " GB",
|
||||
hw_limit / GiB);
|
||||
} else if (ret) {
|
||||
error_setg(errp, "setting the guest size failed");
|
||||
}
|
||||
}
|
||||
|
||||
static void sclp_memory_init(SCLPDevice *sclp)
|
||||
|
|
24
hw/s390x/virtio-ccw-md-stubs.c
Normal file
24
hw/s390x/virtio-ccw-md-stubs.c
Normal file
|
@ -0,0 +1,24 @@
|
|||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/s390x/virtio-ccw-md.h"
|
||||
|
||||
void virtio_ccw_md_pre_plug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp)
|
||||
{
|
||||
error_setg(errp, "virtio based memory devices not supported");
|
||||
}
|
||||
|
||||
void virtio_ccw_md_plug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp)
|
||||
{
|
||||
error_setg(errp, "virtio based memory devices not supported");
|
||||
}
|
||||
|
||||
void virtio_ccw_md_unplug_request(VirtIOMDCcw *vmd, MachineState *ms,
|
||||
Error **errp)
|
||||
{
|
||||
error_setg(errp, "virtio based memory devices not supported");
|
||||
}
|
||||
|
||||
void virtio_ccw_md_unplug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp)
|
||||
{
|
||||
error_setg(errp, "virtio based memory devices not supported");
|
||||
}
|
153
hw/s390x/virtio-ccw-md.c
Normal file
153
hw/s390x/virtio-ccw-md.c
Normal file
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
* Virtio CCW support for abstract virtio based memory device
|
||||
*
|
||||
* Copyright (C) 2024 Red Hat, Inc.
|
||||
*
|
||||
* Authors:
|
||||
* David Hildenbrand <david@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/s390x/virtio-ccw-md.h"
|
||||
#include "hw/mem/memory-device.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
||||
void virtio_ccw_md_pre_plug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp)
|
||||
{
|
||||
DeviceState *dev = DEVICE(vmd);
|
||||
HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev);
|
||||
MemoryDeviceState *md = MEMORY_DEVICE(vmd);
|
||||
Error *local_err = NULL;
|
||||
|
||||
if (!bus_handler && dev->hotplugged) {
|
||||
/*
|
||||
* Without a bus hotplug handler, we cannot control the plug/unplug
|
||||
* order. We should never reach this point when hotplugging, but
|
||||
* better add a safety net.
|
||||
*/
|
||||
error_setg(errp, "hotplug of virtio based memory devices not supported"
|
||||
" on this bus.");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* First, see if we can plug this memory device at all. If that
|
||||
* succeeds, branch of to the actual hotplug handler.
|
||||
*/
|
||||
memory_device_pre_plug(md, ms, &local_err);
|
||||
if (!local_err && bus_handler) {
|
||||
hotplug_handler_pre_plug(bus_handler, dev, &local_err);
|
||||
}
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
|
||||
void virtio_ccw_md_plug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp)
|
||||
{
|
||||
DeviceState *dev = DEVICE(vmd);
|
||||
HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev);
|
||||
MemoryDeviceState *md = MEMORY_DEVICE(vmd);
|
||||
Error *local_err = NULL;
|
||||
|
||||
/*
|
||||
* Plug the memory device first and then branch off to the actual
|
||||
* hotplug handler. If that one fails, we can easily undo the memory
|
||||
* device bits.
|
||||
*/
|
||||
memory_device_plug(md, ms);
|
||||
if (bus_handler) {
|
||||
hotplug_handler_plug(bus_handler, dev, &local_err);
|
||||
if (local_err) {
|
||||
memory_device_unplug(md, ms);
|
||||
}
|
||||
}
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
|
||||
void virtio_ccw_md_unplug_request(VirtIOMDCcw *vmd, MachineState *ms,
|
||||
Error **errp)
|
||||
{
|
||||
VirtIOMDCcwClass *vmdc = VIRTIO_MD_CCW_GET_CLASS(vmd);
|
||||
DeviceState *dev = DEVICE(vmd);
|
||||
HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev);
|
||||
HotplugHandlerClass *hdc;
|
||||
Error *local_err = NULL;
|
||||
|
||||
if (!vmdc->unplug_request_check) {
|
||||
error_setg(errp,
|
||||
"this virtio based memory devices cannot be unplugged");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!bus_handler) {
|
||||
error_setg(errp, "hotunplug of virtio based memory devices not"
|
||||
"supported on this bus");
|
||||
return;
|
||||
}
|
||||
|
||||
vmdc->unplug_request_check(vmd, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Forward the async request or turn it into a sync request (handling it
|
||||
* like qdev_unplug()).
|
||||
*/
|
||||
hdc = HOTPLUG_HANDLER_GET_CLASS(bus_handler);
|
||||
if (hdc->unplug_request) {
|
||||
hotplug_handler_unplug_request(bus_handler, dev, &local_err);
|
||||
} else {
|
||||
virtio_ccw_md_unplug(vmd, ms, &local_err);
|
||||
if (!local_err) {
|
||||
object_unparent(OBJECT(dev));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void virtio_ccw_md_unplug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp)
|
||||
{
|
||||
DeviceState *dev = DEVICE(vmd);
|
||||
HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev);
|
||||
MemoryDeviceState *md = MEMORY_DEVICE(vmd);
|
||||
Error *local_err = NULL;
|
||||
|
||||
/* Unplug the memory device while it is still realized. */
|
||||
memory_device_unplug(md, ms);
|
||||
|
||||
if (bus_handler) {
|
||||
hotplug_handler_unplug(bus_handler, dev, &local_err);
|
||||
if (local_err) {
|
||||
/* Not expected to fail ... but still try to recover. */
|
||||
memory_device_plug(md, ms);
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
/* Very unexpected, but let's just try to do the right thing. */
|
||||
warn_report("Unexpected unplug of virtio based memory device");
|
||||
qdev_unrealize(dev);
|
||||
}
|
||||
}
|
||||
|
||||
static const TypeInfo virtio_ccw_md_info = {
|
||||
.name = TYPE_VIRTIO_MD_CCW,
|
||||
.parent = TYPE_VIRTIO_CCW_DEVICE,
|
||||
.instance_size = sizeof(VirtIOMDCcw),
|
||||
.class_size = sizeof(VirtIOMDCcwClass),
|
||||
.abstract = true,
|
||||
.interfaces = (InterfaceInfo[]) {
|
||||
{ TYPE_MEMORY_DEVICE },
|
||||
{ }
|
||||
},
|
||||
};
|
||||
|
||||
static void virtio_ccw_md_register(void)
|
||||
{
|
||||
type_register_static(&virtio_ccw_md_info);
|
||||
}
|
||||
type_init(virtio_ccw_md_register)
|
44
hw/s390x/virtio-ccw-md.h
Normal file
44
hw/s390x/virtio-ccw-md.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Virtio CCW support for abstract virtio based memory device
|
||||
*
|
||||
* Copyright (C) 2024 Red Hat, Inc.
|
||||
*
|
||||
* Authors:
|
||||
* David Hildenbrand <david@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef HW_S390X_VIRTIO_CCW_MD_H
|
||||
#define HW_S390X_VIRTIO_CCW_MD_H
|
||||
|
||||
#include "virtio-ccw.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
/*
|
||||
* virtio-md-ccw: This extends VirtioCcwDevice.
|
||||
*/
|
||||
#define TYPE_VIRTIO_MD_CCW "virtio-md-ccw"
|
||||
|
||||
OBJECT_DECLARE_TYPE(VirtIOMDCcw, VirtIOMDCcwClass, VIRTIO_MD_CCW)
|
||||
|
||||
struct VirtIOMDCcwClass {
|
||||
/* private */
|
||||
VirtIOCCWDeviceClass parent;
|
||||
|
||||
/* public */
|
||||
void (*unplug_request_check)(VirtIOMDCcw *vmd, Error **errp);
|
||||
};
|
||||
|
||||
struct VirtIOMDCcw {
|
||||
VirtioCcwDevice parent_obj;
|
||||
};
|
||||
|
||||
void virtio_ccw_md_pre_plug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp);
|
||||
void virtio_ccw_md_plug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp);
|
||||
void virtio_ccw_md_unplug_request(VirtIOMDCcw *vmd, MachineState *ms,
|
||||
Error **errp);
|
||||
void virtio_ccw_md_unplug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp);
|
||||
|
||||
#endif /* HW_S390X_VIRTIO_CCW_MD_H */
|
225
hw/s390x/virtio-ccw-mem.c
Normal file
225
hw/s390x/virtio-ccw-mem.c
Normal file
|
@ -0,0 +1,225 @@
|
|||
/*
|
||||
* virtio-mem CCW implementation
|
||||
*
|
||||
* Copyright (C) 2024 Red Hat, Inc.
|
||||
*
|
||||
* Authors:
|
||||
* David Hildenbrand <david@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/module.h"
|
||||
#include "virtio-ccw-mem.h"
|
||||
#include "hw/mem/memory-device.h"
|
||||
#include "qapi/qapi-events-machine.h"
|
||||
#include "qapi/qapi-events-misc.h"
|
||||
|
||||
static void virtio_ccw_mem_realize(VirtioCcwDevice *ccw_dev, Error **errp)
|
||||
{
|
||||
VirtIOMEMCcw *dev = VIRTIO_MEM_CCW(ccw_dev);
|
||||
DeviceState *vdev = DEVICE(&dev->vdev);
|
||||
|
||||
qdev_realize(vdev, BUS(&ccw_dev->bus), errp);
|
||||
}
|
||||
|
||||
static void virtio_ccw_mem_set_addr(MemoryDeviceState *md, uint64_t addr,
|
||||
Error **errp)
|
||||
{
|
||||
object_property_set_uint(OBJECT(md), VIRTIO_MEM_ADDR_PROP, addr, errp);
|
||||
}
|
||||
|
||||
static uint64_t virtio_ccw_mem_get_addr(const MemoryDeviceState *md)
|
||||
{
|
||||
return object_property_get_uint(OBJECT(md), VIRTIO_MEM_ADDR_PROP,
|
||||
&error_abort);
|
||||
}
|
||||
|
||||
static MemoryRegion *virtio_ccw_mem_get_memory_region(MemoryDeviceState *md,
|
||||
Error **errp)
|
||||
{
|
||||
VirtIOMEMCcw *dev = VIRTIO_MEM_CCW(md);
|
||||
VirtIOMEM *vmem = &dev->vdev;
|
||||
VirtIOMEMClass *vmc = VIRTIO_MEM_GET_CLASS(vmem);
|
||||
|
||||
return vmc->get_memory_region(vmem, errp);
|
||||
}
|
||||
|
||||
static void virtio_ccw_mem_decide_memslots(MemoryDeviceState *md,
|
||||
unsigned int limit)
|
||||
{
|
||||
VirtIOMEMCcw *dev = VIRTIO_MEM_CCW(md);
|
||||
VirtIOMEM *vmem = VIRTIO_MEM(&dev->vdev);
|
||||
VirtIOMEMClass *vmc = VIRTIO_MEM_GET_CLASS(vmem);
|
||||
|
||||
vmc->decide_memslots(vmem, limit);
|
||||
}
|
||||
|
||||
static unsigned int virtio_ccw_mem_get_memslots(MemoryDeviceState *md)
|
||||
{
|
||||
VirtIOMEMCcw *dev = VIRTIO_MEM_CCW(md);
|
||||
VirtIOMEM *vmem = VIRTIO_MEM(&dev->vdev);
|
||||
VirtIOMEMClass *vmc = VIRTIO_MEM_GET_CLASS(vmem);
|
||||
|
||||
return vmc->get_memslots(vmem);
|
||||
}
|
||||
|
||||
static uint64_t virtio_ccw_mem_get_plugged_size(const MemoryDeviceState *md,
|
||||
Error **errp)
|
||||
{
|
||||
return object_property_get_uint(OBJECT(md), VIRTIO_MEM_SIZE_PROP,
|
||||
errp);
|
||||
}
|
||||
|
||||
static void virtio_ccw_mem_fill_device_info(const MemoryDeviceState *md,
|
||||
MemoryDeviceInfo *info)
|
||||
{
|
||||
VirtioMEMDeviceInfo *vi = g_new0(VirtioMEMDeviceInfo, 1);
|
||||
VirtIOMEMCcw *dev = VIRTIO_MEM_CCW(md);
|
||||
VirtIOMEM *vmem = &dev->vdev;
|
||||
VirtIOMEMClass *vpc = VIRTIO_MEM_GET_CLASS(vmem);
|
||||
DeviceState *vdev = DEVICE(md);
|
||||
|
||||
if (vdev->id) {
|
||||
vi->id = g_strdup(vdev->id);
|
||||
}
|
||||
|
||||
/* let the real device handle everything else */
|
||||
vpc->fill_device_info(vmem, vi);
|
||||
|
||||
info->u.virtio_mem.data = vi;
|
||||
info->type = MEMORY_DEVICE_INFO_KIND_VIRTIO_MEM;
|
||||
}
|
||||
|
||||
static uint64_t virtio_ccw_mem_get_min_alignment(const MemoryDeviceState *md)
|
||||
{
|
||||
return object_property_get_uint(OBJECT(md), VIRTIO_MEM_BLOCK_SIZE_PROP,
|
||||
&error_abort);
|
||||
}
|
||||
|
||||
static void virtio_ccw_mem_size_change_notify(Notifier *notifier, void *data)
|
||||
{
|
||||
VirtIOMEMCcw *dev = container_of(notifier, VirtIOMEMCcw,
|
||||
size_change_notifier);
|
||||
DeviceState *vdev = DEVICE(dev);
|
||||
char *qom_path = object_get_canonical_path(OBJECT(dev));
|
||||
const uint64_t * const size_p = data;
|
||||
|
||||
qapi_event_send_memory_device_size_change(vdev->id, *size_p, qom_path);
|
||||
g_free(qom_path);
|
||||
}
|
||||
|
||||
static void virtio_ccw_mem_unplug_request_check(VirtIOMDCcw *vmd, Error **errp)
|
||||
{
|
||||
VirtIOMEMCcw *dev = VIRTIO_MEM_CCW(vmd);
|
||||
VirtIOMEM *vmem = &dev->vdev;
|
||||
VirtIOMEMClass *vpc = VIRTIO_MEM_GET_CLASS(vmem);
|
||||
|
||||
vpc->unplug_request_check(vmem, errp);
|
||||
}
|
||||
|
||||
static void virtio_ccw_mem_get_requested_size(Object *obj, Visitor *v,
|
||||
const char *name, void *opaque,
|
||||
Error **errp)
|
||||
{
|
||||
VirtIOMEMCcw *dev = VIRTIO_MEM_CCW(obj);
|
||||
|
||||
object_property_get(OBJECT(&dev->vdev), name, v, errp);
|
||||
}
|
||||
|
||||
static void virtio_ccw_mem_set_requested_size(Object *obj, Visitor *v,
|
||||
const char *name, void *opaque,
|
||||
Error **errp)
|
||||
{
|
||||
VirtIOMEMCcw *dev = VIRTIO_MEM_CCW(obj);
|
||||
DeviceState *vdev = DEVICE(obj);
|
||||
|
||||
/*
|
||||
* If we passed virtio_ccw_mem_unplug_request_check(), making sure that
|
||||
* the requested size is 0, don't allow modifying the requested size
|
||||
* anymore, otherwise the VM might end up hotplugging memory before
|
||||
* handling the unplug request.
|
||||
*/
|
||||
if (vdev->pending_deleted_event) {
|
||||
error_setg(errp, "'%s' cannot be changed if the device is in the"
|
||||
" process of unplug", name);
|
||||
return;
|
||||
}
|
||||
|
||||
object_property_set(OBJECT(&dev->vdev), name, v, errp);
|
||||
}
|
||||
|
||||
static const Property virtio_ccw_mem_properties[] = {
|
||||
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
|
||||
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
|
||||
DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
|
||||
VIRTIO_CCW_MAX_REV),
|
||||
};
|
||||
|
||||
static void virtio_ccw_mem_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
|
||||
MemoryDeviceClass *mdc = MEMORY_DEVICE_CLASS(klass);
|
||||
VirtIOMDCcwClass *vmdc = VIRTIO_MD_CCW_CLASS(klass);
|
||||
|
||||
k->realize = virtio_ccw_mem_realize;
|
||||
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
|
||||
device_class_set_props(dc, virtio_ccw_mem_properties);
|
||||
|
||||
mdc->get_addr = virtio_ccw_mem_get_addr;
|
||||
mdc->set_addr = virtio_ccw_mem_set_addr;
|
||||
mdc->get_plugged_size = virtio_ccw_mem_get_plugged_size;
|
||||
mdc->get_memory_region = virtio_ccw_mem_get_memory_region;
|
||||
mdc->decide_memslots = virtio_ccw_mem_decide_memslots;
|
||||
mdc->get_memslots = virtio_ccw_mem_get_memslots;
|
||||
mdc->fill_device_info = virtio_ccw_mem_fill_device_info;
|
||||
mdc->get_min_alignment = virtio_ccw_mem_get_min_alignment;
|
||||
|
||||
vmdc->unplug_request_check = virtio_ccw_mem_unplug_request_check;
|
||||
}
|
||||
|
||||
static void virtio_ccw_mem_instance_init(Object *obj)
|
||||
{
|
||||
VirtIOMEMCcw *dev = VIRTIO_MEM_CCW(obj);
|
||||
VirtIOMEMClass *vmc;
|
||||
VirtIOMEM *vmem;
|
||||
|
||||
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
|
||||
TYPE_VIRTIO_MEM);
|
||||
|
||||
dev->size_change_notifier.notify = virtio_ccw_mem_size_change_notify;
|
||||
vmem = &dev->vdev;
|
||||
vmc = VIRTIO_MEM_GET_CLASS(vmem);
|
||||
/*
|
||||
* We never remove the notifier again, as we expect both devices to
|
||||
* disappear at the same time.
|
||||
*/
|
||||
vmc->add_size_change_notifier(vmem, &dev->size_change_notifier);
|
||||
|
||||
object_property_add_alias(obj, VIRTIO_MEM_BLOCK_SIZE_PROP,
|
||||
OBJECT(&dev->vdev), VIRTIO_MEM_BLOCK_SIZE_PROP);
|
||||
object_property_add_alias(obj, VIRTIO_MEM_SIZE_PROP, OBJECT(&dev->vdev),
|
||||
VIRTIO_MEM_SIZE_PROP);
|
||||
object_property_add(obj, VIRTIO_MEM_REQUESTED_SIZE_PROP, "size",
|
||||
virtio_ccw_mem_get_requested_size,
|
||||
virtio_ccw_mem_set_requested_size, NULL, NULL);
|
||||
}
|
||||
|
||||
static const TypeInfo virtio_ccw_mem = {
|
||||
.name = TYPE_VIRTIO_MEM_CCW,
|
||||
.parent = TYPE_VIRTIO_MD_CCW,
|
||||
.instance_size = sizeof(VirtIOMEMCcw),
|
||||
.instance_init = virtio_ccw_mem_instance_init,
|
||||
.class_init = virtio_ccw_mem_class_init,
|
||||
};
|
||||
|
||||
static void virtio_ccw_mem_register_types(void)
|
||||
{
|
||||
type_register_static(&virtio_ccw_mem);
|
||||
}
|
||||
type_init(virtio_ccw_mem_register_types)
|
34
hw/s390x/virtio-ccw-mem.h
Normal file
34
hw/s390x/virtio-ccw-mem.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Virtio MEM CCW device
|
||||
*
|
||||
* Copyright (C) 2024 Red Hat, Inc.
|
||||
*
|
||||
* Authors:
|
||||
* David Hildenbrand <david@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef HW_S390X_VIRTIO_CCW_MEM_H
|
||||
#define HW_S390X_VIRTIO_CCW_MEM_H
|
||||
|
||||
#include "virtio-ccw-md.h"
|
||||
#include "hw/virtio/virtio-mem.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
typedef struct VirtIOMEMCcw VirtIOMEMCcw;
|
||||
|
||||
/*
|
||||
* virtio-mem-ccw: This extends VirtIOMDCcw
|
||||
*/
|
||||
#define TYPE_VIRTIO_MEM_CCW "virtio-mem-ccw"
|
||||
DECLARE_INSTANCE_CHECKER(VirtIOMEMCcw, VIRTIO_MEM_CCW, TYPE_VIRTIO_MEM_CCW)
|
||||
|
||||
struct VirtIOMEMCcw {
|
||||
VirtIOMDCcw parent_obj;
|
||||
VirtIOMEM vdev;
|
||||
Notifier size_change_notifier;
|
||||
};
|
||||
|
||||
#endif /* HW_S390X_VIRTIO_CCW_MEM_H */
|
|
@ -29,6 +29,7 @@ config VIRTIO_MMIO
|
|||
config VIRTIO_CCW
|
||||
bool
|
||||
select VIRTIO
|
||||
select VIRTIO_MD_SUPPORTED
|
||||
|
||||
config VIRTIO_BALLOON
|
||||
bool
|
||||
|
|
|
@ -61,6 +61,8 @@ static uint32_t virtio_mem_default_thp_size(void)
|
|||
} else if (qemu_real_host_page_size() == 64 * KiB) {
|
||||
default_thp_size = 512 * MiB;
|
||||
}
|
||||
#elif defined(__s390x__)
|
||||
default_thp_size = 1 * MiB;
|
||||
#endif
|
||||
|
||||
return default_thp_size;
|
||||
|
@ -168,7 +170,7 @@ static bool virtio_mem_has_shared_zeropage(RAMBlock *rb)
|
|||
* necessary (as the section size can change). But it's more likely that the
|
||||
* section size will rather get smaller and not bigger over time.
|
||||
*/
|
||||
#if defined(TARGET_X86_64) || defined(TARGET_I386)
|
||||
#if defined(TARGET_X86_64) || defined(TARGET_I386) || defined(TARGET_S390X)
|
||||
#define VIRTIO_MEM_USABLE_EXTENT (2 * (128 * MiB))
|
||||
#elif defined(TARGET_ARM)
|
||||
#define VIRTIO_MEM_USABLE_EXTENT (2 * (512 * MiB))
|
||||
|
@ -956,6 +958,7 @@ static void virtio_mem_device_realize(DeviceState *dev, Error **errp)
|
|||
VirtIOMEM *vmem = VIRTIO_MEM(dev);
|
||||
uint64_t page_size;
|
||||
RAMBlock *rb;
|
||||
Object *obj;
|
||||
int ret;
|
||||
|
||||
if (!vmem->memdev) {
|
||||
|
@ -1121,7 +1124,28 @@ static void virtio_mem_device_realize(DeviceState *dev, Error **errp)
|
|||
vmstate_register_any(VMSTATE_IF(vmem),
|
||||
&vmstate_virtio_mem_device_early, vmem);
|
||||
}
|
||||
qemu_register_resettable(OBJECT(vmem));
|
||||
|
||||
/*
|
||||
* We only want to unplug all memory to start with a clean slate when
|
||||
* it is safe for the guest -- during system resets that call
|
||||
* qemu_devices_reset().
|
||||
*
|
||||
* We'll filter out selected qemu_devices_reset() calls used for other
|
||||
* purposes, like resetting all devices during wakeup from suspend on
|
||||
* x86 based on the reset type passed to qemu_devices_reset().
|
||||
*
|
||||
* Unplugging all memory during simple device resets can result in the VM
|
||||
* unexpectedly losing RAM, corrupting VM state.
|
||||
*
|
||||
* Simple device resets (or resets triggered by getting a parent device
|
||||
* reset) must not change the state of plugged memory blocks. Therefore,
|
||||
* we need a dedicated reset object that only gets called during
|
||||
* qemu_devices_reset().
|
||||
*/
|
||||
obj = object_new(TYPE_VIRTIO_MEM_SYSTEM_RESET);
|
||||
vmem->system_reset = VIRTIO_MEM_SYSTEM_RESET(obj);
|
||||
vmem->system_reset->vmem = vmem;
|
||||
qemu_register_resettable(obj);
|
||||
|
||||
/*
|
||||
* Set ourselves as RamDiscardManager before the plug handler maps the
|
||||
|
@ -1141,7 +1165,10 @@ static void virtio_mem_device_unrealize(DeviceState *dev)
|
|||
* found via an address space anymore. Unset ourselves.
|
||||
*/
|
||||
memory_region_set_ram_discard_manager(&vmem->memdev->mr, NULL);
|
||||
qemu_unregister_resettable(OBJECT(vmem));
|
||||
|
||||
qemu_unregister_resettable(OBJECT(vmem->system_reset));
|
||||
object_unref(OBJECT(vmem->system_reset));
|
||||
|
||||
if (vmem->early_migration) {
|
||||
vmstate_unregister(VMSTATE_IF(vmem), &vmstate_virtio_mem_device_early,
|
||||
vmem);
|
||||
|
@ -1840,38 +1867,12 @@ static void virtio_mem_unplug_request_check(VirtIOMEM *vmem, Error **errp)
|
|||
}
|
||||
}
|
||||
|
||||
static ResettableState *virtio_mem_get_reset_state(Object *obj)
|
||||
{
|
||||
VirtIOMEM *vmem = VIRTIO_MEM(obj);
|
||||
return &vmem->reset_state;
|
||||
}
|
||||
|
||||
static void virtio_mem_system_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
VirtIOMEM *vmem = VIRTIO_MEM(obj);
|
||||
|
||||
/*
|
||||
* When waking up from standby/suspend-to-ram, do not unplug any memory.
|
||||
*/
|
||||
if (type == RESET_TYPE_WAKEUP) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* During usual resets, we will unplug all memory and shrink the usable
|
||||
* region size. This is, however, not possible in all scenarios. Then,
|
||||
* the guest has to deal with this manually (VIRTIO_MEM_REQ_UNPLUG_ALL).
|
||||
*/
|
||||
virtio_mem_unplug_all(vmem);
|
||||
}
|
||||
|
||||
static void virtio_mem_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
|
||||
VirtIOMEMClass *vmc = VIRTIO_MEM_CLASS(klass);
|
||||
RamDiscardManagerClass *rdmc = RAM_DISCARD_MANAGER_CLASS(klass);
|
||||
ResettableClass *rc = RESETTABLE_CLASS(klass);
|
||||
|
||||
device_class_set_props(dc, virtio_mem_properties);
|
||||
dc->vmsd = &vmstate_virtio_mem;
|
||||
|
@ -1898,9 +1899,6 @@ static void virtio_mem_class_init(ObjectClass *klass, void *data)
|
|||
rdmc->replay_discarded = virtio_mem_rdm_replay_discarded;
|
||||
rdmc->register_listener = virtio_mem_rdm_register_listener;
|
||||
rdmc->unregister_listener = virtio_mem_rdm_unregister_listener;
|
||||
|
||||
rc->get_state = virtio_mem_get_reset_state;
|
||||
rc->phases.hold = virtio_mem_system_reset_hold;
|
||||
}
|
||||
|
||||
static const TypeInfo virtio_mem_info = {
|
||||
|
@ -1923,3 +1921,48 @@ static void virtio_register_types(void)
|
|||
}
|
||||
|
||||
type_init(virtio_register_types)
|
||||
|
||||
OBJECT_DEFINE_SIMPLE_TYPE_WITH_INTERFACES(VirtioMemSystemReset, virtio_mem_system_reset, VIRTIO_MEM_SYSTEM_RESET, OBJECT, { TYPE_RESETTABLE_INTERFACE }, { })
|
||||
|
||||
static void virtio_mem_system_reset_init(Object *obj)
|
||||
{
|
||||
}
|
||||
|
||||
static void virtio_mem_system_reset_finalize(Object *obj)
|
||||
{
|
||||
}
|
||||
|
||||
static ResettableState *virtio_mem_system_reset_get_state(Object *obj)
|
||||
{
|
||||
VirtioMemSystemReset *vmem_reset = VIRTIO_MEM_SYSTEM_RESET(obj);
|
||||
|
||||
return &vmem_reset->reset_state;
|
||||
}
|
||||
|
||||
static void virtio_mem_system_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
VirtioMemSystemReset *vmem_reset = VIRTIO_MEM_SYSTEM_RESET(obj);
|
||||
VirtIOMEM *vmem = vmem_reset->vmem;
|
||||
|
||||
/*
|
||||
* When waking up from standby/suspend-to-ram, do not unplug any memory.
|
||||
*/
|
||||
if (type == RESET_TYPE_WAKEUP) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* During usual resets, we will unplug all memory and shrink the usable
|
||||
* region size. This is, however, not possible in all scenarios. Then,
|
||||
* the guest has to deal with this manually (VIRTIO_MEM_REQ_UNPLUG_ALL).
|
||||
*/
|
||||
virtio_mem_unplug_all(vmem);
|
||||
}
|
||||
|
||||
static void virtio_mem_system_reset_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
ResettableClass *rc = RESETTABLE_CLASS(klass);
|
||||
|
||||
rc->get_state = virtio_mem_system_reset_get_state;
|
||||
rc->phases.hold = virtio_mem_system_reset_hold;
|
||||
}
|
||||
|
|
|
@ -29,10 +29,19 @@ struct S390CcwMachineState {
|
|||
bool dea_key_wrap;
|
||||
bool pv;
|
||||
uint8_t loadparm[8];
|
||||
uint64_t memory_limit;
|
||||
uint64_t max_pagesize;
|
||||
|
||||
SCLPDevice *sclp;
|
||||
};
|
||||
|
||||
static inline uint64_t s390_get_memory_limit(S390CcwMachineState *s390ms)
|
||||
{
|
||||
/* We expect to be called only after the limit was set. */
|
||||
assert(s390ms->memory_limit);
|
||||
return s390ms->memory_limit;
|
||||
}
|
||||
|
||||
#define S390_PTF_REASON_NONE (0x00 << 8)
|
||||
#define S390_PTF_REASON_DONE (0x01 << 8)
|
||||
#define S390_PTF_REASON_BUSY (0x02 << 8)
|
||||
|
|
|
@ -25,6 +25,10 @@
|
|||
OBJECT_DECLARE_TYPE(VirtIOMEM, VirtIOMEMClass,
|
||||
VIRTIO_MEM)
|
||||
|
||||
#define TYPE_VIRTIO_MEM_SYSTEM_RESET "virtio-mem-system-reset"
|
||||
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(VirtioMemSystemReset, VIRTIO_MEM_SYSTEM_RESET)
|
||||
|
||||
#define VIRTIO_MEM_MEMDEV_PROP "memdev"
|
||||
#define VIRTIO_MEM_NODE_PROP "node"
|
||||
#define VIRTIO_MEM_SIZE_PROP "size"
|
||||
|
@ -117,8 +121,15 @@ struct VirtIOMEM {
|
|||
/* listeners to notify on plug/unplug activity. */
|
||||
QLIST_HEAD(, RamDiscardListener) rdl_list;
|
||||
|
||||
/* State of the resettable container */
|
||||
/* Catch system resets -> qemu_devices_reset() only. */
|
||||
VirtioMemSystemReset *system_reset;
|
||||
};
|
||||
|
||||
struct VirtioMemSystemReset {
|
||||
Object parent;
|
||||
|
||||
ResettableState reset_state;
|
||||
VirtIOMEM *vmem;
|
||||
};
|
||||
|
||||
struct VirtIOMEMClass {
|
||||
|
|
|
@ -255,21 +255,6 @@ unsigned int s390_cpu_set_state(uint8_t cpu_state, S390CPU *cpu)
|
|||
return s390_count_running_cpus();
|
||||
}
|
||||
|
||||
int s390_set_memory_limit(uint64_t new_limit, uint64_t *hw_limit)
|
||||
{
|
||||
if (kvm_enabled()) {
|
||||
return kvm_s390_set_mem_limit(new_limit, hw_limit);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void s390_set_max_pagesize(uint64_t pagesize, Error **errp)
|
||||
{
|
||||
if (kvm_enabled()) {
|
||||
kvm_s390_set_max_pagesize(pagesize, errp);
|
||||
}
|
||||
}
|
||||
|
||||
void s390_cmma_reset(void)
|
||||
{
|
||||
if (kvm_enabled()) {
|
||||
|
|
|
@ -881,8 +881,6 @@ static inline void s390_do_cpu_load_normal(CPUState *cs, run_on_cpu_data arg)
|
|||
|
||||
/* cpu.c */
|
||||
void s390_crypto_reset(void);
|
||||
int s390_set_memory_limit(uint64_t new_limit, uint64_t *hw_limit);
|
||||
void s390_set_max_pagesize(uint64_t pagesize, Error **errp);
|
||||
void s390_cmma_reset(void);
|
||||
void s390_enable_css_support(S390CPU *cpu);
|
||||
void s390_do_cpu_set_diag318(CPUState *cs, run_on_cpu_data arg);
|
||||
|
|
|
@ -49,8 +49,9 @@
|
|||
#include "hw/s390x/ebcdic.h"
|
||||
#include "exec/memattrs.h"
|
||||
#include "hw/s390x/s390-virtio-ccw.h"
|
||||
#include "hw/s390x/s390-virtio-hcall.h"
|
||||
#include "hw/s390x/s390-hypercall.h"
|
||||
#include "target/s390x/kvm/pv.h"
|
||||
#include CONFIG_DEVICES
|
||||
|
||||
#define kvm_vm_check_mem_attr(s, attr) \
|
||||
kvm_vm_check_attr(s, KVM_S390_VM_MEM_CTRL, attr)
|
||||
|
@ -1491,20 +1492,6 @@ static int handle_e3(S390CPU *cpu, struct kvm_run *run, uint8_t ipbl)
|
|||
return r;
|
||||
}
|
||||
|
||||
static int handle_hypercall(S390CPU *cpu, struct kvm_run *run)
|
||||
{
|
||||
CPUS390XState *env = &cpu->env;
|
||||
int ret;
|
||||
|
||||
ret = s390_virtio_hypercall(env);
|
||||
if (ret == -EINVAL) {
|
||||
kvm_s390_program_interrupt(cpu, PGM_SPECIFICATION);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void kvm_handle_diag_288(S390CPU *cpu, struct kvm_run *run)
|
||||
{
|
||||
uint64_t r1, r3;
|
||||
|
@ -1600,9 +1587,11 @@ static int handle_diag(S390CPU *cpu, struct kvm_run *run, uint32_t ipb)
|
|||
case DIAG_SET_CONTROL_PROGRAM_CODES:
|
||||
handle_diag_318(cpu, run);
|
||||
break;
|
||||
#ifdef CONFIG_S390_CCW_VIRTIO
|
||||
case DIAG_KVM_HYPERCALL:
|
||||
r = handle_hypercall(cpu, run);
|
||||
handle_diag_500(cpu, RA_IGNORED);
|
||||
break;
|
||||
#endif /* CONFIG_S390_CCW_VIRTIO */
|
||||
case DIAG_KVM_BREAKPOINT:
|
||||
r = handle_sw_breakpoint(cpu, run);
|
||||
break;
|
||||
|
|
|
@ -133,7 +133,7 @@ bool s390_pv_vm_try_disable_async(S390CcwMachineState *ms)
|
|||
* If the feature is not present or if the VM is not larger than 2 GiB,
|
||||
* KVM_PV_ASYNC_CLEANUP_PREPARE fill fail; no point in attempting it.
|
||||
*/
|
||||
if ((MACHINE(ms)->maxram_size <= 2 * GiB) ||
|
||||
if (s390_get_memory_limit(ms) <= 2 * GiB ||
|
||||
!kvm_check_extension(kvm_state, KVM_CAP_S390_PROTECTED_ASYNC_DISABLE)) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -36,13 +36,14 @@
|
|||
#include "system/cpus.h"
|
||||
#include "system/system.h"
|
||||
#include "hw/s390x/ebcdic.h"
|
||||
#include "hw/s390x/s390-virtio-hcall.h"
|
||||
#include "hw/s390x/s390-hypercall.h"
|
||||
#include "hw/s390x/sclp.h"
|
||||
#include "hw/s390x/s390_flic.h"
|
||||
#include "hw/s390x/ioinst.h"
|
||||
#include "hw/s390x/s390-pci-inst.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/s390x/tod.h"
|
||||
#include CONFIG_DEVICES
|
||||
#endif
|
||||
|
||||
/* #define DEBUG_HELPER */
|
||||
|
@ -116,12 +117,15 @@ void HELPER(diag)(CPUS390XState *env, uint32_t r1, uint32_t r3, uint32_t num)
|
|||
uint64_t r;
|
||||
|
||||
switch (num) {
|
||||
#ifdef CONFIG_S390_CCW_VIRTIO
|
||||
case 0x500:
|
||||
/* KVM hypercall */
|
||||
/* QEMU/KVM hypercall */
|
||||
bql_lock();
|
||||
r = s390_virtio_hypercall(env);
|
||||
handle_diag_500(env_archcpu(env), GETPC());
|
||||
bql_unlock();
|
||||
r = 0;
|
||||
break;
|
||||
#endif /* CONFIG_S390_CCW_VIRTIO */
|
||||
case 0x44:
|
||||
/* yield */
|
||||
r = 0;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue