diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2020-04-30 14:00:36 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2020-04-30 14:00:36 +0100 |
commit | 16aaacb307ed607b9780c12702c44f0fe52edc7e (patch) | |
tree | 46cb25b7cfb44f59cb0f49c03b93ad1089199f68 /target | |
parent | 68bfd7db1e8b718187fd0ba4dde32396efcde668 (diff) | |
parent | fbc1384ccd48fa7c0c38f950adf7992a4fb6042e (diff) |
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>
Diffstat (limited to 'target')
-rw-r--r-- | target/s390x/cpu.c | 27 | ||||
-rw-r--r-- | target/s390x/cpu.h | 7 | ||||
-rw-r--r-- | target/s390x/cpu_features_def.inc.h | 1 | ||||
-rw-r--r-- | target/s390x/diag.c | 75 | ||||
-rw-r--r-- | target/s390x/gen-features.c | 1 | ||||
-rw-r--r-- | target/s390x/helper.c | 6 | ||||
-rw-r--r-- | target/s390x/ioinst.c | 96 | ||||
-rw-r--r-- | target/s390x/kvm-stub.c | 5 | ||||
-rw-r--r-- | target/s390x/kvm.c | 79 | ||||
-rw-r--r-- | target/s390x/kvm_s390x.h | 3 | ||||
-rw-r--r-- | target/s390x/mmu_helper.c | 14 |
11 files changed, 256 insertions, 58 deletions
diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c index 427a46e3e1..f2ccf0a06a 100644 --- a/target/s390x/cpu.c +++ b/target/s390x/cpu.c @@ -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 diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h index 1d17709d6e..035427521c 100644 --- a/target/s390x/cpu.h +++ b/target/s390x/cpu.h @@ -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); diff --git a/target/s390x/cpu_features_def.inc.h b/target/s390x/cpu_features_def.inc.h index 31dff0d84e..60db28351d 100644 --- a/target/s390x/cpu_features_def.inc.h +++ b/target/s390x/cpu_features_def.inc.h @@ -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") diff --git a/target/s390x/diag.c b/target/s390x/diag.c index 54e5670b3f..1a48429564 100644 --- a/target/s390x/diag.c +++ b/target/s390x/diag.c @@ -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 { + 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; diff --git a/target/s390x/gen-features.c b/target/s390x/gen-features.c index 6278845b12..8ddeebc544 100644 --- a/target/s390x/gen-features.c +++ b/target/s390x/gen-features.c @@ -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) diff --git a/target/s390x/helper.c b/target/s390x/helper.c index ed72684911..09f60406aa 100644 --- a/target/s390x/helper.c +++ b/target/s390x/helper.c @@ -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; diff --git a/target/s390x/ioinst.c b/target/s390x/ioinst.c index 0e840cc579..7a14c52c12 100644 --- a/target/s390x/ioinst.c +++ b/target/s390x/ioinst.c @@ -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,7 +262,7 @@ 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; @@ -242,6 +270,13 @@ void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, 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 * access execption if it is not) first. @@ -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); + } } } diff --git a/target/s390x/kvm-stub.c b/target/s390x/kvm-stub.c index c4cd497f85..aa185017a2 100644 --- a/target/s390x/kvm-stub.c +++ b/target/s390x/kvm-stub.c @@ -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; diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c index 7f7ebab842..69881a0da0 100644 --- a/target/s390x/kvm.c +++ b/target/s390x/kvm.c @@ -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); diff --git a/target/s390x/kvm_s390x.h b/target/s390x/kvm_s390x.h index 0b21789796..6ab17c81b7 100644 --- a/target/s390x/kvm_s390x.h +++ b/target/s390x/kvm_s390x.h @@ -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); diff --git a/target/s390x/mmu_helper.c b/target/s390x/mmu_helper.c index 0be2f300bb..7d9f3059cd 100644 --- a/target/s390x/mmu_helper.c +++ b/target/s390x/mmu_helper.c @@ -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 |