From 638129ff475dd3b4c0e57e0be598efe41461e9b3 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Tue, 17 Dec 2013 18:27:33 +0100 Subject: [PATCH 1/8] s390x/kvm: Fix diagnose handling. The instruction intercept handler for diagnose used only the displacement when trying to calculate the function code. This is only correct for base 0, however; we need to perform a complete base/displacement address calculation and use bits 48-63 as the function code. Reviewed-by: Thomas Huth Signed-off-by: Cornelia Huck Signed-off-by: Jens Freimann Signed-off-by: Alexander Graf --- target-s390x/cpu.h | 3 +++ target-s390x/kvm.c | 17 ++++++++++++----- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index a2c077bdcd..68b5ab7056 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -352,6 +352,9 @@ static inline hwaddr decode_basedisp_s(CPUS390XState *env, uint32_t ipb) return addr; } +/* Base/displacement are at the same locations. */ +#define decode_basedisp_rs decode_basedisp_s + void s390x_tod_timer(void *opaque); void s390x_cpu_timer(void *opaque); diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index 02ac4ba995..b00a6617a3 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -562,11 +562,19 @@ static void kvm_handle_diag_308(S390CPU *cpu, struct kvm_run *run) handle_diag_308(&cpu->env, r1, r3); } -static int handle_diag(S390CPU *cpu, struct kvm_run *run, int ipb_code) +#define DIAG_KVM_CODE_MASK 0x000000000000ffff + +static int handle_diag(S390CPU *cpu, struct kvm_run *run, uint32_t ipb) { int r = 0; + uint16_t func_code; - switch (ipb_code) { + /* + * For any diagnose call we support, bits 48-63 of the resulting + * address specify the function code; the remainder is ignored. + */ + func_code = decode_basedisp_rs(&cpu->env, ipb) & DIAG_KVM_CODE_MASK; + switch (func_code) { case DIAG_IPL: kvm_handle_diag_308(cpu, run); break; @@ -577,7 +585,7 @@ static int handle_diag(S390CPU *cpu, struct kvm_run *run, int ipb_code) sleep(10); break; default: - DPRINTF("KVM: unknown DIAG: 0x%x\n", ipb_code); + DPRINTF("KVM: unknown DIAG: 0x%x\n", func_code); r = -1; break; } @@ -684,7 +692,6 @@ static void handle_instruction(S390CPU *cpu, struct kvm_run *run) { unsigned int ipa0 = (run->s390_sieic.ipa & 0xff00); uint8_t ipa1 = run->s390_sieic.ipa & 0x00ff; - int ipb_code = (run->s390_sieic.ipb & 0x0fff0000) >> 16; int r = -1; DPRINTF("handle_instruction 0x%x 0x%x\n", @@ -696,7 +703,7 @@ static void handle_instruction(S390CPU *cpu, struct kvm_run *run) r = handle_priv(cpu, run, ipa0 >> 8, ipa1); break; case IPA0_DIAG: - r = handle_diag(cpu, run, ipb_code); + r = handle_diag(cpu, run, run->s390_sieic.ipb); break; case IPA0_SIGP: r = handle_sigp(cpu, run, ipa1); From 4f91e0b5d8b116c16964926a103e01623dbd81b6 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 17 Dec 2013 14:22:04 +0100 Subject: [PATCH 2/8] s390x/kvm: Removed duplicated SIGP defines The SIGP order defines are also available in cpu.h, so there is no need to re-define them in kvm.c. Signed-off-by: Thomas Huth Reviewed-by: Cornelia Huck Signed-off-by: Jens Freimann Signed-off-by: Alexander Graf --- target-s390x/kvm.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index b00a6617a3..52d93a7370 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -82,11 +82,6 @@ #define ICPT_CPU_STOP 0x28 #define ICPT_IO 0x40 -#define SIGP_RESTART 0x06 -#define SIGP_INITIAL_CPU_RESET 0x0b -#define SIGP_STORE_STATUS_ADDR 0x0e -#define SIGP_SET_ARCH 0x12 - const KVMCapabilityInfo kvm_arch_required_capabilities[] = { KVM_CAP_LAST_INFO }; From cd7a0f4cf905c421743357a55f107b86ee1ded9d Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 17 Dec 2013 14:22:05 +0100 Subject: [PATCH 3/8] s390x/kvm: Removed s390_store_status stub The SIGP order STORE STATUS AT ADDRESS will be handled in kernel space, so we do not need the stub in QEMU anymore. Signed-off-by: Thomas Huth Reviewed-by: Cornelia Huck Signed-off-by: Jens Freimann Signed-off-by: Alexander Graf --- target-s390x/kvm.c | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index 52d93a7370..5b243b4bea 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -597,13 +597,6 @@ int kvm_s390_cpu_restart(S390CPU *cpu) return 0; } -static int s390_store_status(CPUS390XState *env, uint32_t parameter) -{ - /* XXX */ - fprintf(stderr, "XXX SIGP store status\n"); - return -1; -} - static int s390_cpu_initial_reset(S390CPU *cpu) { CPUState *cs = CPU(cpu); @@ -629,12 +622,9 @@ static int handle_sigp(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1) { CPUS390XState *env = &cpu->env; uint8_t order_code; - uint32_t parameter; uint16_t cpu_addr; - uint8_t t; int r = -1; S390CPU *target_cpu; - CPUS390XState *target_env; cpu_synchronize_state(CPU(cpu)); @@ -645,28 +635,16 @@ static int handle_sigp(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1) } order_code += (run->s390_sieic.ipb & 0x0fff0000) >> 16; - /* get parameters */ - t = (ipa1 & 0xf0) >> 4; - if (!(t % 2)) { - t++; - } - - parameter = env->regs[t] & 0x7ffffe00; cpu_addr = env->regs[ipa1 & 0x0f]; - target_cpu = s390_cpu_addr2state(cpu_addr); if (target_cpu == NULL) { goto out; } - target_env = &target_cpu->env; switch (order_code) { case SIGP_RESTART: r = kvm_s390_cpu_restart(target_cpu); break; - case SIGP_STORE_STATUS_ADDR: - r = s390_store_status(target_env, parameter); - break; case SIGP_SET_ARCH: /* make the caller panic */ return -1; From 0b9972a2483b27824f3ec71b7b8b4a5961614216 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 17 Dec 2013 14:22:06 +0100 Subject: [PATCH 4/8] s390x/kvm: Fix coding style in handle_sigp() To make scripts/checkpatch.pl happy for the following patches, the coding style in handle_sigp() has to be fixed first. Signed-off-by: Thomas Huth Acked-by: Cornelia Huck Signed-off-by: Jens Freimann Signed-off-by: Alexander Graf --- target-s390x/kvm.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index 5b243b4bea..8c541340f2 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -642,18 +642,18 @@ static int handle_sigp(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1) } switch (order_code) { - case SIGP_RESTART: - r = kvm_s390_cpu_restart(target_cpu); - break; - case SIGP_SET_ARCH: - /* make the caller panic */ - return -1; - case SIGP_INITIAL_CPU_RESET: - r = s390_cpu_initial_reset(target_cpu); - break; - default: - fprintf(stderr, "KVM: unknown SIGP: 0x%x\n", order_code); - break; + case SIGP_RESTART: + r = kvm_s390_cpu_restart(target_cpu); + break; + case SIGP_SET_ARCH: + /* make the caller panic */ + return -1; + case SIGP_INITIAL_CPU_RESET: + r = s390_cpu_initial_reset(target_cpu); + break; + default: + fprintf(stderr, "KVM: unknown SIGP: 0x%x\n", order_code); + break; } out: From b20a461fcd55d2b05e729c587244eddc60b9527f Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 17 Dec 2013 14:22:07 +0100 Subject: [PATCH 5/8] s390x/kvm: Implemented SIGP START This patch adds the missing START order to the SIGP instruction handler. Signed-off-by: Thomas Huth Reviewed-by: Cornelia Huck Signed-off-by: Jens Freimann Signed-off-by: Alexander Graf --- target-s390x/kvm.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index 8c541340f2..fcc159f72e 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -588,6 +588,14 @@ static int handle_diag(S390CPU *cpu, struct kvm_run *run, uint32_t ipb) return r; } +static int kvm_s390_cpu_start(S390CPU *cpu) +{ + s390_add_running_cpu(cpu); + qemu_cpu_kick(CPU(cpu)); + DPRINTF("DONE: KVM cpu start: %p\n", &cpu->env); + return 0; +} + int kvm_s390_cpu_restart(S390CPU *cpu) { kvm_s390_interrupt(cpu, KVM_S390_RESTART, 0); @@ -642,6 +650,9 @@ static int handle_sigp(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1) } switch (order_code) { + case SIGP_START: + r = kvm_s390_cpu_start(target_cpu); + break; case SIGP_RESTART: r = kvm_s390_cpu_restart(target_cpu); break; From b8031adba791325907d8a9e19af8d483996974fd Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 17 Dec 2013 14:22:08 +0100 Subject: [PATCH 6/8] s390x/kvm: Simplified the calculation of the SIGP order code We've already got a helper function for calculating the base/displacement of RS formatted instructions, so we can get rid of the manual calculation of the SIGP order code. Signed-off-by: Thomas Huth Reviewed-by: Cornelia Huck Signed-off-by: Jens Freimann Signed-off-by: Alexander Graf --- target-s390x/kvm.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index fcc159f72e..0bf3d1f49e 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -626,6 +626,8 @@ static int s390_cpu_initial_reset(S390CPU *cpu) return 0; } +#define SIGP_ORDER_MASK 0x000000ff + static int handle_sigp(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1) { CPUS390XState *env = &cpu->env; @@ -637,11 +639,7 @@ static int handle_sigp(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1) cpu_synchronize_state(CPU(cpu)); /* get order code */ - order_code = run->s390_sieic.ipb >> 28; - if (order_code > 0) { - order_code = env->regs[order_code]; - } - order_code += (run->s390_sieic.ipb & 0x0fff0000) >> 16; + order_code = decode_basedisp_rs(env, run->s390_sieic.ipb) & SIGP_ORDER_MASK; cpu_addr = env->regs[ipa1 & 0x0f]; target_cpu = s390_cpu_addr2state(cpu_addr); From 3796f0e1cda41eacf4fc915e7edaf54f2279466c Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 17 Dec 2013 14:22:09 +0100 Subject: [PATCH 7/8] s390x/kvm: Fixed condition code for unknown SIGP orders If SIGP is called with an unknown order code, it has to return CC1 instead of CC3 and set the "invalid order" bit in the return status. Signed-off-by: Thomas Huth Reviewed-by: Cornelia Huck Signed-off-by: Jens Freimann Signed-off-by: Alexander Graf --- target-s390x/kvm.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index 0bf3d1f49e..f7b772668c 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -633,8 +633,9 @@ static int handle_sigp(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1) CPUS390XState *env = &cpu->env; uint8_t order_code; uint16_t cpu_addr; - int r = -1; S390CPU *target_cpu; + uint64_t *statusreg = &env->regs[ipa1 >> 4]; + int cc; cpu_synchronize_state(CPU(cpu)); @@ -644,29 +645,33 @@ static int handle_sigp(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1) cpu_addr = env->regs[ipa1 & 0x0f]; target_cpu = s390_cpu_addr2state(cpu_addr); if (target_cpu == NULL) { + cc = 3; /* not operational */ goto out; } switch (order_code) { case SIGP_START: - r = kvm_s390_cpu_start(target_cpu); + cc = kvm_s390_cpu_start(target_cpu); break; case SIGP_RESTART: - r = kvm_s390_cpu_restart(target_cpu); + cc = kvm_s390_cpu_restart(target_cpu); break; case SIGP_SET_ARCH: /* make the caller panic */ return -1; case SIGP_INITIAL_CPU_RESET: - r = s390_cpu_initial_reset(target_cpu); + cc = s390_cpu_initial_reset(target_cpu); break; default: - fprintf(stderr, "KVM: unknown SIGP: 0x%x\n", order_code); + DPRINTF("KVM: unknown SIGP: 0x%x\n", order_code); + *statusreg &= 0xffffffff00000000UL; + *statusreg |= SIGP_STAT_INVALID_ORDER; + cc = 1; /* status stored */ break; } out: - setcc(cpu, r ? 3 : 0); + setcc(cpu, cc); return 0; } From 10c8599a49f99180c2f79596325a5e856cdac59f Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 17 Dec 2013 19:50:01 +0100 Subject: [PATCH 8/8] s390x/ioinst: CHSC has to set a condition code I missed to set the CC in the CHSC instruction when I refactored the CC setting in the IO instructions with the following commit: 5d9bf1c07c1369ab3506fc82cc65a10f4415d867 s390/ioinst: Moved the CC setting to the IO instruction handlers This patch now restores the correct behaviour of CHSC by setting the condition code 0 at the end of the instruction. Signed-off-by: Thomas Huth Reviewed-by: Cornelia Huck Signed-off-by: Jens Freimann Signed-off-by: Alexander Graf --- target-s390x/ioinst.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target-s390x/ioinst.c b/target-s390x/ioinst.c index 8d6363df4e..b8a6486f51 100644 --- a/target-s390x/ioinst.c +++ b/target-s390x/ioinst.c @@ -622,6 +622,7 @@ void ioinst_handle_chsc(S390CPU *cpu, uint32_t ipb) break; } + setcc(cpu, 0); /* Command execution complete */ out: s390_cpu_physical_memory_unmap(env, req, map_size, 1); }