From 5b08b344bf581a266071389ceeb445e943e01ba1 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Mon, 29 Oct 2012 02:13:21 +0000 Subject: s390: use sync regs for register transfer Newer kernels provide the guest registers in kvm_run. Lets use those if available (i.e. the capability is set). This avoids ioctls on cpu_synchronize_state making intercepts faster. In addition, we have now the prefix register, the access registers the control registers up to date. This helps in certain cases, e.g. for resolving kernel module addresses with gdb on a guest. On return, we update the registers according to the level statement, i.e. we put all registers for KVM_PUT_FULL_STATE and _RESET_STATE. Signed-off-by: Christian Borntraeger Signed-off-by: Jens Freimann Signed-off-by: Alexander Graf --- target-s390x/kvm.c | 112 +++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 92 insertions(+), 20 deletions(-) (limited to 'target-s390x/kvm.c') diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index 07edf93690..e19a44d637 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -67,8 +67,11 @@ const KVMCapabilityInfo kvm_arch_required_capabilities[] = { KVM_CAP_LAST_INFO }; +static int cap_sync_regs; + int kvm_arch_init(KVMState *s) { + cap_sync_regs = kvm_check_extension(s, KVM_CAP_SYNC_REGS); return 0; } @@ -90,47 +93,116 @@ void kvm_arch_reset_vcpu(CPUS390XState *env) int kvm_arch_put_registers(CPUS390XState *env, int level) { + struct kvm_sregs sregs; struct kvm_regs regs; int ret; int i; - ret = kvm_vcpu_ioctl(env, KVM_GET_REGS, ®s); - if (ret < 0) { - return ret; - } + /* always save the PSW and the GPRS*/ + env->kvm_run->psw_addr = env->psw.addr; + env->kvm_run->psw_mask = env->psw.mask; - for (i = 0; i < 16; i++) { - regs.gprs[i] = env->regs[i]; + if (cap_sync_regs && env->kvm_run->kvm_valid_regs & KVM_SYNC_GPRS) { + for (i = 0; i < 16; i++) { + env->kvm_run->s.regs.gprs[i] = env->regs[i]; + env->kvm_run->kvm_dirty_regs |= KVM_SYNC_GPRS; + } + } else { + for (i = 0; i < 16; i++) { + regs.gprs[i] = env->regs[i]; + } + ret = kvm_vcpu_ioctl(env, KVM_SET_REGS, ®s); + if (ret < 0) { + return ret; + } } - ret = kvm_vcpu_ioctl(env, KVM_SET_REGS, ®s); - if (ret < 0) { - return ret; + /* Do we need to save more than that? */ + if (level == KVM_PUT_RUNTIME_STATE) { + return 0; } - env->kvm_run->psw_addr = env->psw.addr; - env->kvm_run->psw_mask = env->psw.mask; + if (cap_sync_regs && + env->kvm_run->kvm_valid_regs & KVM_SYNC_ACRS && + env->kvm_run->kvm_valid_regs & KVM_SYNC_CRS) { + for (i = 0; i < 16; i++) { + env->kvm_run->s.regs.acrs[i] = env->aregs[i]; + env->kvm_run->s.regs.crs[i] = env->cregs[i]; + } + env->kvm_run->kvm_dirty_regs |= KVM_SYNC_ACRS; + env->kvm_run->kvm_dirty_regs |= KVM_SYNC_CRS; + } else { + for (i = 0; i < 16; i++) { + sregs.acrs[i] = env->aregs[i]; + sregs.crs[i] = env->cregs[i]; + } + ret = kvm_vcpu_ioctl(env, KVM_SET_SREGS, &sregs); + if (ret < 0) { + return ret; + } + } - return ret; + /* Finally the prefix */ + if (cap_sync_regs && env->kvm_run->kvm_valid_regs & KVM_SYNC_PREFIX) { + env->kvm_run->s.regs.prefix = env->psa; + env->kvm_run->kvm_dirty_regs |= KVM_SYNC_PREFIX; + } else { + /* prefix is only supported via sync regs */ + } + return 0; } int kvm_arch_get_registers(CPUS390XState *env) { - int ret; + struct kvm_sregs sregs; struct kvm_regs regs; + int ret; int i; - ret = kvm_vcpu_ioctl(env, KVM_GET_REGS, ®s); - if (ret < 0) { - return ret; + /* get the PSW */ + env->psw.addr = env->kvm_run->psw_addr; + env->psw.mask = env->kvm_run->psw_mask; + + /* the GPRS */ + if (cap_sync_regs && env->kvm_run->kvm_valid_regs & KVM_SYNC_GPRS) { + for (i = 0; i < 16; i++) { + env->regs[i] = env->kvm_run->s.regs.gprs[i]; + } + } else { + ret = kvm_vcpu_ioctl(env, KVM_GET_REGS, ®s); + if (ret < 0) { + return ret; + } + for (i = 0; i < 16; i++) { + env->regs[i] = regs.gprs[i]; + } } - for (i = 0; i < 16; i++) { - env->regs[i] = regs.gprs[i]; + /* The ACRS and CRS */ + if (cap_sync_regs && + env->kvm_run->kvm_valid_regs & KVM_SYNC_ACRS && + env->kvm_run->kvm_valid_regs & KVM_SYNC_CRS) { + for (i = 0; i < 16; i++) { + env->aregs[i] = env->kvm_run->s.regs.acrs[i]; + env->cregs[i] = env->kvm_run->s.regs.crs[i]; + } + } else { + ret = kvm_vcpu_ioctl(env, KVM_GET_SREGS, &sregs); + if (ret < 0) { + return ret; + } + for (i = 0; i < 16; i++) { + env->aregs[i] = sregs.acrs[i]; + env->cregs[i] = sregs.crs[i]; + } } - env->psw.addr = env->kvm_run->psw_addr; - env->psw.mask = env->kvm_run->psw_mask; + /* Finally the prefix */ + if (cap_sync_regs && env->kvm_run->kvm_valid_regs & KVM_SYNC_PREFIX) { + env->psa = env->kvm_run->s.regs.prefix; + } else { + /* no prefix without sync regs */ + } return 0; } -- cgit 1.4.1 From f6c98f9286c69cafe108b7e9fb22c2ff5da7d6a9 Mon Sep 17 00:00:00 2001 From: Heinz Graalfs Date: Mon, 29 Oct 2012 02:13:22 +0000 Subject: s390: sclp base support This adds a more generic infrastructure for handling Service-Call requests on s390. Currently we only support a small subset of Read SCP Info directly in target-s390x. This patch provides the base infrastructure for supporting more commands and moves Read SCP Info. In the future we could add additional commands for hotplug, call home and event handling. Signed-off-by: Heinz Graalfs Signed-off-by: Christian Borntraeger Signed-off-by: Jens Freimann Signed-off-by: Alexander Graf --- hw/s390x/Makefile.objs | 1 + hw/s390x/sclp.c | 118 +++++++++++++++++++++++++++++++++++++++++++++ hw/s390x/sclp.h | 76 +++++++++++++++++++++++++++++ target-s390x/cpu.h | 13 +---- target-s390x/kvm.c | 5 +- target-s390x/misc_helper.c | 45 +---------------- 6 files changed, 198 insertions(+), 60 deletions(-) create mode 100644 hw/s390x/sclp.c create mode 100644 hw/s390x/sclp.h (limited to 'target-s390x/kvm.c') diff --git a/hw/s390x/Makefile.objs b/hw/s390x/Makefile.objs index dcdcac8a81..1c14b96687 100644 --- a/hw/s390x/Makefile.objs +++ b/hw/s390x/Makefile.objs @@ -1,3 +1,4 @@ obj-y = s390-virtio-bus.o s390-virtio.o obj-y := $(addprefix ../,$(obj-y)) +obj-y += sclp.o diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c new file mode 100644 index 0000000000..d902a66261 --- /dev/null +++ b/hw/s390x/sclp.c @@ -0,0 +1,118 @@ +/* + * SCLP Support + * + * Copyright IBM, Corp. 2012 + * + * Authors: + * Christian Borntraeger + * Heinz Graalfs + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at your + * option) any later version. See the COPYING file in the top-level directory. + * + */ + +#include "cpu.h" +#include "kvm.h" +#include "memory.h" + +#include "sclp.h" + +/* Provide information about the configuration, CPUs and storage */ +static void read_SCP_info(SCCB *sccb) +{ + ReadInfo *read_info = (ReadInfo *) sccb; + int shift = 0; + + while ((ram_size >> (20 + shift)) > 65535) { + shift++; + } + read_info->rnmax = cpu_to_be16(ram_size >> (20 + shift)); + read_info->rnsize = 1 << shift; + sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION); +} + +static void sclp_execute(SCCB *sccb, uint64_t code) +{ + switch (code) { + case SCLP_CMDW_READ_SCP_INFO: + case SCLP_CMDW_READ_SCP_INFO_FORCED: + read_SCP_info(sccb); + break; + default: + sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND); + break; + } +} + +int sclp_service_call(uint32_t sccb, uint64_t code) +{ + int r = 0; + SCCB work_sccb; + + hwaddr sccb_len = sizeof(SCCB); + + /* first some basic checks on program checks */ + if (cpu_physical_memory_is_io(sccb)) { + r = -PGM_ADDRESSING; + goto out; + } + if (sccb & ~0x7ffffff8ul) { + r = -PGM_SPECIFICATION; + goto out; + } + + /* + * we want to work on a private copy of the sccb, to prevent guests + * from playing dirty tricks by modifying the memory content after + * the host has checked the values + */ + cpu_physical_memory_read(sccb, &work_sccb, sccb_len); + + /* Valid sccb sizes */ + if (be16_to_cpu(work_sccb.h.length) < sizeof(SCCBHeader) || + be16_to_cpu(work_sccb.h.length) > SCCB_SIZE) { + r = -PGM_SPECIFICATION; + goto out; + } + + sclp_execute((SCCB *)&work_sccb, code); + + cpu_physical_memory_write(sccb, &work_sccb, + be16_to_cpu(work_sccb.h.length)); + + sclp_service_interrupt(sccb); + +out: + return r; +} + +void sclp_service_interrupt(uint32_t sccb) +{ + s390_sclp_extint(sccb & ~3); +} + +/* qemu object creation and initialization functions */ + +static void s390_sclp_device_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *dc = SYS_BUS_DEVICE_CLASS(klass); + + dc->init = s390_sclp_dev_init; +} + +static TypeInfo s390_sclp_device_info = { + .name = TYPE_DEVICE_S390_SCLP, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(S390SCLPDevice), + .class_init = s390_sclp_device_class_init, + .class_size = sizeof(S390SCLPDeviceClass), + .abstract = true, +}; + +static void s390_sclp_register_types(void) +{ + type_register_static(&s390_sclp_device_info); +} + +type_init(s390_sclp_register_types) diff --git a/hw/s390x/sclp.h b/hw/s390x/sclp.h new file mode 100644 index 0000000000..e9ad42bec2 --- /dev/null +++ b/hw/s390x/sclp.h @@ -0,0 +1,76 @@ +/* + * SCLP Support + * + * Copyright IBM, Corp. 2012 + * + * Authors: + * Christian Borntraeger + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at your + * option) any later version. See the COPYING file in the top-level directory. + * + */ + +#ifndef HW_S390_SCLP_H +#define HW_S390_SCLP_H + +#include +#include + +/* SCLP command codes */ +#define SCLP_CMDW_READ_SCP_INFO 0x00020001 +#define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001 + +/* SCLP response codes */ +#define SCLP_RC_NORMAL_READ_COMPLETION 0x0010 +#define SCLP_RC_INVALID_SCLP_COMMAND 0x01f0 + +/* Service Call Control Block (SCCB) and its elements */ + +#define SCCB_SIZE 4096 + +/* + * Normally packed structures are not the right thing to do, since all code + * must take care of endianess. We cant use ldl_phys and friends for two + * reasons, though: + * - some of the embedded structures below the SCCB can appear multiple times + * at different locations, so there is no fixed offset + * - we work on a private copy of the SCCB, since there are several length + * fields, that would cause a security nightmare if we allow the guest to + * alter the structure while we parse it. We cannot use ldl_p and friends + * either without doing pointer arithmetics + * So we have to double check that all users of sclp data structures use the + * right endianess wrappers. + */ +typedef struct SCCBHeader { + uint16_t length; + uint8_t function_code; + uint8_t control_mask[3]; + uint16_t response_code; +} QEMU_PACKED SCCBHeader; + +#define SCCB_DATA_LEN (SCCB_SIZE - sizeof(SCCBHeader)) + +typedef struct ReadInfo { + SCCBHeader h; + uint16_t rnmax; + uint8_t rnsize; +} QEMU_PACKED ReadInfo; + +typedef struct SCCB { + SCCBHeader h; + char data[SCCB_DATA_LEN]; + } QEMU_PACKED SCCB; + +typedef struct S390SCLPDevice { + SysBusDevice busdev; +} S390SCLPDevice; + +typedef struct S390SCLPDeviceClass { + DeviceClass qdev; + int (*init)(S390SCLPDevice *sdev); +} S390SCLPDeviceClass; + +void sclp_service_interrupt(uint32_t sccb); + +#endif diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 9997765dd1..5be6e83528 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -596,17 +596,6 @@ static inline const char *cc_name(int cc_op) return cc_names[cc_op]; } -/* SCLP PV interface defines */ -#define SCLP_CMDW_READ_SCP_INFO 0x00020001 -#define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001 - -#define SCP_LENGTH 0x00 -#define SCP_FUNCTION_CODE 0x02 -#define SCP_CONTROL_MASK 0x03 -#define SCP_RESPONSE_CODE 0x06 -#define SCP_MEM_CODE 0x08 -#define SCP_INCREMENT 0x0a - typedef struct LowCore { /* prefix area: defined by architecture */ @@ -955,7 +944,7 @@ static inline void ebcdic_put(uint8_t *p, const char *ascii, int len) void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr); int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc, target_ulong *raddr, int *flags); -int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code); +int sclp_service_call(uint32_t sccb, uint64_t code); uint32_t calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst, uint64_t vr); diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index e19a44d637..a66ac4341c 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -60,9 +60,6 @@ #define SIGP_STORE_STATUS_ADDR 0x0e #define SIGP_SET_ARCH 0x12 -#define SCLP_CMDW_READ_SCP_INFO 0x00020001 -#define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001 - const KVMCapabilityInfo kvm_arch_required_capabilities[] = { KVM_CAP_LAST_INFO }; @@ -344,7 +341,7 @@ static int kvm_sclp_service_call(CPUS390XState *env, struct kvm_run *run, sccb = env->regs[ipbh0 & 0xf]; code = env->regs[(ipbh0 & 0xf0) >> 4]; - r = sclp_service_call(env, sccb, code); + r = sclp_service_call(sccb, code); if (r < 0) { enter_pgmcheck(env, -r); } diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index fdccd58e3d..38d8f2a627 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -67,55 +67,12 @@ void program_interrupt(CPUS390XState *env, uint32_t code, int ilc) } } -/* - * ret < 0 indicates program check, ret = 0, 1, 2, 3 -> cc - */ -int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code) -{ - int r = 0; - int shift = 0; - -#ifdef DEBUG_HELPER - printf("sclp(0x%x, 0x%" PRIx64 ")\n", sccb, code); -#endif - - /* basic checks */ - if (cpu_physical_memory_is_io(sccb)) { - return -PGM_ADDRESSING; - } - if (sccb & ~0x7ffffff8ul) { - return -PGM_SPECIFICATION; - } - - switch (code) { - case SCLP_CMDW_READ_SCP_INFO: - case SCLP_CMDW_READ_SCP_INFO_FORCED: - while ((ram_size >> (20 + shift)) > 65535) { - shift++; - } - stw_phys(sccb + SCP_MEM_CODE, ram_size >> (20 + shift)); - stb_phys(sccb + SCP_INCREMENT, 1 << shift); - stw_phys(sccb + SCP_RESPONSE_CODE, 0x10); - - s390_sclp_extint(sccb & ~3); - break; - default: -#ifdef DEBUG_HELPER - printf("KVM: invalid sclp call 0x%x / 0x%" PRIx64 "x\n", sccb, code); -#endif - r = 3; - break; - } - - return r; -} - /* SCLP service call */ uint32_t HELPER(servc)(CPUS390XState *env, uint32_t r1, uint64_t r2) { int r; - r = sclp_service_call(env, r1, r2); + r = sclp_service_call(r1, r2); if (r < 0) { program_interrupt(env, -r, 4); return 0; -- cgit 1.4.1