xref: /openbmc/qemu/target/s390x/kvm/kvm.c (revision b5ab62b3c0050612c7f9b0b4baeb44ebab42775a)
167043607SCho, Yu-Chen /*
267043607SCho, Yu-Chen  * QEMU S390x KVM implementation
367043607SCho, Yu-Chen  *
467043607SCho, Yu-Chen  * Copyright (c) 2009 Alexander Graf <agraf@suse.de>
567043607SCho, Yu-Chen  * Copyright IBM Corp. 2012
667043607SCho, Yu-Chen  *
767043607SCho, Yu-Chen  * This program is free software; you can redistribute it and/or modify
867043607SCho, Yu-Chen  * it under the terms of the GNU General Public License as published by
967043607SCho, Yu-Chen  * the Free Software Foundation; either version 2 of the License, or
1067043607SCho, Yu-Chen  * (at your option) any later version.
1167043607SCho, Yu-Chen  *
1267043607SCho, Yu-Chen  * This program is distributed in the hope that it will be useful,
1367043607SCho, Yu-Chen  * but WITHOUT ANY WARRANTY; without even the implied warranty of
1467043607SCho, Yu-Chen  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1567043607SCho, Yu-Chen  * General Public License for more details.
1667043607SCho, Yu-Chen  *
1767043607SCho, Yu-Chen  * You should have received a copy of the GNU General Public License
1867043607SCho, Yu-Chen  * along with this program; if not, see <http://www.gnu.org/licenses/>.
1967043607SCho, Yu-Chen  */
2067043607SCho, Yu-Chen 
2167043607SCho, Yu-Chen #include "qemu/osdep.h"
2267043607SCho, Yu-Chen #include <sys/ioctl.h>
2367043607SCho, Yu-Chen 
2467043607SCho, Yu-Chen #include <linux/kvm.h>
2567043607SCho, Yu-Chen #include <asm/ptrace.h>
2667043607SCho, Yu-Chen 
2767043607SCho, Yu-Chen #include "cpu.h"
2867043607SCho, Yu-Chen #include "s390x-internal.h"
2967043607SCho, Yu-Chen #include "kvm_s390x.h"
3067043607SCho, Yu-Chen #include "sysemu/kvm_int.h"
3167043607SCho, Yu-Chen #include "qemu/cutils.h"
3267043607SCho, Yu-Chen #include "qapi/error.h"
3367043607SCho, Yu-Chen #include "qemu/error-report.h"
3467043607SCho, Yu-Chen #include "qemu/timer.h"
3567043607SCho, Yu-Chen #include "qemu/units.h"
3667043607SCho, Yu-Chen #include "qemu/main-loop.h"
3767043607SCho, Yu-Chen #include "qemu/mmap-alloc.h"
3867043607SCho, Yu-Chen #include "qemu/log.h"
3967043607SCho, Yu-Chen #include "sysemu/sysemu.h"
4067043607SCho, Yu-Chen #include "sysemu/hw_accel.h"
4167043607SCho, Yu-Chen #include "sysemu/runstate.h"
4267043607SCho, Yu-Chen #include "sysemu/device_tree.h"
435b7d54d4SAlex Bennée #include "gdbstub/enums.h"
4467043607SCho, Yu-Chen #include "exec/ram_addr.h"
4567043607SCho, Yu-Chen #include "trace.h"
4667043607SCho, Yu-Chen #include "hw/s390x/s390-pci-inst.h"
4767043607SCho, Yu-Chen #include "hw/s390x/s390-pci-bus.h"
4867043607SCho, Yu-Chen #include "hw/s390x/ipl.h"
4967043607SCho, Yu-Chen #include "hw/s390x/ebcdic.h"
5067043607SCho, Yu-Chen #include "exec/memattrs.h"
5167043607SCho, Yu-Chen #include "hw/s390x/s390-virtio-ccw.h"
5267043607SCho, Yu-Chen #include "hw/s390x/s390-virtio-hcall.h"
53f5f9c6eaSPhilippe Mathieu-Daudé #include "target/s390x/kvm/pv.h"
5467043607SCho, Yu-Chen 
5567043607SCho, Yu-Chen #define kvm_vm_check_mem_attr(s, attr) \
5667043607SCho, Yu-Chen     kvm_vm_check_attr(s, KVM_S390_VM_MEM_CTRL, attr)
5767043607SCho, Yu-Chen 
5867043607SCho, Yu-Chen #define IPA0_DIAG                       0x8300
5967043607SCho, Yu-Chen #define IPA0_SIGP                       0xae00
6067043607SCho, Yu-Chen #define IPA0_B2                         0xb200
6167043607SCho, Yu-Chen #define IPA0_B9                         0xb900
6267043607SCho, Yu-Chen #define IPA0_EB                         0xeb00
6367043607SCho, Yu-Chen #define IPA0_E3                         0xe300
6467043607SCho, Yu-Chen 
6567043607SCho, Yu-Chen #define PRIV_B2_SCLP_CALL               0x20
6667043607SCho, Yu-Chen #define PRIV_B2_CSCH                    0x30
6767043607SCho, Yu-Chen #define PRIV_B2_HSCH                    0x31
6867043607SCho, Yu-Chen #define PRIV_B2_MSCH                    0x32
6967043607SCho, Yu-Chen #define PRIV_B2_SSCH                    0x33
7067043607SCho, Yu-Chen #define PRIV_B2_STSCH                   0x34
7167043607SCho, Yu-Chen #define PRIV_B2_TSCH                    0x35
7267043607SCho, Yu-Chen #define PRIV_B2_TPI                     0x36
7367043607SCho, Yu-Chen #define PRIV_B2_SAL                     0x37
7467043607SCho, Yu-Chen #define PRIV_B2_RSCH                    0x38
7567043607SCho, Yu-Chen #define PRIV_B2_STCRW                   0x39
7667043607SCho, Yu-Chen #define PRIV_B2_STCPS                   0x3a
7767043607SCho, Yu-Chen #define PRIV_B2_RCHP                    0x3b
7867043607SCho, Yu-Chen #define PRIV_B2_SCHM                    0x3c
7967043607SCho, Yu-Chen #define PRIV_B2_CHSC                    0x5f
8067043607SCho, Yu-Chen #define PRIV_B2_SIGA                    0x74
8167043607SCho, Yu-Chen #define PRIV_B2_XSCH                    0x76
8267043607SCho, Yu-Chen 
8367043607SCho, Yu-Chen #define PRIV_EB_SQBS                    0x8a
8467043607SCho, Yu-Chen #define PRIV_EB_PCISTB                  0xd0
8567043607SCho, Yu-Chen #define PRIV_EB_SIC                     0xd1
8667043607SCho, Yu-Chen 
8767043607SCho, Yu-Chen #define PRIV_B9_EQBS                    0x9c
8867043607SCho, Yu-Chen #define PRIV_B9_CLP                     0xa0
89af37bad5SPierre Morel #define PRIV_B9_PTF                     0xa2
9067043607SCho, Yu-Chen #define PRIV_B9_PCISTG                  0xd0
9167043607SCho, Yu-Chen #define PRIV_B9_PCILG                   0xd2
9267043607SCho, Yu-Chen #define PRIV_B9_RPCIT                   0xd3
9367043607SCho, Yu-Chen 
9467043607SCho, Yu-Chen #define PRIV_E3_MPCIFC                  0xd0
9567043607SCho, Yu-Chen #define PRIV_E3_STPCIFC                 0xd4
9667043607SCho, Yu-Chen 
9767043607SCho, Yu-Chen #define DIAG_TIMEREVENT                 0x288
9867043607SCho, Yu-Chen #define DIAG_IPL                        0x308
9967043607SCho, Yu-Chen #define DIAG_SET_CONTROL_PROGRAM_CODES  0x318
10067043607SCho, Yu-Chen #define DIAG_KVM_HYPERCALL              0x500
10167043607SCho, Yu-Chen #define DIAG_KVM_BREAKPOINT             0x501
10267043607SCho, Yu-Chen 
10367043607SCho, Yu-Chen #define ICPT_INSTRUCTION                0x04
10467043607SCho, Yu-Chen #define ICPT_PROGRAM                    0x08
10567043607SCho, Yu-Chen #define ICPT_EXT_INT                    0x14
10667043607SCho, Yu-Chen #define ICPT_WAITPSW                    0x1c
10767043607SCho, Yu-Chen #define ICPT_SOFT_INTERCEPT             0x24
10867043607SCho, Yu-Chen #define ICPT_CPU_STOP                   0x28
10967043607SCho, Yu-Chen #define ICPT_OPEREXC                    0x2c
11067043607SCho, Yu-Chen #define ICPT_IO                         0x40
11167043607SCho, Yu-Chen #define ICPT_PV_INSTR                   0x68
11267043607SCho, Yu-Chen #define ICPT_PV_INSTR_NOTIFICATION      0x6c
11367043607SCho, Yu-Chen 
11467043607SCho, Yu-Chen #define NR_LOCAL_IRQS 32
11567043607SCho, Yu-Chen /*
11667043607SCho, Yu-Chen  * Needs to be big enough to contain max_cpus emergency signals
11767043607SCho, Yu-Chen  * and in addition NR_LOCAL_IRQS interrupts
11867043607SCho, Yu-Chen  */
11967043607SCho, Yu-Chen #define VCPU_IRQ_BUF_SIZE(max_cpus) (sizeof(struct kvm_s390_irq) * \
12067043607SCho, Yu-Chen                                      (max_cpus + NR_LOCAL_IRQS))
12167043607SCho, Yu-Chen /*
12267043607SCho, Yu-Chen  * KVM does only support memory slots up to KVM_MEM_MAX_NR_PAGES pages
12367043607SCho, Yu-Chen  * as the dirty bitmap must be managed by bitops that take an int as
12467043607SCho, Yu-Chen  * position indicator. This would end at an unaligned  address
12567043607SCho, Yu-Chen  * (0x7fffff00000). As future variants might provide larger pages
12667043607SCho, Yu-Chen  * and to make all addresses properly aligned, let us split at 4TB.
12767043607SCho, Yu-Chen  */
12867043607SCho, Yu-Chen #define KVM_SLOT_MAX_BYTES (4UL * TiB)
12967043607SCho, Yu-Chen 
13067043607SCho, Yu-Chen static CPUWatchpoint hw_watchpoint;
13167043607SCho, Yu-Chen /*
13267043607SCho, Yu-Chen  * We don't use a list because this structure is also used to transmit the
13367043607SCho, Yu-Chen  * hardware breakpoints to the kernel.
13467043607SCho, Yu-Chen  */
13567043607SCho, Yu-Chen static struct kvm_hw_breakpoint *hw_breakpoints;
13667043607SCho, Yu-Chen static int nb_hw_breakpoints;
13767043607SCho, Yu-Chen 
13867043607SCho, Yu-Chen const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
13967043607SCho, Yu-Chen     KVM_CAP_LAST_INFO
14067043607SCho, Yu-Chen };
14167043607SCho, Yu-Chen 
14267043607SCho, Yu-Chen static int cap_async_pf;
14367043607SCho, Yu-Chen static int cap_mem_op;
14454354861SJanis Schoetterl-Glausch static int cap_mem_op_extension;
14567043607SCho, Yu-Chen static int cap_s390_irq;
14667043607SCho, Yu-Chen static int cap_ri;
14767043607SCho, Yu-Chen static int cap_hpage_1m;
14867043607SCho, Yu-Chen static int cap_vcpu_resets;
14967043607SCho, Yu-Chen static int cap_protected;
150dd1d5fd9SMatthew Rosato static int cap_zpci_op;
151ad3b2e69SJanosch Frank static int cap_protected_dump;
15267043607SCho, Yu-Chen 
15354354861SJanis Schoetterl-Glausch static bool mem_op_storage_key_support;
15454354861SJanis Schoetterl-Glausch 
15567043607SCho, Yu-Chen static int active_cmma;
15667043607SCho, Yu-Chen 
kvm_s390_query_mem_limit(uint64_t * memory_limit)15767043607SCho, Yu-Chen static int kvm_s390_query_mem_limit(uint64_t *memory_limit)
15867043607SCho, Yu-Chen {
15967043607SCho, Yu-Chen     struct kvm_device_attr attr = {
16067043607SCho, Yu-Chen         .group = KVM_S390_VM_MEM_CTRL,
16167043607SCho, Yu-Chen         .attr = KVM_S390_VM_MEM_LIMIT_SIZE,
16267043607SCho, Yu-Chen         .addr = (uint64_t) memory_limit,
16367043607SCho, Yu-Chen     };
16467043607SCho, Yu-Chen 
16567043607SCho, Yu-Chen     return kvm_vm_ioctl(kvm_state, KVM_GET_DEVICE_ATTR, &attr);
16667043607SCho, Yu-Chen }
16767043607SCho, Yu-Chen 
kvm_s390_set_mem_limit(uint64_t new_limit,uint64_t * hw_limit)16867043607SCho, Yu-Chen int kvm_s390_set_mem_limit(uint64_t new_limit, uint64_t *hw_limit)
16967043607SCho, Yu-Chen {
17067043607SCho, Yu-Chen     int rc;
17167043607SCho, Yu-Chen 
17267043607SCho, Yu-Chen     struct kvm_device_attr attr = {
17367043607SCho, Yu-Chen         .group = KVM_S390_VM_MEM_CTRL,
17467043607SCho, Yu-Chen         .attr = KVM_S390_VM_MEM_LIMIT_SIZE,
17567043607SCho, Yu-Chen         .addr = (uint64_t) &new_limit,
17667043607SCho, Yu-Chen     };
17767043607SCho, Yu-Chen 
17867043607SCho, Yu-Chen     if (!kvm_vm_check_mem_attr(kvm_state, KVM_S390_VM_MEM_LIMIT_SIZE)) {
17967043607SCho, Yu-Chen         return 0;
18067043607SCho, Yu-Chen     }
18167043607SCho, Yu-Chen 
18267043607SCho, Yu-Chen     rc = kvm_s390_query_mem_limit(hw_limit);
18367043607SCho, Yu-Chen     if (rc) {
18467043607SCho, Yu-Chen         return rc;
18567043607SCho, Yu-Chen     } else if (*hw_limit < new_limit) {
18667043607SCho, Yu-Chen         return -E2BIG;
18767043607SCho, Yu-Chen     }
18867043607SCho, Yu-Chen 
18967043607SCho, Yu-Chen     return kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr);
19067043607SCho, Yu-Chen }
19167043607SCho, Yu-Chen 
kvm_s390_cmma_active(void)19267043607SCho, Yu-Chen int kvm_s390_cmma_active(void)
19367043607SCho, Yu-Chen {
19467043607SCho, Yu-Chen     return active_cmma;
19567043607SCho, Yu-Chen }
19667043607SCho, Yu-Chen 
kvm_s390_cmma_available(void)19767043607SCho, Yu-Chen static bool kvm_s390_cmma_available(void)
19867043607SCho, Yu-Chen {
19967043607SCho, Yu-Chen     static bool initialized, value;
20067043607SCho, Yu-Chen 
20167043607SCho, Yu-Chen     if (!initialized) {
20267043607SCho, Yu-Chen         initialized = true;
20367043607SCho, Yu-Chen         value = kvm_vm_check_mem_attr(kvm_state, KVM_S390_VM_MEM_ENABLE_CMMA) &&
20467043607SCho, Yu-Chen                 kvm_vm_check_mem_attr(kvm_state, KVM_S390_VM_MEM_CLR_CMMA);
20567043607SCho, Yu-Chen     }
20667043607SCho, Yu-Chen     return value;
20767043607SCho, Yu-Chen }
20867043607SCho, Yu-Chen 
kvm_s390_cmma_reset(void)20967043607SCho, Yu-Chen void kvm_s390_cmma_reset(void)
21067043607SCho, Yu-Chen {
21167043607SCho, Yu-Chen     int rc;
21267043607SCho, Yu-Chen     struct kvm_device_attr attr = {
21367043607SCho, Yu-Chen         .group = KVM_S390_VM_MEM_CTRL,
21467043607SCho, Yu-Chen         .attr = KVM_S390_VM_MEM_CLR_CMMA,
21567043607SCho, Yu-Chen     };
21667043607SCho, Yu-Chen 
21767043607SCho, Yu-Chen     if (!kvm_s390_cmma_active()) {
21867043607SCho, Yu-Chen         return;
21967043607SCho, Yu-Chen     }
22067043607SCho, Yu-Chen 
22167043607SCho, Yu-Chen     rc = kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr);
22267043607SCho, Yu-Chen     trace_kvm_clear_cmma(rc);
22367043607SCho, Yu-Chen }
22467043607SCho, Yu-Chen 
kvm_s390_enable_cmma(void)22567043607SCho, Yu-Chen static void kvm_s390_enable_cmma(void)
22667043607SCho, Yu-Chen {
22767043607SCho, Yu-Chen     int rc;
22867043607SCho, Yu-Chen     struct kvm_device_attr attr = {
22967043607SCho, Yu-Chen         .group = KVM_S390_VM_MEM_CTRL,
23067043607SCho, Yu-Chen         .attr = KVM_S390_VM_MEM_ENABLE_CMMA,
23167043607SCho, Yu-Chen     };
23267043607SCho, Yu-Chen 
23367043607SCho, Yu-Chen     if (cap_hpage_1m) {
23467043607SCho, Yu-Chen         warn_report("CMM will not be enabled because it is not "
23567043607SCho, Yu-Chen                     "compatible with huge memory backings.");
23667043607SCho, Yu-Chen         return;
23767043607SCho, Yu-Chen     }
23867043607SCho, Yu-Chen     rc = kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr);
23967043607SCho, Yu-Chen     active_cmma = !rc;
24067043607SCho, Yu-Chen     trace_kvm_enable_cmma(rc);
24167043607SCho, Yu-Chen }
24267043607SCho, Yu-Chen 
kvm_s390_set_crypto_attr(uint64_t attr)243354383c1SSteffen Eiden static void kvm_s390_set_crypto_attr(uint64_t attr)
24467043607SCho, Yu-Chen {
24567043607SCho, Yu-Chen     struct kvm_device_attr attribute = {
24667043607SCho, Yu-Chen         .group = KVM_S390_VM_CRYPTO,
24767043607SCho, Yu-Chen         .attr  = attr,
24867043607SCho, Yu-Chen     };
24967043607SCho, Yu-Chen 
25067043607SCho, Yu-Chen     int ret = kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attribute);
25167043607SCho, Yu-Chen 
25267043607SCho, Yu-Chen     if (ret) {
25367043607SCho, Yu-Chen         error_report("Failed to set crypto device attribute %lu: %s",
25467043607SCho, Yu-Chen                      attr, strerror(-ret));
25567043607SCho, Yu-Chen     }
25667043607SCho, Yu-Chen }
25767043607SCho, Yu-Chen 
kvm_s390_init_aes_kw(void)25867043607SCho, Yu-Chen static void kvm_s390_init_aes_kw(void)
25967043607SCho, Yu-Chen {
26067043607SCho, Yu-Chen     uint64_t attr = KVM_S390_VM_CRYPTO_DISABLE_AES_KW;
26167043607SCho, Yu-Chen 
26267043607SCho, Yu-Chen     if (object_property_get_bool(OBJECT(qdev_get_machine()), "aes-key-wrap",
26367043607SCho, Yu-Chen                                  NULL)) {
26467043607SCho, Yu-Chen             attr = KVM_S390_VM_CRYPTO_ENABLE_AES_KW;
26567043607SCho, Yu-Chen     }
26667043607SCho, Yu-Chen 
26767043607SCho, Yu-Chen     if (kvm_vm_check_attr(kvm_state, KVM_S390_VM_CRYPTO, attr)) {
268354383c1SSteffen Eiden             kvm_s390_set_crypto_attr(attr);
26967043607SCho, Yu-Chen     }
27067043607SCho, Yu-Chen }
27167043607SCho, Yu-Chen 
kvm_s390_init_dea_kw(void)27267043607SCho, Yu-Chen static void kvm_s390_init_dea_kw(void)
27367043607SCho, Yu-Chen {
27467043607SCho, Yu-Chen     uint64_t attr = KVM_S390_VM_CRYPTO_DISABLE_DEA_KW;
27567043607SCho, Yu-Chen 
27667043607SCho, Yu-Chen     if (object_property_get_bool(OBJECT(qdev_get_machine()), "dea-key-wrap",
27767043607SCho, Yu-Chen                                  NULL)) {
27867043607SCho, Yu-Chen             attr = KVM_S390_VM_CRYPTO_ENABLE_DEA_KW;
27967043607SCho, Yu-Chen     }
28067043607SCho, Yu-Chen 
28167043607SCho, Yu-Chen     if (kvm_vm_check_attr(kvm_state, KVM_S390_VM_CRYPTO, attr)) {
282354383c1SSteffen Eiden             kvm_s390_set_crypto_attr(attr);
28367043607SCho, Yu-Chen     }
28467043607SCho, Yu-Chen }
28567043607SCho, Yu-Chen 
kvm_s390_crypto_reset(void)28667043607SCho, Yu-Chen void kvm_s390_crypto_reset(void)
28767043607SCho, Yu-Chen {
28867043607SCho, Yu-Chen     if (s390_has_feat(S390_FEAT_MSA_EXT_3)) {
28967043607SCho, Yu-Chen         kvm_s390_init_aes_kw();
29067043607SCho, Yu-Chen         kvm_s390_init_dea_kw();
29167043607SCho, Yu-Chen     }
29267043607SCho, Yu-Chen }
29367043607SCho, Yu-Chen 
kvm_s390_set_max_pagesize(uint64_t pagesize,Error ** errp)29467043607SCho, Yu-Chen void kvm_s390_set_max_pagesize(uint64_t pagesize, Error **errp)
29567043607SCho, Yu-Chen {
29667043607SCho, Yu-Chen     if (pagesize == 4 * KiB) {
29767043607SCho, Yu-Chen         return;
29867043607SCho, Yu-Chen     }
29967043607SCho, Yu-Chen 
30067043607SCho, Yu-Chen     if (!hpage_1m_allowed()) {
30167043607SCho, Yu-Chen         error_setg(errp, "This QEMU machine does not support huge page "
30267043607SCho, Yu-Chen                    "mappings");
30367043607SCho, Yu-Chen         return;
30467043607SCho, Yu-Chen     }
30567043607SCho, Yu-Chen 
30667043607SCho, Yu-Chen     if (pagesize != 1 * MiB) {
30767043607SCho, Yu-Chen         error_setg(errp, "Memory backing with 2G pages was specified, "
30867043607SCho, Yu-Chen                    "but KVM does not support this memory backing");
30967043607SCho, Yu-Chen         return;
31067043607SCho, Yu-Chen     }
31167043607SCho, Yu-Chen 
31267043607SCho, Yu-Chen     if (kvm_vm_enable_cap(kvm_state, KVM_CAP_S390_HPAGE_1M, 0)) {
31367043607SCho, Yu-Chen         error_setg(errp, "Memory backing with 1M pages was specified, "
31467043607SCho, Yu-Chen                    "but KVM does not support this memory backing");
31567043607SCho, Yu-Chen         return;
31667043607SCho, Yu-Chen     }
31767043607SCho, Yu-Chen 
31867043607SCho, Yu-Chen     cap_hpage_1m = 1;
31967043607SCho, Yu-Chen }
32067043607SCho, Yu-Chen 
kvm_s390_get_hpage_1m(void)32167043607SCho, Yu-Chen int kvm_s390_get_hpage_1m(void)
32267043607SCho, Yu-Chen {
32367043607SCho, Yu-Chen     return cap_hpage_1m;
32467043607SCho, Yu-Chen }
32567043607SCho, Yu-Chen 
ccw_machine_class_foreach(ObjectClass * oc,void * opaque)32667043607SCho, Yu-Chen static void ccw_machine_class_foreach(ObjectClass *oc, void *opaque)
32767043607SCho, Yu-Chen {
32867043607SCho, Yu-Chen     MachineClass *mc = MACHINE_CLASS(oc);
32967043607SCho, Yu-Chen 
33067043607SCho, Yu-Chen     mc->default_cpu_type = S390_CPU_TYPE_NAME("host");
33167043607SCho, Yu-Chen }
33267043607SCho, Yu-Chen 
kvm_arch_get_default_type(MachineState * ms)3335e0d6590SAkihiko Odaki int kvm_arch_get_default_type(MachineState *ms)
3345e0d6590SAkihiko Odaki {
3355e0d6590SAkihiko Odaki     return 0;
3365e0d6590SAkihiko Odaki }
3375e0d6590SAkihiko Odaki 
kvm_arch_init(MachineState * ms,KVMState * s)33867043607SCho, Yu-Chen int kvm_arch_init(MachineState *ms, KVMState *s)
33967043607SCho, Yu-Chen {
340c35a79cbSThomas Huth     int required_caps[] = {
341c35a79cbSThomas Huth         KVM_CAP_DEVICE_CTRL,
342c35a79cbSThomas Huth         KVM_CAP_SYNC_REGS,
343c35a79cbSThomas Huth     };
344c35a79cbSThomas Huth 
345c35a79cbSThomas Huth     for (int i = 0; i < ARRAY_SIZE(required_caps); i++) {
346c35a79cbSThomas Huth         if (!kvm_check_extension(s, required_caps[i])) {
347c35a79cbSThomas Huth             error_report("KVM is missing capability #%d - "
348c35a79cbSThomas Huth                          "please use kernel 3.15 or newer", required_caps[i]);
349c35a79cbSThomas Huth             return -1;
350c35a79cbSThomas Huth         }
351c35a79cbSThomas Huth     }
352c35a79cbSThomas Huth 
35367043607SCho, Yu-Chen     object_class_foreach(ccw_machine_class_foreach, TYPE_S390_CCW_MACHINE,
35467043607SCho, Yu-Chen                          false, NULL);
35567043607SCho, Yu-Chen 
35667043607SCho, Yu-Chen     if (!kvm_check_extension(s, KVM_CAP_S390_COW)) {
35767043607SCho, Yu-Chen         error_report("KVM is missing capability KVM_CAP_S390_COW - "
35867043607SCho, Yu-Chen                      "unsupported environment");
35967043607SCho, Yu-Chen         return -1;
36067043607SCho, Yu-Chen     }
36167043607SCho, Yu-Chen 
36267043607SCho, Yu-Chen     cap_async_pf = kvm_check_extension(s, KVM_CAP_ASYNC_PF);
36367043607SCho, Yu-Chen     cap_mem_op = kvm_check_extension(s, KVM_CAP_S390_MEM_OP);
36454354861SJanis Schoetterl-Glausch     cap_mem_op_extension = kvm_check_extension(s, KVM_CAP_S390_MEM_OP_EXTENSION);
36554354861SJanis Schoetterl-Glausch     mem_op_storage_key_support = cap_mem_op_extension > 0;
36667043607SCho, Yu-Chen     cap_s390_irq = kvm_check_extension(s, KVM_CAP_S390_INJECT_IRQ);
36767043607SCho, Yu-Chen     cap_vcpu_resets = kvm_check_extension(s, KVM_CAP_S390_VCPU_RESETS);
36867043607SCho, Yu-Chen     cap_protected = kvm_check_extension(s, KVM_CAP_S390_PROTECTED);
369dd1d5fd9SMatthew Rosato     cap_zpci_op = kvm_check_extension(s, KVM_CAP_S390_ZPCI_OP);
370ad3b2e69SJanosch Frank     cap_protected_dump = kvm_check_extension(s, KVM_CAP_S390_PROTECTED_DUMP);
37167043607SCho, Yu-Chen 
37267043607SCho, Yu-Chen     kvm_vm_enable_cap(s, KVM_CAP_S390_USER_SIGP, 0);
37367043607SCho, Yu-Chen     kvm_vm_enable_cap(s, KVM_CAP_S390_VECTOR_REGISTERS, 0);
37467043607SCho, Yu-Chen     kvm_vm_enable_cap(s, KVM_CAP_S390_USER_STSI, 0);
375f530b9e7SPierre Morel     kvm_vm_enable_cap(s, KVM_CAP_S390_CPU_TOPOLOGY, 0);
37667043607SCho, Yu-Chen     if (ri_allowed()) {
37767043607SCho, Yu-Chen         if (kvm_vm_enable_cap(s, KVM_CAP_S390_RI, 0) == 0) {
37867043607SCho, Yu-Chen             cap_ri = 1;
37967043607SCho, Yu-Chen         }
38067043607SCho, Yu-Chen     }
38167043607SCho, Yu-Chen     if (cpu_model_allowed()) {
38267043607SCho, Yu-Chen         kvm_vm_enable_cap(s, KVM_CAP_S390_GS, 0);
38367043607SCho, Yu-Chen     }
38467043607SCho, Yu-Chen 
38567043607SCho, Yu-Chen     /*
38667043607SCho, Yu-Chen      * The migration interface for ais was introduced with kernel 4.13
38767043607SCho, Yu-Chen      * but the capability itself had been active since 4.12. As migration
38867043607SCho, Yu-Chen      * support is considered necessary, we only try to enable this for
38967043607SCho, Yu-Chen      * newer machine types if KVM_CAP_S390_AIS_MIGRATION is available.
39067043607SCho, Yu-Chen      */
39167043607SCho, Yu-Chen     if (cpu_model_allowed() && kvm_kernel_irqchip_allowed() &&
39267043607SCho, Yu-Chen         kvm_check_extension(s, KVM_CAP_S390_AIS_MIGRATION)) {
39367043607SCho, Yu-Chen         kvm_vm_enable_cap(s, KVM_CAP_S390_AIS, 0);
39467043607SCho, Yu-Chen     }
39567043607SCho, Yu-Chen 
39667043607SCho, Yu-Chen     kvm_set_max_memslot_size(KVM_SLOT_MAX_BYTES);
39767043607SCho, Yu-Chen     return 0;
39867043607SCho, Yu-Chen }
39967043607SCho, Yu-Chen 
kvm_arch_irqchip_create(KVMState * s)40067043607SCho, Yu-Chen int kvm_arch_irqchip_create(KVMState *s)
40167043607SCho, Yu-Chen {
40267043607SCho, Yu-Chen     return 0;
40367043607SCho, Yu-Chen }
40467043607SCho, Yu-Chen 
kvm_arch_vcpu_id(CPUState * cpu)40567043607SCho, Yu-Chen unsigned long kvm_arch_vcpu_id(CPUState *cpu)
40667043607SCho, Yu-Chen {
40767043607SCho, Yu-Chen     return cpu->cpu_index;
40867043607SCho, Yu-Chen }
40967043607SCho, Yu-Chen 
kvm_arch_init_vcpu(CPUState * cs)41067043607SCho, Yu-Chen int kvm_arch_init_vcpu(CPUState *cs)
41167043607SCho, Yu-Chen {
41267043607SCho, Yu-Chen     unsigned int max_cpus = MACHINE(qdev_get_machine())->smp.max_cpus;
41367043607SCho, Yu-Chen     S390CPU *cpu = S390_CPU(cs);
41467043607SCho, Yu-Chen     kvm_s390_set_cpu_state(cpu, cpu->env.cpu_state);
41567043607SCho, Yu-Chen     cpu->irqstate = g_malloc0(VCPU_IRQ_BUF_SIZE(max_cpus));
41667043607SCho, Yu-Chen     return 0;
41767043607SCho, Yu-Chen }
41867043607SCho, Yu-Chen 
kvm_arch_destroy_vcpu(CPUState * cs)41967043607SCho, Yu-Chen int kvm_arch_destroy_vcpu(CPUState *cs)
42067043607SCho, Yu-Chen {
42167043607SCho, Yu-Chen     S390CPU *cpu = S390_CPU(cs);
42267043607SCho, Yu-Chen 
42367043607SCho, Yu-Chen     g_free(cpu->irqstate);
42467043607SCho, Yu-Chen     cpu->irqstate = NULL;
42567043607SCho, Yu-Chen 
42667043607SCho, Yu-Chen     return 0;
42767043607SCho, Yu-Chen }
42867043607SCho, Yu-Chen 
kvm_s390_reset_vcpu(S390CPU * cpu,unsigned long type)42967043607SCho, Yu-Chen static void kvm_s390_reset_vcpu(S390CPU *cpu, unsigned long type)
43067043607SCho, Yu-Chen {
43167043607SCho, Yu-Chen     CPUState *cs = CPU(cpu);
43267043607SCho, Yu-Chen 
43367043607SCho, Yu-Chen     /*
43467043607SCho, Yu-Chen      * The reset call is needed here to reset in-kernel vcpu data that
43567043607SCho, Yu-Chen      * we can't access directly from QEMU (i.e. with older kernels
43667043607SCho, Yu-Chen      * which don't support sync_regs/ONE_REG).  Before this ioctl
43767043607SCho, Yu-Chen      * cpu_synchronize_state() is called in common kvm code
43867043607SCho, Yu-Chen      * (kvm-all).
43967043607SCho, Yu-Chen      */
44067043607SCho, Yu-Chen     if (kvm_vcpu_ioctl(cs, type)) {
44167043607SCho, Yu-Chen         error_report("CPU reset failed on CPU %i type %lx",
44267043607SCho, Yu-Chen                      cs->cpu_index, type);
44367043607SCho, Yu-Chen     }
44467043607SCho, Yu-Chen }
44567043607SCho, Yu-Chen 
kvm_s390_reset_vcpu_initial(S390CPU * cpu)44667043607SCho, Yu-Chen void kvm_s390_reset_vcpu_initial(S390CPU *cpu)
44767043607SCho, Yu-Chen {
44867043607SCho, Yu-Chen     kvm_s390_reset_vcpu(cpu, KVM_S390_INITIAL_RESET);
44967043607SCho, Yu-Chen }
45067043607SCho, Yu-Chen 
kvm_s390_reset_vcpu_clear(S390CPU * cpu)45167043607SCho, Yu-Chen void kvm_s390_reset_vcpu_clear(S390CPU *cpu)
45267043607SCho, Yu-Chen {
45367043607SCho, Yu-Chen     if (cap_vcpu_resets) {
45467043607SCho, Yu-Chen         kvm_s390_reset_vcpu(cpu, KVM_S390_CLEAR_RESET);
45567043607SCho, Yu-Chen     } else {
45667043607SCho, Yu-Chen         kvm_s390_reset_vcpu(cpu, KVM_S390_INITIAL_RESET);
45767043607SCho, Yu-Chen     }
45867043607SCho, Yu-Chen }
45967043607SCho, Yu-Chen 
kvm_s390_reset_vcpu_normal(S390CPU * cpu)46067043607SCho, Yu-Chen void kvm_s390_reset_vcpu_normal(S390CPU *cpu)
46167043607SCho, Yu-Chen {
46267043607SCho, Yu-Chen     if (cap_vcpu_resets) {
46367043607SCho, Yu-Chen         kvm_s390_reset_vcpu(cpu, KVM_S390_NORMAL_RESET);
46467043607SCho, Yu-Chen     }
46567043607SCho, Yu-Chen }
46667043607SCho, Yu-Chen 
can_sync_regs(CPUState * cs,int regs)46767043607SCho, Yu-Chen static int can_sync_regs(CPUState *cs, int regs)
46867043607SCho, Yu-Chen {
4691d107166SThomas Huth     return (cs->kvm_run->kvm_valid_regs & regs) == regs;
47067043607SCho, Yu-Chen }
47167043607SCho, Yu-Chen 
4721d107166SThomas Huth #define KVM_SYNC_REQUIRED_REGS (KVM_SYNC_GPRS | KVM_SYNC_ACRS | \
4731d107166SThomas Huth                                 KVM_SYNC_CRS | KVM_SYNC_PREFIX)
4741d107166SThomas Huth 
kvm_arch_put_registers(CPUState * cs,int level,Error ** errp)475*a1676bb3SJulia Suvorova int kvm_arch_put_registers(CPUState *cs, int level, Error **errp)
47667043607SCho, Yu-Chen {
477d0143fa9SPhilippe Mathieu-Daudé     CPUS390XState *env = cpu_env(cs);
47867043607SCho, Yu-Chen     struct kvm_fpu fpu = {};
47967043607SCho, Yu-Chen     int r;
48067043607SCho, Yu-Chen     int i;
48167043607SCho, Yu-Chen 
4821d107166SThomas Huth     g_assert(can_sync_regs(cs, KVM_SYNC_REQUIRED_REGS));
4831d107166SThomas Huth 
48467043607SCho, Yu-Chen     /* always save the PSW  and the GPRS*/
48567043607SCho, Yu-Chen     cs->kvm_run->psw_addr = env->psw.addr;
48667043607SCho, Yu-Chen     cs->kvm_run->psw_mask = env->psw.mask;
48767043607SCho, Yu-Chen 
4881d107166SThomas Huth     memcpy(cs->kvm_run->s.regs.gprs, env->regs, sizeof(cs->kvm_run->s.regs.gprs));
48967043607SCho, Yu-Chen     cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_GPRS;
49067043607SCho, Yu-Chen 
49167043607SCho, Yu-Chen     if (can_sync_regs(cs, KVM_SYNC_VRS)) {
49267043607SCho, Yu-Chen         for (i = 0; i < 32; i++) {
49367043607SCho, Yu-Chen             cs->kvm_run->s.regs.vrs[i][0] = env->vregs[i][0];
49467043607SCho, Yu-Chen             cs->kvm_run->s.regs.vrs[i][1] = env->vregs[i][1];
49567043607SCho, Yu-Chen         }
49667043607SCho, Yu-Chen         cs->kvm_run->s.regs.fpc = env->fpc;
49767043607SCho, Yu-Chen         cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_VRS;
49867043607SCho, Yu-Chen     } else if (can_sync_regs(cs, KVM_SYNC_FPRS)) {
49967043607SCho, Yu-Chen         for (i = 0; i < 16; i++) {
50067043607SCho, Yu-Chen             cs->kvm_run->s.regs.fprs[i] = *get_freg(env, i);
50167043607SCho, Yu-Chen         }
50267043607SCho, Yu-Chen         cs->kvm_run->s.regs.fpc = env->fpc;
50367043607SCho, Yu-Chen         cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_FPRS;
50467043607SCho, Yu-Chen     } else {
50567043607SCho, Yu-Chen         /* Floating point */
50667043607SCho, Yu-Chen         for (i = 0; i < 16; i++) {
50767043607SCho, Yu-Chen             fpu.fprs[i] = *get_freg(env, i);
50867043607SCho, Yu-Chen         }
50967043607SCho, Yu-Chen         fpu.fpc = env->fpc;
51067043607SCho, Yu-Chen 
51167043607SCho, Yu-Chen         r = kvm_vcpu_ioctl(cs, KVM_SET_FPU, &fpu);
51267043607SCho, Yu-Chen         if (r < 0) {
51367043607SCho, Yu-Chen             return r;
51467043607SCho, Yu-Chen         }
51567043607SCho, Yu-Chen     }
51667043607SCho, Yu-Chen 
51767043607SCho, Yu-Chen     /* Do we need to save more than that? */
51867043607SCho, Yu-Chen     if (level == KVM_PUT_RUNTIME_STATE) {
51967043607SCho, Yu-Chen         return 0;
52067043607SCho, Yu-Chen     }
52167043607SCho, Yu-Chen 
5221d107166SThomas Huth     /*
5231d107166SThomas Huth      * Access registers, control registers and the prefix - these are
5241d107166SThomas Huth      * always available via kvm_sync_regs in the kernels that we support
5251d107166SThomas Huth      */
5261d107166SThomas Huth     memcpy(cs->kvm_run->s.regs.acrs, env->aregs, sizeof(cs->kvm_run->s.regs.acrs));
5271d107166SThomas Huth     memcpy(cs->kvm_run->s.regs.crs, env->cregs, sizeof(cs->kvm_run->s.regs.crs));
5281d107166SThomas Huth     cs->kvm_run->s.regs.prefix = env->psa;
5291d107166SThomas Huth     cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_ACRS | KVM_SYNC_CRS | KVM_SYNC_PREFIX;
5301d107166SThomas Huth 
53167043607SCho, Yu-Chen     if (can_sync_regs(cs, KVM_SYNC_ARCH0)) {
53267043607SCho, Yu-Chen         cs->kvm_run->s.regs.cputm = env->cputm;
53367043607SCho, Yu-Chen         cs->kvm_run->s.regs.ckc = env->ckc;
53467043607SCho, Yu-Chen         cs->kvm_run->s.regs.todpr = env->todpr;
53567043607SCho, Yu-Chen         cs->kvm_run->s.regs.gbea = env->gbea;
53667043607SCho, Yu-Chen         cs->kvm_run->s.regs.pp = env->pp;
53767043607SCho, Yu-Chen         cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_ARCH0;
53867043607SCho, Yu-Chen     } else {
53967043607SCho, Yu-Chen         /*
54067043607SCho, Yu-Chen          * These ONE_REGS are not protected by a capability. As they are only
54167043607SCho, Yu-Chen          * necessary for migration we just trace a possible error, but don't
54267043607SCho, Yu-Chen          * return with an error return code.
54367043607SCho, Yu-Chen          */
54467043607SCho, Yu-Chen         kvm_set_one_reg(cs, KVM_REG_S390_CPU_TIMER, &env->cputm);
54567043607SCho, Yu-Chen         kvm_set_one_reg(cs, KVM_REG_S390_CLOCK_COMP, &env->ckc);
54667043607SCho, Yu-Chen         kvm_set_one_reg(cs, KVM_REG_S390_TODPR, &env->todpr);
54767043607SCho, Yu-Chen         kvm_set_one_reg(cs, KVM_REG_S390_GBEA, &env->gbea);
54867043607SCho, Yu-Chen         kvm_set_one_reg(cs, KVM_REG_S390_PP, &env->pp);
54967043607SCho, Yu-Chen     }
55067043607SCho, Yu-Chen 
55167043607SCho, Yu-Chen     if (can_sync_regs(cs, KVM_SYNC_RICCB)) {
55267043607SCho, Yu-Chen         memcpy(cs->kvm_run->s.regs.riccb, env->riccb, 64);
55367043607SCho, Yu-Chen         cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_RICCB;
55467043607SCho, Yu-Chen     }
55567043607SCho, Yu-Chen 
55667043607SCho, Yu-Chen     /* pfault parameters */
55767043607SCho, Yu-Chen     if (can_sync_regs(cs, KVM_SYNC_PFAULT)) {
55867043607SCho, Yu-Chen         cs->kvm_run->s.regs.pft = env->pfault_token;
55967043607SCho, Yu-Chen         cs->kvm_run->s.regs.pfs = env->pfault_select;
56067043607SCho, Yu-Chen         cs->kvm_run->s.regs.pfc = env->pfault_compare;
56167043607SCho, Yu-Chen         cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_PFAULT;
56267043607SCho, Yu-Chen     } else if (cap_async_pf) {
56367043607SCho, Yu-Chen         r = kvm_set_one_reg(cs, KVM_REG_S390_PFTOKEN, &env->pfault_token);
56467043607SCho, Yu-Chen         if (r < 0) {
56567043607SCho, Yu-Chen             return r;
56667043607SCho, Yu-Chen         }
56767043607SCho, Yu-Chen         r = kvm_set_one_reg(cs, KVM_REG_S390_PFCOMPARE, &env->pfault_compare);
56867043607SCho, Yu-Chen         if (r < 0) {
56967043607SCho, Yu-Chen             return r;
57067043607SCho, Yu-Chen         }
57167043607SCho, Yu-Chen         r = kvm_set_one_reg(cs, KVM_REG_S390_PFSELECT, &env->pfault_select);
57267043607SCho, Yu-Chen         if (r < 0) {
57367043607SCho, Yu-Chen             return r;
57467043607SCho, Yu-Chen         }
57567043607SCho, Yu-Chen     }
57667043607SCho, Yu-Chen 
57767043607SCho, Yu-Chen     if (can_sync_regs(cs, KVM_SYNC_GSCB)) {
57867043607SCho, Yu-Chen         memcpy(cs->kvm_run->s.regs.gscb, env->gscb, 32);
57967043607SCho, Yu-Chen         cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_GSCB;
58067043607SCho, Yu-Chen     }
58167043607SCho, Yu-Chen 
58267043607SCho, Yu-Chen     if (can_sync_regs(cs, KVM_SYNC_BPBC)) {
58367043607SCho, Yu-Chen         cs->kvm_run->s.regs.bpbc = env->bpbc;
58467043607SCho, Yu-Chen         cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_BPBC;
58567043607SCho, Yu-Chen     }
58667043607SCho, Yu-Chen 
58767043607SCho, Yu-Chen     if (can_sync_regs(cs, KVM_SYNC_ETOKEN)) {
58867043607SCho, Yu-Chen         cs->kvm_run->s.regs.etoken = env->etoken;
58967043607SCho, Yu-Chen         cs->kvm_run->s.regs.etoken_extension  = env->etoken_extension;
59067043607SCho, Yu-Chen         cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_ETOKEN;
59167043607SCho, Yu-Chen     }
59267043607SCho, Yu-Chen 
59367043607SCho, Yu-Chen     if (can_sync_regs(cs, KVM_SYNC_DIAG318)) {
59467043607SCho, Yu-Chen         cs->kvm_run->s.regs.diag318 = env->diag318_info;
59567043607SCho, Yu-Chen         cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_DIAG318;
59667043607SCho, Yu-Chen     }
59767043607SCho, Yu-Chen 
59867043607SCho, Yu-Chen     return 0;
59967043607SCho, Yu-Chen }
60067043607SCho, Yu-Chen 
kvm_arch_get_registers(CPUState * cs,Error ** errp)601*a1676bb3SJulia Suvorova int kvm_arch_get_registers(CPUState *cs, Error **errp)
60267043607SCho, Yu-Chen {
603d0143fa9SPhilippe Mathieu-Daudé     CPUS390XState *env = cpu_env(cs);
60467043607SCho, Yu-Chen     struct kvm_fpu fpu;
60567043607SCho, Yu-Chen     int i, r;
60667043607SCho, Yu-Chen 
60767043607SCho, Yu-Chen     /* get the PSW */
60867043607SCho, Yu-Chen     env->psw.addr = cs->kvm_run->psw_addr;
60967043607SCho, Yu-Chen     env->psw.mask = cs->kvm_run->psw_mask;
61067043607SCho, Yu-Chen 
6111d107166SThomas Huth     /* the GPRS, ACRS and CRS */
6121d107166SThomas Huth     g_assert(can_sync_regs(cs, KVM_SYNC_REQUIRED_REGS));
6131d107166SThomas Huth     memcpy(env->regs, cs->kvm_run->s.regs.gprs, sizeof(env->regs));
6141d107166SThomas Huth     memcpy(env->aregs, cs->kvm_run->s.regs.acrs, sizeof(env->aregs));
6151d107166SThomas Huth     memcpy(env->cregs, cs->kvm_run->s.regs.crs, sizeof(env->cregs));
61667043607SCho, Yu-Chen 
6171d107166SThomas Huth     /* The prefix */
6181d107166SThomas Huth     env->psa = cs->kvm_run->s.regs.prefix;
61967043607SCho, Yu-Chen 
62067043607SCho, Yu-Chen     /* Floating point and vector registers */
62167043607SCho, Yu-Chen     if (can_sync_regs(cs, KVM_SYNC_VRS)) {
62267043607SCho, Yu-Chen         for (i = 0; i < 32; i++) {
62367043607SCho, Yu-Chen             env->vregs[i][0] = cs->kvm_run->s.regs.vrs[i][0];
62467043607SCho, Yu-Chen             env->vregs[i][1] = cs->kvm_run->s.regs.vrs[i][1];
62567043607SCho, Yu-Chen         }
62667043607SCho, Yu-Chen         env->fpc = cs->kvm_run->s.regs.fpc;
62767043607SCho, Yu-Chen     } else if (can_sync_regs(cs, KVM_SYNC_FPRS)) {
62867043607SCho, Yu-Chen         for (i = 0; i < 16; i++) {
62967043607SCho, Yu-Chen             *get_freg(env, i) = cs->kvm_run->s.regs.fprs[i];
63067043607SCho, Yu-Chen         }
63167043607SCho, Yu-Chen         env->fpc = cs->kvm_run->s.regs.fpc;
63267043607SCho, Yu-Chen     } else {
63367043607SCho, Yu-Chen         r = kvm_vcpu_ioctl(cs, KVM_GET_FPU, &fpu);
63467043607SCho, Yu-Chen         if (r < 0) {
63567043607SCho, Yu-Chen             return r;
63667043607SCho, Yu-Chen         }
63767043607SCho, Yu-Chen         for (i = 0; i < 16; i++) {
63867043607SCho, Yu-Chen             *get_freg(env, i) = fpu.fprs[i];
63967043607SCho, Yu-Chen         }
64067043607SCho, Yu-Chen         env->fpc = fpu.fpc;
64167043607SCho, Yu-Chen     }
64267043607SCho, Yu-Chen 
64367043607SCho, Yu-Chen     if (can_sync_regs(cs, KVM_SYNC_ARCH0)) {
64467043607SCho, Yu-Chen         env->cputm = cs->kvm_run->s.regs.cputm;
64567043607SCho, Yu-Chen         env->ckc = cs->kvm_run->s.regs.ckc;
64667043607SCho, Yu-Chen         env->todpr = cs->kvm_run->s.regs.todpr;
64767043607SCho, Yu-Chen         env->gbea = cs->kvm_run->s.regs.gbea;
64867043607SCho, Yu-Chen         env->pp = cs->kvm_run->s.regs.pp;
64967043607SCho, Yu-Chen     } else {
65067043607SCho, Yu-Chen         /*
65167043607SCho, Yu-Chen          * These ONE_REGS are not protected by a capability. As they are only
65267043607SCho, Yu-Chen          * necessary for migration we just trace a possible error, but don't
65367043607SCho, Yu-Chen          * return with an error return code.
65467043607SCho, Yu-Chen          */
65567043607SCho, Yu-Chen         kvm_get_one_reg(cs, KVM_REG_S390_CPU_TIMER, &env->cputm);
65667043607SCho, Yu-Chen         kvm_get_one_reg(cs, KVM_REG_S390_CLOCK_COMP, &env->ckc);
65767043607SCho, Yu-Chen         kvm_get_one_reg(cs, KVM_REG_S390_TODPR, &env->todpr);
65867043607SCho, Yu-Chen         kvm_get_one_reg(cs, KVM_REG_S390_GBEA, &env->gbea);
65967043607SCho, Yu-Chen         kvm_get_one_reg(cs, KVM_REG_S390_PP, &env->pp);
66067043607SCho, Yu-Chen     }
66167043607SCho, Yu-Chen 
66267043607SCho, Yu-Chen     if (can_sync_regs(cs, KVM_SYNC_RICCB)) {
66367043607SCho, Yu-Chen         memcpy(env->riccb, cs->kvm_run->s.regs.riccb, 64);
66467043607SCho, Yu-Chen     }
66567043607SCho, Yu-Chen 
66667043607SCho, Yu-Chen     if (can_sync_regs(cs, KVM_SYNC_GSCB)) {
66767043607SCho, Yu-Chen         memcpy(env->gscb, cs->kvm_run->s.regs.gscb, 32);
66867043607SCho, Yu-Chen     }
66967043607SCho, Yu-Chen 
67067043607SCho, Yu-Chen     if (can_sync_regs(cs, KVM_SYNC_BPBC)) {
67167043607SCho, Yu-Chen         env->bpbc = cs->kvm_run->s.regs.bpbc;
67267043607SCho, Yu-Chen     }
67367043607SCho, Yu-Chen 
67467043607SCho, Yu-Chen     if (can_sync_regs(cs, KVM_SYNC_ETOKEN)) {
67567043607SCho, Yu-Chen         env->etoken = cs->kvm_run->s.regs.etoken;
67667043607SCho, Yu-Chen         env->etoken_extension = cs->kvm_run->s.regs.etoken_extension;
67767043607SCho, Yu-Chen     }
67867043607SCho, Yu-Chen 
67967043607SCho, Yu-Chen     /* pfault parameters */
68067043607SCho, Yu-Chen     if (can_sync_regs(cs, KVM_SYNC_PFAULT)) {
68167043607SCho, Yu-Chen         env->pfault_token = cs->kvm_run->s.regs.pft;
68267043607SCho, Yu-Chen         env->pfault_select = cs->kvm_run->s.regs.pfs;
68367043607SCho, Yu-Chen         env->pfault_compare = cs->kvm_run->s.regs.pfc;
68467043607SCho, Yu-Chen     } else if (cap_async_pf) {
68567043607SCho, Yu-Chen         r = kvm_get_one_reg(cs, KVM_REG_S390_PFTOKEN, &env->pfault_token);
68667043607SCho, Yu-Chen         if (r < 0) {
68767043607SCho, Yu-Chen             return r;
68867043607SCho, Yu-Chen         }
68967043607SCho, Yu-Chen         r = kvm_get_one_reg(cs, KVM_REG_S390_PFCOMPARE, &env->pfault_compare);
69067043607SCho, Yu-Chen         if (r < 0) {
69167043607SCho, Yu-Chen             return r;
69267043607SCho, Yu-Chen         }
69367043607SCho, Yu-Chen         r = kvm_get_one_reg(cs, KVM_REG_S390_PFSELECT, &env->pfault_select);
69467043607SCho, Yu-Chen         if (r < 0) {
69567043607SCho, Yu-Chen             return r;
69667043607SCho, Yu-Chen         }
69767043607SCho, Yu-Chen     }
69867043607SCho, Yu-Chen 
69967043607SCho, Yu-Chen     if (can_sync_regs(cs, KVM_SYNC_DIAG318)) {
70067043607SCho, Yu-Chen         env->diag318_info = cs->kvm_run->s.regs.diag318;
70167043607SCho, Yu-Chen     }
70267043607SCho, Yu-Chen 
70367043607SCho, Yu-Chen     return 0;
70467043607SCho, Yu-Chen }
70567043607SCho, Yu-Chen 
kvm_s390_get_clock(uint8_t * tod_high,uint64_t * tod_low)70667043607SCho, Yu-Chen int kvm_s390_get_clock(uint8_t *tod_high, uint64_t *tod_low)
70767043607SCho, Yu-Chen {
70867043607SCho, Yu-Chen     int r;
70967043607SCho, Yu-Chen     struct kvm_device_attr attr = {
71067043607SCho, Yu-Chen         .group = KVM_S390_VM_TOD,
71167043607SCho, Yu-Chen         .attr = KVM_S390_VM_TOD_LOW,
71267043607SCho, Yu-Chen         .addr = (uint64_t)tod_low,
71367043607SCho, Yu-Chen     };
71467043607SCho, Yu-Chen 
71567043607SCho, Yu-Chen     r = kvm_vm_ioctl(kvm_state, KVM_GET_DEVICE_ATTR, &attr);
71667043607SCho, Yu-Chen     if (r) {
71767043607SCho, Yu-Chen         return r;
71867043607SCho, Yu-Chen     }
71967043607SCho, Yu-Chen 
72067043607SCho, Yu-Chen     attr.attr = KVM_S390_VM_TOD_HIGH;
72167043607SCho, Yu-Chen     attr.addr = (uint64_t)tod_high;
72267043607SCho, Yu-Chen     return kvm_vm_ioctl(kvm_state, KVM_GET_DEVICE_ATTR, &attr);
72367043607SCho, Yu-Chen }
72467043607SCho, Yu-Chen 
kvm_s390_get_clock_ext(uint8_t * tod_high,uint64_t * tod_low)72567043607SCho, Yu-Chen int kvm_s390_get_clock_ext(uint8_t *tod_high, uint64_t *tod_low)
72667043607SCho, Yu-Chen {
72767043607SCho, Yu-Chen     int r;
72867043607SCho, Yu-Chen     struct kvm_s390_vm_tod_clock gtod;
72967043607SCho, Yu-Chen     struct kvm_device_attr attr = {
73067043607SCho, Yu-Chen         .group = KVM_S390_VM_TOD,
73167043607SCho, Yu-Chen         .attr = KVM_S390_VM_TOD_EXT,
73267043607SCho, Yu-Chen         .addr = (uint64_t)&gtod,
73367043607SCho, Yu-Chen     };
73467043607SCho, Yu-Chen 
73567043607SCho, Yu-Chen     r = kvm_vm_ioctl(kvm_state, KVM_GET_DEVICE_ATTR, &attr);
73667043607SCho, Yu-Chen     *tod_high = gtod.epoch_idx;
73767043607SCho, Yu-Chen     *tod_low  = gtod.tod;
73867043607SCho, Yu-Chen 
73967043607SCho, Yu-Chen     return r;
74067043607SCho, Yu-Chen }
74167043607SCho, Yu-Chen 
kvm_s390_set_clock(uint8_t tod_high,uint64_t tod_low)74267043607SCho, Yu-Chen int kvm_s390_set_clock(uint8_t tod_high, uint64_t tod_low)
74367043607SCho, Yu-Chen {
74467043607SCho, Yu-Chen     int r;
74567043607SCho, Yu-Chen     struct kvm_device_attr attr = {
74667043607SCho, Yu-Chen         .group = KVM_S390_VM_TOD,
74767043607SCho, Yu-Chen         .attr = KVM_S390_VM_TOD_LOW,
74867043607SCho, Yu-Chen         .addr = (uint64_t)&tod_low,
74967043607SCho, Yu-Chen     };
75067043607SCho, Yu-Chen 
75167043607SCho, Yu-Chen     r = kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr);
75267043607SCho, Yu-Chen     if (r) {
75367043607SCho, Yu-Chen         return r;
75467043607SCho, Yu-Chen     }
75567043607SCho, Yu-Chen 
75667043607SCho, Yu-Chen     attr.attr = KVM_S390_VM_TOD_HIGH;
75767043607SCho, Yu-Chen     attr.addr = (uint64_t)&tod_high;
75867043607SCho, Yu-Chen     return kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr);
75967043607SCho, Yu-Chen }
76067043607SCho, Yu-Chen 
kvm_s390_set_clock_ext(uint8_t tod_high,uint64_t tod_low)76167043607SCho, Yu-Chen int kvm_s390_set_clock_ext(uint8_t tod_high, uint64_t tod_low)
76267043607SCho, Yu-Chen {
76367043607SCho, Yu-Chen     struct kvm_s390_vm_tod_clock gtod = {
76467043607SCho, Yu-Chen         .epoch_idx = tod_high,
76567043607SCho, Yu-Chen         .tod  = tod_low,
76667043607SCho, Yu-Chen     };
76767043607SCho, Yu-Chen     struct kvm_device_attr attr = {
76867043607SCho, Yu-Chen         .group = KVM_S390_VM_TOD,
76967043607SCho, Yu-Chen         .attr = KVM_S390_VM_TOD_EXT,
77067043607SCho, Yu-Chen         .addr = (uint64_t)&gtod,
77167043607SCho, Yu-Chen     };
77267043607SCho, Yu-Chen 
77367043607SCho, Yu-Chen     return kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr);
77467043607SCho, Yu-Chen }
77567043607SCho, Yu-Chen 
77667043607SCho, Yu-Chen /**
77767043607SCho, Yu-Chen  * kvm_s390_mem_op:
77867043607SCho, Yu-Chen  * @addr:      the logical start address in guest memory
77967043607SCho, Yu-Chen  * @ar:        the access register number
78067043607SCho, Yu-Chen  * @hostbuf:   buffer in host memory. NULL = do only checks w/o copying
78167043607SCho, Yu-Chen  * @len:       length that should be transferred
78267043607SCho, Yu-Chen  * @is_write:  true = write, false = read
78367043607SCho, Yu-Chen  * Returns:    0 on success, non-zero if an exception or error occurred
78467043607SCho, Yu-Chen  *
78567043607SCho, Yu-Chen  * Use KVM ioctl to read/write from/to guest memory. An access exception
78667043607SCho, Yu-Chen  * is injected into the vCPU in case of translation errors.
78767043607SCho, Yu-Chen  */
kvm_s390_mem_op(S390CPU * cpu,vaddr addr,uint8_t ar,void * hostbuf,int len,bool is_write)78867043607SCho, Yu-Chen int kvm_s390_mem_op(S390CPU *cpu, vaddr addr, uint8_t ar, void *hostbuf,
78967043607SCho, Yu-Chen                     int len, bool is_write)
79067043607SCho, Yu-Chen {
79167043607SCho, Yu-Chen     struct kvm_s390_mem_op mem_op = {
79267043607SCho, Yu-Chen         .gaddr = addr,
79367043607SCho, Yu-Chen         .flags = KVM_S390_MEMOP_F_INJECT_EXCEPTION,
79467043607SCho, Yu-Chen         .size = len,
79567043607SCho, Yu-Chen         .op = is_write ? KVM_S390_MEMOP_LOGICAL_WRITE
79667043607SCho, Yu-Chen                        : KVM_S390_MEMOP_LOGICAL_READ,
79767043607SCho, Yu-Chen         .buf = (uint64_t)hostbuf,
79867043607SCho, Yu-Chen         .ar = ar,
79954354861SJanis Schoetterl-Glausch         .key = (cpu->env.psw.mask & PSW_MASK_KEY) >> PSW_SHIFT_KEY,
80067043607SCho, Yu-Chen     };
80167043607SCho, Yu-Chen     int ret;
80267043607SCho, Yu-Chen 
80367043607SCho, Yu-Chen     if (!cap_mem_op) {
80467043607SCho, Yu-Chen         return -ENOSYS;
80567043607SCho, Yu-Chen     }
80667043607SCho, Yu-Chen     if (!hostbuf) {
80767043607SCho, Yu-Chen         mem_op.flags |= KVM_S390_MEMOP_F_CHECK_ONLY;
80867043607SCho, Yu-Chen     }
80954354861SJanis Schoetterl-Glausch     if (mem_op_storage_key_support) {
81054354861SJanis Schoetterl-Glausch         mem_op.flags |= KVM_S390_MEMOP_F_SKEY_PROTECTION;
81154354861SJanis Schoetterl-Glausch     }
81267043607SCho, Yu-Chen 
81367043607SCho, Yu-Chen     ret = kvm_vcpu_ioctl(CPU(cpu), KVM_S390_MEM_OP, &mem_op);
81467043607SCho, Yu-Chen     if (ret < 0) {
81567043607SCho, Yu-Chen         warn_report("KVM_S390_MEM_OP failed: %s", strerror(-ret));
81667043607SCho, Yu-Chen     }
81767043607SCho, Yu-Chen     return ret;
81867043607SCho, Yu-Chen }
81967043607SCho, Yu-Chen 
kvm_s390_mem_op_pv(S390CPU * cpu,uint64_t offset,void * hostbuf,int len,bool is_write)82067043607SCho, Yu-Chen int kvm_s390_mem_op_pv(S390CPU *cpu, uint64_t offset, void *hostbuf,
82167043607SCho, Yu-Chen                        int len, bool is_write)
82267043607SCho, Yu-Chen {
82367043607SCho, Yu-Chen     struct kvm_s390_mem_op mem_op = {
82467043607SCho, Yu-Chen         .sida_offset = offset,
82567043607SCho, Yu-Chen         .size = len,
82667043607SCho, Yu-Chen         .op = is_write ? KVM_S390_MEMOP_SIDA_WRITE
82767043607SCho, Yu-Chen                        : KVM_S390_MEMOP_SIDA_READ,
82867043607SCho, Yu-Chen         .buf = (uint64_t)hostbuf,
82967043607SCho, Yu-Chen     };
83067043607SCho, Yu-Chen     int ret;
83167043607SCho, Yu-Chen 
83267043607SCho, Yu-Chen     if (!cap_mem_op || !cap_protected) {
83367043607SCho, Yu-Chen         return -ENOSYS;
83467043607SCho, Yu-Chen     }
83567043607SCho, Yu-Chen 
83667043607SCho, Yu-Chen     ret = kvm_vcpu_ioctl(CPU(cpu), KVM_S390_MEM_OP, &mem_op);
83767043607SCho, Yu-Chen     if (ret < 0) {
83867043607SCho, Yu-Chen         error_report("KVM_S390_MEM_OP failed: %s", strerror(-ret));
83967043607SCho, Yu-Chen         abort();
84067043607SCho, Yu-Chen     }
84167043607SCho, Yu-Chen     return ret;
84267043607SCho, Yu-Chen }
84367043607SCho, Yu-Chen 
84467043607SCho, Yu-Chen static uint8_t const *sw_bp_inst;
84567043607SCho, Yu-Chen static uint8_t sw_bp_ilen;
84667043607SCho, Yu-Chen 
determine_sw_breakpoint_instr(void)84767043607SCho, Yu-Chen static void determine_sw_breakpoint_instr(void)
84867043607SCho, Yu-Chen {
84967043607SCho, Yu-Chen         /* DIAG 501 is used for sw breakpoints with old kernels */
85067043607SCho, Yu-Chen         static const uint8_t diag_501[] = {0x83, 0x24, 0x05, 0x01};
85167043607SCho, Yu-Chen         /* Instruction 0x0000 is used for sw breakpoints with recent kernels */
85267043607SCho, Yu-Chen         static const uint8_t instr_0x0000[] = {0x00, 0x00};
85367043607SCho, Yu-Chen 
85467043607SCho, Yu-Chen         if (sw_bp_inst) {
85567043607SCho, Yu-Chen             return;
85667043607SCho, Yu-Chen         }
85767043607SCho, Yu-Chen         if (kvm_vm_enable_cap(kvm_state, KVM_CAP_S390_USER_INSTR0, 0)) {
85867043607SCho, Yu-Chen             sw_bp_inst = diag_501;
85967043607SCho, Yu-Chen             sw_bp_ilen = sizeof(diag_501);
860f4a69168SCédric Le Goater             trace_kvm_sw_breakpoint(4);
86167043607SCho, Yu-Chen         } else {
86267043607SCho, Yu-Chen             sw_bp_inst = instr_0x0000;
86367043607SCho, Yu-Chen             sw_bp_ilen = sizeof(instr_0x0000);
864f4a69168SCédric Le Goater             trace_kvm_sw_breakpoint(2);
86567043607SCho, Yu-Chen         }
86667043607SCho, Yu-Chen }
86767043607SCho, Yu-Chen 
kvm_arch_insert_sw_breakpoint(CPUState * cs,struct kvm_sw_breakpoint * bp)86867043607SCho, Yu-Chen int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
86967043607SCho, Yu-Chen {
87067043607SCho, Yu-Chen     determine_sw_breakpoint_instr();
87167043607SCho, Yu-Chen 
87267043607SCho, Yu-Chen     if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn,
87367043607SCho, Yu-Chen                             sw_bp_ilen, 0) ||
87467043607SCho, Yu-Chen         cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)sw_bp_inst, sw_bp_ilen, 1)) {
87567043607SCho, Yu-Chen         return -EINVAL;
87667043607SCho, Yu-Chen     }
87767043607SCho, Yu-Chen     return 0;
87867043607SCho, Yu-Chen }
87967043607SCho, Yu-Chen 
kvm_arch_remove_sw_breakpoint(CPUState * cs,struct kvm_sw_breakpoint * bp)88067043607SCho, Yu-Chen int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
88167043607SCho, Yu-Chen {
88267043607SCho, Yu-Chen     uint8_t t[MAX_ILEN];
88367043607SCho, Yu-Chen 
88467043607SCho, Yu-Chen     if (cpu_memory_rw_debug(cs, bp->pc, t, sw_bp_ilen, 0)) {
88567043607SCho, Yu-Chen         return -EINVAL;
88667043607SCho, Yu-Chen     } else if (memcmp(t, sw_bp_inst, sw_bp_ilen)) {
88767043607SCho, Yu-Chen         return -EINVAL;
88867043607SCho, Yu-Chen     } else if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn,
88967043607SCho, Yu-Chen                                    sw_bp_ilen, 1)) {
89067043607SCho, Yu-Chen         return -EINVAL;
89167043607SCho, Yu-Chen     }
89267043607SCho, Yu-Chen 
89367043607SCho, Yu-Chen     return 0;
89467043607SCho, Yu-Chen }
89567043607SCho, Yu-Chen 
find_hw_breakpoint(target_ulong addr,int len,int type)89667043607SCho, Yu-Chen static struct kvm_hw_breakpoint *find_hw_breakpoint(target_ulong addr,
89767043607SCho, Yu-Chen                                                     int len, int type)
89867043607SCho, Yu-Chen {
89967043607SCho, Yu-Chen     int n;
90067043607SCho, Yu-Chen 
90167043607SCho, Yu-Chen     for (n = 0; n < nb_hw_breakpoints; n++) {
90267043607SCho, Yu-Chen         if (hw_breakpoints[n].addr == addr && hw_breakpoints[n].type == type &&
90367043607SCho, Yu-Chen             (hw_breakpoints[n].len == len || len == -1)) {
90467043607SCho, Yu-Chen             return &hw_breakpoints[n];
90567043607SCho, Yu-Chen         }
90667043607SCho, Yu-Chen     }
90767043607SCho, Yu-Chen 
90867043607SCho, Yu-Chen     return NULL;
90967043607SCho, Yu-Chen }
91067043607SCho, Yu-Chen 
insert_hw_breakpoint(target_ulong addr,int len,int type)91167043607SCho, Yu-Chen static int insert_hw_breakpoint(target_ulong addr, int len, int type)
91267043607SCho, Yu-Chen {
91367043607SCho, Yu-Chen     int size;
91467043607SCho, Yu-Chen 
91567043607SCho, Yu-Chen     if (find_hw_breakpoint(addr, len, type)) {
91667043607SCho, Yu-Chen         return -EEXIST;
91767043607SCho, Yu-Chen     }
91867043607SCho, Yu-Chen 
91967043607SCho, Yu-Chen     size = (nb_hw_breakpoints + 1) * sizeof(struct kvm_hw_breakpoint);
92067043607SCho, Yu-Chen 
92167043607SCho, Yu-Chen     if (!hw_breakpoints) {
92267043607SCho, Yu-Chen         nb_hw_breakpoints = 0;
92367043607SCho, Yu-Chen         hw_breakpoints = (struct kvm_hw_breakpoint *)g_try_malloc(size);
92467043607SCho, Yu-Chen     } else {
92567043607SCho, Yu-Chen         hw_breakpoints =
92667043607SCho, Yu-Chen             (struct kvm_hw_breakpoint *)g_try_realloc(hw_breakpoints, size);
92767043607SCho, Yu-Chen     }
92867043607SCho, Yu-Chen 
92967043607SCho, Yu-Chen     if (!hw_breakpoints) {
93067043607SCho, Yu-Chen         nb_hw_breakpoints = 0;
93167043607SCho, Yu-Chen         return -ENOMEM;
93267043607SCho, Yu-Chen     }
93367043607SCho, Yu-Chen 
93467043607SCho, Yu-Chen     hw_breakpoints[nb_hw_breakpoints].addr = addr;
93567043607SCho, Yu-Chen     hw_breakpoints[nb_hw_breakpoints].len = len;
93667043607SCho, Yu-Chen     hw_breakpoints[nb_hw_breakpoints].type = type;
93767043607SCho, Yu-Chen 
93867043607SCho, Yu-Chen     nb_hw_breakpoints++;
93967043607SCho, Yu-Chen 
94067043607SCho, Yu-Chen     return 0;
94167043607SCho, Yu-Chen }
94267043607SCho, Yu-Chen 
kvm_arch_insert_hw_breakpoint(vaddr addr,vaddr len,int type)943b8a6eb18SAnton Johansson int kvm_arch_insert_hw_breakpoint(vaddr addr, vaddr len, int type)
94467043607SCho, Yu-Chen {
94567043607SCho, Yu-Chen     switch (type) {
94667043607SCho, Yu-Chen     case GDB_BREAKPOINT_HW:
94767043607SCho, Yu-Chen         type = KVM_HW_BP;
94867043607SCho, Yu-Chen         break;
94967043607SCho, Yu-Chen     case GDB_WATCHPOINT_WRITE:
95067043607SCho, Yu-Chen         if (len < 1) {
95167043607SCho, Yu-Chen             return -EINVAL;
95267043607SCho, Yu-Chen         }
95367043607SCho, Yu-Chen         type = KVM_HW_WP_WRITE;
95467043607SCho, Yu-Chen         break;
95567043607SCho, Yu-Chen     default:
95667043607SCho, Yu-Chen         return -ENOSYS;
95767043607SCho, Yu-Chen     }
95867043607SCho, Yu-Chen     return insert_hw_breakpoint(addr, len, type);
95967043607SCho, Yu-Chen }
96067043607SCho, Yu-Chen 
kvm_arch_remove_hw_breakpoint(vaddr addr,vaddr len,int type)961b8a6eb18SAnton Johansson int kvm_arch_remove_hw_breakpoint(vaddr addr, vaddr len, int type)
96267043607SCho, Yu-Chen {
96367043607SCho, Yu-Chen     int size;
96467043607SCho, Yu-Chen     struct kvm_hw_breakpoint *bp = find_hw_breakpoint(addr, len, type);
96567043607SCho, Yu-Chen 
96667043607SCho, Yu-Chen     if (bp == NULL) {
96767043607SCho, Yu-Chen         return -ENOENT;
96867043607SCho, Yu-Chen     }
96967043607SCho, Yu-Chen 
97067043607SCho, Yu-Chen     nb_hw_breakpoints--;
97167043607SCho, Yu-Chen     if (nb_hw_breakpoints > 0) {
97267043607SCho, Yu-Chen         /*
97367043607SCho, Yu-Chen          * In order to trim the array, move the last element to the position to
97467043607SCho, Yu-Chen          * be removed - if necessary.
97567043607SCho, Yu-Chen          */
97667043607SCho, Yu-Chen         if (bp != &hw_breakpoints[nb_hw_breakpoints]) {
97767043607SCho, Yu-Chen             *bp = hw_breakpoints[nb_hw_breakpoints];
97867043607SCho, Yu-Chen         }
97967043607SCho, Yu-Chen         size = nb_hw_breakpoints * sizeof(struct kvm_hw_breakpoint);
98067043607SCho, Yu-Chen         hw_breakpoints =
9810a553c12SMarkus Armbruster              g_realloc(hw_breakpoints, size);
98267043607SCho, Yu-Chen     } else {
98367043607SCho, Yu-Chen         g_free(hw_breakpoints);
98467043607SCho, Yu-Chen         hw_breakpoints = NULL;
98567043607SCho, Yu-Chen     }
98667043607SCho, Yu-Chen 
98767043607SCho, Yu-Chen     return 0;
98867043607SCho, Yu-Chen }
98967043607SCho, Yu-Chen 
kvm_arch_remove_all_hw_breakpoints(void)99067043607SCho, Yu-Chen void kvm_arch_remove_all_hw_breakpoints(void)
99167043607SCho, Yu-Chen {
99267043607SCho, Yu-Chen     nb_hw_breakpoints = 0;
99367043607SCho, Yu-Chen     g_free(hw_breakpoints);
99467043607SCho, Yu-Chen     hw_breakpoints = NULL;
99567043607SCho, Yu-Chen }
99667043607SCho, Yu-Chen 
kvm_arch_update_guest_debug(CPUState * cpu,struct kvm_guest_debug * dbg)99767043607SCho, Yu-Chen void kvm_arch_update_guest_debug(CPUState *cpu, struct kvm_guest_debug *dbg)
99867043607SCho, Yu-Chen {
99967043607SCho, Yu-Chen     int i;
100067043607SCho, Yu-Chen 
100167043607SCho, Yu-Chen     if (nb_hw_breakpoints > 0) {
100267043607SCho, Yu-Chen         dbg->arch.nr_hw_bp = nb_hw_breakpoints;
100367043607SCho, Yu-Chen         dbg->arch.hw_bp = hw_breakpoints;
100467043607SCho, Yu-Chen 
100567043607SCho, Yu-Chen         for (i = 0; i < nb_hw_breakpoints; ++i) {
100667043607SCho, Yu-Chen             hw_breakpoints[i].phys_addr = s390_cpu_get_phys_addr_debug(cpu,
100767043607SCho, Yu-Chen                                                        hw_breakpoints[i].addr);
100867043607SCho, Yu-Chen         }
100967043607SCho, Yu-Chen         dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_HW_BP;
101067043607SCho, Yu-Chen     } else {
101167043607SCho, Yu-Chen         dbg->arch.nr_hw_bp = 0;
101267043607SCho, Yu-Chen         dbg->arch.hw_bp = NULL;
101367043607SCho, Yu-Chen     }
101467043607SCho, Yu-Chen }
101567043607SCho, Yu-Chen 
kvm_arch_pre_run(CPUState * cpu,struct kvm_run * run)101667043607SCho, Yu-Chen void kvm_arch_pre_run(CPUState *cpu, struct kvm_run *run)
101767043607SCho, Yu-Chen {
101867043607SCho, Yu-Chen }
101967043607SCho, Yu-Chen 
kvm_arch_post_run(CPUState * cs,struct kvm_run * run)102067043607SCho, Yu-Chen MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run)
102167043607SCho, Yu-Chen {
102267043607SCho, Yu-Chen     return MEMTXATTRS_UNSPECIFIED;
102367043607SCho, Yu-Chen }
102467043607SCho, Yu-Chen 
kvm_arch_process_async_events(CPUState * cs)102567043607SCho, Yu-Chen int kvm_arch_process_async_events(CPUState *cs)
102667043607SCho, Yu-Chen {
102767043607SCho, Yu-Chen     return cs->halted;
102867043607SCho, Yu-Chen }
102967043607SCho, Yu-Chen 
s390_kvm_irq_to_interrupt(struct kvm_s390_irq * irq,struct kvm_s390_interrupt * interrupt)103067043607SCho, Yu-Chen static int s390_kvm_irq_to_interrupt(struct kvm_s390_irq *irq,
103167043607SCho, Yu-Chen                                      struct kvm_s390_interrupt *interrupt)
103267043607SCho, Yu-Chen {
103367043607SCho, Yu-Chen     int r = 0;
103467043607SCho, Yu-Chen 
103567043607SCho, Yu-Chen     interrupt->type = irq->type;
103667043607SCho, Yu-Chen     switch (irq->type) {
103767043607SCho, Yu-Chen     case KVM_S390_INT_VIRTIO:
103867043607SCho, Yu-Chen         interrupt->parm = irq->u.ext.ext_params;
103967043607SCho, Yu-Chen         /* fall through */
104067043607SCho, Yu-Chen     case KVM_S390_INT_PFAULT_INIT:
104167043607SCho, Yu-Chen     case KVM_S390_INT_PFAULT_DONE:
104267043607SCho, Yu-Chen         interrupt->parm64 = irq->u.ext.ext_params2;
104367043607SCho, Yu-Chen         break;
104467043607SCho, Yu-Chen     case KVM_S390_PROGRAM_INT:
104567043607SCho, Yu-Chen         interrupt->parm = irq->u.pgm.code;
104667043607SCho, Yu-Chen         break;
104767043607SCho, Yu-Chen     case KVM_S390_SIGP_SET_PREFIX:
104867043607SCho, Yu-Chen         interrupt->parm = irq->u.prefix.address;
104967043607SCho, Yu-Chen         break;
105067043607SCho, Yu-Chen     case KVM_S390_INT_SERVICE:
105167043607SCho, Yu-Chen         interrupt->parm = irq->u.ext.ext_params;
105267043607SCho, Yu-Chen         break;
105367043607SCho, Yu-Chen     case KVM_S390_MCHK:
105467043607SCho, Yu-Chen         interrupt->parm = irq->u.mchk.cr14;
105567043607SCho, Yu-Chen         interrupt->parm64 = irq->u.mchk.mcic;
105667043607SCho, Yu-Chen         break;
105767043607SCho, Yu-Chen     case KVM_S390_INT_EXTERNAL_CALL:
105867043607SCho, Yu-Chen         interrupt->parm = irq->u.extcall.code;
105967043607SCho, Yu-Chen         break;
106067043607SCho, Yu-Chen     case KVM_S390_INT_EMERGENCY:
106167043607SCho, Yu-Chen         interrupt->parm = irq->u.emerg.code;
106267043607SCho, Yu-Chen         break;
106367043607SCho, Yu-Chen     case KVM_S390_SIGP_STOP:
106467043607SCho, Yu-Chen     case KVM_S390_RESTART:
106567043607SCho, Yu-Chen         break; /* These types have no parameters */
106667043607SCho, Yu-Chen     case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX:
106767043607SCho, Yu-Chen         interrupt->parm = irq->u.io.subchannel_id << 16;
106867043607SCho, Yu-Chen         interrupt->parm |= irq->u.io.subchannel_nr;
106967043607SCho, Yu-Chen         interrupt->parm64 = (uint64_t)irq->u.io.io_int_parm << 32;
107067043607SCho, Yu-Chen         interrupt->parm64 |= irq->u.io.io_int_word;
107167043607SCho, Yu-Chen         break;
107267043607SCho, Yu-Chen     default:
107367043607SCho, Yu-Chen         r = -EINVAL;
107467043607SCho, Yu-Chen         break;
107567043607SCho, Yu-Chen     }
107667043607SCho, Yu-Chen     return r;
107767043607SCho, Yu-Chen }
107867043607SCho, Yu-Chen 
inject_vcpu_irq_legacy(CPUState * cs,struct kvm_s390_irq * irq)107967043607SCho, Yu-Chen static void inject_vcpu_irq_legacy(CPUState *cs, struct kvm_s390_irq *irq)
108067043607SCho, Yu-Chen {
108167043607SCho, Yu-Chen     struct kvm_s390_interrupt kvmint = {};
108267043607SCho, Yu-Chen     int r;
108367043607SCho, Yu-Chen 
108467043607SCho, Yu-Chen     r = s390_kvm_irq_to_interrupt(irq, &kvmint);
108567043607SCho, Yu-Chen     if (r < 0) {
108667043607SCho, Yu-Chen         fprintf(stderr, "%s called with bogus interrupt\n", __func__);
108767043607SCho, Yu-Chen         exit(1);
108867043607SCho, Yu-Chen     }
108967043607SCho, Yu-Chen 
109067043607SCho, Yu-Chen     r = kvm_vcpu_ioctl(cs, KVM_S390_INTERRUPT, &kvmint);
109167043607SCho, Yu-Chen     if (r < 0) {
109267043607SCho, Yu-Chen         fprintf(stderr, "KVM failed to inject interrupt\n");
109367043607SCho, Yu-Chen         exit(1);
109467043607SCho, Yu-Chen     }
109567043607SCho, Yu-Chen }
109667043607SCho, Yu-Chen 
kvm_s390_vcpu_interrupt(S390CPU * cpu,struct kvm_s390_irq * irq)109767043607SCho, Yu-Chen void kvm_s390_vcpu_interrupt(S390CPU *cpu, struct kvm_s390_irq *irq)
109867043607SCho, Yu-Chen {
109967043607SCho, Yu-Chen     CPUState *cs = CPU(cpu);
110067043607SCho, Yu-Chen     int r;
110167043607SCho, Yu-Chen 
110267043607SCho, Yu-Chen     if (cap_s390_irq) {
110367043607SCho, Yu-Chen         r = kvm_vcpu_ioctl(cs, KVM_S390_IRQ, irq);
110467043607SCho, Yu-Chen         if (!r) {
110567043607SCho, Yu-Chen             return;
110667043607SCho, Yu-Chen         }
110767043607SCho, Yu-Chen         error_report("KVM failed to inject interrupt %llx", irq->type);
110867043607SCho, Yu-Chen         exit(1);
110967043607SCho, Yu-Chen     }
111067043607SCho, Yu-Chen 
111167043607SCho, Yu-Chen     inject_vcpu_irq_legacy(cs, irq);
111267043607SCho, Yu-Chen }
111367043607SCho, Yu-Chen 
kvm_s390_floating_interrupt_legacy(struct kvm_s390_irq * irq)111467043607SCho, Yu-Chen void kvm_s390_floating_interrupt_legacy(struct kvm_s390_irq *irq)
111567043607SCho, Yu-Chen {
111667043607SCho, Yu-Chen     struct kvm_s390_interrupt kvmint = {};
111767043607SCho, Yu-Chen     int r;
111867043607SCho, Yu-Chen 
111967043607SCho, Yu-Chen     r = s390_kvm_irq_to_interrupt(irq, &kvmint);
112067043607SCho, Yu-Chen     if (r < 0) {
112167043607SCho, Yu-Chen         fprintf(stderr, "%s called with bogus interrupt\n", __func__);
112267043607SCho, Yu-Chen         exit(1);
112367043607SCho, Yu-Chen     }
112467043607SCho, Yu-Chen 
112567043607SCho, Yu-Chen     r = kvm_vm_ioctl(kvm_state, KVM_S390_INTERRUPT, &kvmint);
112667043607SCho, Yu-Chen     if (r < 0) {
112767043607SCho, Yu-Chen         fprintf(stderr, "KVM failed to inject interrupt\n");
112867043607SCho, Yu-Chen         exit(1);
112967043607SCho, Yu-Chen     }
113067043607SCho, Yu-Chen }
113167043607SCho, Yu-Chen 
kvm_s390_program_interrupt(S390CPU * cpu,uint16_t code)113267043607SCho, Yu-Chen void kvm_s390_program_interrupt(S390CPU *cpu, uint16_t code)
113367043607SCho, Yu-Chen {
113467043607SCho, Yu-Chen     struct kvm_s390_irq irq = {
113567043607SCho, Yu-Chen         .type = KVM_S390_PROGRAM_INT,
113667043607SCho, Yu-Chen         .u.pgm.code = code,
113767043607SCho, Yu-Chen     };
113867043607SCho, Yu-Chen     qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n",
113967043607SCho, Yu-Chen                   cpu->env.psw.addr);
114067043607SCho, Yu-Chen     kvm_s390_vcpu_interrupt(cpu, &irq);
114167043607SCho, Yu-Chen }
114267043607SCho, Yu-Chen 
kvm_s390_access_exception(S390CPU * cpu,uint16_t code,uint64_t te_code)114367043607SCho, Yu-Chen void kvm_s390_access_exception(S390CPU *cpu, uint16_t code, uint64_t te_code)
114467043607SCho, Yu-Chen {
114567043607SCho, Yu-Chen     struct kvm_s390_irq irq = {
114667043607SCho, Yu-Chen         .type = KVM_S390_PROGRAM_INT,
114767043607SCho, Yu-Chen         .u.pgm.code = code,
114867043607SCho, Yu-Chen         .u.pgm.trans_exc_code = te_code,
114967043607SCho, Yu-Chen         .u.pgm.exc_access_id = te_code & 3,
115067043607SCho, Yu-Chen     };
115167043607SCho, Yu-Chen 
115267043607SCho, Yu-Chen     kvm_s390_vcpu_interrupt(cpu, &irq);
115367043607SCho, Yu-Chen }
115467043607SCho, Yu-Chen 
kvm_sclp_service_call(S390CPU * cpu,struct kvm_run * run,uint16_t ipbh0)115567043607SCho, Yu-Chen static void kvm_sclp_service_call(S390CPU *cpu, struct kvm_run *run,
115667043607SCho, Yu-Chen                                  uint16_t ipbh0)
115767043607SCho, Yu-Chen {
115867043607SCho, Yu-Chen     CPUS390XState *env = &cpu->env;
115967043607SCho, Yu-Chen     uint64_t sccb;
116067043607SCho, Yu-Chen     uint32_t code;
116167043607SCho, Yu-Chen     int r;
116267043607SCho, Yu-Chen 
116367043607SCho, Yu-Chen     sccb = env->regs[ipbh0 & 0xf];
116467043607SCho, Yu-Chen     code = env->regs[(ipbh0 & 0xf0) >> 4];
116567043607SCho, Yu-Chen 
116667043607SCho, Yu-Chen     switch (run->s390_sieic.icptcode) {
116767043607SCho, Yu-Chen     case ICPT_PV_INSTR_NOTIFICATION:
116867043607SCho, Yu-Chen         g_assert(s390_is_pv());
116967043607SCho, Yu-Chen         /* The notification intercepts are currently handled by KVM */
117067043607SCho, Yu-Chen         error_report("unexpected SCLP PV notification");
117167043607SCho, Yu-Chen         exit(1);
117267043607SCho, Yu-Chen         break;
117367043607SCho, Yu-Chen     case ICPT_PV_INSTR:
117467043607SCho, Yu-Chen         g_assert(s390_is_pv());
11756d3910c9SPhilippe Mathieu-Daudé         sclp_service_call_protected(cpu, sccb, code);
117667043607SCho, Yu-Chen         /* Setting the CC is done by the Ultravisor. */
117767043607SCho, Yu-Chen         break;
117867043607SCho, Yu-Chen     case ICPT_INSTRUCTION:
117967043607SCho, Yu-Chen         g_assert(!s390_is_pv());
11806d3910c9SPhilippe Mathieu-Daudé         r = sclp_service_call(cpu, sccb, code);
118167043607SCho, Yu-Chen         if (r < 0) {
118267043607SCho, Yu-Chen             kvm_s390_program_interrupt(cpu, -r);
118367043607SCho, Yu-Chen             return;
118467043607SCho, Yu-Chen         }
118567043607SCho, Yu-Chen         setcc(cpu, r);
118667043607SCho, Yu-Chen     }
118767043607SCho, Yu-Chen }
118867043607SCho, Yu-Chen 
handle_b2(S390CPU * cpu,struct kvm_run * run,uint8_t ipa1)118967043607SCho, Yu-Chen static int handle_b2(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1)
119067043607SCho, Yu-Chen {
119167043607SCho, Yu-Chen     CPUS390XState *env = &cpu->env;
119267043607SCho, Yu-Chen     int rc = 0;
119367043607SCho, Yu-Chen     uint16_t ipbh0 = (run->s390_sieic.ipb & 0xffff0000) >> 16;
119467043607SCho, Yu-Chen 
119567043607SCho, Yu-Chen     switch (ipa1) {
119667043607SCho, Yu-Chen     case PRIV_B2_XSCH:
119767043607SCho, Yu-Chen         ioinst_handle_xsch(cpu, env->regs[1], RA_IGNORED);
119867043607SCho, Yu-Chen         break;
119967043607SCho, Yu-Chen     case PRIV_B2_CSCH:
120067043607SCho, Yu-Chen         ioinst_handle_csch(cpu, env->regs[1], RA_IGNORED);
120167043607SCho, Yu-Chen         break;
120267043607SCho, Yu-Chen     case PRIV_B2_HSCH:
120367043607SCho, Yu-Chen         ioinst_handle_hsch(cpu, env->regs[1], RA_IGNORED);
120467043607SCho, Yu-Chen         break;
120567043607SCho, Yu-Chen     case PRIV_B2_MSCH:
120667043607SCho, Yu-Chen         ioinst_handle_msch(cpu, env->regs[1], run->s390_sieic.ipb, RA_IGNORED);
120767043607SCho, Yu-Chen         break;
120867043607SCho, Yu-Chen     case PRIV_B2_SSCH:
120967043607SCho, Yu-Chen         ioinst_handle_ssch(cpu, env->regs[1], run->s390_sieic.ipb, RA_IGNORED);
121067043607SCho, Yu-Chen         break;
121167043607SCho, Yu-Chen     case PRIV_B2_STCRW:
121267043607SCho, Yu-Chen         ioinst_handle_stcrw(cpu, run->s390_sieic.ipb, RA_IGNORED);
121367043607SCho, Yu-Chen         break;
121467043607SCho, Yu-Chen     case PRIV_B2_STSCH:
121567043607SCho, Yu-Chen         ioinst_handle_stsch(cpu, env->regs[1], run->s390_sieic.ipb, RA_IGNORED);
121667043607SCho, Yu-Chen         break;
121767043607SCho, Yu-Chen     case PRIV_B2_TSCH:
121867043607SCho, Yu-Chen         /* We should only get tsch via KVM_EXIT_S390_TSCH. */
121967043607SCho, Yu-Chen         fprintf(stderr, "Spurious tsch intercept\n");
122067043607SCho, Yu-Chen         break;
122167043607SCho, Yu-Chen     case PRIV_B2_CHSC:
122267043607SCho, Yu-Chen         ioinst_handle_chsc(cpu, run->s390_sieic.ipb, RA_IGNORED);
122367043607SCho, Yu-Chen         break;
122467043607SCho, Yu-Chen     case PRIV_B2_TPI:
122567043607SCho, Yu-Chen         /* This should have been handled by kvm already. */
122667043607SCho, Yu-Chen         fprintf(stderr, "Spurious tpi intercept\n");
122767043607SCho, Yu-Chen         break;
122867043607SCho, Yu-Chen     case PRIV_B2_SCHM:
122967043607SCho, Yu-Chen         ioinst_handle_schm(cpu, env->regs[1], env->regs[2],
123067043607SCho, Yu-Chen                            run->s390_sieic.ipb, RA_IGNORED);
123167043607SCho, Yu-Chen         break;
123267043607SCho, Yu-Chen     case PRIV_B2_RSCH:
123367043607SCho, Yu-Chen         ioinst_handle_rsch(cpu, env->regs[1], RA_IGNORED);
123467043607SCho, Yu-Chen         break;
123567043607SCho, Yu-Chen     case PRIV_B2_RCHP:
123667043607SCho, Yu-Chen         ioinst_handle_rchp(cpu, env->regs[1], RA_IGNORED);
123767043607SCho, Yu-Chen         break;
123867043607SCho, Yu-Chen     case PRIV_B2_STCPS:
123967043607SCho, Yu-Chen         /* We do not provide this instruction, it is suppressed. */
124067043607SCho, Yu-Chen         break;
124167043607SCho, Yu-Chen     case PRIV_B2_SAL:
124267043607SCho, Yu-Chen         ioinst_handle_sal(cpu, env->regs[1], RA_IGNORED);
124367043607SCho, Yu-Chen         break;
124467043607SCho, Yu-Chen     case PRIV_B2_SIGA:
124567043607SCho, Yu-Chen         /* Not provided, set CC = 3 for subchannel not operational */
124667043607SCho, Yu-Chen         setcc(cpu, 3);
124767043607SCho, Yu-Chen         break;
124867043607SCho, Yu-Chen     case PRIV_B2_SCLP_CALL:
124967043607SCho, Yu-Chen         kvm_sclp_service_call(cpu, run, ipbh0);
125067043607SCho, Yu-Chen         break;
125167043607SCho, Yu-Chen     default:
125267043607SCho, Yu-Chen         rc = -1;
1253f4a69168SCédric Le Goater         trace_kvm_insn_unhandled_priv(ipa1);
125467043607SCho, Yu-Chen         break;
125567043607SCho, Yu-Chen     }
125667043607SCho, Yu-Chen 
125767043607SCho, Yu-Chen     return rc;
125867043607SCho, Yu-Chen }
125967043607SCho, Yu-Chen 
get_base_disp_rxy(S390CPU * cpu,struct kvm_run * run,uint8_t * ar)126067043607SCho, Yu-Chen static uint64_t get_base_disp_rxy(S390CPU *cpu, struct kvm_run *run,
126167043607SCho, Yu-Chen                                   uint8_t *ar)
126267043607SCho, Yu-Chen {
126367043607SCho, Yu-Chen     CPUS390XState *env = &cpu->env;
126467043607SCho, Yu-Chen     uint32_t x2 = (run->s390_sieic.ipa & 0x000f);
126567043607SCho, Yu-Chen     uint32_t base2 = run->s390_sieic.ipb >> 28;
126667043607SCho, Yu-Chen     uint32_t disp2 = ((run->s390_sieic.ipb & 0x0fff0000) >> 16) +
126767043607SCho, Yu-Chen                      ((run->s390_sieic.ipb & 0xff00) << 4);
126867043607SCho, Yu-Chen 
126967043607SCho, Yu-Chen     if (disp2 & 0x80000) {
127067043607SCho, Yu-Chen         disp2 += 0xfff00000;
127167043607SCho, Yu-Chen     }
127267043607SCho, Yu-Chen     if (ar) {
127367043607SCho, Yu-Chen         *ar = base2;
127467043607SCho, Yu-Chen     }
127567043607SCho, Yu-Chen 
127667043607SCho, Yu-Chen     return (base2 ? env->regs[base2] : 0) +
127767043607SCho, Yu-Chen            (x2 ? env->regs[x2] : 0) + (long)(int)disp2;
127867043607SCho, Yu-Chen }
127967043607SCho, Yu-Chen 
get_base_disp_rsy(S390CPU * cpu,struct kvm_run * run,uint8_t * ar)128067043607SCho, Yu-Chen static uint64_t get_base_disp_rsy(S390CPU *cpu, struct kvm_run *run,
128167043607SCho, Yu-Chen                                   uint8_t *ar)
128267043607SCho, Yu-Chen {
128367043607SCho, Yu-Chen     CPUS390XState *env = &cpu->env;
128467043607SCho, Yu-Chen     uint32_t base2 = run->s390_sieic.ipb >> 28;
128567043607SCho, Yu-Chen     uint32_t disp2 = ((run->s390_sieic.ipb & 0x0fff0000) >> 16) +
128667043607SCho, Yu-Chen                      ((run->s390_sieic.ipb & 0xff00) << 4);
128767043607SCho, Yu-Chen 
128867043607SCho, Yu-Chen     if (disp2 & 0x80000) {
128967043607SCho, Yu-Chen         disp2 += 0xfff00000;
129067043607SCho, Yu-Chen     }
129167043607SCho, Yu-Chen     if (ar) {
129267043607SCho, Yu-Chen         *ar = base2;
129367043607SCho, Yu-Chen     }
129467043607SCho, Yu-Chen 
129567043607SCho, Yu-Chen     return (base2 ? env->regs[base2] : 0) + (long)(int)disp2;
129667043607SCho, Yu-Chen }
129767043607SCho, Yu-Chen 
kvm_clp_service_call(S390CPU * cpu,struct kvm_run * run)129867043607SCho, Yu-Chen static int kvm_clp_service_call(S390CPU *cpu, struct kvm_run *run)
129967043607SCho, Yu-Chen {
130067043607SCho, Yu-Chen     uint8_t r2 = (run->s390_sieic.ipb & 0x000f0000) >> 16;
130167043607SCho, Yu-Chen 
130267043607SCho, Yu-Chen     if (s390_has_feat(S390_FEAT_ZPCI)) {
130367043607SCho, Yu-Chen         return clp_service_call(cpu, r2, RA_IGNORED);
130467043607SCho, Yu-Chen     } else {
130567043607SCho, Yu-Chen         return -1;
130667043607SCho, Yu-Chen     }
130767043607SCho, Yu-Chen }
130867043607SCho, Yu-Chen 
kvm_pcilg_service_call(S390CPU * cpu,struct kvm_run * run)130967043607SCho, Yu-Chen static int kvm_pcilg_service_call(S390CPU *cpu, struct kvm_run *run)
131067043607SCho, Yu-Chen {
131167043607SCho, Yu-Chen     uint8_t r1 = (run->s390_sieic.ipb & 0x00f00000) >> 20;
131267043607SCho, Yu-Chen     uint8_t r2 = (run->s390_sieic.ipb & 0x000f0000) >> 16;
131367043607SCho, Yu-Chen 
131467043607SCho, Yu-Chen     if (s390_has_feat(S390_FEAT_ZPCI)) {
131567043607SCho, Yu-Chen         return pcilg_service_call(cpu, r1, r2, RA_IGNORED);
131667043607SCho, Yu-Chen     } else {
131767043607SCho, Yu-Chen         return -1;
131867043607SCho, Yu-Chen     }
131967043607SCho, Yu-Chen }
132067043607SCho, Yu-Chen 
kvm_pcistg_service_call(S390CPU * cpu,struct kvm_run * run)132167043607SCho, Yu-Chen static int kvm_pcistg_service_call(S390CPU *cpu, struct kvm_run *run)
132267043607SCho, Yu-Chen {
132367043607SCho, Yu-Chen     uint8_t r1 = (run->s390_sieic.ipb & 0x00f00000) >> 20;
132467043607SCho, Yu-Chen     uint8_t r2 = (run->s390_sieic.ipb & 0x000f0000) >> 16;
132567043607SCho, Yu-Chen 
132667043607SCho, Yu-Chen     if (s390_has_feat(S390_FEAT_ZPCI)) {
132767043607SCho, Yu-Chen         return pcistg_service_call(cpu, r1, r2, RA_IGNORED);
132867043607SCho, Yu-Chen     } else {
132967043607SCho, Yu-Chen         return -1;
133067043607SCho, Yu-Chen     }
133167043607SCho, Yu-Chen }
133267043607SCho, Yu-Chen 
kvm_stpcifc_service_call(S390CPU * cpu,struct kvm_run * run)133367043607SCho, Yu-Chen static int kvm_stpcifc_service_call(S390CPU *cpu, struct kvm_run *run)
133467043607SCho, Yu-Chen {
133567043607SCho, Yu-Chen     uint8_t r1 = (run->s390_sieic.ipa & 0x00f0) >> 4;
133667043607SCho, Yu-Chen     uint64_t fiba;
133767043607SCho, Yu-Chen     uint8_t ar;
133867043607SCho, Yu-Chen 
133967043607SCho, Yu-Chen     if (s390_has_feat(S390_FEAT_ZPCI)) {
134067043607SCho, Yu-Chen         fiba = get_base_disp_rxy(cpu, run, &ar);
134167043607SCho, Yu-Chen 
134267043607SCho, Yu-Chen         return stpcifc_service_call(cpu, r1, fiba, ar, RA_IGNORED);
134367043607SCho, Yu-Chen     } else {
134467043607SCho, Yu-Chen         return -1;
134567043607SCho, Yu-Chen     }
134667043607SCho, Yu-Chen }
134767043607SCho, Yu-Chen 
kvm_sic_service_call(S390CPU * cpu,struct kvm_run * run)134867043607SCho, Yu-Chen static int kvm_sic_service_call(S390CPU *cpu, struct kvm_run *run)
134967043607SCho, Yu-Chen {
135067043607SCho, Yu-Chen     CPUS390XState *env = &cpu->env;
135167043607SCho, Yu-Chen     uint8_t r1 = (run->s390_sieic.ipa & 0x00f0) >> 4;
135267043607SCho, Yu-Chen     uint8_t r3 = run->s390_sieic.ipa & 0x000f;
135367043607SCho, Yu-Chen     uint8_t isc;
135467043607SCho, Yu-Chen     uint16_t mode;
135567043607SCho, Yu-Chen     int r;
135667043607SCho, Yu-Chen 
135767043607SCho, Yu-Chen     mode = env->regs[r1] & 0xffff;
135867043607SCho, Yu-Chen     isc = (env->regs[r3] >> 27) & 0x7;
13596233759aSPhilippe Mathieu-Daudé     r = css_do_sic(cpu, isc, mode);
136067043607SCho, Yu-Chen     if (r) {
136167043607SCho, Yu-Chen         kvm_s390_program_interrupt(cpu, -r);
136267043607SCho, Yu-Chen     }
136367043607SCho, Yu-Chen 
136467043607SCho, Yu-Chen     return 0;
136567043607SCho, Yu-Chen }
136667043607SCho, Yu-Chen 
kvm_rpcit_service_call(S390CPU * cpu,struct kvm_run * run)136767043607SCho, Yu-Chen static int kvm_rpcit_service_call(S390CPU *cpu, struct kvm_run *run)
136867043607SCho, Yu-Chen {
136967043607SCho, Yu-Chen     uint8_t r1 = (run->s390_sieic.ipb & 0x00f00000) >> 20;
137067043607SCho, Yu-Chen     uint8_t r2 = (run->s390_sieic.ipb & 0x000f0000) >> 16;
137167043607SCho, Yu-Chen 
137267043607SCho, Yu-Chen     if (s390_has_feat(S390_FEAT_ZPCI)) {
137367043607SCho, Yu-Chen         return rpcit_service_call(cpu, r1, r2, RA_IGNORED);
137467043607SCho, Yu-Chen     } else {
137567043607SCho, Yu-Chen         return -1;
137667043607SCho, Yu-Chen     }
137767043607SCho, Yu-Chen }
137867043607SCho, Yu-Chen 
kvm_pcistb_service_call(S390CPU * cpu,struct kvm_run * run)137967043607SCho, Yu-Chen static int kvm_pcistb_service_call(S390CPU *cpu, struct kvm_run *run)
138067043607SCho, Yu-Chen {
138167043607SCho, Yu-Chen     uint8_t r1 = (run->s390_sieic.ipa & 0x00f0) >> 4;
138267043607SCho, Yu-Chen     uint8_t r3 = run->s390_sieic.ipa & 0x000f;
138367043607SCho, Yu-Chen     uint64_t gaddr;
138467043607SCho, Yu-Chen     uint8_t ar;
138567043607SCho, Yu-Chen 
138667043607SCho, Yu-Chen     if (s390_has_feat(S390_FEAT_ZPCI)) {
138767043607SCho, Yu-Chen         gaddr = get_base_disp_rsy(cpu, run, &ar);
138867043607SCho, Yu-Chen 
138967043607SCho, Yu-Chen         return pcistb_service_call(cpu, r1, r3, gaddr, ar, RA_IGNORED);
139067043607SCho, Yu-Chen     } else {
139167043607SCho, Yu-Chen         return -1;
139267043607SCho, Yu-Chen     }
139367043607SCho, Yu-Chen }
139467043607SCho, Yu-Chen 
kvm_mpcifc_service_call(S390CPU * cpu,struct kvm_run * run)139567043607SCho, Yu-Chen static int kvm_mpcifc_service_call(S390CPU *cpu, struct kvm_run *run)
139667043607SCho, Yu-Chen {
139767043607SCho, Yu-Chen     uint8_t r1 = (run->s390_sieic.ipa & 0x00f0) >> 4;
139867043607SCho, Yu-Chen     uint64_t fiba;
139967043607SCho, Yu-Chen     uint8_t ar;
140067043607SCho, Yu-Chen 
140167043607SCho, Yu-Chen     if (s390_has_feat(S390_FEAT_ZPCI)) {
140267043607SCho, Yu-Chen         fiba = get_base_disp_rxy(cpu, run, &ar);
140367043607SCho, Yu-Chen 
140467043607SCho, Yu-Chen         return mpcifc_service_call(cpu, r1, fiba, ar, RA_IGNORED);
140567043607SCho, Yu-Chen     } else {
140667043607SCho, Yu-Chen         return -1;
140767043607SCho, Yu-Chen     }
140867043607SCho, Yu-Chen }
140967043607SCho, Yu-Chen 
kvm_handle_ptf(S390CPU * cpu,struct kvm_run * run)1410af37bad5SPierre Morel static void kvm_handle_ptf(S390CPU *cpu, struct kvm_run *run)
1411af37bad5SPierre Morel {
1412af37bad5SPierre Morel     uint8_t r1 = (run->s390_sieic.ipb >> 20) & 0x0f;
1413af37bad5SPierre Morel 
1414af37bad5SPierre Morel     s390_handle_ptf(cpu, r1, RA_IGNORED);
1415af37bad5SPierre Morel }
1416af37bad5SPierre Morel 
handle_b9(S390CPU * cpu,struct kvm_run * run,uint8_t ipa1)141767043607SCho, Yu-Chen static int handle_b9(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1)
141867043607SCho, Yu-Chen {
141967043607SCho, Yu-Chen     int r = 0;
142067043607SCho, Yu-Chen 
142167043607SCho, Yu-Chen     switch (ipa1) {
142267043607SCho, Yu-Chen     case PRIV_B9_CLP:
142367043607SCho, Yu-Chen         r = kvm_clp_service_call(cpu, run);
142467043607SCho, Yu-Chen         break;
142567043607SCho, Yu-Chen     case PRIV_B9_PCISTG:
142667043607SCho, Yu-Chen         r = kvm_pcistg_service_call(cpu, run);
142767043607SCho, Yu-Chen         break;
142867043607SCho, Yu-Chen     case PRIV_B9_PCILG:
142967043607SCho, Yu-Chen         r = kvm_pcilg_service_call(cpu, run);
143067043607SCho, Yu-Chen         break;
143167043607SCho, Yu-Chen     case PRIV_B9_RPCIT:
143267043607SCho, Yu-Chen         r = kvm_rpcit_service_call(cpu, run);
143367043607SCho, Yu-Chen         break;
1434af37bad5SPierre Morel     case PRIV_B9_PTF:
1435af37bad5SPierre Morel         kvm_handle_ptf(cpu, run);
1436af37bad5SPierre Morel         break;
143767043607SCho, Yu-Chen     case PRIV_B9_EQBS:
143867043607SCho, Yu-Chen         /* just inject exception */
143967043607SCho, Yu-Chen         r = -1;
144067043607SCho, Yu-Chen         break;
144167043607SCho, Yu-Chen     default:
144267043607SCho, Yu-Chen         r = -1;
1443f4a69168SCédric Le Goater         trace_kvm_insn_unhandled_priv(ipa1);
144467043607SCho, Yu-Chen         break;
144567043607SCho, Yu-Chen     }
144667043607SCho, Yu-Chen 
144767043607SCho, Yu-Chen     return r;
144867043607SCho, Yu-Chen }
144967043607SCho, Yu-Chen 
handle_eb(S390CPU * cpu,struct kvm_run * run,uint8_t ipbl)145067043607SCho, Yu-Chen static int handle_eb(S390CPU *cpu, struct kvm_run *run, uint8_t ipbl)
145167043607SCho, Yu-Chen {
145267043607SCho, Yu-Chen     int r = 0;
145367043607SCho, Yu-Chen 
145467043607SCho, Yu-Chen     switch (ipbl) {
145567043607SCho, Yu-Chen     case PRIV_EB_PCISTB:
145667043607SCho, Yu-Chen         r = kvm_pcistb_service_call(cpu, run);
145767043607SCho, Yu-Chen         break;
145867043607SCho, Yu-Chen     case PRIV_EB_SIC:
145967043607SCho, Yu-Chen         r = kvm_sic_service_call(cpu, run);
146067043607SCho, Yu-Chen         break;
146167043607SCho, Yu-Chen     case PRIV_EB_SQBS:
146267043607SCho, Yu-Chen         /* just inject exception */
146367043607SCho, Yu-Chen         r = -1;
146467043607SCho, Yu-Chen         break;
146567043607SCho, Yu-Chen     default:
146667043607SCho, Yu-Chen         r = -1;
1467f4a69168SCédric Le Goater         trace_kvm_insn_unhandled_priv(ipbl);
146867043607SCho, Yu-Chen         break;
146967043607SCho, Yu-Chen     }
147067043607SCho, Yu-Chen 
147167043607SCho, Yu-Chen     return r;
147267043607SCho, Yu-Chen }
147367043607SCho, Yu-Chen 
handle_e3(S390CPU * cpu,struct kvm_run * run,uint8_t ipbl)147467043607SCho, Yu-Chen static int handle_e3(S390CPU *cpu, struct kvm_run *run, uint8_t ipbl)
147567043607SCho, Yu-Chen {
147667043607SCho, Yu-Chen     int r = 0;
147767043607SCho, Yu-Chen 
147867043607SCho, Yu-Chen     switch (ipbl) {
147967043607SCho, Yu-Chen     case PRIV_E3_MPCIFC:
148067043607SCho, Yu-Chen         r = kvm_mpcifc_service_call(cpu, run);
148167043607SCho, Yu-Chen         break;
148267043607SCho, Yu-Chen     case PRIV_E3_STPCIFC:
148367043607SCho, Yu-Chen         r = kvm_stpcifc_service_call(cpu, run);
148467043607SCho, Yu-Chen         break;
148567043607SCho, Yu-Chen     default:
148667043607SCho, Yu-Chen         r = -1;
1487f4a69168SCédric Le Goater         trace_kvm_insn_unhandled_priv(ipbl);
148867043607SCho, Yu-Chen         break;
148967043607SCho, Yu-Chen     }
149067043607SCho, Yu-Chen 
149167043607SCho, Yu-Chen     return r;
149267043607SCho, Yu-Chen }
149367043607SCho, Yu-Chen 
handle_hypercall(S390CPU * cpu,struct kvm_run * run)149467043607SCho, Yu-Chen static int handle_hypercall(S390CPU *cpu, struct kvm_run *run)
149567043607SCho, Yu-Chen {
149667043607SCho, Yu-Chen     CPUS390XState *env = &cpu->env;
149767043607SCho, Yu-Chen     int ret;
149867043607SCho, Yu-Chen 
149967043607SCho, Yu-Chen     ret = s390_virtio_hypercall(env);
150067043607SCho, Yu-Chen     if (ret == -EINVAL) {
150167043607SCho, Yu-Chen         kvm_s390_program_interrupt(cpu, PGM_SPECIFICATION);
150267043607SCho, Yu-Chen         return 0;
150367043607SCho, Yu-Chen     }
150467043607SCho, Yu-Chen 
150567043607SCho, Yu-Chen     return ret;
150667043607SCho, Yu-Chen }
150767043607SCho, Yu-Chen 
kvm_handle_diag_288(S390CPU * cpu,struct kvm_run * run)150867043607SCho, Yu-Chen static void kvm_handle_diag_288(S390CPU *cpu, struct kvm_run *run)
150967043607SCho, Yu-Chen {
151067043607SCho, Yu-Chen     uint64_t r1, r3;
151167043607SCho, Yu-Chen     int rc;
151267043607SCho, Yu-Chen 
151367043607SCho, Yu-Chen     r1 = (run->s390_sieic.ipa & 0x00f0) >> 4;
151467043607SCho, Yu-Chen     r3 = run->s390_sieic.ipa & 0x000f;
151567043607SCho, Yu-Chen     rc = handle_diag_288(&cpu->env, r1, r3);
151667043607SCho, Yu-Chen     if (rc) {
151767043607SCho, Yu-Chen         kvm_s390_program_interrupt(cpu, PGM_SPECIFICATION);
151867043607SCho, Yu-Chen     }
151967043607SCho, Yu-Chen }
152067043607SCho, Yu-Chen 
kvm_handle_diag_308(S390CPU * cpu,struct kvm_run * run)152167043607SCho, Yu-Chen static void kvm_handle_diag_308(S390CPU *cpu, struct kvm_run *run)
152267043607SCho, Yu-Chen {
152367043607SCho, Yu-Chen     uint64_t r1, r3;
152467043607SCho, Yu-Chen 
152567043607SCho, Yu-Chen     r1 = (run->s390_sieic.ipa & 0x00f0) >> 4;
152667043607SCho, Yu-Chen     r3 = run->s390_sieic.ipa & 0x000f;
152767043607SCho, Yu-Chen     handle_diag_308(&cpu->env, r1, r3, RA_IGNORED);
152867043607SCho, Yu-Chen }
152967043607SCho, Yu-Chen 
handle_sw_breakpoint(S390CPU * cpu,struct kvm_run * run)153067043607SCho, Yu-Chen static int handle_sw_breakpoint(S390CPU *cpu, struct kvm_run *run)
153167043607SCho, Yu-Chen {
153267043607SCho, Yu-Chen     CPUS390XState *env = &cpu->env;
153367043607SCho, Yu-Chen     unsigned long pc;
153467043607SCho, Yu-Chen 
153567043607SCho, Yu-Chen     pc = env->psw.addr - sw_bp_ilen;
153667043607SCho, Yu-Chen     if (kvm_find_sw_breakpoint(CPU(cpu), pc)) {
153767043607SCho, Yu-Chen         env->psw.addr = pc;
153867043607SCho, Yu-Chen         return EXCP_DEBUG;
153967043607SCho, Yu-Chen     }
154067043607SCho, Yu-Chen 
154167043607SCho, Yu-Chen     return -ENOENT;
154267043607SCho, Yu-Chen }
154367043607SCho, Yu-Chen 
kvm_s390_set_diag318(CPUState * cs,uint64_t diag318_info)154467043607SCho, Yu-Chen void kvm_s390_set_diag318(CPUState *cs, uint64_t diag318_info)
154567043607SCho, Yu-Chen {
154667043607SCho, Yu-Chen     CPUS390XState *env = &S390_CPU(cs)->env;
154767043607SCho, Yu-Chen 
154867043607SCho, Yu-Chen     /* Feat bit is set only if KVM supports sync for diag318 */
154967043607SCho, Yu-Chen     if (s390_has_feat(S390_FEAT_DIAG_318)) {
155067043607SCho, Yu-Chen         env->diag318_info = diag318_info;
155167043607SCho, Yu-Chen         cs->kvm_run->s.regs.diag318 = diag318_info;
155267043607SCho, Yu-Chen         cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_DIAG318;
1553c35aff18SCollin Walling         /*
1554c35aff18SCollin Walling          * diag 318 info is zeroed during a clear reset and
1555c35aff18SCollin Walling          * diag 308 IPL subcodes.
1556c35aff18SCollin Walling          */
155767043607SCho, Yu-Chen     }
155867043607SCho, Yu-Chen }
155967043607SCho, Yu-Chen 
handle_diag_318(S390CPU * cpu,struct kvm_run * run)156067043607SCho, Yu-Chen static void handle_diag_318(S390CPU *cpu, struct kvm_run *run)
156167043607SCho, Yu-Chen {
156267043607SCho, Yu-Chen     uint64_t reg = (run->s390_sieic.ipa & 0x00f0) >> 4;
156367043607SCho, Yu-Chen     uint64_t diag318_info = run->s.regs.gprs[reg];
156467043607SCho, Yu-Chen     CPUState *t;
156567043607SCho, Yu-Chen 
156667043607SCho, Yu-Chen     /*
156767043607SCho, Yu-Chen      * DIAG 318 can only be enabled with KVM support. As such, let's
156867043607SCho, Yu-Chen      * ensure a guest cannot execute this instruction erroneously.
156967043607SCho, Yu-Chen      */
157067043607SCho, Yu-Chen     if (!s390_has_feat(S390_FEAT_DIAG_318)) {
157167043607SCho, Yu-Chen         kvm_s390_program_interrupt(cpu, PGM_SPECIFICATION);
157267043607SCho, Yu-Chen         return;
157367043607SCho, Yu-Chen     }
157467043607SCho, Yu-Chen 
157567043607SCho, Yu-Chen     CPU_FOREACH(t) {
157667043607SCho, Yu-Chen         run_on_cpu(t, s390_do_cpu_set_diag318,
157767043607SCho, Yu-Chen                    RUN_ON_CPU_HOST_ULONG(diag318_info));
157867043607SCho, Yu-Chen     }
157967043607SCho, Yu-Chen }
158067043607SCho, Yu-Chen 
158167043607SCho, Yu-Chen #define DIAG_KVM_CODE_MASK 0x000000000000ffff
158267043607SCho, Yu-Chen 
handle_diag(S390CPU * cpu,struct kvm_run * run,uint32_t ipb)158367043607SCho, Yu-Chen static int handle_diag(S390CPU *cpu, struct kvm_run *run, uint32_t ipb)
158467043607SCho, Yu-Chen {
158567043607SCho, Yu-Chen     int r = 0;
158667043607SCho, Yu-Chen     uint16_t func_code;
158767043607SCho, Yu-Chen 
158867043607SCho, Yu-Chen     /*
158967043607SCho, Yu-Chen      * For any diagnose call we support, bits 48-63 of the resulting
159067043607SCho, Yu-Chen      * address specify the function code; the remainder is ignored.
159167043607SCho, Yu-Chen      */
159267043607SCho, Yu-Chen     func_code = decode_basedisp_rs(&cpu->env, ipb, NULL) & DIAG_KVM_CODE_MASK;
159367043607SCho, Yu-Chen     switch (func_code) {
159467043607SCho, Yu-Chen     case DIAG_TIMEREVENT:
159567043607SCho, Yu-Chen         kvm_handle_diag_288(cpu, run);
159667043607SCho, Yu-Chen         break;
159767043607SCho, Yu-Chen     case DIAG_IPL:
159867043607SCho, Yu-Chen         kvm_handle_diag_308(cpu, run);
159967043607SCho, Yu-Chen         break;
160067043607SCho, Yu-Chen     case DIAG_SET_CONTROL_PROGRAM_CODES:
160167043607SCho, Yu-Chen         handle_diag_318(cpu, run);
160267043607SCho, Yu-Chen         break;
160367043607SCho, Yu-Chen     case DIAG_KVM_HYPERCALL:
160467043607SCho, Yu-Chen         r = handle_hypercall(cpu, run);
160567043607SCho, Yu-Chen         break;
160667043607SCho, Yu-Chen     case DIAG_KVM_BREAKPOINT:
160767043607SCho, Yu-Chen         r = handle_sw_breakpoint(cpu, run);
160867043607SCho, Yu-Chen         break;
160967043607SCho, Yu-Chen     default:
1610f4a69168SCédric Le Goater         trace_kvm_insn_diag(func_code);
161167043607SCho, Yu-Chen         kvm_s390_program_interrupt(cpu, PGM_SPECIFICATION);
161267043607SCho, Yu-Chen         break;
161367043607SCho, Yu-Chen     }
161467043607SCho, Yu-Chen 
161567043607SCho, Yu-Chen     return r;
161667043607SCho, Yu-Chen }
161767043607SCho, Yu-Chen 
kvm_s390_handle_sigp(S390CPU * cpu,uint8_t ipa1,uint32_t ipb)161867043607SCho, Yu-Chen static int kvm_s390_handle_sigp(S390CPU *cpu, uint8_t ipa1, uint32_t ipb)
161967043607SCho, Yu-Chen {
162067043607SCho, Yu-Chen     CPUS390XState *env = &cpu->env;
162167043607SCho, Yu-Chen     const uint8_t r1 = ipa1 >> 4;
162267043607SCho, Yu-Chen     const uint8_t r3 = ipa1 & 0x0f;
162367043607SCho, Yu-Chen     int ret;
162467043607SCho, Yu-Chen     uint8_t order;
162567043607SCho, Yu-Chen 
162667043607SCho, Yu-Chen     /* get order code */
162767043607SCho, Yu-Chen     order = decode_basedisp_rs(env, ipb, NULL) & SIGP_ORDER_MASK;
162867043607SCho, Yu-Chen 
162967043607SCho, Yu-Chen     ret = handle_sigp(env, order, r1, r3);
163067043607SCho, Yu-Chen     setcc(cpu, ret);
163167043607SCho, Yu-Chen     return 0;
163267043607SCho, Yu-Chen }
163367043607SCho, Yu-Chen 
handle_instruction(S390CPU * cpu,struct kvm_run * run)163467043607SCho, Yu-Chen static int handle_instruction(S390CPU *cpu, struct kvm_run *run)
163567043607SCho, Yu-Chen {
163667043607SCho, Yu-Chen     unsigned int ipa0 = (run->s390_sieic.ipa & 0xff00);
163767043607SCho, Yu-Chen     uint8_t ipa1 = run->s390_sieic.ipa & 0x00ff;
163867043607SCho, Yu-Chen     int r = -1;
163967043607SCho, Yu-Chen 
1640f4a69168SCédric Le Goater     trace_kvm_insn(run->s390_sieic.ipa, run->s390_sieic.ipb);
164167043607SCho, Yu-Chen     switch (ipa0) {
164267043607SCho, Yu-Chen     case IPA0_B2:
164367043607SCho, Yu-Chen         r = handle_b2(cpu, run, ipa1);
164467043607SCho, Yu-Chen         break;
164567043607SCho, Yu-Chen     case IPA0_B9:
164667043607SCho, Yu-Chen         r = handle_b9(cpu, run, ipa1);
164767043607SCho, Yu-Chen         break;
164867043607SCho, Yu-Chen     case IPA0_EB:
164967043607SCho, Yu-Chen         r = handle_eb(cpu, run, run->s390_sieic.ipb & 0xff);
165067043607SCho, Yu-Chen         break;
165167043607SCho, Yu-Chen     case IPA0_E3:
165267043607SCho, Yu-Chen         r = handle_e3(cpu, run, run->s390_sieic.ipb & 0xff);
165367043607SCho, Yu-Chen         break;
165467043607SCho, Yu-Chen     case IPA0_DIAG:
165567043607SCho, Yu-Chen         r = handle_diag(cpu, run, run->s390_sieic.ipb);
165667043607SCho, Yu-Chen         break;
165767043607SCho, Yu-Chen     case IPA0_SIGP:
165867043607SCho, Yu-Chen         r = kvm_s390_handle_sigp(cpu, ipa1, run->s390_sieic.ipb);
165967043607SCho, Yu-Chen         break;
166067043607SCho, Yu-Chen     }
166167043607SCho, Yu-Chen 
166267043607SCho, Yu-Chen     if (r < 0) {
166367043607SCho, Yu-Chen         r = 0;
166467043607SCho, Yu-Chen         kvm_s390_program_interrupt(cpu, PGM_OPERATION);
166567043607SCho, Yu-Chen     }
166667043607SCho, Yu-Chen 
166767043607SCho, Yu-Chen     return r;
166867043607SCho, Yu-Chen }
166967043607SCho, Yu-Chen 
unmanageable_intercept(S390CPU * cpu,S390CrashReason reason,int pswoffset)167067043607SCho, Yu-Chen static void unmanageable_intercept(S390CPU *cpu, S390CrashReason reason,
167167043607SCho, Yu-Chen                                    int pswoffset)
167267043607SCho, Yu-Chen {
167367043607SCho, Yu-Chen     CPUState *cs = CPU(cpu);
167467043607SCho, Yu-Chen 
167567043607SCho, Yu-Chen     s390_cpu_halt(cpu);
167667043607SCho, Yu-Chen     cpu->env.crash_reason = reason;
167767043607SCho, Yu-Chen     qemu_system_guest_panicked(cpu_get_crash_info(cs));
167867043607SCho, Yu-Chen }
167967043607SCho, Yu-Chen 
168067043607SCho, Yu-Chen /* try to detect pgm check loops */
handle_oper_loop(S390CPU * cpu,struct kvm_run * run)168167043607SCho, Yu-Chen static int handle_oper_loop(S390CPU *cpu, struct kvm_run *run)
168267043607SCho, Yu-Chen {
168367043607SCho, Yu-Chen     CPUState *cs = CPU(cpu);
168467043607SCho, Yu-Chen     PSW oldpsw, newpsw;
168567043607SCho, Yu-Chen 
168667043607SCho, Yu-Chen     newpsw.mask = ldq_phys(cs->as, cpu->env.psa +
168767043607SCho, Yu-Chen                            offsetof(LowCore, program_new_psw));
168867043607SCho, Yu-Chen     newpsw.addr = ldq_phys(cs->as, cpu->env.psa +
168967043607SCho, Yu-Chen                            offsetof(LowCore, program_new_psw) + 8);
169067043607SCho, Yu-Chen     oldpsw.mask  = run->psw_mask;
169167043607SCho, Yu-Chen     oldpsw.addr  = run->psw_addr;
169267043607SCho, Yu-Chen     /*
169367043607SCho, Yu-Chen      * Avoid endless loops of operation exceptions, if the pgm new
169467043607SCho, Yu-Chen      * PSW will cause a new operation exception.
169567043607SCho, Yu-Chen      * The heuristic checks if the pgm new psw is within 6 bytes before
169667043607SCho, Yu-Chen      * the faulting psw address (with same DAT, AS settings) and the
169767043607SCho, Yu-Chen      * new psw is not a wait psw and the fault was not triggered by
169867043607SCho, Yu-Chen      * problem state. In that case go into crashed state.
169967043607SCho, Yu-Chen      */
170067043607SCho, Yu-Chen 
170167043607SCho, Yu-Chen     if (oldpsw.addr - newpsw.addr <= 6 &&
170267043607SCho, Yu-Chen         !(newpsw.mask & PSW_MASK_WAIT) &&
170367043607SCho, Yu-Chen         !(oldpsw.mask & PSW_MASK_PSTATE) &&
170467043607SCho, Yu-Chen         (newpsw.mask & PSW_MASK_ASC) == (oldpsw.mask & PSW_MASK_ASC) &&
170567043607SCho, Yu-Chen         (newpsw.mask & PSW_MASK_DAT) == (oldpsw.mask & PSW_MASK_DAT)) {
170667043607SCho, Yu-Chen         unmanageable_intercept(cpu, S390_CRASH_REASON_OPINT_LOOP,
170767043607SCho, Yu-Chen                                offsetof(LowCore, program_new_psw));
170867043607SCho, Yu-Chen         return EXCP_HALTED;
170967043607SCho, Yu-Chen     }
171067043607SCho, Yu-Chen     return 0;
171167043607SCho, Yu-Chen }
171267043607SCho, Yu-Chen 
handle_intercept(S390CPU * cpu)171367043607SCho, Yu-Chen static int handle_intercept(S390CPU *cpu)
171467043607SCho, Yu-Chen {
171567043607SCho, Yu-Chen     CPUState *cs = CPU(cpu);
171667043607SCho, Yu-Chen     struct kvm_run *run = cs->kvm_run;
171767043607SCho, Yu-Chen     int icpt_code = run->s390_sieic.icptcode;
171867043607SCho, Yu-Chen     int r = 0;
171967043607SCho, Yu-Chen 
1720f4a69168SCédric Le Goater     trace_kvm_intercept(icpt_code, (long)run->psw_addr);
172167043607SCho, Yu-Chen     switch (icpt_code) {
172267043607SCho, Yu-Chen         case ICPT_INSTRUCTION:
172367043607SCho, Yu-Chen         case ICPT_PV_INSTR:
172467043607SCho, Yu-Chen         case ICPT_PV_INSTR_NOTIFICATION:
172567043607SCho, Yu-Chen             r = handle_instruction(cpu, run);
172667043607SCho, Yu-Chen             break;
172767043607SCho, Yu-Chen         case ICPT_PROGRAM:
172867043607SCho, Yu-Chen             unmanageable_intercept(cpu, S390_CRASH_REASON_PGMINT_LOOP,
172967043607SCho, Yu-Chen                                    offsetof(LowCore, program_new_psw));
173067043607SCho, Yu-Chen             r = EXCP_HALTED;
173167043607SCho, Yu-Chen             break;
173267043607SCho, Yu-Chen         case ICPT_EXT_INT:
173367043607SCho, Yu-Chen             unmanageable_intercept(cpu, S390_CRASH_REASON_EXTINT_LOOP,
173467043607SCho, Yu-Chen                                    offsetof(LowCore, external_new_psw));
173567043607SCho, Yu-Chen             r = EXCP_HALTED;
173667043607SCho, Yu-Chen             break;
173767043607SCho, Yu-Chen         case ICPT_WAITPSW:
173867043607SCho, Yu-Chen             /* disabled wait, since enabled wait is handled in kernel */
173967043607SCho, Yu-Chen             s390_handle_wait(cpu);
174067043607SCho, Yu-Chen             r = EXCP_HALTED;
174167043607SCho, Yu-Chen             break;
174267043607SCho, Yu-Chen         case ICPT_CPU_STOP:
174367043607SCho, Yu-Chen             do_stop_interrupt(&cpu->env);
174467043607SCho, Yu-Chen             r = EXCP_HALTED;
174567043607SCho, Yu-Chen             break;
174667043607SCho, Yu-Chen         case ICPT_OPEREXC:
174767043607SCho, Yu-Chen             /* check for break points */
174867043607SCho, Yu-Chen             r = handle_sw_breakpoint(cpu, run);
174967043607SCho, Yu-Chen             if (r == -ENOENT) {
175067043607SCho, Yu-Chen                 /* Then check for potential pgm check loops */
175167043607SCho, Yu-Chen                 r = handle_oper_loop(cpu, run);
175267043607SCho, Yu-Chen                 if (r == 0) {
175367043607SCho, Yu-Chen                     kvm_s390_program_interrupt(cpu, PGM_OPERATION);
175467043607SCho, Yu-Chen                 }
175567043607SCho, Yu-Chen             }
175667043607SCho, Yu-Chen             break;
175767043607SCho, Yu-Chen         case ICPT_SOFT_INTERCEPT:
175867043607SCho, Yu-Chen             fprintf(stderr, "KVM unimplemented icpt SOFT\n");
175967043607SCho, Yu-Chen             exit(1);
176067043607SCho, Yu-Chen             break;
176167043607SCho, Yu-Chen         case ICPT_IO:
176267043607SCho, Yu-Chen             fprintf(stderr, "KVM unimplemented icpt IO\n");
176367043607SCho, Yu-Chen             exit(1);
176467043607SCho, Yu-Chen             break;
176567043607SCho, Yu-Chen         default:
176667043607SCho, Yu-Chen             fprintf(stderr, "Unknown intercept code: %d\n", icpt_code);
176767043607SCho, Yu-Chen             exit(1);
176867043607SCho, Yu-Chen             break;
176967043607SCho, Yu-Chen     }
177067043607SCho, Yu-Chen 
177167043607SCho, Yu-Chen     return r;
177267043607SCho, Yu-Chen }
177367043607SCho, Yu-Chen 
handle_tsch(S390CPU * cpu)177467043607SCho, Yu-Chen static int handle_tsch(S390CPU *cpu)
177567043607SCho, Yu-Chen {
177667043607SCho, Yu-Chen     CPUState *cs = CPU(cpu);
177767043607SCho, Yu-Chen     struct kvm_run *run = cs->kvm_run;
177867043607SCho, Yu-Chen     int ret;
177967043607SCho, Yu-Chen 
178067043607SCho, Yu-Chen     ret = ioinst_handle_tsch(cpu, cpu->env.regs[1], run->s390_tsch.ipb,
178167043607SCho, Yu-Chen                              RA_IGNORED);
178267043607SCho, Yu-Chen     if (ret < 0) {
178367043607SCho, Yu-Chen         /*
178467043607SCho, Yu-Chen          * Failure.
178567043607SCho, Yu-Chen          * If an I/O interrupt had been dequeued, we have to reinject it.
178667043607SCho, Yu-Chen          */
178767043607SCho, Yu-Chen         if (run->s390_tsch.dequeued) {
178867043607SCho, Yu-Chen             s390_io_interrupt(run->s390_tsch.subchannel_id,
178967043607SCho, Yu-Chen                               run->s390_tsch.subchannel_nr,
179067043607SCho, Yu-Chen                               run->s390_tsch.io_int_parm,
179167043607SCho, Yu-Chen                               run->s390_tsch.io_int_word);
179267043607SCho, Yu-Chen         }
179367043607SCho, Yu-Chen         ret = 0;
179467043607SCho, Yu-Chen     }
179567043607SCho, Yu-Chen     return ret;
179667043607SCho, Yu-Chen }
179767043607SCho, Yu-Chen 
insert_stsi_3_2_2(S390CPU * cpu,__u64 addr,uint8_t ar)179867043607SCho, Yu-Chen static void insert_stsi_3_2_2(S390CPU *cpu, __u64 addr, uint8_t ar)
179967043607SCho, Yu-Chen {
180067043607SCho, Yu-Chen     const MachineState *ms = MACHINE(qdev_get_machine());
180167043607SCho, Yu-Chen     uint16_t conf_cpus = 0, reserved_cpus = 0;
180267043607SCho, Yu-Chen     SysIB_322 sysib;
180367043607SCho, Yu-Chen     int del, i;
180467043607SCho, Yu-Chen 
180567043607SCho, Yu-Chen     if (s390_is_pv()) {
180667043607SCho, Yu-Chen         s390_cpu_pv_mem_read(cpu, 0, &sysib, sizeof(sysib));
180767043607SCho, Yu-Chen     } else if (s390_cpu_virt_mem_read(cpu, addr, ar, &sysib, sizeof(sysib))) {
180867043607SCho, Yu-Chen         return;
180967043607SCho, Yu-Chen     }
181067043607SCho, Yu-Chen     /* Shift the stack of Extended Names to prepare for our own data */
181167043607SCho, Yu-Chen     memmove(&sysib.ext_names[1], &sysib.ext_names[0],
181267043607SCho, Yu-Chen             sizeof(sysib.ext_names[0]) * (sysib.count - 1));
181367043607SCho, Yu-Chen     /* First virt level, that doesn't provide Ext Names delimits stack. It is
181467043607SCho, Yu-Chen      * assumed it's not capable of managing Extended Names for lower levels.
181567043607SCho, Yu-Chen      */
181667043607SCho, Yu-Chen     for (del = 1; del < sysib.count; del++) {
181767043607SCho, Yu-Chen         if (!sysib.vm[del].ext_name_encoding || !sysib.ext_names[del][0]) {
181867043607SCho, Yu-Chen             break;
181967043607SCho, Yu-Chen         }
182067043607SCho, Yu-Chen     }
182167043607SCho, Yu-Chen     if (del < sysib.count) {
182267043607SCho, Yu-Chen         memset(sysib.ext_names[del], 0,
182367043607SCho, Yu-Chen                sizeof(sysib.ext_names[0]) * (sysib.count - del));
182467043607SCho, Yu-Chen     }
182567043607SCho, Yu-Chen 
182667043607SCho, Yu-Chen     /* count the cpus and split them into configured and reserved ones */
182767043607SCho, Yu-Chen     for (i = 0; i < ms->possible_cpus->len; i++) {
182867043607SCho, Yu-Chen         if (ms->possible_cpus->cpus[i].cpu) {
182967043607SCho, Yu-Chen             conf_cpus++;
183067043607SCho, Yu-Chen         } else {
183167043607SCho, Yu-Chen             reserved_cpus++;
183267043607SCho, Yu-Chen         }
183367043607SCho, Yu-Chen     }
183467043607SCho, Yu-Chen     sysib.vm[0].total_cpus = conf_cpus + reserved_cpus;
183567043607SCho, Yu-Chen     sysib.vm[0].conf_cpus = conf_cpus;
183667043607SCho, Yu-Chen     sysib.vm[0].reserved_cpus = reserved_cpus;
183767043607SCho, Yu-Chen 
183867043607SCho, Yu-Chen     /* Insert short machine name in EBCDIC, padded with blanks */
183967043607SCho, Yu-Chen     if (qemu_name) {
184067043607SCho, Yu-Chen         memset(sysib.vm[0].name, 0x40, sizeof(sysib.vm[0].name));
184167043607SCho, Yu-Chen         ebcdic_put(sysib.vm[0].name, qemu_name, MIN(sizeof(sysib.vm[0].name),
184267043607SCho, Yu-Chen                                                     strlen(qemu_name)));
184367043607SCho, Yu-Chen     }
184467043607SCho, Yu-Chen     sysib.vm[0].ext_name_encoding = 2; /* 2 = UTF-8 */
184567043607SCho, Yu-Chen     /* If hypervisor specifies zero Extended Name in STSI322 SYSIB, it's
184667043607SCho, Yu-Chen      * considered by s390 as not capable of providing any Extended Name.
184767043607SCho, Yu-Chen      * Therefore if no name was specified on qemu invocation, we go with the
184867043607SCho, Yu-Chen      * same "KVMguest" default, which KVM has filled into short name field.
184967043607SCho, Yu-Chen      */
185067043607SCho, Yu-Chen     strpadcpy((char *)sysib.ext_names[0],
185167043607SCho, Yu-Chen               sizeof(sysib.ext_names[0]),
185267043607SCho, Yu-Chen               qemu_name ?: "KVMguest", '\0');
185367043607SCho, Yu-Chen 
185467043607SCho, Yu-Chen     /* Insert UUID */
185567043607SCho, Yu-Chen     memcpy(sysib.vm[0].uuid, &qemu_uuid, sizeof(sysib.vm[0].uuid));
185667043607SCho, Yu-Chen 
185767043607SCho, Yu-Chen     if (s390_is_pv()) {
185867043607SCho, Yu-Chen         s390_cpu_pv_mem_write(cpu, 0, &sysib, sizeof(sysib));
185967043607SCho, Yu-Chen     } else {
186067043607SCho, Yu-Chen         s390_cpu_virt_mem_write(cpu, addr, ar, &sysib, sizeof(sysib));
186167043607SCho, Yu-Chen     }
186267043607SCho, Yu-Chen }
186367043607SCho, Yu-Chen 
handle_stsi(S390CPU * cpu)186467043607SCho, Yu-Chen static int handle_stsi(S390CPU *cpu)
186567043607SCho, Yu-Chen {
186667043607SCho, Yu-Chen     CPUState *cs = CPU(cpu);
186767043607SCho, Yu-Chen     struct kvm_run *run = cs->kvm_run;
186867043607SCho, Yu-Chen 
186967043607SCho, Yu-Chen     switch (run->s390_stsi.fc) {
187067043607SCho, Yu-Chen     case 3:
187167043607SCho, Yu-Chen         if (run->s390_stsi.sel1 != 2 || run->s390_stsi.sel2 != 2) {
187267043607SCho, Yu-Chen             return 0;
187367043607SCho, Yu-Chen         }
187467043607SCho, Yu-Chen         insert_stsi_3_2_2(cpu, run->s390_stsi.addr, run->s390_stsi.ar);
187567043607SCho, Yu-Chen         return 0;
1876f4f54b58SPierre Morel     case 15:
1877f4f54b58SPierre Morel         insert_stsi_15_1_x(cpu, run->s390_stsi.sel2, run->s390_stsi.addr,
1878f4f54b58SPierre Morel                            run->s390_stsi.ar, RA_IGNORED);
1879f4f54b58SPierre Morel         return 0;
188067043607SCho, Yu-Chen     default:
188167043607SCho, Yu-Chen         return 0;
188267043607SCho, Yu-Chen     }
188367043607SCho, Yu-Chen }
188467043607SCho, Yu-Chen 
kvm_arch_handle_debug_exit(S390CPU * cpu)188567043607SCho, Yu-Chen static int kvm_arch_handle_debug_exit(S390CPU *cpu)
188667043607SCho, Yu-Chen {
188767043607SCho, Yu-Chen     CPUState *cs = CPU(cpu);
188867043607SCho, Yu-Chen     struct kvm_run *run = cs->kvm_run;
188967043607SCho, Yu-Chen 
189067043607SCho, Yu-Chen     int ret = 0;
189167043607SCho, Yu-Chen     struct kvm_debug_exit_arch *arch_info = &run->debug.arch;
189267043607SCho, Yu-Chen 
189367043607SCho, Yu-Chen     switch (arch_info->type) {
189467043607SCho, Yu-Chen     case KVM_HW_WP_WRITE:
189567043607SCho, Yu-Chen         if (find_hw_breakpoint(arch_info->addr, -1, arch_info->type)) {
189667043607SCho, Yu-Chen             cs->watchpoint_hit = &hw_watchpoint;
189767043607SCho, Yu-Chen             hw_watchpoint.vaddr = arch_info->addr;
189867043607SCho, Yu-Chen             hw_watchpoint.flags = BP_MEM_WRITE;
189967043607SCho, Yu-Chen             ret = EXCP_DEBUG;
190067043607SCho, Yu-Chen         }
190167043607SCho, Yu-Chen         break;
190267043607SCho, Yu-Chen     case KVM_HW_BP:
190367043607SCho, Yu-Chen         if (find_hw_breakpoint(arch_info->addr, -1, arch_info->type)) {
190467043607SCho, Yu-Chen             ret = EXCP_DEBUG;
190567043607SCho, Yu-Chen         }
190667043607SCho, Yu-Chen         break;
190767043607SCho, Yu-Chen     case KVM_SINGLESTEP:
190867043607SCho, Yu-Chen         if (cs->singlestep_enabled) {
190967043607SCho, Yu-Chen             ret = EXCP_DEBUG;
191067043607SCho, Yu-Chen         }
191167043607SCho, Yu-Chen         break;
191267043607SCho, Yu-Chen     default:
191367043607SCho, Yu-Chen         ret = -ENOSYS;
191467043607SCho, Yu-Chen     }
191567043607SCho, Yu-Chen 
191667043607SCho, Yu-Chen     return ret;
191767043607SCho, Yu-Chen }
191867043607SCho, Yu-Chen 
kvm_arch_handle_exit(CPUState * cs,struct kvm_run * run)191967043607SCho, Yu-Chen int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
192067043607SCho, Yu-Chen {
192167043607SCho, Yu-Chen     S390CPU *cpu = S390_CPU(cs);
192267043607SCho, Yu-Chen     int ret = 0;
192367043607SCho, Yu-Chen 
1924195801d7SStefan Hajnoczi     bql_lock();
192567043607SCho, Yu-Chen 
192667043607SCho, Yu-Chen     kvm_cpu_synchronize_state(cs);
192767043607SCho, Yu-Chen 
192867043607SCho, Yu-Chen     switch (run->exit_reason) {
192967043607SCho, Yu-Chen         case KVM_EXIT_S390_SIEIC:
193067043607SCho, Yu-Chen             ret = handle_intercept(cpu);
193167043607SCho, Yu-Chen             break;
193267043607SCho, Yu-Chen         case KVM_EXIT_S390_RESET:
193367043607SCho, Yu-Chen             s390_ipl_reset_request(cs, S390_RESET_REIPL);
193467043607SCho, Yu-Chen             break;
193567043607SCho, Yu-Chen         case KVM_EXIT_S390_TSCH:
193667043607SCho, Yu-Chen             ret = handle_tsch(cpu);
193767043607SCho, Yu-Chen             break;
193867043607SCho, Yu-Chen         case KVM_EXIT_S390_STSI:
193967043607SCho, Yu-Chen             ret = handle_stsi(cpu);
194067043607SCho, Yu-Chen             break;
194167043607SCho, Yu-Chen         case KVM_EXIT_DEBUG:
194267043607SCho, Yu-Chen             ret = kvm_arch_handle_debug_exit(cpu);
194367043607SCho, Yu-Chen             break;
194467043607SCho, Yu-Chen         default:
194567043607SCho, Yu-Chen             fprintf(stderr, "Unknown KVM exit: %d\n", run->exit_reason);
194667043607SCho, Yu-Chen             break;
194767043607SCho, Yu-Chen     }
1948195801d7SStefan Hajnoczi     bql_unlock();
194967043607SCho, Yu-Chen 
195067043607SCho, Yu-Chen     if (ret == 0) {
195167043607SCho, Yu-Chen         ret = EXCP_INTERRUPT;
195267043607SCho, Yu-Chen     }
195367043607SCho, Yu-Chen     return ret;
195467043607SCho, Yu-Chen }
195567043607SCho, Yu-Chen 
kvm_arch_stop_on_emulation_error(CPUState * cpu)195667043607SCho, Yu-Chen bool kvm_arch_stop_on_emulation_error(CPUState *cpu)
195767043607SCho, Yu-Chen {
195867043607SCho, Yu-Chen     return true;
195967043607SCho, Yu-Chen }
196067043607SCho, Yu-Chen 
kvm_s390_enable_css_support(S390CPU * cpu)196167043607SCho, Yu-Chen void kvm_s390_enable_css_support(S390CPU *cpu)
196267043607SCho, Yu-Chen {
196367043607SCho, Yu-Chen     int r;
196467043607SCho, Yu-Chen 
196567043607SCho, Yu-Chen     /* Activate host kernel channel subsystem support. */
196667043607SCho, Yu-Chen     r = kvm_vcpu_enable_cap(CPU(cpu), KVM_CAP_S390_CSS_SUPPORT, 0);
196767043607SCho, Yu-Chen     assert(r == 0);
196867043607SCho, Yu-Chen }
196967043607SCho, Yu-Chen 
kvm_arch_init_irq_routing(KVMState * s)197067043607SCho, Yu-Chen void kvm_arch_init_irq_routing(KVMState *s)
197167043607SCho, Yu-Chen {
197267043607SCho, Yu-Chen     /*
197367043607SCho, Yu-Chen      * Note that while irqchip capabilities generally imply that cpustates
197467043607SCho, Yu-Chen      * are handled in-kernel, it is not true for s390 (yet); therefore, we
197567043607SCho, Yu-Chen      * have to override the common code kvm_halt_in_kernel_allowed setting.
197667043607SCho, Yu-Chen      */
197767043607SCho, Yu-Chen     if (kvm_check_extension(s, KVM_CAP_IRQ_ROUTING)) {
197867043607SCho, Yu-Chen         kvm_gsi_routing_allowed = true;
197967043607SCho, Yu-Chen         kvm_halt_in_kernel_allowed = false;
198067043607SCho, Yu-Chen     }
198167043607SCho, Yu-Chen }
198267043607SCho, Yu-Chen 
kvm_s390_assign_subch_ioeventfd(EventNotifier * notifier,uint32_t sch,int vq,bool assign)198367043607SCho, Yu-Chen int kvm_s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch,
198467043607SCho, Yu-Chen                                     int vq, bool assign)
198567043607SCho, Yu-Chen {
198667043607SCho, Yu-Chen     struct kvm_ioeventfd kick = {
198767043607SCho, Yu-Chen         .flags = KVM_IOEVENTFD_FLAG_VIRTIO_CCW_NOTIFY |
198867043607SCho, Yu-Chen         KVM_IOEVENTFD_FLAG_DATAMATCH,
198967043607SCho, Yu-Chen         .fd = event_notifier_get_fd(notifier),
199067043607SCho, Yu-Chen         .datamatch = vq,
199167043607SCho, Yu-Chen         .addr = sch,
199267043607SCho, Yu-Chen         .len = 8,
199367043607SCho, Yu-Chen     };
199467043607SCho, Yu-Chen     trace_kvm_assign_subch_ioeventfd(kick.fd, kick.addr, assign,
199567043607SCho, Yu-Chen                                      kick.datamatch);
199667043607SCho, Yu-Chen     if (!kvm_check_extension(kvm_state, KVM_CAP_IOEVENTFD)) {
199767043607SCho, Yu-Chen         return -ENOSYS;
199867043607SCho, Yu-Chen     }
199967043607SCho, Yu-Chen     if (!assign) {
200067043607SCho, Yu-Chen         kick.flags |= KVM_IOEVENTFD_FLAG_DEASSIGN;
200167043607SCho, Yu-Chen     }
200267043607SCho, Yu-Chen     return kvm_vm_ioctl(kvm_state, KVM_IOEVENTFD, &kick);
200367043607SCho, Yu-Chen }
200467043607SCho, Yu-Chen 
kvm_s390_get_protected_dump(void)2005ad3b2e69SJanosch Frank int kvm_s390_get_protected_dump(void)
2006ad3b2e69SJanosch Frank {
2007ad3b2e69SJanosch Frank     return cap_protected_dump;
2008ad3b2e69SJanosch Frank }
2009ad3b2e69SJanosch Frank 
kvm_s390_get_ri(void)201067043607SCho, Yu-Chen int kvm_s390_get_ri(void)
201167043607SCho, Yu-Chen {
201267043607SCho, Yu-Chen     return cap_ri;
201367043607SCho, Yu-Chen }
201467043607SCho, Yu-Chen 
kvm_s390_set_cpu_state(S390CPU * cpu,uint8_t cpu_state)201567043607SCho, Yu-Chen int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state)
201667043607SCho, Yu-Chen {
201767043607SCho, Yu-Chen     struct kvm_mp_state mp_state = {};
201867043607SCho, Yu-Chen     int ret;
201967043607SCho, Yu-Chen 
202067043607SCho, Yu-Chen     /* the kvm part might not have been initialized yet */
202167043607SCho, Yu-Chen     if (CPU(cpu)->kvm_state == NULL) {
202267043607SCho, Yu-Chen         return 0;
202367043607SCho, Yu-Chen     }
202467043607SCho, Yu-Chen 
202567043607SCho, Yu-Chen     switch (cpu_state) {
202667043607SCho, Yu-Chen     case S390_CPU_STATE_STOPPED:
202767043607SCho, Yu-Chen         mp_state.mp_state = KVM_MP_STATE_STOPPED;
202867043607SCho, Yu-Chen         break;
202967043607SCho, Yu-Chen     case S390_CPU_STATE_CHECK_STOP:
203067043607SCho, Yu-Chen         mp_state.mp_state = KVM_MP_STATE_CHECK_STOP;
203167043607SCho, Yu-Chen         break;
203267043607SCho, Yu-Chen     case S390_CPU_STATE_OPERATING:
203367043607SCho, Yu-Chen         mp_state.mp_state = KVM_MP_STATE_OPERATING;
203467043607SCho, Yu-Chen         break;
203567043607SCho, Yu-Chen     case S390_CPU_STATE_LOAD:
203667043607SCho, Yu-Chen         mp_state.mp_state = KVM_MP_STATE_LOAD;
203767043607SCho, Yu-Chen         break;
203867043607SCho, Yu-Chen     default:
203967043607SCho, Yu-Chen         error_report("Requested CPU state is not a valid S390 CPU state: %u",
204067043607SCho, Yu-Chen                      cpu_state);
204167043607SCho, Yu-Chen         exit(1);
204267043607SCho, Yu-Chen     }
204367043607SCho, Yu-Chen 
204467043607SCho, Yu-Chen     ret = kvm_vcpu_ioctl(CPU(cpu), KVM_SET_MP_STATE, &mp_state);
204567043607SCho, Yu-Chen     if (ret) {
204667043607SCho, Yu-Chen         trace_kvm_failed_cpu_state_set(CPU(cpu)->cpu_index, cpu_state,
204767043607SCho, Yu-Chen                                        strerror(-ret));
204867043607SCho, Yu-Chen     }
204967043607SCho, Yu-Chen 
205067043607SCho, Yu-Chen     return ret;
205167043607SCho, Yu-Chen }
205267043607SCho, Yu-Chen 
kvm_s390_vcpu_interrupt_pre_save(S390CPU * cpu)205367043607SCho, Yu-Chen void kvm_s390_vcpu_interrupt_pre_save(S390CPU *cpu)
205467043607SCho, Yu-Chen {
205567043607SCho, Yu-Chen     unsigned int max_cpus = MACHINE(qdev_get_machine())->smp.max_cpus;
205667043607SCho, Yu-Chen     struct kvm_s390_irq_state irq_state = {
205767043607SCho, Yu-Chen         .buf = (uint64_t) cpu->irqstate,
205867043607SCho, Yu-Chen         .len = VCPU_IRQ_BUF_SIZE(max_cpus),
205967043607SCho, Yu-Chen     };
206067043607SCho, Yu-Chen     CPUState *cs = CPU(cpu);
206167043607SCho, Yu-Chen     int32_t bytes;
206267043607SCho, Yu-Chen 
206367043607SCho, Yu-Chen     if (!kvm_check_extension(kvm_state, KVM_CAP_S390_IRQ_STATE)) {
206467043607SCho, Yu-Chen         return;
206567043607SCho, Yu-Chen     }
206667043607SCho, Yu-Chen 
206767043607SCho, Yu-Chen     bytes = kvm_vcpu_ioctl(cs, KVM_S390_GET_IRQ_STATE, &irq_state);
206867043607SCho, Yu-Chen     if (bytes < 0) {
206967043607SCho, Yu-Chen         cpu->irqstate_saved_size = 0;
207067043607SCho, Yu-Chen         error_report("Migration of interrupt state failed");
207167043607SCho, Yu-Chen         return;
207267043607SCho, Yu-Chen     }
207367043607SCho, Yu-Chen 
207467043607SCho, Yu-Chen     cpu->irqstate_saved_size = bytes;
207567043607SCho, Yu-Chen }
207667043607SCho, Yu-Chen 
kvm_s390_vcpu_interrupt_post_load(S390CPU * cpu)207767043607SCho, Yu-Chen int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu)
207867043607SCho, Yu-Chen {
207967043607SCho, Yu-Chen     CPUState *cs = CPU(cpu);
208067043607SCho, Yu-Chen     struct kvm_s390_irq_state irq_state = {
208167043607SCho, Yu-Chen         .buf = (uint64_t) cpu->irqstate,
208267043607SCho, Yu-Chen         .len = cpu->irqstate_saved_size,
208367043607SCho, Yu-Chen     };
208467043607SCho, Yu-Chen     int r;
208567043607SCho, Yu-Chen 
208667043607SCho, Yu-Chen     if (cpu->irqstate_saved_size == 0) {
208767043607SCho, Yu-Chen         return 0;
208867043607SCho, Yu-Chen     }
208967043607SCho, Yu-Chen 
209067043607SCho, Yu-Chen     if (!kvm_check_extension(kvm_state, KVM_CAP_S390_IRQ_STATE)) {
209167043607SCho, Yu-Chen         return -ENOSYS;
209267043607SCho, Yu-Chen     }
209367043607SCho, Yu-Chen 
209467043607SCho, Yu-Chen     r = kvm_vcpu_ioctl(cs, KVM_S390_SET_IRQ_STATE, &irq_state);
209567043607SCho, Yu-Chen     if (r) {
209667043607SCho, Yu-Chen         error_report("Setting interrupt state failed %d", r);
209767043607SCho, Yu-Chen     }
209867043607SCho, Yu-Chen     return r;
209967043607SCho, Yu-Chen }
210067043607SCho, Yu-Chen 
kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry * route,uint64_t address,uint32_t data,PCIDevice * dev)210167043607SCho, Yu-Chen int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route,
210267043607SCho, Yu-Chen                              uint64_t address, uint32_t data, PCIDevice *dev)
210367043607SCho, Yu-Chen {
210467043607SCho, Yu-Chen     S390PCIBusDevice *pbdev;
210567043607SCho, Yu-Chen     uint32_t vec = data & ZPCI_MSI_VEC_MASK;
210667043607SCho, Yu-Chen 
210767043607SCho, Yu-Chen     if (!dev) {
2108f4a69168SCédric Le Goater         trace_kvm_msi_route_fixup("no pci device");
210967043607SCho, Yu-Chen         return -ENODEV;
211067043607SCho, Yu-Chen     }
211167043607SCho, Yu-Chen 
211267043607SCho, Yu-Chen     pbdev = s390_pci_find_dev_by_target(s390_get_phb(), DEVICE(dev)->id);
211367043607SCho, Yu-Chen     if (!pbdev) {
2114f4a69168SCédric Le Goater         trace_kvm_msi_route_fixup("no zpci device");
211567043607SCho, Yu-Chen         return -ENODEV;
211667043607SCho, Yu-Chen     }
211767043607SCho, Yu-Chen 
211867043607SCho, Yu-Chen     route->type = KVM_IRQ_ROUTING_S390_ADAPTER;
211967043607SCho, Yu-Chen     route->flags = 0;
212067043607SCho, Yu-Chen     route->u.adapter.summary_addr = pbdev->routes.adapter.summary_addr;
212167043607SCho, Yu-Chen     route->u.adapter.ind_addr = pbdev->routes.adapter.ind_addr;
212267043607SCho, Yu-Chen     route->u.adapter.summary_offset = pbdev->routes.adapter.summary_offset;
212367043607SCho, Yu-Chen     route->u.adapter.ind_offset = pbdev->routes.adapter.ind_offset + vec;
212467043607SCho, Yu-Chen     route->u.adapter.adapter_id = pbdev->routes.adapter.adapter_id;
212567043607SCho, Yu-Chen     return 0;
212667043607SCho, Yu-Chen }
212767043607SCho, Yu-Chen 
kvm_arch_add_msi_route_post(struct kvm_irq_routing_entry * route,int vector,PCIDevice * dev)212867043607SCho, Yu-Chen int kvm_arch_add_msi_route_post(struct kvm_irq_routing_entry *route,
212967043607SCho, Yu-Chen                                 int vector, PCIDevice *dev)
213067043607SCho, Yu-Chen {
213167043607SCho, Yu-Chen     return 0;
213267043607SCho, Yu-Chen }
213367043607SCho, Yu-Chen 
kvm_arch_release_virq_post(int virq)213467043607SCho, Yu-Chen int kvm_arch_release_virq_post(int virq)
213567043607SCho, Yu-Chen {
213667043607SCho, Yu-Chen     return 0;
213767043607SCho, Yu-Chen }
213867043607SCho, Yu-Chen 
kvm_arch_msi_data_to_gsi(uint32_t data)213967043607SCho, Yu-Chen int kvm_arch_msi_data_to_gsi(uint32_t data)
214067043607SCho, Yu-Chen {
214167043607SCho, Yu-Chen     abort();
214267043607SCho, Yu-Chen }
214367043607SCho, Yu-Chen 
query_cpu_subfunc(S390FeatBitmap features)214467043607SCho, Yu-Chen static int query_cpu_subfunc(S390FeatBitmap features)
214567043607SCho, Yu-Chen {
214667043607SCho, Yu-Chen     struct kvm_s390_vm_cpu_subfunc prop = {};
214767043607SCho, Yu-Chen     struct kvm_device_attr attr = {
214867043607SCho, Yu-Chen         .group = KVM_S390_VM_CPU_MODEL,
214967043607SCho, Yu-Chen         .attr = KVM_S390_VM_CPU_MACHINE_SUBFUNC,
215067043607SCho, Yu-Chen         .addr = (uint64_t) &prop,
215167043607SCho, Yu-Chen     };
215267043607SCho, Yu-Chen     int rc;
215367043607SCho, Yu-Chen 
215467043607SCho, Yu-Chen     rc = kvm_vm_ioctl(kvm_state, KVM_GET_DEVICE_ATTR, &attr);
215567043607SCho, Yu-Chen     if (rc) {
215667043607SCho, Yu-Chen         return  rc;
215767043607SCho, Yu-Chen     }
215867043607SCho, Yu-Chen 
215967043607SCho, Yu-Chen     /*
216067043607SCho, Yu-Chen      * We're going to add all subfunctions now, if the corresponding feature
216167043607SCho, Yu-Chen      * is available that unlocks the query functions.
216267043607SCho, Yu-Chen      */
216367043607SCho, Yu-Chen     s390_add_from_feat_block(features, S390_FEAT_TYPE_PLO, prop.plo);
216467043607SCho, Yu-Chen     if (test_bit(S390_FEAT_TOD_CLOCK_STEERING, features)) {
216567043607SCho, Yu-Chen         s390_add_from_feat_block(features, S390_FEAT_TYPE_PTFF, prop.ptff);
216667043607SCho, Yu-Chen     }
216767043607SCho, Yu-Chen     if (test_bit(S390_FEAT_MSA, features)) {
216867043607SCho, Yu-Chen         s390_add_from_feat_block(features, S390_FEAT_TYPE_KMAC, prop.kmac);
216967043607SCho, Yu-Chen         s390_add_from_feat_block(features, S390_FEAT_TYPE_KMC, prop.kmc);
217067043607SCho, Yu-Chen         s390_add_from_feat_block(features, S390_FEAT_TYPE_KM, prop.km);
217167043607SCho, Yu-Chen         s390_add_from_feat_block(features, S390_FEAT_TYPE_KIMD, prop.kimd);
217267043607SCho, Yu-Chen         s390_add_from_feat_block(features, S390_FEAT_TYPE_KLMD, prop.klmd);
217367043607SCho, Yu-Chen     }
217467043607SCho, Yu-Chen     if (test_bit(S390_FEAT_MSA_EXT_3, features)) {
217567043607SCho, Yu-Chen         s390_add_from_feat_block(features, S390_FEAT_TYPE_PCKMO, prop.pckmo);
217667043607SCho, Yu-Chen     }
217767043607SCho, Yu-Chen     if (test_bit(S390_FEAT_MSA_EXT_4, features)) {
217867043607SCho, Yu-Chen         s390_add_from_feat_block(features, S390_FEAT_TYPE_KMCTR, prop.kmctr);
217967043607SCho, Yu-Chen         s390_add_from_feat_block(features, S390_FEAT_TYPE_KMF, prop.kmf);
218067043607SCho, Yu-Chen         s390_add_from_feat_block(features, S390_FEAT_TYPE_KMO, prop.kmo);
218167043607SCho, Yu-Chen         s390_add_from_feat_block(features, S390_FEAT_TYPE_PCC, prop.pcc);
218267043607SCho, Yu-Chen     }
218367043607SCho, Yu-Chen     if (test_bit(S390_FEAT_MSA_EXT_5, features)) {
218467043607SCho, Yu-Chen         s390_add_from_feat_block(features, S390_FEAT_TYPE_PPNO, prop.ppno);
218567043607SCho, Yu-Chen     }
218667043607SCho, Yu-Chen     if (test_bit(S390_FEAT_MSA_EXT_8, features)) {
218767043607SCho, Yu-Chen         s390_add_from_feat_block(features, S390_FEAT_TYPE_KMA, prop.kma);
218867043607SCho, Yu-Chen     }
218967043607SCho, Yu-Chen     if (test_bit(S390_FEAT_MSA_EXT_9, features)) {
219067043607SCho, Yu-Chen         s390_add_from_feat_block(features, S390_FEAT_TYPE_KDSA, prop.kdsa);
219167043607SCho, Yu-Chen     }
219267043607SCho, Yu-Chen     if (test_bit(S390_FEAT_ESORT_BASE, features)) {
219367043607SCho, Yu-Chen         s390_add_from_feat_block(features, S390_FEAT_TYPE_SORTL, prop.sortl);
219467043607SCho, Yu-Chen     }
219567043607SCho, Yu-Chen     if (test_bit(S390_FEAT_DEFLATE_BASE, features)) {
219667043607SCho, Yu-Chen         s390_add_from_feat_block(features, S390_FEAT_TYPE_DFLTCC, prop.dfltcc);
219767043607SCho, Yu-Chen     }
219867043607SCho, Yu-Chen     return 0;
219967043607SCho, Yu-Chen }
220067043607SCho, Yu-Chen 
configure_cpu_subfunc(const S390FeatBitmap features)220167043607SCho, Yu-Chen static int configure_cpu_subfunc(const S390FeatBitmap features)
220267043607SCho, Yu-Chen {
220367043607SCho, Yu-Chen     struct kvm_s390_vm_cpu_subfunc prop = {};
220467043607SCho, Yu-Chen     struct kvm_device_attr attr = {
220567043607SCho, Yu-Chen         .group = KVM_S390_VM_CPU_MODEL,
220667043607SCho, Yu-Chen         .attr = KVM_S390_VM_CPU_PROCESSOR_SUBFUNC,
220767043607SCho, Yu-Chen         .addr = (uint64_t) &prop,
220867043607SCho, Yu-Chen     };
220967043607SCho, Yu-Chen 
221067043607SCho, Yu-Chen     if (!kvm_vm_check_attr(kvm_state, KVM_S390_VM_CPU_MODEL,
221167043607SCho, Yu-Chen                            KVM_S390_VM_CPU_PROCESSOR_SUBFUNC)) {
221267043607SCho, Yu-Chen         /* hardware support might be missing, IBC will handle most of this */
221367043607SCho, Yu-Chen         return 0;
221467043607SCho, Yu-Chen     }
221567043607SCho, Yu-Chen 
221667043607SCho, Yu-Chen     s390_fill_feat_block(features, S390_FEAT_TYPE_PLO, prop.plo);
221767043607SCho, Yu-Chen     if (test_bit(S390_FEAT_TOD_CLOCK_STEERING, features)) {
221867043607SCho, Yu-Chen         s390_fill_feat_block(features, S390_FEAT_TYPE_PTFF, prop.ptff);
221967043607SCho, Yu-Chen     }
222067043607SCho, Yu-Chen     if (test_bit(S390_FEAT_MSA, features)) {
222167043607SCho, Yu-Chen         s390_fill_feat_block(features, S390_FEAT_TYPE_KMAC, prop.kmac);
222267043607SCho, Yu-Chen         s390_fill_feat_block(features, S390_FEAT_TYPE_KMC, prop.kmc);
222367043607SCho, Yu-Chen         s390_fill_feat_block(features, S390_FEAT_TYPE_KM, prop.km);
222467043607SCho, Yu-Chen         s390_fill_feat_block(features, S390_FEAT_TYPE_KIMD, prop.kimd);
222567043607SCho, Yu-Chen         s390_fill_feat_block(features, S390_FEAT_TYPE_KLMD, prop.klmd);
222667043607SCho, Yu-Chen     }
222767043607SCho, Yu-Chen     if (test_bit(S390_FEAT_MSA_EXT_3, features)) {
222867043607SCho, Yu-Chen         s390_fill_feat_block(features, S390_FEAT_TYPE_PCKMO, prop.pckmo);
222967043607SCho, Yu-Chen     }
223067043607SCho, Yu-Chen     if (test_bit(S390_FEAT_MSA_EXT_4, features)) {
223167043607SCho, Yu-Chen         s390_fill_feat_block(features, S390_FEAT_TYPE_KMCTR, prop.kmctr);
223267043607SCho, Yu-Chen         s390_fill_feat_block(features, S390_FEAT_TYPE_KMF, prop.kmf);
223367043607SCho, Yu-Chen         s390_fill_feat_block(features, S390_FEAT_TYPE_KMO, prop.kmo);
223467043607SCho, Yu-Chen         s390_fill_feat_block(features, S390_FEAT_TYPE_PCC, prop.pcc);
223567043607SCho, Yu-Chen     }
223667043607SCho, Yu-Chen     if (test_bit(S390_FEAT_MSA_EXT_5, features)) {
223767043607SCho, Yu-Chen         s390_fill_feat_block(features, S390_FEAT_TYPE_PPNO, prop.ppno);
223867043607SCho, Yu-Chen     }
223967043607SCho, Yu-Chen     if (test_bit(S390_FEAT_MSA_EXT_8, features)) {
224067043607SCho, Yu-Chen         s390_fill_feat_block(features, S390_FEAT_TYPE_KMA, prop.kma);
224167043607SCho, Yu-Chen     }
224267043607SCho, Yu-Chen     if (test_bit(S390_FEAT_MSA_EXT_9, features)) {
224367043607SCho, Yu-Chen         s390_fill_feat_block(features, S390_FEAT_TYPE_KDSA, prop.kdsa);
224467043607SCho, Yu-Chen     }
224567043607SCho, Yu-Chen     if (test_bit(S390_FEAT_ESORT_BASE, features)) {
224667043607SCho, Yu-Chen         s390_fill_feat_block(features, S390_FEAT_TYPE_SORTL, prop.sortl);
224767043607SCho, Yu-Chen     }
224867043607SCho, Yu-Chen     if (test_bit(S390_FEAT_DEFLATE_BASE, features)) {
224967043607SCho, Yu-Chen         s390_fill_feat_block(features, S390_FEAT_TYPE_DFLTCC, prop.dfltcc);
225067043607SCho, Yu-Chen     }
225167043607SCho, Yu-Chen     return kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr);
225267043607SCho, Yu-Chen }
225367043607SCho, Yu-Chen 
ap_available(void)2254354383c1SSteffen Eiden static bool ap_available(void)
2255354383c1SSteffen Eiden {
2256354383c1SSteffen Eiden     return kvm_vm_check_attr(kvm_state, KVM_S390_VM_CRYPTO,
2257354383c1SSteffen Eiden                              KVM_S390_VM_CRYPTO_ENABLE_APIE);
2258354383c1SSteffen Eiden }
2259354383c1SSteffen Eiden 
ap_enabled(const S390FeatBitmap features)2260354383c1SSteffen Eiden static bool ap_enabled(const S390FeatBitmap features)
2261354383c1SSteffen Eiden {
2262354383c1SSteffen Eiden     return test_bit(S390_FEAT_AP, features);
2263354383c1SSteffen Eiden }
2264354383c1SSteffen Eiden 
uv_feat_supported(void)22655ac95151SSteffen Eiden static bool uv_feat_supported(void)
22665ac95151SSteffen Eiden {
22675ac95151SSteffen Eiden     return kvm_vm_check_attr(kvm_state, KVM_S390_VM_CPU_MODEL,
22685ac95151SSteffen Eiden                              KVM_S390_VM_CPU_PROCESSOR_UV_FEAT_GUEST);
22695ac95151SSteffen Eiden }
22705ac95151SSteffen Eiden 
query_uv_feat_guest(S390FeatBitmap features)22715ac95151SSteffen Eiden static int query_uv_feat_guest(S390FeatBitmap features)
22725ac95151SSteffen Eiden {
22735ac95151SSteffen Eiden     struct kvm_s390_vm_cpu_uv_feat prop = {};
22745ac95151SSteffen Eiden     struct kvm_device_attr attr = {
22755ac95151SSteffen Eiden         .group = KVM_S390_VM_CPU_MODEL,
22765ac95151SSteffen Eiden         .attr = KVM_S390_VM_CPU_MACHINE_UV_FEAT_GUEST,
22775ac95151SSteffen Eiden         .addr = (uint64_t) &prop,
22785ac95151SSteffen Eiden     };
22795ac95151SSteffen Eiden     int rc;
22805ac95151SSteffen Eiden 
22815ac95151SSteffen Eiden     /* AP support check is currently the only user of the UV feature test */
22825ac95151SSteffen Eiden     if (!(uv_feat_supported() && ap_available())) {
22835ac95151SSteffen Eiden         return 0;
22845ac95151SSteffen Eiden     }
22855ac95151SSteffen Eiden 
22865ac95151SSteffen Eiden     rc = kvm_vm_ioctl(kvm_state, KVM_GET_DEVICE_ATTR, &attr);
22875ac95151SSteffen Eiden     if (rc) {
22885ac95151SSteffen Eiden         return  rc;
22895ac95151SSteffen Eiden     }
22905ac95151SSteffen Eiden 
22915ac95151SSteffen Eiden     if (prop.ap) {
22925ac95151SSteffen Eiden         set_bit(S390_FEAT_UV_FEAT_AP, features);
22935ac95151SSteffen Eiden     }
22945ac95151SSteffen Eiden     if (prop.ap_intr) {
22955ac95151SSteffen Eiden         set_bit(S390_FEAT_UV_FEAT_AP_INTR, features);
22965ac95151SSteffen Eiden     }
22975ac95151SSteffen Eiden 
22985ac95151SSteffen Eiden     return 0;
22995ac95151SSteffen Eiden }
23005ac95151SSteffen Eiden 
230167043607SCho, Yu-Chen static int kvm_to_feat[][2] = {
230267043607SCho, Yu-Chen     { KVM_S390_VM_CPU_FEAT_ESOP, S390_FEAT_ESOP },
230367043607SCho, Yu-Chen     { KVM_S390_VM_CPU_FEAT_SIEF2, S390_FEAT_SIE_F2 },
230467043607SCho, Yu-Chen     { KVM_S390_VM_CPU_FEAT_64BSCAO , S390_FEAT_SIE_64BSCAO },
230567043607SCho, Yu-Chen     { KVM_S390_VM_CPU_FEAT_SIIF, S390_FEAT_SIE_SIIF },
230667043607SCho, Yu-Chen     { KVM_S390_VM_CPU_FEAT_GPERE, S390_FEAT_SIE_GPERE },
230767043607SCho, Yu-Chen     { KVM_S390_VM_CPU_FEAT_GSLS, S390_FEAT_SIE_GSLS },
230867043607SCho, Yu-Chen     { KVM_S390_VM_CPU_FEAT_IB, S390_FEAT_SIE_IB },
230967043607SCho, Yu-Chen     { KVM_S390_VM_CPU_FEAT_CEI, S390_FEAT_SIE_CEI },
231067043607SCho, Yu-Chen     { KVM_S390_VM_CPU_FEAT_IBS, S390_FEAT_SIE_IBS },
231167043607SCho, Yu-Chen     { KVM_S390_VM_CPU_FEAT_SKEY, S390_FEAT_SIE_SKEY },
231267043607SCho, Yu-Chen     { KVM_S390_VM_CPU_FEAT_CMMA, S390_FEAT_SIE_CMMA },
231367043607SCho, Yu-Chen     { KVM_S390_VM_CPU_FEAT_PFMFI, S390_FEAT_SIE_PFMFI},
231467043607SCho, Yu-Chen     { KVM_S390_VM_CPU_FEAT_SIGPIF, S390_FEAT_SIE_SIGPIF},
231567043607SCho, Yu-Chen     { KVM_S390_VM_CPU_FEAT_KSS, S390_FEAT_SIE_KSS},
231667043607SCho, Yu-Chen };
231767043607SCho, Yu-Chen 
query_cpu_feat(S390FeatBitmap features)231867043607SCho, Yu-Chen static int query_cpu_feat(S390FeatBitmap features)
231967043607SCho, Yu-Chen {
232067043607SCho, Yu-Chen     struct kvm_s390_vm_cpu_feat prop = {};
232167043607SCho, Yu-Chen     struct kvm_device_attr attr = {
232267043607SCho, Yu-Chen         .group = KVM_S390_VM_CPU_MODEL,
232367043607SCho, Yu-Chen         .attr = KVM_S390_VM_CPU_MACHINE_FEAT,
232467043607SCho, Yu-Chen         .addr = (uint64_t) &prop,
232567043607SCho, Yu-Chen     };
232667043607SCho, Yu-Chen     int rc;
232767043607SCho, Yu-Chen     int i;
232867043607SCho, Yu-Chen 
232967043607SCho, Yu-Chen     rc = kvm_vm_ioctl(kvm_state, KVM_GET_DEVICE_ATTR, &attr);
233067043607SCho, Yu-Chen     if (rc) {
233167043607SCho, Yu-Chen         return  rc;
233267043607SCho, Yu-Chen     }
233367043607SCho, Yu-Chen 
233467043607SCho, Yu-Chen     for (i = 0; i < ARRAY_SIZE(kvm_to_feat); i++) {
233567043607SCho, Yu-Chen         if (test_be_bit(kvm_to_feat[i][0], (uint8_t *) prop.feat)) {
233667043607SCho, Yu-Chen             set_bit(kvm_to_feat[i][1], features);
233767043607SCho, Yu-Chen         }
233867043607SCho, Yu-Chen     }
233967043607SCho, Yu-Chen     return 0;
234067043607SCho, Yu-Chen }
234167043607SCho, Yu-Chen 
configure_cpu_feat(const S390FeatBitmap features)234267043607SCho, Yu-Chen static int configure_cpu_feat(const S390FeatBitmap features)
234367043607SCho, Yu-Chen {
234467043607SCho, Yu-Chen     struct kvm_s390_vm_cpu_feat prop = {};
234567043607SCho, Yu-Chen     struct kvm_device_attr attr = {
234667043607SCho, Yu-Chen         .group = KVM_S390_VM_CPU_MODEL,
234767043607SCho, Yu-Chen         .attr = KVM_S390_VM_CPU_PROCESSOR_FEAT,
234867043607SCho, Yu-Chen         .addr = (uint64_t) &prop,
234967043607SCho, Yu-Chen     };
235067043607SCho, Yu-Chen     int i;
235167043607SCho, Yu-Chen 
235267043607SCho, Yu-Chen     for (i = 0; i < ARRAY_SIZE(kvm_to_feat); i++) {
235367043607SCho, Yu-Chen         if (test_bit(kvm_to_feat[i][1], features)) {
235467043607SCho, Yu-Chen             set_be_bit(kvm_to_feat[i][0], (uint8_t *) prop.feat);
235567043607SCho, Yu-Chen         }
235667043607SCho, Yu-Chen     }
235767043607SCho, Yu-Chen     return kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr);
235867043607SCho, Yu-Chen }
235967043607SCho, Yu-Chen 
kvm_s390_cpu_models_supported(void)236067043607SCho, Yu-Chen bool kvm_s390_cpu_models_supported(void)
236167043607SCho, Yu-Chen {
236267043607SCho, Yu-Chen     if (!cpu_model_allowed()) {
236367043607SCho, Yu-Chen         /* compatibility machines interfere with the cpu model */
236467043607SCho, Yu-Chen         return false;
236567043607SCho, Yu-Chen     }
236667043607SCho, Yu-Chen     return kvm_vm_check_attr(kvm_state, KVM_S390_VM_CPU_MODEL,
236767043607SCho, Yu-Chen                              KVM_S390_VM_CPU_MACHINE) &&
236867043607SCho, Yu-Chen            kvm_vm_check_attr(kvm_state, KVM_S390_VM_CPU_MODEL,
236967043607SCho, Yu-Chen                              KVM_S390_VM_CPU_PROCESSOR) &&
237067043607SCho, Yu-Chen            kvm_vm_check_attr(kvm_state, KVM_S390_VM_CPU_MODEL,
237167043607SCho, Yu-Chen                              KVM_S390_VM_CPU_MACHINE_FEAT) &&
237267043607SCho, Yu-Chen            kvm_vm_check_attr(kvm_state, KVM_S390_VM_CPU_MODEL,
237367043607SCho, Yu-Chen                              KVM_S390_VM_CPU_PROCESSOR_FEAT) &&
237467043607SCho, Yu-Chen            kvm_vm_check_attr(kvm_state, KVM_S390_VM_CPU_MODEL,
237567043607SCho, Yu-Chen                              KVM_S390_VM_CPU_MACHINE_SUBFUNC);
237667043607SCho, Yu-Chen }
237767043607SCho, Yu-Chen 
kvm_s390_get_host_cpu_model(S390CPUModel * model,Error ** errp)237847ab3b21SZhao Liu bool kvm_s390_get_host_cpu_model(S390CPUModel *model, Error **errp)
237967043607SCho, Yu-Chen {
238067043607SCho, Yu-Chen     struct kvm_s390_vm_cpu_machine prop = {};
238167043607SCho, Yu-Chen     struct kvm_device_attr attr = {
238267043607SCho, Yu-Chen         .group = KVM_S390_VM_CPU_MODEL,
238367043607SCho, Yu-Chen         .attr = KVM_S390_VM_CPU_MACHINE,
238467043607SCho, Yu-Chen         .addr = (uint64_t) &prop,
238567043607SCho, Yu-Chen     };
238667043607SCho, Yu-Chen     uint16_t unblocked_ibc = 0, cpu_type = 0;
238767043607SCho, Yu-Chen     int rc;
238867043607SCho, Yu-Chen 
238967043607SCho, Yu-Chen     memset(model, 0, sizeof(*model));
239067043607SCho, Yu-Chen 
239167043607SCho, Yu-Chen     if (!kvm_s390_cpu_models_supported()) {
239267043607SCho, Yu-Chen         error_setg(errp, "KVM doesn't support CPU models");
239347ab3b21SZhao Liu         return false;
239467043607SCho, Yu-Chen     }
239567043607SCho, Yu-Chen 
239667043607SCho, Yu-Chen     /* query the basic cpu model properties */
239767043607SCho, Yu-Chen     rc = kvm_vm_ioctl(kvm_state, KVM_GET_DEVICE_ATTR, &attr);
239867043607SCho, Yu-Chen     if (rc) {
239967043607SCho, Yu-Chen         error_setg(errp, "KVM: Error querying host CPU model: %d", rc);
240047ab3b21SZhao Liu         return false;
240167043607SCho, Yu-Chen     }
240267043607SCho, Yu-Chen 
240367043607SCho, Yu-Chen     cpu_type = cpuid_type(prop.cpuid);
240467043607SCho, Yu-Chen     if (has_ibc(prop.ibc)) {
240567043607SCho, Yu-Chen         model->lowest_ibc = lowest_ibc(prop.ibc);
240667043607SCho, Yu-Chen         unblocked_ibc = unblocked_ibc(prop.ibc);
240767043607SCho, Yu-Chen     }
240867043607SCho, Yu-Chen     model->cpu_id = cpuid_id(prop.cpuid);
240967043607SCho, Yu-Chen     model->cpu_id_format = cpuid_format(prop.cpuid);
241067043607SCho, Yu-Chen     model->cpu_ver = 0xff;
241167043607SCho, Yu-Chen 
241267043607SCho, Yu-Chen     /* get supported cpu features indicated via STFL(E) */
241367043607SCho, Yu-Chen     s390_add_from_feat_block(model->features, S390_FEAT_TYPE_STFL,
241467043607SCho, Yu-Chen                              (uint8_t *) prop.fac_mask);
241567043607SCho, Yu-Chen     /* dat-enhancement facility 2 has no bit but was introduced with stfle */
241667043607SCho, Yu-Chen     if (test_bit(S390_FEAT_STFLE, model->features)) {
241767043607SCho, Yu-Chen         set_bit(S390_FEAT_DAT_ENH_2, model->features);
241867043607SCho, Yu-Chen     }
241967043607SCho, Yu-Chen     /* get supported cpu features indicated e.g. via SCLP */
242067043607SCho, Yu-Chen     rc = query_cpu_feat(model->features);
242167043607SCho, Yu-Chen     if (rc) {
242267043607SCho, Yu-Chen         error_setg(errp, "KVM: Error querying CPU features: %d", rc);
242347ab3b21SZhao Liu         return false;
242467043607SCho, Yu-Chen     }
242567043607SCho, Yu-Chen     /* get supported cpu subfunctions indicated via query / test bit */
242667043607SCho, Yu-Chen     rc = query_cpu_subfunc(model->features);
242767043607SCho, Yu-Chen     if (rc) {
242867043607SCho, Yu-Chen         error_setg(errp, "KVM: Error querying CPU subfunctions: %d", rc);
242947ab3b21SZhao Liu         return false;
243067043607SCho, Yu-Chen     }
243167043607SCho, Yu-Chen 
243267043607SCho, Yu-Chen     /* PTFF subfunctions might be indicated although kernel support missing */
243367043607SCho, Yu-Chen     if (!test_bit(S390_FEAT_MULTIPLE_EPOCH, model->features)) {
243467043607SCho, Yu-Chen         clear_bit(S390_FEAT_PTFF_QSIE, model->features);
243567043607SCho, Yu-Chen         clear_bit(S390_FEAT_PTFF_QTOUE, model->features);
243667043607SCho, Yu-Chen         clear_bit(S390_FEAT_PTFF_STOE, model->features);
243767043607SCho, Yu-Chen         clear_bit(S390_FEAT_PTFF_STOUE, model->features);
243867043607SCho, Yu-Chen     }
243967043607SCho, Yu-Chen 
244067043607SCho, Yu-Chen     /* with cpu model support, CMM is only indicated if really available */
244167043607SCho, Yu-Chen     if (kvm_s390_cmma_available()) {
244267043607SCho, Yu-Chen         set_bit(S390_FEAT_CMM, model->features);
244367043607SCho, Yu-Chen     } else {
244467043607SCho, Yu-Chen         /* no cmm -> no cmm nt */
244567043607SCho, Yu-Chen         clear_bit(S390_FEAT_CMM_NT, model->features);
244667043607SCho, Yu-Chen     }
244767043607SCho, Yu-Chen 
244867043607SCho, Yu-Chen     /* bpb needs kernel support for migration, VSIE and reset */
244967043607SCho, Yu-Chen     if (!kvm_check_extension(kvm_state, KVM_CAP_S390_BPB)) {
245067043607SCho, Yu-Chen         clear_bit(S390_FEAT_BPB, model->features);
245167043607SCho, Yu-Chen     }
245267043607SCho, Yu-Chen 
245367043607SCho, Yu-Chen     /*
245467043607SCho, Yu-Chen      * If we have support for protected virtualization, indicate
245567043607SCho, Yu-Chen      * the protected virtualization IPL unpack facility.
245667043607SCho, Yu-Chen      */
245767043607SCho, Yu-Chen     if (cap_protected) {
245867043607SCho, Yu-Chen         set_bit(S390_FEAT_UNPACK, model->features);
245967043607SCho, Yu-Chen     }
246067043607SCho, Yu-Chen 
2461f530b9e7SPierre Morel     /*
2462f530b9e7SPierre Morel      * If we have kernel support for CPU Topology indicate the
2463f530b9e7SPierre Morel      * configuration-topology facility.
2464f530b9e7SPierre Morel      */
2465f530b9e7SPierre Morel     if (kvm_check_extension(kvm_state, KVM_CAP_S390_CPU_TOPOLOGY)) {
2466f530b9e7SPierre Morel         set_bit(S390_FEAT_CONFIGURATION_TOPOLOGY, model->features);
2467f530b9e7SPierre Morel     }
2468f530b9e7SPierre Morel 
246967043607SCho, Yu-Chen     /* We emulate a zPCI bus and AEN, therefore we don't need HW support */
247067043607SCho, Yu-Chen     set_bit(S390_FEAT_ZPCI, model->features);
247167043607SCho, Yu-Chen     set_bit(S390_FEAT_ADAPTER_EVENT_NOTIFICATION, model->features);
247267043607SCho, Yu-Chen 
247367043607SCho, Yu-Chen     if (s390_known_cpu_type(cpu_type)) {
247467043607SCho, Yu-Chen         /* we want the exact model, even if some features are missing */
247567043607SCho, Yu-Chen         model->def = s390_find_cpu_def(cpu_type, ibc_gen(unblocked_ibc),
247667043607SCho, Yu-Chen                                        ibc_ec_ga(unblocked_ibc), NULL);
247767043607SCho, Yu-Chen     } else {
247867043607SCho, Yu-Chen         /* model unknown, e.g. too new - search using features */
247967043607SCho, Yu-Chen         model->def = s390_find_cpu_def(0, ibc_gen(unblocked_ibc),
248067043607SCho, Yu-Chen                                        ibc_ec_ga(unblocked_ibc),
248167043607SCho, Yu-Chen                                        model->features);
248267043607SCho, Yu-Chen     }
248367043607SCho, Yu-Chen     if (!model->def) {
248467043607SCho, Yu-Chen         error_setg(errp, "KVM: host CPU model could not be identified");
248547ab3b21SZhao Liu         return false;
248667043607SCho, Yu-Chen     }
248767043607SCho, Yu-Chen     /* for now, we can only provide the AP feature with HW support */
2488354383c1SSteffen Eiden     if (ap_available()) {
248967043607SCho, Yu-Chen         set_bit(S390_FEAT_AP, model->features);
249067043607SCho, Yu-Chen     }
249167043607SCho, Yu-Chen 
249267043607SCho, Yu-Chen     /*
249367043607SCho, Yu-Chen      * Extended-Length SCCB is handled entirely within QEMU.
249467043607SCho, Yu-Chen      * For PV guests this is completely fenced by the Ultravisor, as Service
249567043607SCho, Yu-Chen      * Call error checking and STFLE interpretation are handled via SIE.
249667043607SCho, Yu-Chen      */
249767043607SCho, Yu-Chen     set_bit(S390_FEAT_EXTENDED_LENGTH_SCCB, model->features);
249867043607SCho, Yu-Chen 
249967043607SCho, Yu-Chen     if (kvm_check_extension(kvm_state, KVM_CAP_S390_DIAG318)) {
250067043607SCho, Yu-Chen         set_bit(S390_FEAT_DIAG_318, model->features);
250167043607SCho, Yu-Chen     }
250267043607SCho, Yu-Chen 
25035ac95151SSteffen Eiden     /* Test for Ultravisor features that influence secure guest behavior */
25045ac95151SSteffen Eiden     query_uv_feat_guest(model->features);
25055ac95151SSteffen Eiden 
250667043607SCho, Yu-Chen     /* strip of features that are not part of the maximum model */
250767043607SCho, Yu-Chen     bitmap_and(model->features, model->features, model->def->full_feat,
250867043607SCho, Yu-Chen                S390_FEAT_MAX);
250947ab3b21SZhao Liu     return true;
251067043607SCho, Yu-Chen }
251167043607SCho, Yu-Chen 
configure_uv_feat_guest(const S390FeatBitmap features)25125ac95151SSteffen Eiden static int configure_uv_feat_guest(const S390FeatBitmap features)
25135ac95151SSteffen Eiden {
25145ac95151SSteffen Eiden     struct kvm_s390_vm_cpu_uv_feat uv_feat = {};
25155ac95151SSteffen Eiden     struct kvm_device_attr attribute = {
25165ac95151SSteffen Eiden         .group = KVM_S390_VM_CPU_MODEL,
25175ac95151SSteffen Eiden         .attr = KVM_S390_VM_CPU_PROCESSOR_UV_FEAT_GUEST,
25185ac95151SSteffen Eiden         .addr = (__u64) &uv_feat,
25195ac95151SSteffen Eiden     };
25205ac95151SSteffen Eiden 
25215ac95151SSteffen Eiden     /* AP support check is currently the only user of the UV feature test */
25225ac95151SSteffen Eiden     if (!(uv_feat_supported() && ap_enabled(features))) {
25235ac95151SSteffen Eiden         return 0;
25245ac95151SSteffen Eiden     }
25255ac95151SSteffen Eiden 
25265ac95151SSteffen Eiden     if (test_bit(S390_FEAT_UV_FEAT_AP, features)) {
25275ac95151SSteffen Eiden         uv_feat.ap = 1;
25285ac95151SSteffen Eiden     }
25295ac95151SSteffen Eiden     if (test_bit(S390_FEAT_UV_FEAT_AP_INTR, features)) {
25305ac95151SSteffen Eiden         uv_feat.ap_intr = 1;
25315ac95151SSteffen Eiden     }
25325ac95151SSteffen Eiden 
25335ac95151SSteffen Eiden     return kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attribute);
25345ac95151SSteffen Eiden }
25355ac95151SSteffen Eiden 
kvm_s390_configure_apie(bool interpret)253667043607SCho, Yu-Chen static void kvm_s390_configure_apie(bool interpret)
253767043607SCho, Yu-Chen {
253867043607SCho, Yu-Chen     uint64_t attr = interpret ? KVM_S390_VM_CRYPTO_ENABLE_APIE :
253967043607SCho, Yu-Chen                                 KVM_S390_VM_CRYPTO_DISABLE_APIE;
254067043607SCho, Yu-Chen 
254167043607SCho, Yu-Chen     if (kvm_vm_check_attr(kvm_state, KVM_S390_VM_CRYPTO, attr)) {
2542354383c1SSteffen Eiden         kvm_s390_set_crypto_attr(attr);
254367043607SCho, Yu-Chen     }
254467043607SCho, Yu-Chen }
254567043607SCho, Yu-Chen 
kvm_s390_apply_cpu_model(const S390CPUModel * model,Error ** errp)254638098df3SZhao Liu bool kvm_s390_apply_cpu_model(const S390CPUModel *model, Error **errp)
254767043607SCho, Yu-Chen {
254867043607SCho, Yu-Chen     struct kvm_s390_vm_cpu_processor prop  = {
254967043607SCho, Yu-Chen         .fac_list = { 0 },
255067043607SCho, Yu-Chen     };
255167043607SCho, Yu-Chen     struct kvm_device_attr attr = {
255267043607SCho, Yu-Chen         .group = KVM_S390_VM_CPU_MODEL,
255367043607SCho, Yu-Chen         .attr = KVM_S390_VM_CPU_PROCESSOR,
255467043607SCho, Yu-Chen         .addr = (uint64_t) &prop,
255567043607SCho, Yu-Chen     };
255667043607SCho, Yu-Chen     int rc;
255767043607SCho, Yu-Chen 
255867043607SCho, Yu-Chen     if (!model) {
255967043607SCho, Yu-Chen         /* compatibility handling if cpu models are disabled */
256067043607SCho, Yu-Chen         if (kvm_s390_cmma_available()) {
256167043607SCho, Yu-Chen             kvm_s390_enable_cmma();
256267043607SCho, Yu-Chen         }
256338098df3SZhao Liu         return true;
256467043607SCho, Yu-Chen     }
256567043607SCho, Yu-Chen     if (!kvm_s390_cpu_models_supported()) {
256667043607SCho, Yu-Chen         error_setg(errp, "KVM doesn't support CPU models");
256738098df3SZhao Liu         return false;
256867043607SCho, Yu-Chen     }
256967043607SCho, Yu-Chen     prop.cpuid = s390_cpuid_from_cpu_model(model);
257067043607SCho, Yu-Chen     prop.ibc = s390_ibc_from_cpu_model(model);
257167043607SCho, Yu-Chen     /* configure cpu features indicated via STFL(e) */
257267043607SCho, Yu-Chen     s390_fill_feat_block(model->features, S390_FEAT_TYPE_STFL,
257367043607SCho, Yu-Chen                          (uint8_t *) prop.fac_list);
257467043607SCho, Yu-Chen     rc = kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr);
257567043607SCho, Yu-Chen     if (rc) {
257667043607SCho, Yu-Chen         error_setg(errp, "KVM: Error configuring the CPU model: %d", rc);
257738098df3SZhao Liu         return false;
257867043607SCho, Yu-Chen     }
257967043607SCho, Yu-Chen     /* configure cpu features indicated e.g. via SCLP */
258067043607SCho, Yu-Chen     rc = configure_cpu_feat(model->features);
258167043607SCho, Yu-Chen     if (rc) {
258267043607SCho, Yu-Chen         error_setg(errp, "KVM: Error configuring CPU features: %d", rc);
258338098df3SZhao Liu         return false;
258467043607SCho, Yu-Chen     }
258567043607SCho, Yu-Chen     /* configure cpu subfunctions indicated via query / test bit */
258667043607SCho, Yu-Chen     rc = configure_cpu_subfunc(model->features);
258767043607SCho, Yu-Chen     if (rc) {
258867043607SCho, Yu-Chen         error_setg(errp, "KVM: Error configuring CPU subfunctions: %d", rc);
258938098df3SZhao Liu         return false;
259067043607SCho, Yu-Chen     }
259167043607SCho, Yu-Chen     /* enable CMM via CMMA */
259267043607SCho, Yu-Chen     if (test_bit(S390_FEAT_CMM, model->features)) {
259367043607SCho, Yu-Chen         kvm_s390_enable_cmma();
259467043607SCho, Yu-Chen     }
259567043607SCho, Yu-Chen 
2596354383c1SSteffen Eiden     if (ap_enabled(model->features)) {
259767043607SCho, Yu-Chen         kvm_s390_configure_apie(true);
259867043607SCho, Yu-Chen     }
25995ac95151SSteffen Eiden 
26005ac95151SSteffen Eiden     /* configure UV-features for the guest indicated via query / test_bit */
26015ac95151SSteffen Eiden     rc = configure_uv_feat_guest(model->features);
26025ac95151SSteffen Eiden     if (rc) {
26035ac95151SSteffen Eiden         error_setg(errp, "KVM: Error configuring CPU UV features %d", rc);
260438098df3SZhao Liu         return false;
26055ac95151SSteffen Eiden     }
260638098df3SZhao Liu     return true;
260767043607SCho, Yu-Chen }
260867043607SCho, Yu-Chen 
kvm_s390_restart_interrupt(S390CPU * cpu)260967043607SCho, Yu-Chen void kvm_s390_restart_interrupt(S390CPU *cpu)
261067043607SCho, Yu-Chen {
261167043607SCho, Yu-Chen     struct kvm_s390_irq irq = {
261267043607SCho, Yu-Chen         .type = KVM_S390_RESTART,
261367043607SCho, Yu-Chen     };
261467043607SCho, Yu-Chen 
261567043607SCho, Yu-Chen     kvm_s390_vcpu_interrupt(cpu, &irq);
261667043607SCho, Yu-Chen }
261767043607SCho, Yu-Chen 
kvm_s390_stop_interrupt(S390CPU * cpu)261867043607SCho, Yu-Chen void kvm_s390_stop_interrupt(S390CPU *cpu)
261967043607SCho, Yu-Chen {
262067043607SCho, Yu-Chen     struct kvm_s390_irq irq = {
262167043607SCho, Yu-Chen         .type = KVM_S390_SIGP_STOP,
262267043607SCho, Yu-Chen     };
262367043607SCho, Yu-Chen 
262467043607SCho, Yu-Chen     kvm_s390_vcpu_interrupt(cpu, &irq);
262567043607SCho, Yu-Chen }
262667043607SCho, Yu-Chen 
kvm_s390_get_zpci_op(void)2627dd1d5fd9SMatthew Rosato int kvm_s390_get_zpci_op(void)
2628dd1d5fd9SMatthew Rosato {
2629dd1d5fd9SMatthew Rosato     return cap_zpci_op;
2630dd1d5fd9SMatthew Rosato }
26313dba0a33SPaolo Bonzini 
kvm_s390_topology_set_mtcr(uint64_t attr)26323d6e75f4SPierre Morel int kvm_s390_topology_set_mtcr(uint64_t attr)
26333d6e75f4SPierre Morel {
26343d6e75f4SPierre Morel     struct kvm_device_attr attribute = {
26353d6e75f4SPierre Morel         .group = KVM_S390_VM_CPU_TOPOLOGY,
26363d6e75f4SPierre Morel         .attr  = attr,
26373d6e75f4SPierre Morel     };
26383d6e75f4SPierre Morel 
26393d6e75f4SPierre Morel     if (!s390_has_feat(S390_FEAT_CONFIGURATION_TOPOLOGY)) {
26403d6e75f4SPierre Morel         return 0;
26413d6e75f4SPierre Morel     }
26423d6e75f4SPierre Morel     if (!kvm_vm_check_attr(kvm_state, KVM_S390_VM_CPU_TOPOLOGY, attr)) {
26433d6e75f4SPierre Morel         return -ENOTSUP;
26443d6e75f4SPierre Morel     }
26453d6e75f4SPierre Morel 
26463d6e75f4SPierre Morel     return kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attribute);
26473d6e75f4SPierre Morel }
26483d6e75f4SPierre Morel 
kvm_arch_accel_class_init(ObjectClass * oc)26493dba0a33SPaolo Bonzini void kvm_arch_accel_class_init(ObjectClass *oc)
26503dba0a33SPaolo Bonzini {
26513dba0a33SPaolo Bonzini }
2652