- update Linux headers to 5.7-rc3 (and virtio-net fixup)

- support for protected virtualization aka secure execution
 -----BEGIN PGP SIGNATURE-----
 
 iQJGBAABCAAwFiEEw9DWbcNiT/aowBjO3s9rk8bwL68FAl6qnUsSHGNvaHVja0By
 ZWRoYXQuY29tAAoJEN7Pa5PG8C+vTXYP/ilclCvbjJzpvOgAi7SIrK7E/lI3ARS6
 N0sTNCCgAbjd6SYWLje/eNPSMnOTtZRcryjk3kfy1jwU5KTCh51RNa6xHfXY3vN5
 ScC8YrLp5Tr+CHBZq6j3JAz+gAbvOTPqalkNwjhG1AY5Vl8jtZ2Qd5NSxkdoWCiI
 jQJ0v8zwEZAAthlGbMqpyDZjOoMCqiOnuwnHu8VfG8DE3bkigVZvlO1rObtZxD5H
 EgLurkVFk2NpxHTPMt+HsU/fIS7WVuhfnJIhnICOqWNp7juB4jrZke31NIXHOUcf
 fdMF+SSzopsAr8urGFmO8uSIlY5zl8BDDfTznTSIuyaZ1P4Y336riEM0U0cCyO28
 4ObMQ5CgwYhjGvbIbhA+HEEFn9KQZRJk6QJTZI6nPIYrCkYO9ZbGVAutrtP7uei6
 MUGW05Yt1qZ/g1FmoeRetgcU3KXacDo8T6UedlwWiSP/lDwiPak6snHoXJShb3mw
 0z2zlQVRhlZrA1fpzWogfslWohM4CrEtAnCjLy7ng3y/E/CIlEu2V7I2BKbNPa22
 KehcqPqkqa/wmEkxY56yXOxZIchA51PqWa9EVjaLkac0t0JH5WJt99SpbLQ/SRll
 WN8Z2BP4Usri1s/PHN1l+WXaJydMvpsWlhLpGpmQRuMpKI5l7Gyfzj8zvM4/9iXK
 hc2D5Ao1Fufu
 =iKIk
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/cohuck/tags/s390x-20200430' into staging

- update Linux headers to 5.7-rc3 (and virtio-net fixup)
- support for protected virtualization aka secure execution

# gpg: Signature made Thu 30 Apr 2020 10:41:31 BST
# gpg:                using RSA key C3D0D66DC3624FF6A8C018CEDECF6B93C6F02FAF
# gpg:                issuer "cohuck@redhat.com"
# gpg: Good signature from "Cornelia Huck <conny@cornelia-huck.de>" [marginal]
# gpg:                 aka "Cornelia Huck <huckc@linux.vnet.ibm.com>" [full]
# gpg:                 aka "Cornelia Huck <cornelia.huck@de.ibm.com>" [full]
# gpg:                 aka "Cornelia Huck <cohuck@kernel.org>" [marginal]
# gpg:                 aka "Cornelia Huck <cohuck@redhat.com>" [marginal]
# Primary key fingerprint: C3D0 D66D C362 4FF6 A8C0  18CE DECF 6B93 C6F0 2FAF

* remotes/cohuck/tags/s390x-20200430:
  s390x/s390-virtio-ccw: Fix build on systems without KVM
  s390x/pv: Retry ioctls on -EINTR
  s390x: protvirt: Fix stray error_report_err in s390_machine_protect
  s390x: Add unpack facility feature to GA1
  docs: system: Add protvirt docs
  s390x: protvirt: Handle SIGP store status correctly
  s390x: protvirt: Move IO control structures over SIDA
  s390x: protvirt: Disable address checks for PV guest IO emulation
  s390x: protvirt: Move diag 308 data over SIDA
  s390x: protvirt: Set guest IPL PSW
  s390x: protvirt: SCLP interpretation
  s390x: protvirt: Move STSI data over SIDAD
  s390x: Add SIDA memory ops
  s390x: protvirt: KVM intercept changes
  s390x: protvirt: Inhibit balloon when switching to protected mode
  s390x: protvirt: Add migration blocker
  s390x: protvirt: Support unpack facility
  s390x: Move diagnose 308 subcodes and rcs into ipl.h
  linux-headers: update against Linux 5.7-rc3
  virtio-net: fix rsc_ext compat handling

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2020-04-30 14:00:36 +01:00
commit 16aaacb307
41 changed files with 1118 additions and 100 deletions

View File

@ -396,6 +396,8 @@ F: target/s390x/machine.c
F: target/s390x/sigp.c
F: target/s390x/cpu_features*.[ch]
F: target/s390x/cpu_models.[ch]
F: hw/s390x/pv.c
F: include/hw/s390x/pv.h
F: hw/intc/s390_flic.c
F: hw/intc/s390_flic_kvm.c
F: include/hw/s390x/s390_flic.h

View File

@ -0,0 +1,60 @@
Protected Virtualization on s390x
=================================
The memory and most of the registers of Protected Virtual Machines
(PVMs) are encrypted or inaccessible to the hypervisor, effectively
prohibiting VM introspection when the VM is running. At rest, PVMs are
encrypted and can only be decrypted by the firmware, represented by an
entity called Ultravisor, of specific IBM Z machines.
Prerequisites
-------------
To run PVMs, a machine with the Protected Virtualization feature, as
indicated by the Ultravisor Call facility (stfle bit 158), is
required. The Ultravisor needs to be initialized at boot by setting
`prot_virt=1` on the host's kernel command line.
Running PVMs requires using the KVM hypervisor.
If those requirements are met, the capability `KVM_CAP_S390_PROTECTED`
will indicate that KVM can support PVMs on that LPAR.
QEMU Settings
-------------
To indicate to the VM that it can transition into protected mode, the
`Unpack facility` (stfle bit 161 represented by the feature
`unpack`/`S390_FEAT_UNPACK`) needs to be part of the cpu model of
the VM.
All I/O devices need to use the IOMMU.
Passthrough (vfio) devices are currently not supported.
Host huge page backings are not supported. However guests can use huge
pages as indicated by its facilities.
Boot Process
------------
A secure guest image can either be loaded from disk or supplied on the
QEMU command line. Booting from disk is done by the unmodified
s390-ccw BIOS. I.e., the bootmap is interpreted, multiple components
are read into memory and control is transferred to one of the
components (zipl stage3). Stage3 does some fixups and then transfers
control to some program residing in guest memory, which is normally
the OS kernel. The secure image has another component prepended
(stage3a) that uses the new diag308 subcodes 8 and 10 to trigger the
transition into secure mode.
Booting from the image supplied on the QEMU command line requires that
the file passed via -kernel has the same memory layout as would result
from the disk boot. This memory layout includes the encrypted
components (kernel, initrd, cmdline), the stage3a loader and
metadata. In case this boot method is used, the command line
options -initrd and -cmdline are ineffective. The preparation of a PVM
image is done via the `genprotimg` tool from the s390-tools
collection.

View File

@ -24,3 +24,8 @@ or vfio-ap is also available.
.. toctree::
s390x/vfio-ap
Architectural features
======================
.. toctree::
s390x/protvirt

View File

@ -83,6 +83,8 @@
#define VIRTIO_NET_HDR_F_RSC_INFO 4 /* rsc_ext data in csum_ fields */
#define VIRTIO_NET_F_RSC_EXT 61
#endif
static inline __virtio16 *virtio_net_rsc_ext_num_packets(
struct virtio_net_hdr *hdr)
{
@ -95,8 +97,6 @@ static inline __virtio16 *virtio_net_rsc_ext_num_dupacks(
return &hdr->csum_offset;
}
#endif
static VirtIOFeature feature_sizes[] = {
{.flags = 1ULL << VIRTIO_NET_F_MAC,
.end = endof(struct virtio_net_config, mac)},

View File

@ -31,6 +31,7 @@ obj-y += tod-qemu.o
obj-$(CONFIG_KVM) += tod-kvm.o
obj-$(CONFIG_KVM) += s390-skeys-kvm.o
obj-$(CONFIG_KVM) += s390-stattrib-kvm.o
obj-$(CONFIG_KVM) += pv.o
obj-y += s390-ccw.o
obj-y += ap-device.o
obj-y += ap-bridge.o

View File

@ -1,10 +1,11 @@
/*
* bootloader support
*
* Copyright IBM, Corp. 2012
* Copyright IBM, Corp. 2012, 2020
*
* Authors:
* Christian Borntraeger <borntraeger@de.ibm.com>
* Janosch Frank <frankja@linux.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.
@ -27,6 +28,7 @@
#include "hw/s390x/vfio-ccw.h"
#include "hw/s390x/css.h"
#include "hw/s390x/ebcdic.h"
#include "hw/s390x/pv.h"
#include "ipl.h"
#include "qemu/error-report.h"
#include "qemu/config-file.h"
@ -566,12 +568,31 @@ void s390_ipl_update_diag308(IplParameterBlock *iplb)
{
S390IPLState *ipl = get_ipl_device();
ipl->iplb = *iplb;
ipl->iplb_valid = true;
/*
* The IPLB set and retrieved by subcodes 8/9 is completely
* separate from the one managed via subcodes 5/6.
*/
if (iplb->pbt == S390_IPL_TYPE_PV) {
ipl->iplb_pv = *iplb;
ipl->iplb_valid_pv = true;
} else {
ipl->iplb = *iplb;
ipl->iplb_valid = true;
}
ipl->netboot = is_virtio_net_device(iplb);
update_machine_ipl_properties(iplb);
}
IplParameterBlock *s390_ipl_get_iplb_pv(void)
{
S390IPLState *ipl = get_ipl_device();
if (!ipl->iplb_valid_pv) {
return NULL;
}
return &ipl->iplb_pv;
}
IplParameterBlock *s390_ipl_get_iplb(void)
{
S390IPLState *ipl = get_ipl_device();
@ -660,6 +681,38 @@ static void s390_ipl_prepare_qipl(S390CPU *cpu)
cpu_physical_memory_unmap(addr, len, 1, len);
}
int s390_ipl_prepare_pv_header(void)
{
IplParameterBlock *ipib = s390_ipl_get_iplb_pv();
IPLBlockPV *ipib_pv = &ipib->pv;
void *hdr = g_malloc(ipib_pv->pv_header_len);
int rc;
cpu_physical_memory_read(ipib_pv->pv_header_addr, hdr,
ipib_pv->pv_header_len);
rc = s390_pv_set_sec_parms((uintptr_t)hdr,
ipib_pv->pv_header_len);
g_free(hdr);
return rc;
}
int s390_ipl_pv_unpack(void)
{
IplParameterBlock *ipib = s390_ipl_get_iplb_pv();
IPLBlockPV *ipib_pv = &ipib->pv;
int i, rc = 0;
for (i = 0; i < ipib_pv->num_comp; i++) {
rc = s390_pv_unpack(ipib_pv->components[i].addr,
TARGET_PAGE_ALIGN(ipib_pv->components[i].size),
ipib_pv->components[i].tweak_pref);
if (rc) {
break;
}
}
return rc;
}
void s390_ipl_prepare_cpu(S390CPU *cpu)
{
S390IPLState *ipl = get_ipl_device();

View File

@ -1,8 +1,9 @@
/*
* s390 IPL device
*
* Copyright 2015 IBM Corp.
* Copyright 2015, 2020 IBM Corp.
* Author(s): Zhang Fan <bjfanzh@cn.ibm.com>
* Janosch Frank <frankja@linux.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
@ -13,8 +14,27 @@
#define HW_S390_IPL_H
#include "cpu.h"
#include "exec/address-spaces.h"
#include "hw/qdev-core.h"
struct IPLBlockPVComp {
uint64_t tweak_pref;
uint64_t addr;
uint64_t size;
} QEMU_PACKED;
typedef struct IPLBlockPVComp IPLBlockPVComp;
struct IPLBlockPV {
uint8_t reserved18[87]; /* 0x18 */
uint8_t version; /* 0x6f */
uint32_t reserved70; /* 0x70 */
uint32_t num_comp; /* 0x74 */
uint64_t pv_header_addr; /* 0x78 */
uint64_t pv_header_len; /* 0x80 */
struct IPLBlockPVComp components[];
} QEMU_PACKED;
typedef struct IPLBlockPV IPLBlockPV;
struct IplBlockCcw {
uint8_t reserved0[85];
uint8_t ssid;
@ -71,6 +91,7 @@ union IplParameterBlock {
union {
IplBlockCcw ccw;
IplBlockFcp fcp;
IPLBlockPV pv;
IplBlockQemuScsi scsi;
};
} QEMU_PACKED;
@ -85,8 +106,11 @@ typedef union IplParameterBlock IplParameterBlock;
int s390_ipl_set_loadparm(uint8_t *loadparm);
void s390_ipl_update_diag308(IplParameterBlock *iplb);
int s390_ipl_prepare_pv_header(void);
int s390_ipl_pv_unpack(void);
void s390_ipl_prepare_cpu(S390CPU *cpu);
IplParameterBlock *s390_ipl_get_iplb(void);
IplParameterBlock *s390_ipl_get_iplb_pv(void);
enum s390_reset {
/* default is a reset not triggered by a CPU e.g. issued by QMP */
@ -94,6 +118,7 @@ enum s390_reset {
S390_RESET_REIPL,
S390_RESET_MODIFIED_CLEAR,
S390_RESET_LOAD_NORMAL,
S390_RESET_PV,
};
void s390_ipl_reset_request(CPUState *cs, enum s390_reset reset_type);
void s390_ipl_get_reset_request(CPUState **cs, enum s390_reset *reset_type);
@ -133,6 +158,7 @@ struct S390IPLState {
/*< private >*/
DeviceState parent_obj;
IplParameterBlock iplb;
IplParameterBlock iplb_pv;
QemuIplParameters qipl;
uint64_t start_addr;
uint64_t compat_start_addr;
@ -140,6 +166,7 @@ struct S390IPLState {
uint64_t compat_bios_start_addr;
bool enforce_bios;
bool iplb_valid;
bool iplb_valid_pv;
bool netboot;
/* reset related properties don't have to be migrated or reset */
enum s390_reset reset_type;
@ -159,11 +186,29 @@ struct S390IPLState {
typedef struct S390IPLState S390IPLState;
QEMU_BUILD_BUG_MSG(offsetof(S390IPLState, iplb) & 3, "alignment of iplb wrong");
#define DIAG_308_RC_OK 0x0001
#define DIAG_308_RC_NO_CONF 0x0102
#define DIAG_308_RC_INVALID 0x0402
#define DIAG_308_RC_NO_PV_CONF 0x0902
#define DIAG_308_RC_INVAL_FOR_PV 0x0a02
#define DIAG308_RESET_MOD_CLR 0
#define DIAG308_RESET_LOAD_NORM 1
#define DIAG308_LOAD_CLEAR 3
#define DIAG308_LOAD_NORMAL_DUMP 4
#define DIAG308_SET 5
#define DIAG308_STORE 6
#define DIAG308_PV_SET 8
#define DIAG308_PV_STORE 9
#define DIAG308_PV_START 10
#define S390_IPL_TYPE_FCP 0x00
#define S390_IPL_TYPE_CCW 0x02
#define S390_IPL_TYPE_PV 0x05
#define S390_IPL_TYPE_QEMU_SCSI 0xff
#define S390_IPLB_HEADER_LEN 8
#define S390_IPLB_MIN_PV_LEN 148
#define S390_IPLB_MIN_CCW_LEN 200
#define S390_IPLB_MIN_FCP_LEN 384
#define S390_IPLB_MIN_QEMU_SCSI_LEN 200
@ -173,6 +218,62 @@ static inline bool iplb_valid_len(IplParameterBlock *iplb)
return be32_to_cpu(iplb->len) <= sizeof(IplParameterBlock);
}
static inline bool ipl_valid_pv_components(IplParameterBlock *iplb)
{
IPLBlockPV *ipib_pv = &iplb->pv;
int i;
if (ipib_pv->num_comp == 0) {
return false;
}
for (i = 0; i < ipib_pv->num_comp; i++) {
/* Addr must be 4k aligned */
if (ipib_pv->components[i].addr & ~TARGET_PAGE_MASK) {
return false;
}
/* Tweak prefix is monotonically increasing with each component */
if (i < ipib_pv->num_comp - 1 &&
ipib_pv->components[i].tweak_pref >=
ipib_pv->components[i + 1].tweak_pref) {
return false;
}
}
return true;
}
static inline bool ipl_valid_pv_header(IplParameterBlock *iplb)
{
IPLBlockPV *ipib_pv = &iplb->pv;
if (ipib_pv->pv_header_len > 2 * TARGET_PAGE_SIZE) {
return false;
}
if (!address_space_access_valid(&address_space_memory,
ipib_pv->pv_header_addr,
ipib_pv->pv_header_len,
false,
MEMTXATTRS_UNSPECIFIED)) {
return false;
}
return true;
}
static inline bool iplb_valid_pv(IplParameterBlock *iplb)
{
if (iplb->pbt != S390_IPL_TYPE_PV ||
be32_to_cpu(iplb->len) < S390_IPLB_MIN_PV_LEN) {
return false;
}
if (!ipl_valid_pv_header(iplb)) {
return false;
}
return ipl_valid_pv_components(iplb);
}
static inline bool iplb_valid(IplParameterBlock *iplb)
{
switch (iplb->pbt) {

113
hw/s390x/pv.c Normal file
View File

@ -0,0 +1,113 @@
/*
* Protected Virtualization functions
*
* Copyright IBM Corp. 2020
* Author(s):
* Janosch Frank <frankja@linux.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 <linux/kvm.h>
#include "cpu.h"
#include "qemu/error-report.h"
#include "sysemu/kvm.h"
#include "hw/s390x/ipl.h"
#include "hw/s390x/pv.h"
static int __s390_pv_cmd(uint32_t cmd, const char *cmdname, void *data)
{
struct kvm_pv_cmd pv_cmd = {
.cmd = cmd,
.data = (uint64_t)data,
};
int rc;
do {
rc = kvm_vm_ioctl(kvm_state, KVM_S390_PV_COMMAND, &pv_cmd);
} while (rc == -EINTR);
if (rc) {
error_report("KVM PV command %d (%s) failed: header rc %x rrc %x "
"IOCTL rc: %d", cmd, cmdname, pv_cmd.rc, pv_cmd.rrc,
rc);
}
return rc;
}
/*
* This macro lets us pass the command as a string to the function so
* we can print it on an error.
*/
#define s390_pv_cmd(cmd, data) __s390_pv_cmd(cmd, #cmd, data);
#define s390_pv_cmd_exit(cmd, data) \
{ \
int rc; \
\
rc = __s390_pv_cmd(cmd, #cmd, data);\
if (rc) { \
exit(1); \
} \
}
int s390_pv_vm_enable(void)
{
return s390_pv_cmd(KVM_PV_ENABLE, NULL);
}
void s390_pv_vm_disable(void)
{
s390_pv_cmd_exit(KVM_PV_DISABLE, NULL);
}
int s390_pv_set_sec_parms(uint64_t origin, uint64_t length)
{
struct kvm_s390_pv_sec_parm args = {
.origin = origin,
.length = length,
};
return s390_pv_cmd(KVM_PV_SET_SEC_PARMS, &args);
}
/*
* Called for each component in the SE type IPL parameter block 0.
*/
int s390_pv_unpack(uint64_t addr, uint64_t size, uint64_t tweak)
{
struct kvm_s390_pv_unp args = {
.addr = addr,
.size = size,
.tweak = tweak,
};
return s390_pv_cmd(KVM_PV_UNPACK, &args);
}
void s390_pv_perf_clear_reset(void)
{
s390_pv_cmd_exit(KVM_PV_PREP_RESET, NULL);
}
int s390_pv_verify(void)
{
return s390_pv_cmd(KVM_PV_VERIFY, NULL);
}
void s390_pv_unshare(void)
{
s390_pv_cmd_exit(KVM_PV_UNSHARE_ALL, NULL);
}
void s390_pv_inject_reset_error(CPUState *cs)
{
int r1 = (cs->kvm_run->s390_sieic.ipa & 0x00f0) >> 4;
CPUS390XState *env = &S390_CPU(cs)->env;
/* Report that we are unable to enter protected mode */
env->regs[r1 + 1] = DIAG_308_RC_INVAL_FOR_PV;
}

View File

@ -1,9 +1,10 @@
/*
* virtio ccw machine
*
* Copyright 2012 IBM Corp.
* Copyright 2012, 2020 IBM Corp.
* Copyright (c) 2009 Alexander Graf <agraf@suse.de>
* Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
* Janosch Frank <frankja@linux.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
@ -42,6 +43,11 @@
#include "hw/qdev-properties.h"
#include "hw/s390x/tod.h"
#include "sysemu/sysemu.h"
#include "sysemu/balloon.h"
#include "hw/s390x/pv.h"
#include "migration/blocker.h"
static Error *pv_mig_blocker;
S390CPU *s390_cpu_addr2state(uint16_t cpu_addr)
{
@ -317,10 +323,93 @@ static inline void s390_do_cpu_ipl(CPUState *cs, run_on_cpu_data arg)
s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu);
}
static void s390_machine_unprotect(S390CcwMachineState *ms)
{
s390_pv_vm_disable();
ms->pv = false;
migrate_del_blocker(pv_mig_blocker);
error_free_or_abort(&pv_mig_blocker);
qemu_balloon_inhibit(false);
}
static int s390_machine_protect(S390CcwMachineState *ms)
{
Error *local_err = NULL;
int rc;
/*
* Ballooning on protected VMs needs support in the guest for
* sharing and unsharing balloon pages. Block ballooning for
* now, until we have a solution to make at least Linux guests
* either support it or fail gracefully.
*/
qemu_balloon_inhibit(true);
error_setg(&pv_mig_blocker,
"protected VMs are currently not migrateable.");
rc = migrate_add_blocker(pv_mig_blocker, &local_err);
if (rc) {
qemu_balloon_inhibit(false);
error_report_err(local_err);
error_free_or_abort(&pv_mig_blocker);
return rc;
}
/* Create SE VM */
rc = s390_pv_vm_enable();
if (rc) {
qemu_balloon_inhibit(false);
migrate_del_blocker(pv_mig_blocker);
error_free_or_abort(&pv_mig_blocker);
return rc;
}
ms->pv = true;
/* Set SE header and unpack */
rc = s390_ipl_prepare_pv_header();
if (rc) {
goto out_err;
}
/* Decrypt image */
rc = s390_ipl_pv_unpack();
if (rc) {
goto out_err;
}
/* Verify integrity */
rc = s390_pv_verify();
if (rc) {
goto out_err;
}
return rc;
out_err:
s390_machine_unprotect(ms);
return rc;
}
static void s390_pv_prepare_reset(S390CcwMachineState *ms)
{
CPUState *cs;
if (!s390_is_pv()) {
return;
}
/* Unsharing requires all cpus to be stopped */
CPU_FOREACH(cs) {
s390_cpu_set_state(S390_CPU_STATE_STOPPED, S390_CPU(cs));
}
s390_pv_unshare();
s390_pv_perf_clear_reset();
}
static void s390_machine_reset(MachineState *machine)
{
S390CcwMachineState *ms = S390_CCW_MACHINE(machine);
enum s390_reset reset_type;
CPUState *cs, *t;
S390CPU *cpu;
/* get the reset parameters, reset them once done */
s390_ipl_get_reset_request(&cs, &reset_type);
@ -328,9 +417,15 @@ static void s390_machine_reset(MachineState *machine)
/* all CPUs are paused and synchronized at this point */
s390_cmma_reset();
cpu = S390_CPU(cs);
switch (reset_type) {
case S390_RESET_EXTERNAL:
case S390_RESET_REIPL:
if (s390_is_pv()) {
s390_machine_unprotect(ms);
}
qemu_devices_reset();
s390_crypto_reset();
@ -338,22 +433,56 @@ static void s390_machine_reset(MachineState *machine)
run_on_cpu(cs, s390_do_cpu_ipl, RUN_ON_CPU_NULL);
break;
case S390_RESET_MODIFIED_CLEAR:
/*
* Susbsystem reset needs to be done before we unshare memory
* and lose access to VIRTIO structures in guest memory.
*/
subsystem_reset();
s390_crypto_reset();
s390_pv_prepare_reset(ms);
CPU_FOREACH(t) {
run_on_cpu(t, s390_do_cpu_full_reset, RUN_ON_CPU_NULL);
}
subsystem_reset();
s390_crypto_reset();
run_on_cpu(cs, s390_do_cpu_load_normal, RUN_ON_CPU_NULL);
break;
case S390_RESET_LOAD_NORMAL:
/*
* Susbsystem reset needs to be done before we unshare memory
* and lose access to VIRTIO structures in guest memory.
*/
subsystem_reset();
s390_pv_prepare_reset(ms);
CPU_FOREACH(t) {
if (t == cs) {
continue;
}
run_on_cpu(t, s390_do_cpu_reset, RUN_ON_CPU_NULL);
}
subsystem_reset();
run_on_cpu(cs, s390_do_cpu_initial_reset, RUN_ON_CPU_NULL);
run_on_cpu(cs, s390_do_cpu_load_normal, RUN_ON_CPU_NULL);
break;
case S390_RESET_PV: /* Subcode 10 */
subsystem_reset();
s390_crypto_reset();
CPU_FOREACH(t) {
if (t == cs) {
continue;
}
run_on_cpu(t, s390_do_cpu_full_reset, RUN_ON_CPU_NULL);
}
run_on_cpu(cs, s390_do_cpu_reset, RUN_ON_CPU_NULL);
if (s390_machine_protect(ms)) {
s390_pv_inject_reset_error(cs);
/*
* Continue after the diag308 so the guest knows something
* went wrong.
*/
s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu);
return;
}
run_on_cpu(cs, s390_do_cpu_load_normal, RUN_ON_CPU_NULL);
break;
default:

View File

@ -33,6 +33,22 @@ static inline SCLPDevice *get_sclp_device(void)
return sclp;
}
static inline bool sclp_command_code_valid(uint32_t code)
{
switch (code & SCLP_CMD_CODE_MASK) {
case SCLP_CMDW_READ_SCP_INFO:
case SCLP_CMDW_READ_SCP_INFO_FORCED:
case SCLP_CMDW_READ_CPU_INFO:
case SCLP_CMDW_CONFIGURE_IOA:
case SCLP_CMDW_DECONFIGURE_IOA:
case SCLP_CMD_READ_EVENT_DATA:
case SCLP_CMD_WRITE_EVENT_DATA:
case SCLP_CMD_WRITE_EVENT_MASK:
return true;
}
return false;
}
static void prepare_cpu_entries(SCLPDevice *sclp, CPUEntry *entry, int *count)
{
MachineState *ms = MACHINE(qdev_get_machine());
@ -193,6 +209,34 @@ static void sclp_execute(SCLPDevice *sclp, SCCB *sccb, uint32_t code)
}
}
/*
* We only need the address to have something valid for the
* service_interrupt call.
*/
#define SCLP_PV_DUMMY_ADDR 0x4000
int sclp_service_call_protected(CPUS390XState *env, uint64_t sccb,
uint32_t code)
{
SCLPDevice *sclp = get_sclp_device();
SCLPDeviceClass *sclp_c = SCLP_GET_CLASS(sclp);
SCCB work_sccb;
hwaddr sccb_len = sizeof(SCCB);
s390_cpu_pv_mem_read(env_archcpu(env), 0, &work_sccb, sccb_len);
if (!sclp_command_code_valid(code)) {
work_sccb.h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND);
goto out_write;
}
sclp_c->execute(sclp, &work_sccb, code);
out_write:
s390_cpu_pv_mem_write(env_archcpu(env), 0, &work_sccb,
be16_to_cpu(work_sccb.h.length));
sclp_c->service_interrupt(sclp, SCLP_PV_DUMMY_ADDR);
return 0;
}
int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code)
{
SCLPDevice *sclp = get_sclp_device();
@ -225,17 +269,7 @@ int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code)
return -PGM_SPECIFICATION;
}
switch (code & SCLP_CMD_CODE_MASK) {
case SCLP_CMDW_READ_SCP_INFO:
case SCLP_CMDW_READ_SCP_INFO_FORCED:
case SCLP_CMDW_READ_CPU_INFO:
case SCLP_CMDW_CONFIGURE_IOA:
case SCLP_CMDW_DECONFIGURE_IOA:
case SCLP_CMD_READ_EVENT_DATA:
case SCLP_CMD_WRITE_EVENT_DATA:
case SCLP_CMD_WRITE_EVENT_MASK:
break;
default:
if (!sclp_command_code_valid(code)) {
work_sccb.h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND);
goto out_write;
}

58
include/hw/s390x/pv.h Normal file
View File

@ -0,0 +1,58 @@
/*
* Protected Virtualization header
*
* Copyright IBM Corp. 2020
* Author(s):
* Janosch Frank <frankja@linux.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_PV_H
#define HW_S390_PV_H
#ifdef CONFIG_KVM
#include "cpu.h"
#include "hw/s390x/s390-virtio-ccw.h"
static inline bool s390_is_pv(void)
{
static S390CcwMachineState *ccw;
Object *obj;
if (ccw) {
return ccw->pv;
}
/* we have to bail out for the "none" machine */
obj = object_dynamic_cast(qdev_get_machine(),
TYPE_S390_CCW_MACHINE);
if (!obj) {
return false;
}
ccw = S390_CCW_MACHINE(obj);
return ccw->pv;
}
int s390_pv_vm_enable(void);
void s390_pv_vm_disable(void);
int s390_pv_set_sec_parms(uint64_t origin, uint64_t length);
int s390_pv_unpack(uint64_t addr, uint64_t size, uint64_t tweak);
void s390_pv_perf_clear_reset(void);
int s390_pv_verify(void);
void s390_pv_unshare(void);
void s390_pv_inject_reset_error(CPUState *cs);
#else /* CONFIG_KVM */
static inline bool s390_is_pv(void) { return false; }
static inline int s390_pv_vm_enable(void) { return 0; }
static inline void s390_pv_vm_disable(void) {}
static inline int s390_pv_set_sec_parms(uint64_t origin, uint64_t length) { return 0; }
static inline int s390_pv_unpack(uint64_t addr, uint64_t size, uint64_t tweak) { return 0; }
static inline void s390_pv_perf_clear_reset(void) {}
static inline int s390_pv_verify(void) { return 0; }
static inline void s390_pv_unshare(void) {}
static inline void s390_pv_inject_reset_error(CPUState *cs) {};
#endif /* CONFIG_KVM */
#endif /* HW_S390_PV_H */

View File

@ -28,6 +28,7 @@ typedef struct S390CcwMachineState {
/*< public >*/
bool aes_key_wrap;
bool dea_key_wrap;
bool pv;
uint8_t loadparm[8];
} S390CcwMachineState;

View File

@ -217,5 +217,7 @@ void s390_sclp_init(void);
void sclp_service_interrupt(uint32_t sccb);
void raise_irq_cpu_hotplug(void);
int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code);
int sclp_service_call_protected(CPUS390XState *env, uint64_t sccb,
uint32_t code);
#endif

View File

@ -596,6 +596,9 @@ struct ethtool_pauseparam {
* @ETH_SS_LINK_MODES: link mode names
* @ETH_SS_MSG_CLASSES: debug message class names
* @ETH_SS_WOL_MODES: wake-on-lan modes
* @ETH_SS_SOF_TIMESTAMPING: SOF_TIMESTAMPING_* flags
* @ETH_SS_TS_TX_TYPES: timestamping Tx types
* @ETH_SS_TS_RX_FILTERS: timestamping Rx filters
*/
enum ethtool_stringset {
ETH_SS_TEST = 0,
@ -610,6 +613,9 @@ enum ethtool_stringset {
ETH_SS_LINK_MODES,
ETH_SS_MSG_CLASSES,
ETH_SS_WOL_MODES,
ETH_SS_SOF_TIMESTAMPING,
ETH_SS_TS_TX_TYPES,
ETH_SS_TS_RX_FILTERS,
/* add new constants above here */
ETH_SS_COUNT
@ -1330,6 +1336,7 @@ enum ethtool_fec_config_bits {
ETHTOOL_FEC_OFF_BIT,
ETHTOOL_FEC_RS_BIT,
ETHTOOL_FEC_BASER_BIT,
ETHTOOL_FEC_LLRS_BIT,
};
#define ETHTOOL_FEC_NONE (1 << ETHTOOL_FEC_NONE_BIT)
@ -1337,6 +1344,7 @@ enum ethtool_fec_config_bits {
#define ETHTOOL_FEC_OFF (1 << ETHTOOL_FEC_OFF_BIT)
#define ETHTOOL_FEC_RS (1 << ETHTOOL_FEC_RS_BIT)
#define ETHTOOL_FEC_BASER (1 << ETHTOOL_FEC_BASER_BIT)
#define ETHTOOL_FEC_LLRS (1 << ETHTOOL_FEC_LLRS_BIT)
/* CMDs currently supported */
#define ETHTOOL_GSET 0x00000001 /* DEPRECATED, Get settings.
@ -1521,7 +1529,7 @@ enum ethtool_link_mode_bit_indices {
ETHTOOL_LINK_MODE_400000baseLR8_ER8_FR8_Full_BIT = 71,
ETHTOOL_LINK_MODE_400000baseDR8_Full_BIT = 72,
ETHTOOL_LINK_MODE_400000baseCR8_Full_BIT = 73,
ETHTOOL_LINK_MODE_FEC_LLRS_BIT = 74,
/* must be last entry */
__ETHTOOL_LINK_MODE_MASK_NBITS
};

View File

@ -1,4 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
/*
* Input event codes
*
@ -652,6 +652,9 @@
/* Electronic privacy screen control */
#define KEY_PRIVACY_SCREEN_TOGGLE 0x279
/* Select an area of screen to be copied */
#define KEY_SELECTIVE_SCREENSHOT 0x27a
/*
* Some keyboards have keys which do not have a defined meaning, these keys
* are intended to be programmed / bound to macros by the user. For most

View File

@ -605,6 +605,7 @@
#define PCI_EXP_SLTCTL_PWR_OFF 0x0400 /* Power Off */
#define PCI_EXP_SLTCTL_EIC 0x0800 /* Electromechanical Interlock Control */
#define PCI_EXP_SLTCTL_DLLSCE 0x1000 /* Data Link Layer State Changed Enable */
#define PCI_EXP_SLTCTL_IBPD_DISABLE 0x4000 /* In-band PD disable */
#define PCI_EXP_SLTSTA 26 /* Slot Status */
#define PCI_EXP_SLTSTA_ABP 0x0001 /* Attention Button Pressed */
#define PCI_EXP_SLTSTA_PFD 0x0002 /* Power Fault Detected */
@ -680,6 +681,7 @@
#define PCI_EXP_LNKSTA2 50 /* Link Status 2 */
#define PCI_CAP_EXP_ENDPOINT_SIZEOF_V2 52 /* v2 endpoints with link end here */
#define PCI_EXP_SLTCAP2 52 /* Slot Capabilities 2 */
#define PCI_EXP_SLTCAP2_IBPD 0x00000001 /* In-band PD Disable Supported */
#define PCI_EXP_SLTCTL2 56 /* Slot Control 2 */
#define PCI_EXP_SLTSTA2 58 /* Slot Status 2 */

View File

@ -119,6 +119,14 @@ struct vhost_scsi_target {
unsigned short reserved;
};
/* VHOST_VDPA specific definitions */
struct vhost_vdpa_config {
uint32_t off;
uint32_t len;
uint8_t buf[0];
};
/* Feature bits */
/* Log all write descriptors. Can be changed while device is active. */
#define VHOST_F_LOG_ALL 26

View File

@ -36,6 +36,7 @@
#define VIRTIO_BALLOON_F_DEFLATE_ON_OOM 2 /* Deflate balloon on OOM */
#define VIRTIO_BALLOON_F_FREE_PAGE_HINT 3 /* VQ to report free pages */
#define VIRTIO_BALLOON_F_PAGE_POISON 4 /* Guest is using page poisoning */
#define VIRTIO_BALLOON_F_REPORTING 5 /* Page reporting virtqueue */
/* Size of a PFN in the balloon interface. */
#define VIRTIO_BALLOON_PFN_SHIFT 12
@ -47,8 +48,15 @@ struct virtio_balloon_config {
uint32_t num_pages;
/* Number of pages we've actually got in balloon. */
uint32_t actual;
/* Free page report command id, readonly by guest */
uint32_t free_page_report_cmd_id;
/*
* Free page hint command id, readonly by guest.
* Was previously named free_page_report_cmd_id so we
* need to carry that name for legacy support.
*/
union {
uint32_t free_page_hint_cmd_id;
uint32_t free_page_report_cmd_id; /* deprecated */
};
/* Stores PAGE_POISON if page poisoning is in use */
uint32_t poison_val;
};

View File

@ -46,5 +46,6 @@
#define VIRTIO_ID_IOMMU 23 /* virtio IOMMU */
#define VIRTIO_ID_FS 26 /* virtio filesystem */
#define VIRTIO_ID_PMEM 27 /* virtio pmem */
#define VIRTIO_ID_MAC80211_HWSIM 29 /* virtio mac80211-hwsim */
#endif /* _LINUX_VIRTIO_IDS_H */

View File

@ -57,6 +57,9 @@
* Steering */
#define VIRTIO_NET_F_CTRL_MAC_ADDR 23 /* Set MAC address */
#define VIRTIO_NET_F_HASH_REPORT 57 /* Supports hash report */
#define VIRTIO_NET_F_RSS 60 /* Supports RSS RX steering */
#define VIRTIO_NET_F_RSC_EXT 61 /* extended coalescing info */
#define VIRTIO_NET_F_STANDBY 62 /* Act as standby for another device
* with the same MAC.
*/
@ -69,6 +72,17 @@
#define VIRTIO_NET_S_LINK_UP 1 /* Link is up */
#define VIRTIO_NET_S_ANNOUNCE 2 /* Announcement is needed */
/* supported/enabled hash types */
#define VIRTIO_NET_RSS_HASH_TYPE_IPv4 (1 << 0)
#define VIRTIO_NET_RSS_HASH_TYPE_TCPv4 (1 << 1)
#define VIRTIO_NET_RSS_HASH_TYPE_UDPv4 (1 << 2)
#define VIRTIO_NET_RSS_HASH_TYPE_IPv6 (1 << 3)
#define VIRTIO_NET_RSS_HASH_TYPE_TCPv6 (1 << 4)
#define VIRTIO_NET_RSS_HASH_TYPE_UDPv6 (1 << 5)
#define VIRTIO_NET_RSS_HASH_TYPE_IP_EX (1 << 6)
#define VIRTIO_NET_RSS_HASH_TYPE_TCP_EX (1 << 7)
#define VIRTIO_NET_RSS_HASH_TYPE_UDP_EX (1 << 8)
struct virtio_net_config {
/* The config defining mac address (if VIRTIO_NET_F_MAC) */
uint8_t mac[ETH_ALEN];
@ -92,6 +106,12 @@ struct virtio_net_config {
* Any other value stands for unknown.
*/
uint8_t duplex;
/* maximum size of RSS key */
uint8_t rss_max_key_size;
/* maximum number of indirection table entries */
uint16_t rss_max_indirection_table_length;
/* bitmask of supported VIRTIO_NET_RSS_HASH_ types */
uint32_t supported_hash_types;
} QEMU_PACKED;
/*
@ -104,6 +124,7 @@ struct virtio_net_config {
struct virtio_net_hdr_v1 {
#define VIRTIO_NET_HDR_F_NEEDS_CSUM 1 /* Use csum_start, csum_offset */
#define VIRTIO_NET_HDR_F_DATA_VALID 2 /* Csum is valid */
#define VIRTIO_NET_HDR_F_RSC_INFO 4 /* rsc info in csum_ fields */
uint8_t flags;
#define VIRTIO_NET_HDR_GSO_NONE 0 /* Not a GSO frame */
#define VIRTIO_NET_HDR_GSO_TCPV4 1 /* GSO frame, IPv4 TCP (TSO) */
@ -113,11 +134,46 @@ struct virtio_net_hdr_v1 {
uint8_t gso_type;
__virtio16 hdr_len; /* Ethernet + IP + tcp/udp hdrs */
__virtio16 gso_size; /* Bytes to append to hdr_len per frame */
__virtio16 csum_start; /* Position to start checksumming from */
__virtio16 csum_offset; /* Offset after that to place checksum */
union {
struct {
__virtio16 csum_start;
__virtio16 csum_offset;
};
/* Checksum calculation */
struct {
/* Position to start checksumming from */
__virtio16 start;
/* Offset after that to place checksum */
__virtio16 offset;
} csum;
/* Receive Segment Coalescing */
struct {
/* Number of coalesced segments */
uint16_t segments;
/* Number of duplicated acks */
uint16_t dup_acks;
} rsc;
};
__virtio16 num_buffers; /* Number of merged rx buffers */
};
struct virtio_net_hdr_v1_hash {
struct virtio_net_hdr_v1 hdr;
uint32_t hash_value;
#define VIRTIO_NET_HASH_REPORT_NONE 0
#define VIRTIO_NET_HASH_REPORT_IPv4 1
#define VIRTIO_NET_HASH_REPORT_TCPv4 2
#define VIRTIO_NET_HASH_REPORT_UDPv4 3
#define VIRTIO_NET_HASH_REPORT_IPv6 4
#define VIRTIO_NET_HASH_REPORT_TCPv6 5
#define VIRTIO_NET_HASH_REPORT_UDPv6 6
#define VIRTIO_NET_HASH_REPORT_IPv6_EX 7
#define VIRTIO_NET_HASH_REPORT_TCPv6_EX 8
#define VIRTIO_NET_HASH_REPORT_UDPv6_EX 9
uint16_t hash_report;
uint16_t padding;
};
#ifndef VIRTIO_NET_NO_LEGACY
/* This header comes first in the scatter-gather list.
* For legacy virtio, if VIRTIO_F_ANY_LAYOUT is not negotiated, it must
@ -228,7 +284,9 @@ struct virtio_net_ctrl_mac {
/*
* Control Receive Flow Steering
*
*/
#define VIRTIO_NET_CTRL_MQ 4
/*
* The command VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET
* enables Receive Flow Steering, specifying the number of the transmit and
* receive queues that will be used. After the command is consumed and acked by
@ -241,11 +299,47 @@ struct virtio_net_ctrl_mq {
__virtio16 virtqueue_pairs;
};
#define VIRTIO_NET_CTRL_MQ 4
#define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET 0
#define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN 1
#define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX 0x8000
/*
* The command VIRTIO_NET_CTRL_MQ_RSS_CONFIG has the same effect as
* VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET does and additionally configures
* the receive steering to use a hash calculated for incoming packet
* to decide on receive virtqueue to place the packet. The command
* also provides parameters to calculate a hash and receive virtqueue.
*/
struct virtio_net_rss_config {
uint32_t hash_types;
uint16_t indirection_table_mask;
uint16_t unclassified_queue;
uint16_t indirection_table[1/* + indirection_table_mask */];
uint16_t max_tx_vq;
uint8_t hash_key_length;
uint8_t hash_key_data[/* hash_key_length */];
};
#define VIRTIO_NET_CTRL_MQ_RSS_CONFIG 1
/*
* The command VIRTIO_NET_CTRL_MQ_HASH_CONFIG requests the device
* to include in the virtio header of the packet the value of the
* calculated hash and the report type of hash. It also provides
* parameters for hash calculation. The command requires feature
* VIRTIO_NET_F_HASH_REPORT to be negotiated to extend the
* layout of virtio header as defined in virtio_net_hdr_v1_hash.
*/
struct virtio_net_hash_config {
uint32_t hash_types;
/* for compatibility with virtio_net_rss_config */
uint16_t reserved[4];
uint8_t hash_key_length;
uint8_t hash_key_data[/* hash_key_length */];
};
#define VIRTIO_NET_CTRL_MQ_HASH_CONFIG 2
/*
* Control network offloads
*

View File

@ -16,3 +16,5 @@ In addition, other licenses may also apply. Please see:
Documentation/process/license-rules.rst
for more details.
All contributions to the Linux Kernel are subject to this COPYING file.

View File

@ -390,6 +390,7 @@ struct kvm_sync_regs {
#define KVM_STATE_NESTED_GUEST_MODE 0x00000001
#define KVM_STATE_NESTED_RUN_PENDING 0x00000002
#define KVM_STATE_NESTED_EVMCS 0x00000004
#define KVM_STATE_NESTED_MTF_PENDING 0x00000008
#define KVM_STATE_NESTED_SMM_GUEST_MODE 0x00000001
#define KVM_STATE_NESTED_SMM_VMXON 0x00000002

View File

@ -429,4 +429,5 @@
#define __NR_openat2 437
#define __NR_pidfd_getfd 438
#endif /* _ASM_X86_UNISTD_32_H */

View File

@ -351,4 +351,5 @@
#define __NR_openat2 437
#define __NR_pidfd_getfd 438
#endif /* _ASM_X86_UNISTD_64_H */

View File

@ -340,4 +340,5 @@
#define __NR_preadv2 (__X32_SYSCALL_BIT + 546)
#define __NR_pwritev2 (__X32_SYSCALL_BIT + 547)
#endif /* _ASM_X86_UNISTD_X32_H */

View File

@ -474,12 +474,17 @@ struct kvm_s390_mem_op {
__u32 size; /* amount of bytes */
__u32 op; /* type of operation */
__u64 buf; /* buffer in userspace */
__u8 ar; /* the access register number */
__u8 reserved[31]; /* should be set to 0 */
union {
__u8 ar; /* the access register number */
__u32 sida_offset; /* offset into the sida */
__u8 reserved[32]; /* should be set to 0 */
};
};
/* types for kvm_s390_mem_op->op */
#define KVM_S390_MEMOP_LOGICAL_READ 0
#define KVM_S390_MEMOP_LOGICAL_WRITE 1
#define KVM_S390_MEMOP_SIDA_READ 2
#define KVM_S390_MEMOP_SIDA_WRITE 3
/* flags for kvm_s390_mem_op->flags */
#define KVM_S390_MEMOP_F_CHECK_ONLY (1ULL << 0)
#define KVM_S390_MEMOP_F_INJECT_EXCEPTION (1ULL << 1)
@ -1010,6 +1015,8 @@ struct kvm_ppc_resize_hpt {
#define KVM_CAP_ARM_NISV_TO_USER 177
#define KVM_CAP_ARM_INJECT_EXT_DABT 178
#define KVM_CAP_S390_VCPU_RESETS 179
#define KVM_CAP_S390_PROTECTED 180
#define KVM_CAP_PPC_SECURE_GUEST 181
#ifdef KVM_CAP_IRQ_ROUTING
@ -1478,6 +1485,39 @@ struct kvm_enc_region {
#define KVM_S390_NORMAL_RESET _IO(KVMIO, 0xc3)
#define KVM_S390_CLEAR_RESET _IO(KVMIO, 0xc4)
struct kvm_s390_pv_sec_parm {
__u64 origin;
__u64 length;
};
struct kvm_s390_pv_unp {
__u64 addr;
__u64 size;
__u64 tweak;
};
enum pv_cmd_id {
KVM_PV_ENABLE,
KVM_PV_DISABLE,
KVM_PV_SET_SEC_PARMS,
KVM_PV_UNPACK,
KVM_PV_VERIFY,
KVM_PV_PREP_RESET,
KVM_PV_UNSHARE_ALL,
};
struct kvm_pv_cmd {
__u32 cmd; /* Command to be executed */
__u16 rc; /* Ultravisor return code */
__u16 rrc; /* Ultravisor return reason code */
__u64 data; /* Data or address */
__u32 flags; /* flags for future extensions. Must be 0 for now */
__u32 reserved[3];
};
/* Available with KVM_CAP_S390_PROTECTED */
#define KVM_S390_PV_COMMAND _IOWR(KVMIO, 0xc5, struct kvm_pv_cmd)
/* Secure Encrypted Virtualization command */
enum sev_cmd_id {
/* Guest initialization commands */
@ -1628,4 +1668,7 @@ struct kvm_hyperv_eventfd {
#define KVM_HYPERV_CONN_ID_MASK 0x00ffffff
#define KVM_HYPERV_EVENTFD_DEASSIGN (1 << 0)
#define KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE (1 << 0)
#define KVM_DIRTY_LOG_INITIALLY_SET (1 << 1)
#endif /* __LINUX_KVM_H */

View File

@ -5,8 +5,9 @@
#include <asm/mman.h>
#include <asm-generic/hugetlb_encode.h>
#define MREMAP_MAYMOVE 1
#define MREMAP_FIXED 2
#define MREMAP_MAYMOVE 1
#define MREMAP_FIXED 2
#define MREMAP_DONTUNMAP 4
#define OVERCOMMIT_GUESS 0
#define OVERCOMMIT_ALWAYS 1

View File

@ -19,7 +19,8 @@
* means the userland is reading).
*/
#define UFFD_API ((__u64)0xAA)
#define UFFD_API_FEATURES (UFFD_FEATURE_EVENT_FORK | \
#define UFFD_API_FEATURES (UFFD_FEATURE_PAGEFAULT_FLAG_WP | \
UFFD_FEATURE_EVENT_FORK | \
UFFD_FEATURE_EVENT_REMAP | \
UFFD_FEATURE_EVENT_REMOVE | \
UFFD_FEATURE_EVENT_UNMAP | \
@ -34,7 +35,8 @@
#define UFFD_API_RANGE_IOCTLS \
((__u64)1 << _UFFDIO_WAKE | \
(__u64)1 << _UFFDIO_COPY | \
(__u64)1 << _UFFDIO_ZEROPAGE)
(__u64)1 << _UFFDIO_ZEROPAGE | \
(__u64)1 << _UFFDIO_WRITEPROTECT)
#define UFFD_API_RANGE_IOCTLS_BASIC \
((__u64)1 << _UFFDIO_WAKE | \
(__u64)1 << _UFFDIO_COPY)
@ -52,6 +54,7 @@
#define _UFFDIO_WAKE (0x02)
#define _UFFDIO_COPY (0x03)
#define _UFFDIO_ZEROPAGE (0x04)
#define _UFFDIO_WRITEPROTECT (0x06)
#define _UFFDIO_API (0x3F)
/* userfaultfd ioctl ids */
@ -68,6 +71,8 @@
struct uffdio_copy)
#define UFFDIO_ZEROPAGE _IOWR(UFFDIO, _UFFDIO_ZEROPAGE, \
struct uffdio_zeropage)
#define UFFDIO_WRITEPROTECT _IOWR(UFFDIO, _UFFDIO_WRITEPROTECT, \
struct uffdio_writeprotect)
/* read() structure */
struct uffd_msg {
@ -203,13 +208,14 @@ struct uffdio_copy {
__u64 dst;
__u64 src;
__u64 len;
/*
* There will be a wrprotection flag later that allows to map
* pages wrprotected on the fly. And such a flag will be
* available if the wrprotection ioctl are implemented for the
* range according to the uffdio_register.ioctls.
*/
#define UFFDIO_COPY_MODE_DONTWAKE ((__u64)1<<0)
/*
* UFFDIO_COPY_MODE_WP will map the page write protected on
* the fly. UFFDIO_COPY_MODE_WP is available only if the
* write protected ioctl is implemented for the range
* according to the uffdio_register.ioctls.
*/
#define UFFDIO_COPY_MODE_WP ((__u64)1<<1)
__u64 mode;
/*
@ -231,4 +237,24 @@ struct uffdio_zeropage {
__s64 zeropage;
};
struct uffdio_writeprotect {
struct uffdio_range range;
/*
* UFFDIO_WRITEPROTECT_MODE_WP: set the flag to write protect a range,
* unset the flag to undo protection of a range which was previously
* write protected.
*
* UFFDIO_WRITEPROTECT_MODE_DONTWAKE: set the flag to avoid waking up
* any wait thread after the operation succeeds.
*
* NOTE: Write protecting a region (WP=1) is unrelated to page faults,
* therefore DONTWAKE flag is meaningless with WP=1. Removing write
* protection (WP=0) in response to a page fault wakes the faulting
* task unless DONTWAKE is set.
*/
#define UFFDIO_WRITEPROTECT_MODE_WP ((__u64)1<<0)
#define UFFDIO_WRITEPROTECT_MODE_DONTWAKE ((__u64)1<<1)
__u64 mode;
};
#endif /* _LINUX_USERFAULTFD_H */

View File

@ -707,6 +707,43 @@ struct vfio_device_ioeventfd {
#define VFIO_DEVICE_IOEVENTFD _IO(VFIO_TYPE, VFIO_BASE + 16)
/**
* VFIO_DEVICE_FEATURE - _IORW(VFIO_TYPE, VFIO_BASE + 17,
* struct vfio_device_feature)
*
* Get, set, or probe feature data of the device. The feature is selected
* using the FEATURE_MASK portion of the flags field. Support for a feature
* can be probed by setting both the FEATURE_MASK and PROBE bits. A probe
* may optionally include the GET and/or SET bits to determine read vs write
* access of the feature respectively. Probing a feature will return success
* if the feature is supported and all of the optionally indicated GET/SET
* methods are supported. The format of the data portion of the structure is
* specific to the given feature. The data portion is not required for
* probing. GET and SET are mutually exclusive, except for use with PROBE.
*
* Return 0 on success, -errno on failure.
*/
struct vfio_device_feature {
__u32 argsz;
__u32 flags;
#define VFIO_DEVICE_FEATURE_MASK (0xffff) /* 16-bit feature index */
#define VFIO_DEVICE_FEATURE_GET (1 << 16) /* Get feature into data[] */
#define VFIO_DEVICE_FEATURE_SET (1 << 17) /* Set feature from data[] */
#define VFIO_DEVICE_FEATURE_PROBE (1 << 18) /* Probe feature support */
__u8 data[];
};
#define VFIO_DEVICE_FEATURE _IO(VFIO_TYPE, VFIO_BASE + 17)
/*
* Provide support for setting a PCI VF Token, which is used as a shared
* secret between PF and VF drivers. This feature may only be set on a
* PCI SR-IOV PF when SR-IOV is enabled on the PF and there are no existing
* open VFs. Data provided when setting this feature is a 16-byte array
* (__u8 b[16]), representing a UUID.
*/
#define VFIO_DEVICE_FEATURE_PCI_VF_TOKEN (0)
/* -------- API for Type1 VFIO IOMMU -------- */
/**

View File

@ -116,4 +116,28 @@
#define VHOST_VSOCK_SET_GUEST_CID _IOW(VHOST_VIRTIO, 0x60, __u64)
#define VHOST_VSOCK_SET_RUNNING _IOW(VHOST_VIRTIO, 0x61, int)
/* VHOST_VDPA specific defines */
/* Get the device id. The device ids follow the same definition of
* the device id defined in virtio-spec.
*/
#define VHOST_VDPA_GET_DEVICE_ID _IOR(VHOST_VIRTIO, 0x70, __u32)
/* Get and set the status. The status bits follow the same definition
* of the device status defined in virtio-spec.
*/
#define VHOST_VDPA_GET_STATUS _IOR(VHOST_VIRTIO, 0x71, __u8)
#define VHOST_VDPA_SET_STATUS _IOW(VHOST_VIRTIO, 0x72, __u8)
/* Get and set the device config. The device config follows the same
* definition of the device config defined in virtio-spec.
*/
#define VHOST_VDPA_GET_CONFIG _IOR(VHOST_VIRTIO, 0x73, \
struct vhost_vdpa_config)
#define VHOST_VDPA_SET_CONFIG _IOW(VHOST_VIRTIO, 0x74, \
struct vhost_vdpa_config)
/* Enable/disable the ring. */
#define VHOST_VDPA_SET_VRING_ENABLE _IOW(VHOST_VIRTIO, 0x75, \
struct vhost_vring_state)
/* Get the max ring size. */
#define VHOST_VDPA_GET_VRING_NUM _IOR(VHOST_VIRTIO, 0x76, __u16)
#endif

View File

@ -37,6 +37,7 @@
#include "sysemu/hw_accel.h"
#include "hw/qdev-properties.h"
#ifndef CONFIG_USER_ONLY
#include "hw/s390x/pv.h"
#include "hw/boards.h"
#include "sysemu/arch_init.h"
#include "sysemu/sysemu.h"
@ -76,16 +77,24 @@ static bool s390_cpu_has_work(CPUState *cs)
static void s390_cpu_load_normal(CPUState *s)
{
S390CPU *cpu = S390_CPU(s);
uint64_t spsw = ldq_phys(s->as, 0);
cpu->env.psw.mask = spsw & PSW_MASK_SHORT_CTRL;
/*
* Invert short psw indication, so SIE will report a specification
* exception if it was not set.
*/
cpu->env.psw.mask ^= PSW_MASK_SHORTPSW;
cpu->env.psw.addr = spsw & PSW_MASK_SHORT_ADDR;
uint64_t spsw;
if (!s390_is_pv()) {
spsw = ldq_phys(s->as, 0);
cpu->env.psw.mask = spsw & PSW_MASK_SHORT_CTRL;
/*
* Invert short psw indication, so SIE will report a specification
* exception if it was not set.
*/
cpu->env.psw.mask ^= PSW_MASK_SHORTPSW;
cpu->env.psw.addr = spsw & PSW_MASK_SHORT_ADDR;
} else {
/*
* Firmware requires us to set the load state before we set
* the cpu to operating on protected guests.
*/
s390_cpu_set_state(S390_CPU_STATE_LOAD, cpu);
}
s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu);
}
#endif

View File

@ -823,7 +823,12 @@ int s390_cpu_virt_mem_rw(S390CPU *cpu, vaddr laddr, uint8_t ar, void *hostbuf,
#define s390_cpu_virt_mem_check_write(cpu, laddr, ar, len) \
s390_cpu_virt_mem_rw(cpu, laddr, ar, NULL, len, true)
void s390_cpu_virt_mem_handle_exc(S390CPU *cpu, uintptr_t ra);
int s390_cpu_pv_mem_rw(S390CPU *cpu, unsigned int offset, void *hostbuf,
int len, bool is_write);
#define s390_cpu_pv_mem_read(cpu, offset, dest, len) \
s390_cpu_pv_mem_rw(cpu, offset, dest, len, false)
#define s390_cpu_pv_mem_write(cpu, offset, dest, len) \
s390_cpu_pv_mem_rw(cpu, offset, dest, len, true)
/* sigp.c */
int s390_cpu_restart(S390CPU *cpu);

View File

@ -107,6 +107,7 @@ DEF_FEAT(DEFLATE_BASE, "deflate-base", STFL, 151, "Deflate-conversion facility (
DEF_FEAT(VECTOR_PACKED_DECIMAL_ENH, "vxpdeh", STFL, 152, "Vector-Packed-Decimal-Enhancement Facility")
DEF_FEAT(MSA_EXT_9, "msa9-base", STFL, 155, "Message-security-assist-extension-9 facility (excluding subfunctions)")
DEF_FEAT(ETOKEN, "etoken", STFL, 156, "Etoken facility")
DEF_FEAT(UNPACK, "unpack", STFL, 161, "Unpack facility")
/* Features exposed via SCLP SCCB Byte 80 - 98 (bit numbers relative to byte-80) */
DEF_FEAT(SIE_GSLS, "gsls", SCLP_CONF_CHAR, 40, "SIE: Guest-storage-limit-suppression facility")

View File

@ -20,6 +20,8 @@
#include "sysemu/cpus.h"
#include "hw/s390x/ipl.h"
#include "hw/s390x/s390-virtio-ccw.h"
#include "hw/s390x/pv.h"
#include "kvm_s390x.h"
int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3)
{
@ -49,20 +51,13 @@ int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3)
return diag288_class->handle_timer(diag288, func, timeout);
}
#define DIAG_308_RC_OK 0x0001
#define DIAG_308_RC_NO_CONF 0x0102
#define DIAG_308_RC_INVALID 0x0402
#define DIAG308_RESET_MOD_CLR 0
#define DIAG308_RESET_LOAD_NORM 1
#define DIAG308_LOAD_CLEAR 3
#define DIAG308_LOAD_NORMAL_DUMP 4
#define DIAG308_SET 5
#define DIAG308_STORE 6
static int diag308_parm_check(CPUS390XState *env, uint64_t r1, uint64_t addr,
uintptr_t ra, bool write)
{
/* Handled by the Ultravisor */
if (s390_is_pv()) {
return 0;
}
if ((r1 & 1) || (addr & ~TARGET_PAGE_MASK)) {
s390_program_interrupt(env, PGM_SPECIFICATION, ra);
return -1;
@ -78,7 +73,9 @@ static int diag308_parm_check(CPUS390XState *env, uint64_t r1, uint64_t addr,
void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra)
{
bool valid;
CPUState *cs = env_cpu(env);
S390CPU *cpu = S390_CPU(cs);
uint64_t addr = env->regs[r1];
uint64_t subcode = env->regs[r3];
IplParameterBlock *iplb;
@ -93,6 +90,11 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra)
return;
}
if (subcode >= DIAG308_PV_SET && !s390_has_feat(S390_FEAT_UNPACK)) {
s390_program_interrupt(env, PGM_SPECIFICATION, ra);
return;
}
switch (subcode) {
case DIAG308_RESET_MOD_CLR:
s390_ipl_reset_request(cs, S390_RESET_MODIFIED_CLEAR);
@ -105,19 +107,30 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra)
s390_ipl_reset_request(cs, S390_RESET_REIPL);
break;
case DIAG308_SET:
case DIAG308_PV_SET:
if (diag308_parm_check(env, r1, addr, ra, false)) {
return;
}
iplb = g_new0(IplParameterBlock, 1);
cpu_physical_memory_read(addr, iplb, sizeof(iplb->len));
if (!s390_is_pv()) {
cpu_physical_memory_read(addr, iplb, sizeof(iplb->len));
} else {
s390_cpu_pv_mem_read(cpu, 0, iplb, sizeof(iplb->len));
}
if (!iplb_valid_len(iplb)) {
env->regs[r1 + 1] = DIAG_308_RC_INVALID;
goto out;
}
cpu_physical_memory_read(addr, iplb, be32_to_cpu(iplb->len));
if (!s390_is_pv()) {
cpu_physical_memory_read(addr, iplb, be32_to_cpu(iplb->len));
} else {
s390_cpu_pv_mem_read(cpu, 0, iplb, be32_to_cpu(iplb->len));
}
if (!iplb_valid(iplb)) {
valid = subcode == DIAG308_PV_SET ? iplb_valid_pv(iplb) : iplb_valid(iplb);
if (!valid) {
env->regs[r1 + 1] = DIAG_308_RC_INVALID;
goto out;
}
@ -128,17 +141,43 @@ out:
g_free(iplb);
return;
case DIAG308_STORE:
case DIAG308_PV_STORE:
if (diag308_parm_check(env, r1, addr, ra, true)) {
return;
}
iplb = s390_ipl_get_iplb();
if (iplb) {
cpu_physical_memory_write(addr, iplb, be32_to_cpu(iplb->len));
env->regs[r1 + 1] = DIAG_308_RC_OK;
if (subcode == DIAG308_PV_STORE) {
iplb = s390_ipl_get_iplb_pv();
} else {
env->regs[r1 + 1] = DIAG_308_RC_NO_CONF;
iplb = s390_ipl_get_iplb();
}
if (!iplb) {
env->regs[r1 + 1] = DIAG_308_RC_NO_CONF;
return;
}
if (!s390_is_pv()) {
cpu_physical_memory_write(addr, iplb, be32_to_cpu(iplb->len));
} else {
s390_cpu_pv_mem_write(cpu, 0, iplb, be32_to_cpu(iplb->len));
}
env->regs[r1 + 1] = DIAG_308_RC_OK;
return;
case DIAG308_PV_START:
iplb = s390_ipl_get_iplb_pv();
if (!iplb) {
env->regs[r1 + 1] = DIAG_308_RC_NO_PV_CONF;
return;
}
if (kvm_s390_get_hpage_1m()) {
error_report("Protected VMs can currently not be backed with "
"huge pages");
env->regs[r1 + 1] = DIAG_308_RC_INVAL_FOR_PV;
return;
}
s390_ipl_reset_request(cs, S390_RESET_PV);
break;
default:
s390_program_interrupt(env, PGM_SPECIFICATION, ra);
break;

View File

@ -562,6 +562,7 @@ static uint16_t full_GEN15_GA1[] = {
S390_FEAT_GROUP_MSA_EXT_9,
S390_FEAT_GROUP_MSA_EXT_9_PCKMO,
S390_FEAT_ETOKEN,
S390_FEAT_UNPACK,
};
/* Default features (in order of release)

View File

@ -25,6 +25,7 @@
#include "qemu/timer.h"
#include "qemu/qemu-print.h"
#include "hw/s390x/ioinst.h"
#include "hw/s390x/pv.h"
#include "sysemu/hw_accel.h"
#include "sysemu/runstate.h"
#ifndef CONFIG_USER_ONLY
@ -246,6 +247,11 @@ int s390_store_status(S390CPU *cpu, hwaddr addr, bool store_arch)
hwaddr len = sizeof(*sa);
int i;
/* For PVMs storing will occur when this cpu enters SIE again */
if (s390_is_pv()) {
return 0;
}
sa = cpu_physical_memory_map(addr, &len, true);
if (!sa) {
return -EFAULT;

View File

@ -16,6 +16,25 @@
#include "hw/s390x/ioinst.h"
#include "trace.h"
#include "hw/s390x/s390-pci-bus.h"
#include "hw/s390x/pv.h"
/* All I/O instructions but chsc use the s format */
static uint64_t get_address_from_regs(CPUS390XState *env, uint32_t ipb,
uint8_t *ar)
{
/*
* Addresses for protected guests are all offsets into the
* satellite block which holds the IO control structures. Those
* control structures are always starting at offset 0 and are
* always aligned and accessible. So we can return 0 here which
* will pass the following address checks.
*/
if (s390_is_pv()) {
*ar = 0;
return 0;
}
return decode_basedisp_s(env, ipb, ar);
}
int ioinst_disassemble_sch_ident(uint32_t value, int *m, int *cssid, int *ssid,
int *schid)
@ -114,12 +133,14 @@ void ioinst_handle_msch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, uintptr_t ra)
CPUS390XState *env = &cpu->env;
uint8_t ar;
addr = decode_basedisp_s(env, ipb, &ar);
addr = get_address_from_regs(env, ipb, &ar);
if (addr & 3) {
s390_program_interrupt(env, PGM_SPECIFICATION, ra);
return;
}
if (s390_cpu_virt_mem_read(cpu, addr, ar, &schib, sizeof(schib))) {
if (s390_is_pv()) {
s390_cpu_pv_mem_read(cpu, addr, &schib, sizeof(schib));
} else if (s390_cpu_virt_mem_read(cpu, addr, ar, &schib, sizeof(schib))) {
s390_cpu_virt_mem_handle_exc(cpu, ra);
return;
}
@ -171,12 +192,14 @@ void ioinst_handle_ssch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, uintptr_t ra)
CPUS390XState *env = &cpu->env;
uint8_t ar;
addr = decode_basedisp_s(env, ipb, &ar);
addr = get_address_from_regs(env, ipb, &ar);
if (addr & 3) {
s390_program_interrupt(env, PGM_SPECIFICATION, ra);
return;
}
if (s390_cpu_virt_mem_read(cpu, addr, ar, &orig_orb, sizeof(orb))) {
if (s390_is_pv()) {
s390_cpu_pv_mem_read(cpu, addr, &orig_orb, sizeof(orb));
} else if (s390_cpu_virt_mem_read(cpu, addr, ar, &orig_orb, sizeof(orb))) {
s390_cpu_virt_mem_handle_exc(cpu, ra);
return;
}
@ -203,7 +226,7 @@ void ioinst_handle_stcrw(S390CPU *cpu, uint32_t ipb, uintptr_t ra)
CPUS390XState *env = &cpu->env;
uint8_t ar;
addr = decode_basedisp_s(env, ipb, &ar);
addr = get_address_from_regs(env, ipb, &ar);
if (addr & 3) {
s390_program_interrupt(env, PGM_SPECIFICATION, ra);
return;
@ -212,14 +235,19 @@ void ioinst_handle_stcrw(S390CPU *cpu, uint32_t ipb, uintptr_t ra)
cc = css_do_stcrw(&crw);
/* 0 - crw stored, 1 - zeroes stored */
if (s390_cpu_virt_mem_write(cpu, addr, ar, &crw, sizeof(crw)) == 0) {
if (s390_is_pv()) {
s390_cpu_pv_mem_write(cpu, addr, &crw, sizeof(crw));
setcc(cpu, cc);
} else {
if (cc == 0) {
/* Write failed: requeue CRW since STCRW is suppressing */
css_undo_stcrw(&crw);
if (s390_cpu_virt_mem_write(cpu, addr, ar, &crw, sizeof(crw)) == 0) {
setcc(cpu, cc);
} else {
if (cc == 0) {
/* Write failed: requeue CRW since STCRW is suppressing */
css_undo_stcrw(&crw);
}
s390_cpu_virt_mem_handle_exc(cpu, ra);
}
s390_cpu_virt_mem_handle_exc(cpu, ra);
}
}
@ -234,13 +262,20 @@ void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb,
CPUS390XState *env = &cpu->env;
uint8_t ar;
addr = decode_basedisp_s(env, ipb, &ar);
addr = get_address_from_regs(env, ipb, &ar);
if (addr & 3) {
s390_program_interrupt(env, PGM_SPECIFICATION, ra);
return;
}
if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
/*
* The Ultravisor checks schid bit 16 to be one and bits 0-12
* to be 0 and injects a operand exception itself.
*
* Hence we should never end up here.
*/
g_assert(!s390_is_pv());
/*
* As operand exceptions have a lower priority than access exceptions,
* we check whether the memory area is writeable (injecting the
@ -273,14 +308,17 @@ void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb,
}
}
if (cc != 3) {
if (s390_cpu_virt_mem_write(cpu, addr, ar, &schib,
sizeof(schib)) != 0) {
if (s390_is_pv()) {
s390_cpu_pv_mem_write(cpu, addr, &schib, sizeof(schib));
} else if (s390_cpu_virt_mem_write(cpu, addr, ar, &schib,
sizeof(schib)) != 0) {
s390_cpu_virt_mem_handle_exc(cpu, ra);
return;
}
} else {
/* Access exceptions have a higher priority than cc3 */
if (s390_cpu_virt_mem_check_write(cpu, addr, ar, sizeof(schib)) != 0) {
if (!s390_is_pv() &&
s390_cpu_virt_mem_check_write(cpu, addr, ar, sizeof(schib)) != 0) {
s390_cpu_virt_mem_handle_exc(cpu, ra);
return;
}
@ -303,7 +341,7 @@ int ioinst_handle_tsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, uintptr_t ra)
return -EIO;
}
trace_ioinst_sch_id("tsch", cssid, ssid, schid);
addr = decode_basedisp_s(env, ipb, &ar);
addr = get_address_from_regs(env, ipb, &ar);
if (addr & 3) {
s390_program_interrupt(env, PGM_SPECIFICATION, ra);
return -EIO;
@ -317,7 +355,9 @@ int ioinst_handle_tsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, uintptr_t ra)
}
/* 0 - status pending, 1 - not status pending, 3 - not operational */
if (cc != 3) {
if (s390_cpu_virt_mem_write(cpu, addr, ar, &irb, irb_len) != 0) {
if (s390_is_pv()) {
s390_cpu_pv_mem_write(cpu, addr, &irb, irb_len);
} else if (s390_cpu_virt_mem_write(cpu, addr, ar, &irb, irb_len) != 0) {
s390_cpu_virt_mem_handle_exc(cpu, ra);
return -EFAULT;
}
@ -325,7 +365,8 @@ int ioinst_handle_tsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, uintptr_t ra)
} else {
irb_len = sizeof(irb) - sizeof(irb.emw);
/* Access exceptions have a higher priority than cc3 */
if (s390_cpu_virt_mem_check_write(cpu, addr, ar, irb_len) != 0) {
if (!s390_is_pv() &&
s390_cpu_virt_mem_check_write(cpu, addr, ar, irb_len) != 0) {
s390_cpu_virt_mem_handle_exc(cpu, ra);
return -EFAULT;
}
@ -601,7 +642,7 @@ void ioinst_handle_chsc(S390CPU *cpu, uint32_t ipb, uintptr_t ra)
{
ChscReq *req;
ChscResp *res;
uint64_t addr;
uint64_t addr = 0;
int reg;
uint16_t len;
uint16_t command;
@ -610,7 +651,9 @@ void ioinst_handle_chsc(S390CPU *cpu, uint32_t ipb, uintptr_t ra)
trace_ioinst("chsc");
reg = (ipb >> 20) & 0x00f;
addr = env->regs[reg];
if (!s390_is_pv()) {
addr = env->regs[reg];
}
/* Page boundary? */
if (addr & 0xfff) {
s390_program_interrupt(env, PGM_SPECIFICATION, ra);
@ -621,7 +664,9 @@ void ioinst_handle_chsc(S390CPU *cpu, uint32_t ipb, uintptr_t ra)
* present CHSC sub-handlers ... if we ever need more, we should take
* care of req->len here first.
*/
if (s390_cpu_virt_mem_read(cpu, addr, reg, buf, sizeof(ChscReq))) {
if (s390_is_pv()) {
s390_cpu_pv_mem_read(cpu, addr, buf, sizeof(ChscReq));
} else if (s390_cpu_virt_mem_read(cpu, addr, reg, buf, sizeof(ChscReq))) {
s390_cpu_virt_mem_handle_exc(cpu, ra);
return;
}
@ -654,11 +699,16 @@ void ioinst_handle_chsc(S390CPU *cpu, uint32_t ipb, uintptr_t ra)
break;
}
if (!s390_cpu_virt_mem_write(cpu, addr + len, reg, res,
be16_to_cpu(res->len))) {
if (s390_is_pv()) {
s390_cpu_pv_mem_write(cpu, addr + len, res, be16_to_cpu(res->len));
setcc(cpu, 0); /* Command execution complete */
} else {
s390_cpu_virt_mem_handle_exc(cpu, ra);
if (!s390_cpu_virt_mem_write(cpu, addr + len, reg, res,
be16_to_cpu(res->len))) {
setcc(cpu, 0); /* Command execution complete */
} else {
s390_cpu_virt_mem_handle_exc(cpu, ra);
}
}
}

View File

@ -39,6 +39,11 @@ int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu)
return 0;
}
int kvm_s390_get_hpage_1m(void)
{
return 0;
}
int kvm_s390_get_ri(void)
{
return 0;

View File

@ -50,6 +50,7 @@
#include "exec/memattrs.h"
#include "hw/s390x/s390-virtio-ccw.h"
#include "hw/s390x/s390-virtio-hcall.h"
#include "hw/s390x/pv.h"
#ifndef DEBUG_KVM
#define DEBUG_KVM 0
@ -115,6 +116,8 @@
#define ICPT_CPU_STOP 0x28
#define ICPT_OPEREXC 0x2c
#define ICPT_IO 0x40
#define ICPT_PV_INSTR 0x68
#define ICPT_PV_INSTR_NOTIFICATION 0x6c
#define NR_LOCAL_IRQS 32
/*
@ -152,6 +155,7 @@ static int cap_ri;
static int cap_gs;
static int cap_hpage_1m;
static int cap_vcpu_resets;
static int cap_protected;
static int active_cmma;
@ -321,6 +325,11 @@ void kvm_s390_set_max_pagesize(uint64_t pagesize, Error **errp)
cap_hpage_1m = 1;
}
int kvm_s390_get_hpage_1m(void)
{
return cap_hpage_1m;
}
static void ccw_machine_class_foreach(ObjectClass *oc, void *opaque)
{
MachineClass *mc = MACHINE_CLASS(oc);
@ -344,6 +353,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
cap_mem_op = kvm_check_extension(s, KVM_CAP_S390_MEM_OP);
cap_s390_irq = kvm_check_extension(s, KVM_CAP_S390_INJECT_IRQ);
cap_vcpu_resets = kvm_check_extension(s, KVM_CAP_S390_VCPU_RESETS);
cap_protected = kvm_check_extension(s, KVM_CAP_S390_PROTECTED);
if (!kvm_check_extension(s, KVM_CAP_S390_GMAP)
|| !kvm_check_extension(s, KVM_CAP_S390_COW)) {
@ -844,6 +854,30 @@ int kvm_s390_mem_op(S390CPU *cpu, vaddr addr, uint8_t ar, void *hostbuf,
return ret;
}
int kvm_s390_mem_op_pv(S390CPU *cpu, uint64_t offset, void *hostbuf,
int len, bool is_write)
{
struct kvm_s390_mem_op mem_op = {
.sida_offset = offset,
.size = len,
.op = is_write ? KVM_S390_MEMOP_SIDA_WRITE
: KVM_S390_MEMOP_SIDA_READ,
.buf = (uint64_t)hostbuf,
};
int ret;
if (!cap_mem_op || !cap_protected) {
return -ENOSYS;
}
ret = kvm_vcpu_ioctl(CPU(cpu), KVM_S390_MEM_OP, &mem_op);
if (ret < 0) {
error_report("KVM_S390_MEM_OP failed: %s", strerror(-ret));
abort();
}
return ret;
}
/*
* Legacy layout for s390:
* Older S390 KVM requires the topmost vma of the RAM to be
@ -1199,12 +1233,27 @@ static void kvm_sclp_service_call(S390CPU *cpu, struct kvm_run *run,
sccb = env->regs[ipbh0 & 0xf];
code = env->regs[(ipbh0 & 0xf0) >> 4];
r = sclp_service_call(env, sccb, code);
if (r < 0) {
kvm_s390_program_interrupt(cpu, -r);
return;
switch (run->s390_sieic.icptcode) {
case ICPT_PV_INSTR_NOTIFICATION:
g_assert(s390_is_pv());
/* The notification intercepts are currently handled by KVM */
error_report("unexpected SCLP PV notification");
exit(1);
break;
case ICPT_PV_INSTR:
g_assert(s390_is_pv());
sclp_service_call_protected(env, sccb, code);
/* Setting the CC is done by the Ultravisor. */
break;
case ICPT_INSTRUCTION:
g_assert(!s390_is_pv());
r = sclp_service_call(env, sccb, code);
if (r < 0) {
kvm_s390_program_interrupt(cpu, -r);
return;
}
setcc(cpu, r);
}
setcc(cpu, r);
}
static int handle_b2(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1)
@ -1693,6 +1742,8 @@ static int handle_intercept(S390CPU *cpu)
(long)cs->kvm_run->psw_addr);
switch (icpt_code) {
case ICPT_INSTRUCTION:
case ICPT_PV_INSTR:
case ICPT_PV_INSTR_NOTIFICATION:
r = handle_instruction(cpu, run);
break;
case ICPT_PROGRAM:
@ -1773,7 +1824,9 @@ static void insert_stsi_3_2_2(S390CPU *cpu, __u64 addr, uint8_t ar)
SysIB_322 sysib;
int del, i;
if (s390_cpu_virt_mem_read(cpu, addr, ar, &sysib, sizeof(sysib))) {
if (s390_is_pv()) {
s390_cpu_pv_mem_read(cpu, 0, &sysib, sizeof(sysib));
} else if (s390_cpu_virt_mem_read(cpu, addr, ar, &sysib, sizeof(sysib))) {
return;
}
/* Shift the stack of Extended Names to prepare for our own data */
@ -1826,7 +1879,11 @@ static void insert_stsi_3_2_2(S390CPU *cpu, __u64 addr, uint8_t ar)
/* Insert UUID */
memcpy(sysib.vm[0].uuid, &qemu_uuid, sizeof(sysib.vm[0].uuid));
s390_cpu_virt_mem_write(cpu, addr, ar, &sysib, sizeof(sysib));
if (s390_is_pv()) {
s390_cpu_pv_mem_write(cpu, 0, &sysib, sizeof(sysib));
} else {
s390_cpu_virt_mem_write(cpu, addr, ar, &sysib, sizeof(sysib));
}
}
static int handle_stsi(S390CPU *cpu)
@ -2368,6 +2425,14 @@ void kvm_s390_get_host_cpu_model(S390CPUModel *model, Error **errp)
clear_bit(S390_FEAT_BPB, model->features);
}
/*
* If we have support for protected virtualization, indicate
* the protected virtualization IPL unpack facility.
*/
if (cap_protected) {
set_bit(S390_FEAT_UNPACK, model->features);
}
/* We emulate a zPCI bus and AEN, therefore we don't need HW support */
set_bit(S390_FEAT_ZPCI, model->features);
set_bit(S390_FEAT_ADAPTER_EVENT_NOTIFICATION, model->features);

View File

@ -19,10 +19,13 @@ void kvm_s390_vcpu_interrupt(S390CPU *cpu, struct kvm_s390_irq *irq);
void kvm_s390_access_exception(S390CPU *cpu, uint16_t code, uint64_t te_code);
int kvm_s390_mem_op(S390CPU *cpu, vaddr addr, uint8_t ar, void *hostbuf,
int len, bool is_write);
int kvm_s390_mem_op_pv(S390CPU *cpu, vaddr addr, void *hostbuf, int len,
bool is_write);
void kvm_s390_program_interrupt(S390CPU *cpu, uint16_t code);
int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state);
void kvm_s390_vcpu_interrupt_pre_save(S390CPU *cpu);
int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu);
int kvm_s390_get_hpage_1m(void);
int kvm_s390_get_ri(void);
int kvm_s390_get_gs(void);
int kvm_s390_get_clock(uint8_t *tod_high, uint64_t *tod_clock);

View File

@ -474,6 +474,20 @@ static int translate_pages(S390CPU *cpu, vaddr addr, int nr_pages,
return 0;
}
int s390_cpu_pv_mem_rw(S390CPU *cpu, unsigned int offset, void *hostbuf,
int len, bool is_write)
{
int ret;
if (kvm_enabled()) {
ret = kvm_s390_mem_op_pv(cpu, offset, hostbuf, len, is_write);
} else {
/* Protected Virtualization is a KVM/Hardware only feature */
g_assert_not_reached();
}
return ret;
}
/**
* s390_cpu_virt_mem_rw:
* @laddr: the logical start address