Re: [PATCH 1/2] target/s390x: Fix SIGILL psw.addr reporting

2021-05-21 Thread David Hildenbrand

On 21.05.21 05:01, Ilya Leoshkevich wrote:

When a s390x CPU attempts to execute an illegal instruction, an
operation exception is recognized. This is a suppressing exception,
which means that the PSW is advanced by the length of the illegal
instruction.

On the real hardware or in qemu-system-s390x the kernel then raises
SIGILL with si_addr pointing to the suppressed instruction and
psw.addr containing the updated PSW.

Unfortunately qemu-s390x sets both to the address of the suppressed
instruction at the moment. Fix by sharing the PSW advancement logic
with qemu-system-s390x and setting si_addr to the address of the
instruction that raised the exception.

Buglink: https://bugs.launchpad.net/qemu/+bug/1920913
Signed-off-by: Ilya Leoshkevich 
---
  linux-user/s390x/cpu_loop.c |  6 +++-
  target/s390x/excp_helper.c  | 69 -
  target/s390x/internal.h |  1 +
  3 files changed, 43 insertions(+), 33 deletions(-)

diff --git a/linux-user/s390x/cpu_loop.c b/linux-user/s390x/cpu_loop.c
index f2d1215fb1..6f5462d4f8 100644
--- a/linux-user/s390x/cpu_loop.c
+++ b/linux-user/s390x/cpu_loop.c
@@ -21,6 +21,7 @@
  #include "qemu-common.h"
  #include "qemu.h"
  #include "cpu_loop-common.h"
+#include "internal.h"
  
  /* s390x masks the fault address it reports in si_addr for SIGSEGV and SIGBUS */

  #define S390X_FAIL_ADDR_MASK -4096LL
@@ -29,6 +30,7 @@ void cpu_loop(CPUS390XState *env)
  {
  CPUState *cs = env_cpu(env);
  int trapnr, n, sig;
+target_ulong excp_psw_addr;
  target_siginfo_t info;
  target_ulong addr;
  abi_long ret;
@@ -38,6 +40,7 @@ void cpu_loop(CPUS390XState *env)
  trapnr = cpu_exec(cs);
  cpu_exec_end(cs);
  process_queued_cpu_work(cs);
+excp_psw_addr = env->psw.addr;
  
  switch (trapnr) {

  case EXCP_INTERRUPT:
@@ -66,6 +69,7 @@ void cpu_loop(CPUS390XState *env)
  n = TARGET_TRAP_BRKPT;
  goto do_signal_pc;
  case EXCP_PGM:
+s390_cpu_program_interrupt_advance_psw(env);
  n = env->int_pgm_code;
  switch (n) {
  case PGM_OPERATION:
@@ -131,7 +135,7 @@ void cpu_loop(CPUS390XState *env)
  break;
  
  do_signal_pc:

-addr = env->psw.addr;
+addr = excp_psw_addr;
  do_signal:
  info.si_signo = sig;
  info.si_errno = 0;
diff --git a/target/s390x/excp_helper.c b/target/s390x/excp_helper.c
index 20625c2c8f..0a323967ae 100644
--- a/target/s390x/excp_helper.c
+++ b/target/s390x/excp_helper.c
@@ -82,6 +82,42 @@ void HELPER(data_exception)(CPUS390XState *env, uint32_t dxc)
  tcg_s390_data_exception(env, dxc, GETPC());
  }
  
+void s390_cpu_program_interrupt_advance_psw(CPUS390XState *env)

+{
+switch (env->int_pgm_code) {
+case PGM_PER:
+if (env->per_perc_atmid & PER_CODE_EVENT_NULLIFICATION) {
+break;
+}
+/* FALL THROUGH */
+case PGM_OPERATION:
+case PGM_PRIVILEGED:
+case PGM_EXECUTE:
+case PGM_PROTECTION:
+case PGM_ADDRESSING:
+case PGM_SPECIFICATION:
+case PGM_DATA:
+case PGM_FIXPT_OVERFLOW:
+case PGM_FIXPT_DIVIDE:
+case PGM_DEC_OVERFLOW:
+case PGM_DEC_DIVIDE:
+case PGM_HFP_EXP_OVERFLOW:
+case PGM_HFP_EXP_UNDERFLOW:
+case PGM_HFP_SIGNIFICANCE:
+case PGM_HFP_DIVIDE:
+case PGM_TRANS_SPEC:
+case PGM_SPECIAL_OP:
+case PGM_OPERAND:
+case PGM_HFP_SQRT:
+case PGM_PC_TRANS_SPEC:
+case PGM_ALET_SPEC:
+case PGM_MONITOR:
+/* advance the PSW if our exception is not nullifying */
+env->psw.addr += env->int_pgm_ilen;
+break;
+}
+}
+
  #if defined(CONFIG_USER_ONLY)
  
  void s390_cpu_do_interrupt(CPUState *cs)

@@ -202,38 +238,7 @@ static void do_program_interrupt(CPUS390XState *env)
  
  assert(ilen == 2 || ilen == 4 || ilen == 6);
  
-switch (env->int_pgm_code) {

-case PGM_PER:
-if (env->per_perc_atmid & PER_CODE_EVENT_NULLIFICATION) {
-break;
-}
-/* FALL THROUGH */
-case PGM_OPERATION:
-case PGM_PRIVILEGED:
-case PGM_EXECUTE:
-case PGM_PROTECTION:
-case PGM_ADDRESSING:
-case PGM_SPECIFICATION:
-case PGM_DATA:
-case PGM_FIXPT_OVERFLOW:
-case PGM_FIXPT_DIVIDE:
-case PGM_DEC_OVERFLOW:
-case PGM_DEC_DIVIDE:
-case PGM_HFP_EXP_OVERFLOW:
-case PGM_HFP_EXP_UNDERFLOW:
-case PGM_HFP_SIGNIFICANCE:
-case PGM_HFP_DIVIDE:
-case PGM_TRANS_SPEC:
-case PGM_SPECIAL_OP:
-case PGM_OPERAND:
-case PGM_HFP_SQRT:
-case PGM_PC_TRANS_SPEC:
-case PGM_ALET_SPEC:
-case PGM_MONITOR:
-/* advance the PSW if our exception is not nullifying */
-env->psw.addr += ilen;
-break;
-}
+s390_cpu_program_interrupt_advance_psw(env);
  
  qemu_log_mask(CPU_LOG_INT,

"%s: code=0x%x ilen=%d psw: %" PRIx64 " %" PRIx64 "\n",
diff --git 

[PATCH 1/2] target/s390x: Fix SIGILL psw.addr reporting

2021-05-20 Thread Ilya Leoshkevich
When a s390x CPU attempts to execute an illegal instruction, an
operation exception is recognized. This is a suppressing exception,
which means that the PSW is advanced by the length of the illegal
instruction.

On the real hardware or in qemu-system-s390x the kernel then raises
SIGILL with si_addr pointing to the suppressed instruction and
psw.addr containing the updated PSW.

Unfortunately qemu-s390x sets both to the address of the suppressed
instruction at the moment. Fix by sharing the PSW advancement logic
with qemu-system-s390x and setting si_addr to the address of the
instruction that raised the exception.

Buglink: https://bugs.launchpad.net/qemu/+bug/1920913
Signed-off-by: Ilya Leoshkevich 
---
 linux-user/s390x/cpu_loop.c |  6 +++-
 target/s390x/excp_helper.c  | 69 -
 target/s390x/internal.h |  1 +
 3 files changed, 43 insertions(+), 33 deletions(-)

diff --git a/linux-user/s390x/cpu_loop.c b/linux-user/s390x/cpu_loop.c
index f2d1215fb1..6f5462d4f8 100644
--- a/linux-user/s390x/cpu_loop.c
+++ b/linux-user/s390x/cpu_loop.c
@@ -21,6 +21,7 @@
 #include "qemu-common.h"
 #include "qemu.h"
 #include "cpu_loop-common.h"
+#include "internal.h"
 
 /* s390x masks the fault address it reports in si_addr for SIGSEGV and SIGBUS 
*/
 #define S390X_FAIL_ADDR_MASK -4096LL
@@ -29,6 +30,7 @@ void cpu_loop(CPUS390XState *env)
 {
 CPUState *cs = env_cpu(env);
 int trapnr, n, sig;
+target_ulong excp_psw_addr;
 target_siginfo_t info;
 target_ulong addr;
 abi_long ret;
@@ -38,6 +40,7 @@ void cpu_loop(CPUS390XState *env)
 trapnr = cpu_exec(cs);
 cpu_exec_end(cs);
 process_queued_cpu_work(cs);
+excp_psw_addr = env->psw.addr;
 
 switch (trapnr) {
 case EXCP_INTERRUPT:
@@ -66,6 +69,7 @@ void cpu_loop(CPUS390XState *env)
 n = TARGET_TRAP_BRKPT;
 goto do_signal_pc;
 case EXCP_PGM:
+s390_cpu_program_interrupt_advance_psw(env);
 n = env->int_pgm_code;
 switch (n) {
 case PGM_OPERATION:
@@ -131,7 +135,7 @@ void cpu_loop(CPUS390XState *env)
 break;
 
 do_signal_pc:
-addr = env->psw.addr;
+addr = excp_psw_addr;
 do_signal:
 info.si_signo = sig;
 info.si_errno = 0;
diff --git a/target/s390x/excp_helper.c b/target/s390x/excp_helper.c
index 20625c2c8f..0a323967ae 100644
--- a/target/s390x/excp_helper.c
+++ b/target/s390x/excp_helper.c
@@ -82,6 +82,42 @@ void HELPER(data_exception)(CPUS390XState *env, uint32_t dxc)
 tcg_s390_data_exception(env, dxc, GETPC());
 }
 
+void s390_cpu_program_interrupt_advance_psw(CPUS390XState *env)
+{
+switch (env->int_pgm_code) {
+case PGM_PER:
+if (env->per_perc_atmid & PER_CODE_EVENT_NULLIFICATION) {
+break;
+}
+/* FALL THROUGH */
+case PGM_OPERATION:
+case PGM_PRIVILEGED:
+case PGM_EXECUTE:
+case PGM_PROTECTION:
+case PGM_ADDRESSING:
+case PGM_SPECIFICATION:
+case PGM_DATA:
+case PGM_FIXPT_OVERFLOW:
+case PGM_FIXPT_DIVIDE:
+case PGM_DEC_OVERFLOW:
+case PGM_DEC_DIVIDE:
+case PGM_HFP_EXP_OVERFLOW:
+case PGM_HFP_EXP_UNDERFLOW:
+case PGM_HFP_SIGNIFICANCE:
+case PGM_HFP_DIVIDE:
+case PGM_TRANS_SPEC:
+case PGM_SPECIAL_OP:
+case PGM_OPERAND:
+case PGM_HFP_SQRT:
+case PGM_PC_TRANS_SPEC:
+case PGM_ALET_SPEC:
+case PGM_MONITOR:
+/* advance the PSW if our exception is not nullifying */
+env->psw.addr += env->int_pgm_ilen;
+break;
+}
+}
+
 #if defined(CONFIG_USER_ONLY)
 
 void s390_cpu_do_interrupt(CPUState *cs)
@@ -202,38 +238,7 @@ static void do_program_interrupt(CPUS390XState *env)
 
 assert(ilen == 2 || ilen == 4 || ilen == 6);
 
-switch (env->int_pgm_code) {
-case PGM_PER:
-if (env->per_perc_atmid & PER_CODE_EVENT_NULLIFICATION) {
-break;
-}
-/* FALL THROUGH */
-case PGM_OPERATION:
-case PGM_PRIVILEGED:
-case PGM_EXECUTE:
-case PGM_PROTECTION:
-case PGM_ADDRESSING:
-case PGM_SPECIFICATION:
-case PGM_DATA:
-case PGM_FIXPT_OVERFLOW:
-case PGM_FIXPT_DIVIDE:
-case PGM_DEC_OVERFLOW:
-case PGM_DEC_DIVIDE:
-case PGM_HFP_EXP_OVERFLOW:
-case PGM_HFP_EXP_UNDERFLOW:
-case PGM_HFP_SIGNIFICANCE:
-case PGM_HFP_DIVIDE:
-case PGM_TRANS_SPEC:
-case PGM_SPECIAL_OP:
-case PGM_OPERAND:
-case PGM_HFP_SQRT:
-case PGM_PC_TRANS_SPEC:
-case PGM_ALET_SPEC:
-case PGM_MONITOR:
-/* advance the PSW if our exception is not nullifying */
-env->psw.addr += ilen;
-break;
-}
+s390_cpu_program_interrupt_advance_psw(env);
 
 qemu_log_mask(CPU_LOG_INT,
   "%s: code=0x%x ilen=%d psw: %" PRIx64 " %" PRIx64 "\n",
diff --git a/target/s390x/internal.h b/target/s390x/internal.h
index 11515bb617..9f1665ccbf 100644
---