All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH 0/7] linux-user: Streamline handling of SIGSEGV/SIGBUS
@ 2021-09-13 22:05 Richard Henderson
  2021-09-13 22:05 ` [RFC PATCH 1/7] include/exec: Move cpu_signal_handler declaration Richard Henderson
                   ` (7 more replies)
  0 siblings, 8 replies; 18+ messages in thread
From: Richard Henderson @ 2021-09-13 22:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, laurent, imp

Our current setup is:

  host_signal_handler
  cpu_signal_handler
     handle_cpu_signal
        cc->tcg_ops->tlb_fill
           raise_exception
  cpu_loop
     queue_signal

and in the process lose information from the host siginfo_t,
which we (mostly) do not recreate properly.  Moreover, the
intermediate cpu_signal_handler handles the host-specific
portions of extracting pc + is_write from the ucontext_t.

I'm replacing this with

  host_signal_handler
    host_signal_pc
    host_sigsegv_write
    adjust_signal_pc
    handle_sigsegv_accerr_write
    queue_signal
    raise_exception
  cpu_loop

All of the really tcg-specific portions are still in user-exec.c,
and all of the really host-specific portions are now ditributed
across linux-user/host/<arch>/.  Importantly, SEGV_MAPERR and
SEGV_ACCERR are now passed through from the host kernel -- or at
least there's a single place from which to manage it [1].

Note that I've dropped all of the BSD (and Solaris!) code from
user-exec.c.  I thought about moving it similar to linux-user,
but I've caught Warner in the middle of his re-org and the whole
of bsd-user/signal.c is currently empty.  I think it will be
easier to create the new interfaces from scratch when ready.

Still to-do:
  * Make cc->tcg_ops->tlb_fill sysemu only (once again).
  * Drop all of the code from cpu_loop that interfaced with tlb_fill.


r~


[1] I've just this minute realized that the reserved_va mapping that we
do for emulating 32-bit guests will incorrectly give SEGV_ACCERR for pages
that are not mapped by the guest, and should result in SEGV_MAPERR.


Richard Henderson (7):
  include/exec: Move cpu_signal_handler declaration
  accel/tcg: Split out adjust_signal_pc
  accel/tcg: Split out handle_sigsegv_accerr_write
  accel/tcg: Move clear_helper_retaddr to cpu loop
  accel/tcg: Fold cpu_exit_tb_from_sighandler into caller
  linux-user: Handle SIGSEGV/SIGBUS in host_to_target_siginfo_noswap
  linux-user: Reorg cpu_signal_handler

 include/exec/exec-all.h               |  21 +
 linux-user/host/aarch64/host-signal.h |  73 +++
 linux-user/host/alpha/host-signal.h   |  41 ++
 linux-user/host/arm/host-signal.h     |  30 +
 linux-user/host/i386/host-signal.h    |  24 +
 linux-user/host/mips/host-signal.h    |  61 ++
 linux-user/host/ppc/host-signal.h     |  24 +
 linux-user/host/ppc64/host-signal.h   |   1 +
 linux-user/host/riscv32/host-signal.h |  57 ++
 linux-user/host/riscv64/host-signal.h |   1 +
 linux-user/host/s390/host-signal.h    |  92 +++
 linux-user/host/s390x/host-signal.h   |   1 +
 linux-user/host/sparc/host-signal.h   |  53 ++
 linux-user/host/sparc64/host-signal.h |   1 +
 linux-user/host/x86_64/host-signal.h  |  24 +
 target/alpha/cpu.h                    |   6 -
 target/arm/cpu.h                      |   7 -
 target/avr/cpu.h                      |   2 -
 target/cris/cpu.h                     |   8 -
 target/hexagon/cpu.h                  |   3 -
 target/hppa/cpu.h                     |   3 -
 target/i386/cpu.h                     |   7 -
 target/m68k/cpu.h                     |   8 -
 target/microblaze/cpu.h               |   7 -
 target/mips/cpu.h                     |   3 -
 target/mips/internal.h                |   2 -
 target/nios2/cpu.h                    |   2 -
 target/openrisc/cpu.h                 |   2 -
 target/ppc/cpu.h                      |   7 -
 target/riscv/cpu.h                    |   2 -
 target/rx/cpu.h                       |   4 -
 target/s390x/cpu.h                    |   7 -
 target/sh4/cpu.h                      |   3 -
 target/sparc/cpu.h                    |   2 -
 target/tricore/cpu.h                  |   2 -
 target/xtensa/cpu.h                   |   2 -
 accel/tcg/cpu-exec.c                  |   3 +-
 accel/tcg/user-exec.c                 | 807 ++------------------------
 linux-user/signal.c                   | 102 ++--
 39 files changed, 635 insertions(+), 870 deletions(-)
 create mode 100644 linux-user/host/aarch64/host-signal.h
 create mode 100644 linux-user/host/alpha/host-signal.h
 create mode 100644 linux-user/host/arm/host-signal.h
 create mode 100644 linux-user/host/i386/host-signal.h
 create mode 100644 linux-user/host/mips/host-signal.h
 create mode 100644 linux-user/host/ppc/host-signal.h
 create mode 100644 linux-user/host/ppc64/host-signal.h
 create mode 100644 linux-user/host/riscv32/host-signal.h
 create mode 100644 linux-user/host/riscv64/host-signal.h
 create mode 100644 linux-user/host/s390/host-signal.h
 create mode 100644 linux-user/host/s390x/host-signal.h
 create mode 100644 linux-user/host/sparc/host-signal.h
 create mode 100644 linux-user/host/sparc64/host-signal.h
 create mode 100644 linux-user/host/x86_64/host-signal.h

-- 
2.25.1



^ permalink raw reply	[flat|nested] 18+ messages in thread

* [RFC PATCH 1/7] include/exec: Move cpu_signal_handler declaration
  2021-09-13 22:05 [RFC PATCH 0/7] linux-user: Streamline handling of SIGSEGV/SIGBUS Richard Henderson
@ 2021-09-13 22:05 ` Richard Henderson
  2021-09-14  6:03   ` Philippe Mathieu-Daudé
  2021-09-15 16:09   ` Warner Losh
  2021-09-13 22:05 ` [RFC PATCH 2/7] accel/tcg: Split out adjust_signal_pc Richard Henderson
                   ` (6 subsequent siblings)
  7 siblings, 2 replies; 18+ messages in thread
From: Richard Henderson @ 2021-09-13 22:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, Alistair Francis, laurent, imp

There is nothing target specific about this.  The implementation
is host specific, but the declaration is 100% common.

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/exec/exec-all.h | 13 +++++++++++++
 target/alpha/cpu.h      |  6 ------
 target/arm/cpu.h        |  7 -------
 target/avr/cpu.h        |  2 --
 target/cris/cpu.h       |  8 --------
 target/hexagon/cpu.h    |  3 ---
 target/hppa/cpu.h       |  3 ---
 target/i386/cpu.h       |  7 -------
 target/m68k/cpu.h       |  8 --------
 target/microblaze/cpu.h |  7 -------
 target/mips/cpu.h       |  3 ---
 target/mips/internal.h  |  2 --
 target/nios2/cpu.h      |  2 --
 target/openrisc/cpu.h   |  2 --
 target/ppc/cpu.h        |  7 -------
 target/riscv/cpu.h      |  2 --
 target/rx/cpu.h         |  4 ----
 target/s390x/cpu.h      |  7 -------
 target/sh4/cpu.h        |  3 ---
 target/sparc/cpu.h      |  2 --
 target/tricore/cpu.h    |  2 --
 target/xtensa/cpu.h     |  2 --
 22 files changed, 13 insertions(+), 89 deletions(-)

diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
index 5d1b6d80fb..9d5987ba04 100644
--- a/include/exec/exec-all.h
+++ b/include/exec/exec-all.h
@@ -662,6 +662,19 @@ static inline tb_page_addr_t get_page_addr_code_hostp(CPUArchState *env,
     }
     return addr;
 }
+
+/**
+ * cpu_signal_handler
+ * @signum: host signal number
+ * @pinfo: host siginfo_t
+ * @puc: host ucontext_t
+ *
+ * To be called from the SIGBUS and SIGSEGV signal handler to inform the
+ * virtual cpu of exceptions.  Returns true if the signal was handled by
+ * the virtual CPU.
+ */
+int cpu_signal_handler(int signum, void *pinfo, void *puc);
+
 #else
 static inline void mmap_lock(void) {}
 static inline void mmap_unlock(void) {}
diff --git a/target/alpha/cpu.h b/target/alpha/cpu.h
index 4e993bd15b..ce9ec32199 100644
--- a/target/alpha/cpu.h
+++ b/target/alpha/cpu.h
@@ -287,7 +287,6 @@ void alpha_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
                                    int mmu_idx, uintptr_t retaddr);
 
 #define cpu_list alpha_cpu_list
-#define cpu_signal_handler cpu_alpha_signal_handler
 
 typedef CPUAlphaState CPUArchState;
 typedef AlphaCPU ArchCPU;
@@ -440,11 +439,6 @@ void alpha_translate_init(void);
 #define CPU_RESOLVING_TYPE TYPE_ALPHA_CPU
 
 void alpha_cpu_list(void);
-/* you can call this signal handler from your SIGBUS and SIGSEGV
-   signal handlers to inform the virtual CPU of exceptions. non zero
-   is returned if the signal was handled by the virtual CPU.  */
-int cpu_alpha_signal_handler(int host_signum, void *pinfo,
-                             void *puc);
 bool alpha_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
                         MMUAccessType access_type, int mmu_idx,
                         bool probe, uintptr_t retaddr);
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index cfd755cff9..6c78957e54 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -1121,12 +1121,6 @@ static inline bool is_a64(CPUARMState *env)
     return env->aarch64;
 }
 
-/* you can call this signal handler from your SIGBUS and SIGSEGV
-   signal handlers to inform the virtual CPU of exceptions. non zero
-   is returned if the signal was handled by the virtual CPU.  */
-int cpu_arm_signal_handler(int host_signum, void *pinfo,
-                           void *puc);
-
 /**
  * pmu_op_start/finish
  * @env: CPUARMState
@@ -3015,7 +3009,6 @@ bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync);
 #define ARM_CPU_TYPE_NAME(name) (name ARM_CPU_TYPE_SUFFIX)
 #define CPU_RESOLVING_TYPE TYPE_ARM_CPU
 
-#define cpu_signal_handler cpu_arm_signal_handler
 #define cpu_list arm_cpu_list
 
 /* ARM has the following "translation regimes" (as the ARM ARM calls them):
diff --git a/target/avr/cpu.h b/target/avr/cpu.h
index 93e3faa0a9..dceacf3cd7 100644
--- a/target/avr/cpu.h
+++ b/target/avr/cpu.h
@@ -175,7 +175,6 @@ static inline void set_avr_feature(CPUAVRState *env, int feature)
 }
 
 #define cpu_list avr_cpu_list
-#define cpu_signal_handler cpu_avr_signal_handler
 #define cpu_mmu_index avr_cpu_mmu_index
 
 static inline int avr_cpu_mmu_index(CPUAVRState *env, bool ifetch)
@@ -187,7 +186,6 @@ void avr_cpu_tcg_init(void);
 
 void avr_cpu_list(void);
 int cpu_avr_exec(CPUState *cpu);
-int cpu_avr_signal_handler(int host_signum, void *pinfo, void *puc);
 int avr_cpu_memory_rw_debug(CPUState *cs, vaddr address, uint8_t *buf,
                             int len, bool is_write);
 
diff --git a/target/cris/cpu.h b/target/cris/cpu.h
index be021899ae..6603565f83 100644
--- a/target/cris/cpu.h
+++ b/target/cris/cpu.h
@@ -199,12 +199,6 @@ int crisv10_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
 int cris_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
 int cris_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
 
-/* you can call this signal handler from your SIGBUS and SIGSEGV
-   signal handlers to inform the virtual CPU of exceptions. non zero
-   is returned if the signal was handled by the virtual CPU.  */
-int cpu_cris_signal_handler(int host_signum, void *pinfo,
-                           void *puc);
-
 void cris_initialize_tcg(void);
 void cris_initialize_crisv10_tcg(void);
 
@@ -250,8 +244,6 @@ enum {
 #define CRIS_CPU_TYPE_NAME(name) (name CRIS_CPU_TYPE_SUFFIX)
 #define CPU_RESOLVING_TYPE TYPE_CRIS_CPU
 
-#define cpu_signal_handler cpu_cris_signal_handler
-
 /* MMU modes definitions */
 #define MMU_USER_IDX 1
 static inline int cpu_mmu_index (CPUCRISState *env, bool ifetch)
diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h
index 2855dd3881..f7d043865b 100644
--- a/target/hexagon/cpu.h
+++ b/target/hexagon/cpu.h
@@ -129,9 +129,6 @@ typedef struct HexagonCPU {
 
 #include "cpu_bits.h"
 
-#define cpu_signal_handler cpu_hexagon_signal_handler
-int cpu_hexagon_signal_handler(int host_signum, void *pinfo, void *puc);
-
 static inline void cpu_get_tb_cpu_state(CPUHexagonState *env, target_ulong *pc,
                                         target_ulong *cs_base, uint32_t *flags)
 {
diff --git a/target/hppa/cpu.h b/target/hppa/cpu.h
index 7854675b90..d3cb7a279f 100644
--- a/target/hppa/cpu.h
+++ b/target/hppa/cpu.h
@@ -319,9 +319,6 @@ static inline void cpu_hppa_change_prot_id(CPUHPPAState *env) { }
 void cpu_hppa_change_prot_id(CPUHPPAState *env);
 #endif
 
-#define cpu_signal_handler cpu_hppa_signal_handler
-
-int cpu_hppa_signal_handler(int host_signum, void *pinfo, void *puc);
 hwaddr hppa_cpu_get_phys_page_debug(CPUState *cs, vaddr addr);
 int hppa_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
 int hppa_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index 7dd664791a..c2954c71ea 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -1947,12 +1947,6 @@ void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32);
 void cpu_x86_fxsave(CPUX86State *s, target_ulong ptr);
 void cpu_x86_fxrstor(CPUX86State *s, target_ulong ptr);
 
-/* you can call this signal handler from your SIGBUS and SIGSEGV
-   signal handlers to inform the virtual CPU of exceptions. non zero
-   is returned if the signal was handled by the virtual CPU.  */
-int cpu_x86_signal_handler(int host_signum, void *pinfo,
-                           void *puc);
-
 /* cpu.c */
 void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1,
                               uint32_t vendor2, uint32_t vendor3);
@@ -2020,7 +2014,6 @@ uint64_t cpu_get_tsc(CPUX86State *env);
 #define TARGET_DEFAULT_CPU_TYPE X86_CPU_TYPE_NAME("qemu32")
 #endif
 
-#define cpu_signal_handler cpu_x86_signal_handler
 #define cpu_list x86_cpu_list
 
 /* MMU modes definitions */
diff --git a/target/m68k/cpu.h b/target/m68k/cpu.h
index 550eb028b6..a3423729ef 100644
--- a/target/m68k/cpu.h
+++ b/target/m68k/cpu.h
@@ -177,13 +177,6 @@ int m68k_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
 
 void m68k_tcg_init(void);
 void m68k_cpu_init_gdb(M68kCPU *cpu);
-/*
- * you can call this signal handler from your SIGBUS and SIGSEGV
- * signal handlers to inform the virtual CPU of exceptions. non zero
- * is returned if the signal was handled by the virtual CPU.
- */
-int cpu_m68k_signal_handler(int host_signum, void *pinfo,
-                           void *puc);
 uint32_t cpu_m68k_get_ccr(CPUM68KState *env);
 void cpu_m68k_set_ccr(CPUM68KState *env, uint32_t);
 void cpu_m68k_set_sr(CPUM68KState *env, uint32_t);
@@ -563,7 +556,6 @@ enum {
 #define M68K_CPU_TYPE_NAME(model) model M68K_CPU_TYPE_SUFFIX
 #define CPU_RESOLVING_TYPE TYPE_M68K_CPU
 
-#define cpu_signal_handler cpu_m68k_signal_handler
 #define cpu_list m68k_cpu_list
 
 /* MMU modes definitions */
diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h
index 40401c33b7..13ed3cd4dd 100644
--- a/target/microblaze/cpu.h
+++ b/target/microblaze/cpu.h
@@ -385,16 +385,9 @@ static inline void mb_cpu_write_msr(CPUMBState *env, uint32_t val)
 }
 
 void mb_tcg_init(void);
-/* you can call this signal handler from your SIGBUS and SIGSEGV
-   signal handlers to inform the virtual CPU of exceptions. non zero
-   is returned if the signal was handled by the virtual CPU.  */
-int cpu_mb_signal_handler(int host_signum, void *pinfo,
-                          void *puc);
 
 #define CPU_RESOLVING_TYPE TYPE_MICROBLAZE_CPU
 
-#define cpu_signal_handler cpu_mb_signal_handler
-
 /* MMU modes definitions */
 #define MMU_NOMMU_IDX   0
 #define MMU_KERNEL_IDX  1
diff --git a/target/mips/cpu.h b/target/mips/cpu.h
index 1dfe69c6c0..56b1cbd091 100644
--- a/target/mips/cpu.h
+++ b/target/mips/cpu.h
@@ -1193,7 +1193,6 @@ struct MIPSCPU {
 
 void mips_cpu_list(void);
 
-#define cpu_signal_handler cpu_mips_signal_handler
 #define cpu_list mips_cpu_list
 
 extern void cpu_wrdsp(uint32_t rs, uint32_t mask_num, CPUMIPSState *env);
@@ -1277,8 +1276,6 @@ enum {
  */
 #define CPU_INTERRUPT_WAKE CPU_INTERRUPT_TGT_INT_0
 
-int cpu_mips_signal_handler(int host_signum, void *pinfo, void *puc);
-
 #define MIPS_CPU_TYPE_SUFFIX "-" TYPE_MIPS_CPU
 #define MIPS_CPU_TYPE_NAME(model) model MIPS_CPU_TYPE_SUFFIX
 #define CPU_RESOLVING_TYPE TYPE_MIPS_CPU
diff --git a/target/mips/internal.h b/target/mips/internal.h
index eecdd10116..daddb05fd4 100644
--- a/target/mips/internal.h
+++ b/target/mips/internal.h
@@ -156,8 +156,6 @@ extern const VMStateDescription vmstate_mips_cpu;
 
 #endif /* !CONFIG_USER_ONLY */
 
-#define cpu_signal_handler cpu_mips_signal_handler
-
 static inline bool cpu_mips_hw_interrupts_enabled(CPUMIPSState *env)
 {
     return (env->CP0_Status & (1 << CP0St_IE)) &&
diff --git a/target/nios2/cpu.h b/target/nios2/cpu.h
index 2ab82fdc71..88a511209c 100644
--- a/target/nios2/cpu.h
+++ b/target/nios2/cpu.h
@@ -193,7 +193,6 @@ struct Nios2CPU {
 
 void nios2_tcg_init(void);
 void nios2_cpu_do_interrupt(CPUState *cs);
-int cpu_nios2_signal_handler(int host_signum, void *pinfo, void *puc);
 void dump_mmu(CPUNios2State *env);
 void nios2_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
 hwaddr nios2_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
@@ -206,7 +205,6 @@ void do_nios2_semihosting(CPUNios2State *env);
 #define CPU_RESOLVING_TYPE TYPE_NIOS2_CPU
 
 #define cpu_gen_code cpu_nios2_gen_code
-#define cpu_signal_handler cpu_nios2_signal_handler
 
 #define CPU_SAVE_VERSION 1
 
diff --git a/target/openrisc/cpu.h b/target/openrisc/cpu.h
index be6df81a81..187a4a114e 100644
--- a/target/openrisc/cpu.h
+++ b/target/openrisc/cpu.h
@@ -320,11 +320,9 @@ void openrisc_translate_init(void);
 bool openrisc_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
                            MMUAccessType access_type, int mmu_idx,
                            bool probe, uintptr_t retaddr);
-int cpu_openrisc_signal_handler(int host_signum, void *pinfo, void *puc);
 int print_insn_or1k(bfd_vma addr, disassemble_info *info);
 
 #define cpu_list cpu_openrisc_list
-#define cpu_signal_handler cpu_openrisc_signal_handler
 
 #ifndef CONFIG_USER_ONLY
 extern const VMStateDescription vmstate_openrisc_cpu;
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 362e7c4c5c..01d3773bc7 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -1278,12 +1278,6 @@ extern const VMStateDescription vmstate_ppc_cpu;
 
 /*****************************************************************************/
 void ppc_translate_init(void);
-/*
- * you can call this signal handler from your SIGBUS and SIGSEGV
- * signal handlers to inform the virtual CPU of exceptions. non zero
- * is returned if the signal was handled by the virtual CPU.
- */
-int cpu_ppc_signal_handler(int host_signum, void *pinfo, void *puc);
 bool ppc_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
                       MMUAccessType access_type, int mmu_idx,
                       bool probe, uintptr_t retaddr);
@@ -1371,7 +1365,6 @@ int ppc_dcr_write(ppc_dcr_t *dcr_env, int dcrn, uint32_t val);
 #define POWERPC_CPU_TYPE_NAME(model) model POWERPC_CPU_TYPE_SUFFIX
 #define CPU_RESOLVING_TYPE TYPE_POWERPC_CPU
 
-#define cpu_signal_handler cpu_ppc_signal_handler
 #define cpu_list ppc_cpu_list
 
 /* MMU modes definitions */
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index e735e53e26..465142616a 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -356,7 +356,6 @@ void riscv_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
 char *riscv_isa_string(RISCVCPU *cpu);
 void riscv_cpu_list(void);
 
-#define cpu_signal_handler riscv_cpu_signal_handler
 #define cpu_list riscv_cpu_list
 #define cpu_mmu_index riscv_cpu_mmu_index
 
@@ -372,7 +371,6 @@ void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(uint32_t),
 void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv);
 
 void riscv_translate_init(void);
-int riscv_cpu_signal_handler(int host_signum, void *pinfo, void *puc);
 void QEMU_NORETURN riscv_raise_exception(CPURISCVState *env,
                                          uint32_t exception, uintptr_t pc);
 
diff --git a/target/rx/cpu.h b/target/rx/cpu.h
index faa3606f52..4ac71aec37 100644
--- a/target/rx/cpu.h
+++ b/target/rx/cpu.h
@@ -134,13 +134,9 @@ int rx_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
 hwaddr rx_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
 
 void rx_translate_init(void);
-int cpu_rx_signal_handler(int host_signum, void *pinfo,
-                           void *puc);
-
 void rx_cpu_list(void);
 void rx_cpu_unpack_psw(CPURXState *env, uint32_t psw, int rte);
 
-#define cpu_signal_handler cpu_rx_signal_handler
 #define cpu_list rx_cpu_list
 
 #include "exec/cpu-all.h"
diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h
index b26ae8fff2..3153d053e9 100644
--- a/target/s390x/cpu.h
+++ b/target/s390x/cpu.h
@@ -809,13 +809,6 @@ void s390_set_qemu_cpu_model(uint16_t type, uint8_t gen, uint8_t ec_ga,
 #define S390_CPU_TYPE_NAME(name) (name S390_CPU_TYPE_SUFFIX)
 #define CPU_RESOLVING_TYPE TYPE_S390_CPU
 
-/* you can call this signal handler from your SIGBUS and SIGSEGV
-   signal handlers to inform the virtual CPU of exceptions. non zero
-   is returned if the signal was handled by the virtual CPU.  */
-int cpu_s390x_signal_handler(int host_signum, void *pinfo, void *puc);
-#define cpu_signal_handler cpu_s390x_signal_handler
-
-
 /* interrupt.c */
 #define RA_IGNORED                  0
 void s390_program_interrupt(CPUS390XState *env, uint32_t code, uintptr_t ra);
diff --git a/target/sh4/cpu.h b/target/sh4/cpu.h
index 017a770214..56f7c32df9 100644
--- a/target/sh4/cpu.h
+++ b/target/sh4/cpu.h
@@ -213,8 +213,6 @@ void superh_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
                                     int mmu_idx, uintptr_t retaddr);
 
 void sh4_translate_init(void);
-int cpu_sh4_signal_handler(int host_signum, void *pinfo,
-                           void *puc);
 bool superh_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
                          MMUAccessType access_type, int mmu_idx,
                          bool probe, uintptr_t retaddr);
@@ -250,7 +248,6 @@ void cpu_load_tlb(CPUSH4State * env);
 #define SUPERH_CPU_TYPE_NAME(model) model SUPERH_CPU_TYPE_SUFFIX
 #define CPU_RESOLVING_TYPE TYPE_SUPERH_CPU
 
-#define cpu_signal_handler cpu_sh4_signal_handler
 #define cpu_list sh4_cpu_list
 
 /* MMU modes definitions */
diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h
index ff8ae73002..6b40d02237 100644
--- a/target/sparc/cpu.h
+++ b/target/sparc/cpu.h
@@ -649,13 +649,11 @@ hwaddr cpu_get_phys_page_nofault(CPUSPARCState *env, target_ulong addr,
                                            int mmu_idx);
 #endif
 #endif
-int cpu_sparc_signal_handler(int host_signum, void *pinfo, void *puc);
 
 #define SPARC_CPU_TYPE_SUFFIX "-" TYPE_SPARC_CPU
 #define SPARC_CPU_TYPE_NAME(model) model SPARC_CPU_TYPE_SUFFIX
 #define CPU_RESOLVING_TYPE TYPE_SPARC_CPU
 
-#define cpu_signal_handler cpu_sparc_signal_handler
 #define cpu_list sparc_cpu_list
 
 /* MMU modes definitions */
diff --git a/target/tricore/cpu.h b/target/tricore/cpu.h
index 4b61a2c03f..c461387e71 100644
--- a/target/tricore/cpu.h
+++ b/target/tricore/cpu.h
@@ -362,7 +362,6 @@ void fpu_set_state(CPUTriCoreState *env);
 
 void tricore_cpu_list(void);
 
-#define cpu_signal_handler cpu_tricore_signal_handler
 #define cpu_list tricore_cpu_list
 
 static inline int cpu_mmu_index(CPUTriCoreState *env, bool ifetch)
@@ -377,7 +376,6 @@ typedef TriCoreCPU ArchCPU;
 
 void cpu_state_reset(CPUTriCoreState *s);
 void tricore_tcg_init(void);
-int cpu_tricore_signal_handler(int host_signum, void *pinfo, void *puc);
 
 static inline void cpu_get_tb_cpu_state(CPUTriCoreState *env, target_ulong *pc,
                                         target_ulong *cs_base, uint32_t *flags)
diff --git a/target/xtensa/cpu.h b/target/xtensa/cpu.h
index cbb720e7cc..646965f379 100644
--- a/target/xtensa/cpu.h
+++ b/target/xtensa/cpu.h
@@ -584,7 +584,6 @@ void xtensa_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
                                     MMUAccessType access_type,
                                     int mmu_idx, uintptr_t retaddr);
 
-#define cpu_signal_handler cpu_xtensa_signal_handler
 #define cpu_list xtensa_cpu_list
 
 #define XTENSA_CPU_TYPE_SUFFIX "-" TYPE_XTENSA_CPU
@@ -613,7 +612,6 @@ void check_interrupts(CPUXtensaState *s);
 void xtensa_irq_init(CPUXtensaState *env);
 qemu_irq *xtensa_get_extints(CPUXtensaState *env);
 qemu_irq xtensa_get_runstall(CPUXtensaState *env);
-int cpu_xtensa_signal_handler(int host_signum, void *pinfo, void *puc);
 void xtensa_cpu_list(void);
 void xtensa_sync_window_from_phys(CPUXtensaState *env);
 void xtensa_sync_phys_from_window(CPUXtensaState *env);
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [RFC PATCH 2/7] accel/tcg: Split out adjust_signal_pc
  2021-09-13 22:05 [RFC PATCH 0/7] linux-user: Streamline handling of SIGSEGV/SIGBUS Richard Henderson
  2021-09-13 22:05 ` [RFC PATCH 1/7] include/exec: Move cpu_signal_handler declaration Richard Henderson
@ 2021-09-13 22:05 ` Richard Henderson
  2021-09-14  6:07   ` Philippe Mathieu-Daudé
  2021-09-13 22:05 ` [RFC PATCH 3/7] accel/tcg: Split out handle_sigsegv_accerr_write Richard Henderson
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 18+ messages in thread
From: Richard Henderson @ 2021-09-13 22:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, laurent, imp

Split out a function to adjust the raw signal pc into a
value that could be passed to cpu_restore_state.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/exec/exec-all.h |  8 +++++++
 accel/tcg/user-exec.c   | 50 ++++++++++++++++++++++++++---------------
 2 files changed, 40 insertions(+), 18 deletions(-)

diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
index 9d5987ba04..7207912306 100644
--- a/include/exec/exec-all.h
+++ b/include/exec/exec-all.h
@@ -663,6 +663,14 @@ static inline tb_page_addr_t get_page_addr_code_hostp(CPUArchState *env,
     return addr;
 }
 
+/**
+ * adjust_signal_pc:
+ * @pc: raw pc from the host signal ucontext_t.
+ *
+ * Return the pc to pass to cpu_restore_state.
+ */
+uintptr_t adjust_signal_pc(uintptr_t pc);
+
 /**
  * cpu_signal_handler
  * @signum: host signal number
diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c
index 8fed542622..1f7b7a3692 100644
--- a/accel/tcg/user-exec.c
+++ b/accel/tcg/user-exec.c
@@ -57,18 +57,14 @@ static void QEMU_NORETURN cpu_exit_tb_from_sighandler(CPUState *cpu,
     cpu_loop_exit_noexc(cpu);
 }
 
-/* 'pc' is the host PC at which the exception was raised. 'address' is
-   the effective address of the memory exception. 'is_write' is 1 if a
-   write caused the exception and otherwise 0'. 'old_set' is the
-   signal set which should be restored */
-static inline int handle_cpu_signal(uintptr_t pc, siginfo_t *info,
-                                    int is_write, sigset_t *old_set)
+/**
+ * adjust_signal_pc:
+ * @pc: raw pc from the host signal ucontext_t.
+ *
+ * Return the pc to pass to cpu_restore_state.
+ */
+uintptr_t adjust_signal_pc(uintptr_t pc)
 {
-    CPUState *cpu = current_cpu;
-    CPUClass *cc;
-    unsigned long address = (unsigned long)info->si_addr;
-    MMUAccessType access_type = is_write ? MMU_DATA_STORE : MMU_DATA_LOAD;
-
     switch (helper_retaddr) {
     default:
         /*
@@ -77,8 +73,7 @@ static inline int handle_cpu_signal(uintptr_t pc, siginfo_t *info,
          * pointer into the generated code that will unwind to the
          * correct guest pc.
          */
-        pc = helper_retaddr;
-        break;
+        return helper_retaddr;
 
     case 0:
         /*
@@ -97,8 +92,7 @@ static inline int handle_cpu_signal(uintptr_t pc, siginfo_t *info,
          * Therefore, adjust to compensate for what will be done later
          * by cpu_restore_state_from_tb.
          */
-        pc += GETPC_ADJ;
-        break;
+        return pc + GETPC_ADJ;
 
     case 1:
         /*
@@ -113,11 +107,31 @@ static inline int handle_cpu_signal(uintptr_t pc, siginfo_t *info,
          *
          * Like tb_gen_code, release the memory lock before cpu_loop_exit.
          */
-        pc = 0;
-        access_type = MMU_INST_FETCH;
         mmap_unlock();
-        break;
+        return 0;
     }
+}
+
+/* 'pc' is the host PC at which the exception was raised. 'address' is
+   the effective address of the memory exception. 'is_write' is 1 if a
+   write caused the exception and otherwise 0'. 'old_set' is the
+   signal set which should be restored */
+static inline int handle_cpu_signal(uintptr_t pc, siginfo_t *info,
+                                    int is_write, sigset_t *old_set)
+{
+    CPUState *cpu = current_cpu;
+    CPUClass *cc;
+    unsigned long address = (unsigned long)info->si_addr;
+    MMUAccessType access_type;
+
+    if (is_write) {
+        access_type = MMU_DATA_STORE;
+    } else if (helper_retaddr == 1) {
+        access_type = MMU_INST_FETCH;
+    } else {
+        access_type = MMU_DATA_LOAD;
+    }
+    pc = adjust_signal_pc(pc);
 
     /* For synchronous signals we expect to be coming from the vCPU
      * thread (so current_cpu should be valid) and either from running
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [RFC PATCH 3/7] accel/tcg: Split out handle_sigsegv_accerr_write
  2021-09-13 22:05 [RFC PATCH 0/7] linux-user: Streamline handling of SIGSEGV/SIGBUS Richard Henderson
  2021-09-13 22:05 ` [RFC PATCH 1/7] include/exec: Move cpu_signal_handler declaration Richard Henderson
  2021-09-13 22:05 ` [RFC PATCH 2/7] accel/tcg: Split out adjust_signal_pc Richard Henderson
@ 2021-09-13 22:05 ` Richard Henderson
  2021-09-14  6:58   ` Philippe Mathieu-Daudé
  2021-09-13 22:05 ` [RFC PATCH 4/7] accel/tcg: Move clear_helper_retaddr to cpu loop Richard Henderson
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 18+ messages in thread
From: Richard Henderson @ 2021-09-13 22:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, laurent, imp

This is the major portion of handle_cpu_signal which is specific
to tcg, handling the page protections for the translations.
Most of the rest will migrate to linux-user/ shortly.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/exec/exec-all.h | 12 ++++++
 accel/tcg/user-exec.c   | 96 +++++++++++++++++++++++++----------------
 2 files changed, 72 insertions(+), 36 deletions(-)

diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
index 7207912306..f582d3e688 100644
--- a/include/exec/exec-all.h
+++ b/include/exec/exec-all.h
@@ -671,6 +671,18 @@ static inline tb_page_addr_t get_page_addr_code_hostp(CPUArchState *env,
  */
 uintptr_t adjust_signal_pc(uintptr_t pc);
 
+/**
+ * handle_sigsegv_accerr_write:
+ * @cpu: the cpu context
+ * @old_set: the sigset_t from the signal ucontext_t
+ * @host_pc: the host pc, adjusted for the signal
+ * @host_addr: the host address of the fault
+ *
+ * Return true if the write fault has been handled, and should be re-tried.
+ */
+bool handle_sigsegv_accerr_write(CPUState *cpu, sigset_t *old_set,
+                                 uintptr_t host_pc, uintptr_t host_addr);
+
 /**
  * cpu_signal_handler
  * @signum: host signal number
diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c
index 1f7b7a3692..daef34a426 100644
--- a/accel/tcg/user-exec.c
+++ b/accel/tcg/user-exec.c
@@ -112,6 +112,60 @@ uintptr_t adjust_signal_pc(uintptr_t pc)
     }
 }
 
+/**
+ * handle_sigsegv_accerr_write:
+ * @cpu: the cpu context
+ * @old_set: the sigset_t from the signal ucontext_t
+ * @host_pc: the host pc, adjusted for the signal
+ * @host_addr: the host address of the fault
+ *
+ * Return true if the write fault has been handled, and should be re-tried.
+ *
+ * Note that it is important that we don't call page_unprotect() unless
+ * this is really a "write to nonwriteable page" fault, because
+ * page_unprotect() assumes that if it is called for an access to
+ * a page that's writeable this means we had two threads racing and
+ * another thread got there first and already made the page writeable;
+ * so we will retry the access. If we were to call page_unprotect()
+ * for some other kind of fault that should really be passed to the
+ * guest, we'd end up in an infinite loop of retrying the faulting access.
+ */
+bool handle_sigsegv_accerr_write(CPUState *cpu, sigset_t *old_set,
+                                 uintptr_t host_pc, uintptr_t host_addr)
+{
+    if (!h2g_valid(host_addr)) {
+        return false;
+    }
+
+    switch (page_unprotect(h2g(host_addr), host_pc)) {
+    case 0:
+        /*
+         * Fault not caused by a page marked unwritable to protect
+         * cached translations, must be the guest binary's problem.
+         */
+        return false;
+    case 1:
+        /*
+         * Fault caused by protection of cached translation; TBs
+         * invalidated, so resume execution.  Retain helper_retaddr
+         * for a possible second fault.
+         */
+        return true;
+    case 2:
+        /*
+         * Fault caused by protection of cached translation, and the
+         * currently executing TB was modified and must be exited
+         * immediately.  Clear helper_retaddr for next execution.
+         */
+        clear_helper_retaddr();
+        cpu_exit_tb_from_sighandler(cpu, old_set);
+        /* NORETURN */
+
+    default:
+        g_assert_not_reached();
+    }
+}
+
 /* 'pc' is the host PC at which the exception was raised. 'address' is
    the effective address of the memory exception. 'is_write' is 1 if a
    write caused the exception and otherwise 0'. 'old_set' is the
@@ -150,43 +204,13 @@ static inline int handle_cpu_signal(uintptr_t pc, siginfo_t *info,
     printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
            pc, address, is_write, *(unsigned long *)old_set);
 #endif
-    /* XXX: locking issue */
-    /* Note that it is important that we don't call page_unprotect() unless
-     * this is really a "write to nonwriteable page" fault, because
-     * page_unprotect() assumes that if it is called for an access to
-     * a page that's writeable this means we had two threads racing and
-     * another thread got there first and already made the page writeable;
-     * so we will retry the access. If we were to call page_unprotect()
-     * for some other kind of fault that should really be passed to the
-     * guest, we'd end up in an infinite loop of retrying the faulting
-     * access.
-     */
-    if (is_write && info->si_signo == SIGSEGV && info->si_code == SEGV_ACCERR &&
-        h2g_valid(address)) {
-        switch (page_unprotect(h2g(address), pc)) {
-        case 0:
-            /* Fault not caused by a page marked unwritable to protect
-             * cached translations, must be the guest binary's problem.
-             */
-            break;
-        case 1:
-            /* Fault caused by protection of cached translation; TBs
-             * invalidated, so resume execution.  Retain helper_retaddr
-             * for a possible second fault.
-             */
-            return 1;
-        case 2:
-            /* Fault caused by protection of cached translation, and the
-             * currently executing TB was modified and must be exited
-             * immediately.  Clear helper_retaddr for next execution.
-             */
-            clear_helper_retaddr();
-            cpu_exit_tb_from_sighandler(cpu, old_set);
-            /* NORETURN */
 
-        default:
-            g_assert_not_reached();
-        }
+    /* XXX: locking issue */
+    if (is_write &&
+        info->si_signo == SIGSEGV &&
+        info->si_code == SEGV_ACCERR &&
+        handle_sigsegv_accerr_write(cpu, old_set, pc, address)) {
+        return 1;
     }
 
     /* Convert forcefully to guest address space, invalid addresses
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [RFC PATCH 4/7] accel/tcg: Move clear_helper_retaddr to cpu loop
  2021-09-13 22:05 [RFC PATCH 0/7] linux-user: Streamline handling of SIGSEGV/SIGBUS Richard Henderson
                   ` (2 preceding siblings ...)
  2021-09-13 22:05 ` [RFC PATCH 3/7] accel/tcg: Split out handle_sigsegv_accerr_write Richard Henderson
@ 2021-09-13 22:05 ` Richard Henderson
  2021-09-13 22:05 ` [RFC PATCH 5/7] accel/tcg: Fold cpu_exit_tb_from_sighandler into caller Richard Henderson
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 18+ messages in thread
From: Richard Henderson @ 2021-09-13 22:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, laurent, imp

Currently there are only two places that require we reset this
value before exiting to the main loop, but that will change.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 accel/tcg/cpu-exec.c  | 3 ++-
 accel/tcg/user-exec.c | 2 --
 2 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c
index 75dbc1e4e3..13c4436e5d 100644
--- a/accel/tcg/cpu-exec.c
+++ b/accel/tcg/cpu-exec.c
@@ -451,6 +451,7 @@ void cpu_exec_step_atomic(CPUState *cpu)
          * memory.
          */
 #ifndef CONFIG_SOFTMMU
+        clear_helper_retaddr();
         tcg_debug_assert(!have_mmap_lock());
 #endif
         if (qemu_mutex_iothread_locked()) {
@@ -460,7 +461,6 @@ void cpu_exec_step_atomic(CPUState *cpu)
         qemu_plugin_disable_mem_helpers(cpu);
     }
 
-
     /*
      * As we start the exclusive region before codegen we must still
      * be in the region if we longjump out of either the codegen or
@@ -903,6 +903,7 @@ int cpu_exec(CPUState *cpu)
 #endif
 
 #ifndef CONFIG_SOFTMMU
+        clear_helper_retaddr();
         tcg_debug_assert(!have_mmap_lock());
 #endif
         if (qemu_mutex_iothread_locked()) {
diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c
index daef34a426..83351db719 100644
--- a/accel/tcg/user-exec.c
+++ b/accel/tcg/user-exec.c
@@ -157,7 +157,6 @@ bool handle_sigsegv_accerr_write(CPUState *cpu, sigset_t *old_set,
          * currently executing TB was modified and must be exited
          * immediately.  Clear helper_retaddr for next execution.
          */
-        clear_helper_retaddr();
         cpu_exit_tb_from_sighandler(cpu, old_set);
         /* NORETURN */
 
@@ -222,7 +221,6 @@ static inline int handle_cpu_signal(uintptr_t pc, siginfo_t *info,
      * an exception.  Undo signal and retaddr state prior to longjmp.
      */
     sigprocmask(SIG_SETMASK, old_set, NULL);
-    clear_helper_retaddr();
 
     cc = CPU_GET_CLASS(cpu);
     cc->tcg_ops->tlb_fill(cpu, address, 0, access_type,
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [RFC PATCH 5/7] accel/tcg: Fold cpu_exit_tb_from_sighandler into caller
  2021-09-13 22:05 [RFC PATCH 0/7] linux-user: Streamline handling of SIGSEGV/SIGBUS Richard Henderson
                   ` (3 preceding siblings ...)
  2021-09-13 22:05 ` [RFC PATCH 4/7] accel/tcg: Move clear_helper_retaddr to cpu loop Richard Henderson
@ 2021-09-13 22:05 ` Richard Henderson
  2021-09-13 22:05 ` [RFC PATCH 6/7] linux-user: Handle SIGSEGV/SIGBUS in host_to_target_siginfo_noswap Richard Henderson
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 18+ messages in thread
From: Richard Henderson @ 2021-09-13 22:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, laurent, imp

Remove the comment about siglongjmp.  We do use sigsetjmp
in the main cpu loop, but we do not save the signal mask
as most exits from the cpu loop do not require them.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 accel/tcg/user-exec.c | 15 ++-------------
 1 file changed, 2 insertions(+), 13 deletions(-)

diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c
index 83351db719..ad6b4f6abf 100644
--- a/accel/tcg/user-exec.c
+++ b/accel/tcg/user-exec.c
@@ -46,17 +46,6 @@ __thread uintptr_t helper_retaddr;
 
 //#define DEBUG_SIGNAL
 
-/* exit the current TB from a signal handler. The host registers are
-   restored in a state compatible with the CPU emulator
- */
-static void QEMU_NORETURN cpu_exit_tb_from_sighandler(CPUState *cpu,
-                                                      sigset_t *old_set)
-{
-    /* XXX: use siglongjmp ? */
-    sigprocmask(SIG_SETMASK, old_set, NULL);
-    cpu_loop_exit_noexc(cpu);
-}
-
 /**
  * adjust_signal_pc:
  * @pc: raw pc from the host signal ucontext_t.
@@ -157,9 +146,9 @@ bool handle_sigsegv_accerr_write(CPUState *cpu, sigset_t *old_set,
          * currently executing TB was modified and must be exited
          * immediately.  Clear helper_retaddr for next execution.
          */
-        cpu_exit_tb_from_sighandler(cpu, old_set);
+        sigprocmask(SIG_SETMASK, old_set, NULL);
+        cpu_loop_exit_noexc(cpu);
         /* NORETURN */
-
     default:
         g_assert_not_reached();
     }
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [RFC PATCH 6/7] linux-user: Handle SIGSEGV/SIGBUS in host_to_target_siginfo_noswap
  2021-09-13 22:05 [RFC PATCH 0/7] linux-user: Streamline handling of SIGSEGV/SIGBUS Richard Henderson
                   ` (4 preceding siblings ...)
  2021-09-13 22:05 ` [RFC PATCH 5/7] accel/tcg: Fold cpu_exit_tb_from_sighandler into caller Richard Henderson
@ 2021-09-13 22:05 ` Richard Henderson
  2021-09-15 16:23   ` Warner Losh
  2021-09-13 22:05 ` [RFC PATCH 7/7] linux-user: Reorg cpu_signal_handler Richard Henderson
  2021-09-14  1:18 ` [RFC PATCH 0/7] linux-user: Streamline handling of SIGSEGV/SIGBUS Richard Henderson
  7 siblings, 1 reply; 18+ messages in thread
From: Richard Henderson @ 2021-09-13 22:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, laurent, imp

Remap the faulting address from the host address space into
the guest address space.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/signal.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/linux-user/signal.c b/linux-user/signal.c
index a8faea6f09..73c0f9066b 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -405,6 +405,15 @@ static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
             tinfo->_sifields._sigpoll._fd = info->si_fd;
             si_type = QEMU_SI_POLL;
             break;
+        case TARGET_SIGSEGV:
+        case TARGET_SIGBUS:
+            /*
+             * Remap the host address into the target space.
+             * Even an invalid guest address is still valid for a fault.
+             */
+            tinfo->_sifields._sigfault._addr = h2g_nocheck(info->si_addr);
+            si_type = QEMU_SI_FAULT;
+            break;
         default:
             /* Assume a sigqueue()/mq_notify()/rt_sigqueueinfo() source. */
             tinfo->_sifields._rt._pid = info->si_pid;
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [RFC PATCH 7/7] linux-user: Reorg cpu_signal_handler
  2021-09-13 22:05 [RFC PATCH 0/7] linux-user: Streamline handling of SIGSEGV/SIGBUS Richard Henderson
                   ` (5 preceding siblings ...)
  2021-09-13 22:05 ` [RFC PATCH 6/7] linux-user: Handle SIGSEGV/SIGBUS in host_to_target_siginfo_noswap Richard Henderson
@ 2021-09-13 22:05 ` Richard Henderson
  2021-09-15 16:43   ` Warner Losh
  2021-09-16  8:51   ` Philippe Mathieu-Daudé
  2021-09-14  1:18 ` [RFC PATCH 0/7] linux-user: Streamline handling of SIGSEGV/SIGBUS Richard Henderson
  7 siblings, 2 replies; 18+ messages in thread
From: Richard Henderson @ 2021-09-13 22:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, laurent, imp

Split out two functions into linux-user/host/arch/host-signal.h.
Since linux-user requires a linux host, drop all of the BSD and
Solaris ifdefs.  These should be recreated under bsd-user/ when
the current blanks there are filled.

Fold the remnants of handle_cpu_signal into host_signal_handler.

Drop the call to cc->tcg_ops->tlb_fill.  This was simply an indirect
method to raise SIGSEGV; it is far easier to pass the host siginfo_t
along to the guest.  This fixes all of the guest cpu_loop code that
currently fails to properly fill in SEGV_MAPERR vs SEGV_ACCERR.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/exec/exec-all.h               |  12 -
 linux-user/host/aarch64/host-signal.h |  73 +++
 linux-user/host/alpha/host-signal.h   |  41 ++
 linux-user/host/arm/host-signal.h     |  30 ++
 linux-user/host/i386/host-signal.h    |  24 +
 linux-user/host/mips/host-signal.h    |  61 +++
 linux-user/host/ppc/host-signal.h     |  24 +
 linux-user/host/ppc64/host-signal.h   |   1 +
 linux-user/host/riscv32/host-signal.h |  57 +++
 linux-user/host/riscv64/host-signal.h |   1 +
 linux-user/host/s390/host-signal.h    |  92 ++++
 linux-user/host/s390x/host-signal.h   |   1 +
 linux-user/host/sparc/host-signal.h   |  53 ++
 linux-user/host/sparc64/host-signal.h |   1 +
 linux-user/host/x86_64/host-signal.h  |  24 +
 accel/tcg/user-exec.c                 | 712 --------------------------
 linux-user/signal.c                   |  93 ++--
 17 files changed, 543 insertions(+), 757 deletions(-)
 create mode 100644 linux-user/host/aarch64/host-signal.h
 create mode 100644 linux-user/host/alpha/host-signal.h
 create mode 100644 linux-user/host/arm/host-signal.h
 create mode 100644 linux-user/host/i386/host-signal.h
 create mode 100644 linux-user/host/mips/host-signal.h
 create mode 100644 linux-user/host/ppc/host-signal.h
 create mode 100644 linux-user/host/ppc64/host-signal.h
 create mode 100644 linux-user/host/riscv32/host-signal.h
 create mode 100644 linux-user/host/riscv64/host-signal.h
 create mode 100644 linux-user/host/s390/host-signal.h
 create mode 100644 linux-user/host/s390x/host-signal.h
 create mode 100644 linux-user/host/sparc/host-signal.h
 create mode 100644 linux-user/host/sparc64/host-signal.h
 create mode 100644 linux-user/host/x86_64/host-signal.h

diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
index f582d3e688..addcec6381 100644
--- a/include/exec/exec-all.h
+++ b/include/exec/exec-all.h
@@ -683,18 +683,6 @@ uintptr_t adjust_signal_pc(uintptr_t pc);
 bool handle_sigsegv_accerr_write(CPUState *cpu, sigset_t *old_set,
                                  uintptr_t host_pc, uintptr_t host_addr);
 
-/**
- * cpu_signal_handler
- * @signum: host signal number
- * @pinfo: host siginfo_t
- * @puc: host ucontext_t
- *
- * To be called from the SIGBUS and SIGSEGV signal handler to inform the
- * virtual cpu of exceptions.  Returns true if the signal was handled by
- * the virtual CPU.
- */
-int cpu_signal_handler(int signum, void *pinfo, void *puc);
-
 #else
 static inline void mmap_lock(void) {}
 static inline void mmap_unlock(void) {}
diff --git a/linux-user/host/aarch64/host-signal.h b/linux-user/host/aarch64/host-signal.h
new file mode 100644
index 0000000000..818da17a21
--- /dev/null
+++ b/linux-user/host/aarch64/host-signal.h
@@ -0,0 +1,73 @@
+/*
+ * host-signal.h: signal info dependent on the host architecture
+ *
+ * Copyright (C) 2021 Linaro Limited
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef AARCH64_HOST_SIGNAL_H
+#define AARCH64_HOST_SIGNAL_H
+
+/* Pre-3.16 kernel headers don't have these, so provide fallback definitions */
+#ifndef ESR_MAGIC
+#define ESR_MAGIC 0x45535201
+struct esr_context {
+    struct _aarch64_ctx head;
+    uint64_t esr;
+};
+#endif
+
+static inline struct _aarch64_ctx *first_ctx(ucontext_t *uc)
+{
+    return (struct _aarch64_ctx *)&uc->uc_mcontext.__reserved;
+}
+
+static inline struct _aarch64_ctx *next_ctx(struct _aarch64_ctx *hdr)
+{
+    return (struct _aarch64_ctx *)((char *)hdr + hdr->size);
+}
+
+static inline uintptr_t host_signal_pc(ucontext_t *uc)
+{
+    return uc->uc_mcontext.pc;
+}
+
+static inline bool host_sigsegv_write(siginfo_t *info, ucontext_t *uc)
+{
+    struct _aarch64_ctx *hdr;
+    uint32_t insn;
+
+    /* Find the esr_context, which has the WnR bit in it */
+    for (hdr = first_ctx(uc); hdr->magic; hdr = next_ctx(hdr)) {
+        if (hdr->magic == ESR_MAGIC) {
+            struct esr_context const *esrctx = (struct esr_context const *)hdr;
+            uint64_t esr = esrctx->esr;
+
+            /* For data aborts ESR.EC is 0b10010x: then bit 6 is the WnR bit */
+            return extract32(esr, 27, 5) == 0x12 && extract32(esr, 6, 1) == 1;
+        }
+    }
+
+    /*
+     * Fall back to parsing instructions; will only be needed
+     * for really ancient (pre-3.16) kernels.
+     */
+    insn = *(uint32_t *)host_signal_pc(uc);
+
+    return (insn & 0xbfff0000) == 0x0c000000   /* C3.3.1 */
+        || (insn & 0xbfe00000) == 0x0c800000   /* C3.3.2 */
+        || (insn & 0xbfdf0000) == 0x0d000000   /* C3.3.3 */
+        || (insn & 0xbfc00000) == 0x0d800000   /* C3.3.4 */
+        || (insn & 0x3f400000) == 0x08000000   /* C3.3.6 */
+        || (insn & 0x3bc00000) == 0x39000000   /* C3.3.13 */
+        || (insn & 0x3fc00000) == 0x3d800000   /* ... 128bit */
+        /* Ignore bits 10, 11 & 21, controlling indexing.  */
+        || (insn & 0x3bc00000) == 0x38000000   /* C3.3.8-12 */
+        || (insn & 0x3fe00000) == 0x3c800000   /* ... 128bit */
+        /* Ignore bits 23 & 24, controlling indexing.  */
+        || (insn & 0x3a400000) == 0x28000000; /* C3.3.7,14-16 */
+}
+
+#endif
diff --git a/linux-user/host/alpha/host-signal.h b/linux-user/host/alpha/host-signal.h
new file mode 100644
index 0000000000..eaf83added
--- /dev/null
+++ b/linux-user/host/alpha/host-signal.h
@@ -0,0 +1,41 @@
+/*
+ * host-signal.h: signal info dependent on the host architecture
+ *
+ * Copyright (C) 2021 Linaro Limited
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef ALPHA_HOST_SIGNAL_H
+#define ALPHA_HOST_SIGNAL_H
+
+static inline uintptr_t host_signal_pc(ucontext_t *uc)
+{
+    return uc->uc_mcontext.sc_pc;
+}
+
+static inline bool host_sigsegv_write(siginfo_t *info, ucontext_t *uc)
+{
+    uint32_t *pc = uc->uc_mcontext.sc_pc;
+    uint32_t insn = *pc;
+
+    /* XXX: need kernel patch to get write flag faster */
+    switch (insn >> 26) {
+    case 0x0d: /* stw */
+    case 0x0e: /* stb */
+    case 0x0f: /* stq_u */
+    case 0x24: /* stf */
+    case 0x25: /* stg */
+    case 0x26: /* sts */
+    case 0x27: /* stt */
+    case 0x2c: /* stl */
+    case 0x2d: /* stq */
+    case 0x2e: /* stl_c */
+    case 0x2f: /* stq_c */
+        return true;
+    }
+    return false;
+}
+
+#endif
diff --git a/linux-user/host/arm/host-signal.h b/linux-user/host/arm/host-signal.h
new file mode 100644
index 0000000000..ae6bcde6c1
--- /dev/null
+++ b/linux-user/host/arm/host-signal.h
@@ -0,0 +1,30 @@
+/*
+ * host-signal.h: signal info dependent on the host architecture
+ *
+ * Copyright (C) 2021 Linaro Limited
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef ARM_HOST_SIGNAL_H
+#define ARM_HOST_SIGNAL_H
+
+static inline uintptr_t host_signal_pc(ucontext_t *uc)
+{
+    return uc->uc_mcontext.gregs[R15];
+}
+
+static inline bool host_sigsegv_write(siginfo_t *info, ucontext_t *uc,
+                                      uintptr_t pc)
+{
+    /*
+     * In the FSR, bit 11 is WnR, assuming a v6 or
+     * later processor.  On v5 we will always report
+     * this as a read, which will fail later.
+     */
+    uint32_t fsr = uc->uc_mcontext.error_code;
+    return extract32(fsr, 11, 1);
+}
+
+#endif
diff --git a/linux-user/host/i386/host-signal.h b/linux-user/host/i386/host-signal.h
new file mode 100644
index 0000000000..a8ca5e4a89
--- /dev/null
+++ b/linux-user/host/i386/host-signal.h
@@ -0,0 +1,24 @@
+/*
+ * host-signal.h: signal info dependent on the host architecture
+ *
+ * Copyright (C) 2021 Linaro Limited
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef I386_HOST_SIGNAL_H
+#define I386_HOST_SIGNAL_H
+
+static inline uintptr_t host_signal_pc(ucontext_t *uc)
+{
+    return uc->uc_mcontext.gregs[REG_EIP];
+}
+
+static inline bool host_sigsegv_write(siginfo_t *info, ucontext_t *uc)
+{
+    return uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe
+        && (uc->uc_mcontext.gregs[REG_ERR] & 0x2);
+}
+
+#endif
diff --git a/linux-user/host/mips/host-signal.h b/linux-user/host/mips/host-signal.h
new file mode 100644
index 0000000000..815bbd61fa
--- /dev/null
+++ b/linux-user/host/mips/host-signal.h
@@ -0,0 +1,61 @@
+/*
+ * host-signal.h: signal info dependent on the host architecture
+ *
+ * Copyright (C) 2021 Linaro Limited
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef MIPS_HOST_SIGNAL_H
+#define MIPS_HOST_SIGNAL_H
+
+static inline uintptr_t host_signal_pc(ucontext_t *uc)
+{
+    return uc->uc_mcontext.pc;
+}
+
+#if defined(__misp16) || defined(__mips_micromips)
+#error "Unsupported encoding"
+#endif
+
+static inline bool host_sigsegv_write(siginfo_t *info, ucontext_t *uc)
+{
+    uint32_t *insn = *(uint32_t *)host_signal_pc(uc);
+
+    /* Detect all store instructions at program counter. */
+    switch ((insn >> 26) & 077) {
+    case 050: /* SB */
+    case 051: /* SH */
+    case 052: /* SWL */
+    case 053: /* SW */
+    case 054: /* SDL */
+    case 055: /* SDR */
+    case 056: /* SWR */
+    case 070: /* SC */
+    case 071: /* SWC1 */
+    case 074: /* SCD */
+    case 075: /* SDC1 */
+    case 077: /* SD */
+#if !defined(__mips_isa_rev) || __mips_isa_rev < 6
+    case 072: /* SWC2 */
+    case 076: /* SDC2 */
+#endif
+        return true;
+    case 023: /* COP1X */
+        /*
+         * Required in all versions of MIPS64 since
+         * MIPS64r1 and subsequent versions of MIPS32r2.
+         */
+        switch (insn & 077) {
+        case 010: /* SWXC1 */
+        case 011: /* SDXC1 */
+        case 015: /* SUXC1 */
+            return true;
+        }
+        break;
+    }
+    return false;
+}
+
+#endif
diff --git a/linux-user/host/ppc/host-signal.h b/linux-user/host/ppc/host-signal.h
new file mode 100644
index 0000000000..b8dce622b4
--- /dev/null
+++ b/linux-user/host/ppc/host-signal.h
@@ -0,0 +1,24 @@
+/*
+ * host-signal.h: signal info dependent on the host architecture
+ *
+ * Copyright (C) 2021 Linaro Limited
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef PPC_HOST_SIGNAL_H
+#define PPC_HOST_SIGNAL_H
+
+static inline uintptr_t host_signal_pc(ucontext_t *uc)
+{
+    return uc->uc_mcontext.regs->nip;
+}
+
+static inline bool host_sigsegv_write(siginfo_t *info, ucontext_t *uc)
+{
+    return uc->uc_mcontext.regs->trap != 0x400
+        && (uc->uc_mcontext.regs->dsisr & 0x02000000);
+}
+
+#endif
diff --git a/linux-user/host/ppc64/host-signal.h b/linux-user/host/ppc64/host-signal.h
new file mode 100644
index 0000000000..a353c22a90
--- /dev/null
+++ b/linux-user/host/ppc64/host-signal.h
@@ -0,0 +1 @@
+#include "../ppc/host-signal.h"
diff --git a/linux-user/host/riscv32/host-signal.h b/linux-user/host/riscv32/host-signal.h
new file mode 100644
index 0000000000..f877412f96
--- /dev/null
+++ b/linux-user/host/riscv32/host-signal.h
@@ -0,0 +1,57 @@
+/*
+ * host-signal.h: signal info dependent on the host architecture
+ *
+ * Copyright (C) 2021 Linaro Limited
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef RISCV_HOST_SIGNAL_H
+#define RISCV_HOST_SIGNAL_H
+
+static inline uintptr_t host_signal_pc(ucontext_t *uc)
+{
+    return uc->uc_mcontext.__gregs[REG_PC];
+}
+
+static inline bool host_sigsegv_write(siginfo_t *info, ucontext_t *uc)
+{
+    /*
+     * Detect store by reading the instruction at the program counter.
+     * Do not read more than 16 bits, because we have not yet determined
+     * the size of the instruction.
+     */
+    const uint16_t *pinsn = (const uint16_t *)host_signal_pc(uc);
+    uint16_t insn = pinsn[0];
+
+    /* 16-bit instructions */
+    switch (insn & 0xe003) {
+    case 0xa000: /* c.fsd */
+    case 0xc000: /* c.sw */
+    case 0xe000: /* c.sd (rv64) / c.fsw (rv32) */
+    case 0xa002: /* c.fsdsp */
+    case 0xc002: /* c.swsp */
+    case 0xe002: /* c.sdsp (rv64) / c.fswsp (rv32) */
+        return true;
+    }
+
+    /* 32-bit instructions, major opcodes */
+    switch (insn & 0x7f) {
+    case 0x23: /* store */
+    case 0x27: /* store-fp */
+        return true;
+    case 0x2f: /* amo */
+        /*
+         * The AMO function code is in bits 25-31, unread as yet.
+         * The AMO functions are LR (read), SC (write), and the
+         * rest are all read-modify-write.
+         */
+        insn = pinsn[1];
+        return (insn >> 11) != 2; /* LR */
+    }
+
+    return false;
+}
+
+#endif
diff --git a/linux-user/host/riscv64/host-signal.h b/linux-user/host/riscv64/host-signal.h
new file mode 100644
index 0000000000..6e27f725ab
--- /dev/null
+++ b/linux-user/host/riscv64/host-signal.h
@@ -0,0 +1 @@
+#include "../riscv32/host-signal.h"
diff --git a/linux-user/host/s390/host-signal.h b/linux-user/host/s390/host-signal.h
new file mode 100644
index 0000000000..8d34b32b9f
--- /dev/null
+++ b/linux-user/host/s390/host-signal.h
@@ -0,0 +1,92 @@
+/*
+ * host-signal.h: signal info dependent on the host architecture
+ *
+ * Copyright (C) 2021 Linaro Limited
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef S390_HOST_SIGNAL_H
+#define S390_HOST_SIGNAL_H
+
+static inline uintptr_t host_signal_pc(ucontext_t *uc)
+{
+    return uc->uc_mcontext.psw.addr;
+}
+
+static inline bool host_sigsegv_write(siginfo_t *info, ucontext_t *uc)
+{
+    uint16_t *pinsn = (uint16_t *)host_signal_pc(uc);
+
+    /*
+     * ??? On linux, the non-rt signal handler has 4 (!) arguments instead
+     * of the normal 2 arguments.  The 4th argument contains the "Translation-
+     * Exception Identification for DAT Exceptions" from the hardware (aka
+     * "int_parm_long"), which does in fact contain the is_write value.
+     * The rt signal handler, as far as I can tell, does not give this value
+     * at all.  Not that we could get to it from here even if it were.
+     * So fall back to parsing instructions.  Treat read-modify-write ones as
+     * writes, which is not fully correct, but for tracking self-modifying code
+     * this is better than treating them as reads.  Checking si_addr page flags
+     * might be a viable improvement, albeit a racy one.
+     */
+    /* ??? This is not even close to complete.  */
+    switch (pinsn[0] >> 8) {
+    case 0x50: /* ST */
+    case 0x42: /* STC */
+    case 0x40: /* STH */
+    case 0xba: /* CS */
+    case 0xbb: /* CDS */
+        return true;
+    case 0xc4: /* RIL format insns */
+        switch (pinsn[0] & 0xf) {
+        case 0xf: /* STRL */
+        case 0xb: /* STGRL */
+        case 0x7: /* STHRL */
+            return true;
+        }
+        break;
+    case 0xc8: /* SSF format insns */
+        switch (pinsn[0] & 0xf) {
+        case 0x2: /* CSST */
+            return true;
+        }
+        break;
+    case 0xe3: /* RXY format insns */
+        switch (pinsn[2] & 0xff) {
+        case 0x50: /* STY */
+        case 0x24: /* STG */
+        case 0x72: /* STCY */
+        case 0x70: /* STHY */
+        case 0x8e: /* STPQ */
+        case 0x3f: /* STRVH */
+        case 0x3e: /* STRV */
+        case 0x2f: /* STRVG */
+            return true;
+        }
+        break;
+    case 0xeb: /* RSY format insns */
+        switch (pinsn[2] & 0xff) {
+        case 0x14: /* CSY */
+        case 0x30: /* CSG */
+        case 0x31: /* CDSY */
+        case 0x3e: /* CDSG */
+        case 0xe4: /* LANG */
+        case 0xe6: /* LAOG */
+        case 0xe7: /* LAXG */
+        case 0xe8: /* LAAG */
+        case 0xea: /* LAALG */
+        case 0xf4: /* LAN */
+        case 0xf6: /* LAO */
+        case 0xf7: /* LAX */
+        case 0xfa: /* LAAL */
+        case 0xf8: /* LAA */
+            return true;
+        }
+        break;
+    }
+    return false;
+}
+
+#endif
diff --git a/linux-user/host/s390x/host-signal.h b/linux-user/host/s390x/host-signal.h
new file mode 100644
index 0000000000..0e83f9358d
--- /dev/null
+++ b/linux-user/host/s390x/host-signal.h
@@ -0,0 +1 @@
+#include "../s390/host-signal.h"
diff --git a/linux-user/host/sparc/host-signal.h b/linux-user/host/sparc/host-signal.h
new file mode 100644
index 0000000000..47d3b1512e
--- /dev/null
+++ b/linux-user/host/sparc/host-signal.h
@@ -0,0 +1,53 @@
+/*
+ * host-signal.h: signal info dependent on the host architecture
+ *
+ * Copyright (C) 2021 Linaro Limited
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef SPARC_HOST_SIGNAL_H
+#define SPARC_HOST_SIGNAL_H
+
+static inline uintptr_t host_signal_pc(ucontext_t *uc)
+{
+#ifdef __arch64__
+    return uc->uc_mcontext.mc_gregs[MC_PC];
+#else
+    return uc->uc_mcontext.gregs[REG_PC];
+#endif
+}
+
+static inline bool host_sigsegv_write(siginfo_t *info, ucontext_t *uc)
+{
+    uint32_t insn = *(uint32_t *)host_signal_pc(uc);
+
+    if ((insn >> 30) == 3) {
+        switch ((insn >> 19) & 0x3f) {
+        case 0x05: /* stb */
+        case 0x15: /* stba */
+        case 0x06: /* sth */
+        case 0x16: /* stha */
+        case 0x04: /* st */
+        case 0x14: /* sta */
+        case 0x07: /* std */
+        case 0x17: /* stda */
+        case 0x0e: /* stx */
+        case 0x1e: /* stxa */
+        case 0x24: /* stf */
+        case 0x34: /* stfa */
+        case 0x27: /* stdf */
+        case 0x37: /* stdfa */
+        case 0x26: /* stqf */
+        case 0x36: /* stqfa */
+        case 0x25: /* stfsr */
+        case 0x3c: /* casa */
+        case 0x3e: /* casxa */
+            return true;
+        }
+    }
+    return false;
+}
+
+#endif
diff --git a/linux-user/host/sparc64/host-signal.h b/linux-user/host/sparc64/host-signal.h
new file mode 100644
index 0000000000..1191fe2d40
--- /dev/null
+++ b/linux-user/host/sparc64/host-signal.h
@@ -0,0 +1 @@
+#include "../sparc/host-signal.h"
diff --git a/linux-user/host/x86_64/host-signal.h b/linux-user/host/x86_64/host-signal.h
new file mode 100644
index 0000000000..d5fb3e4484
--- /dev/null
+++ b/linux-user/host/x86_64/host-signal.h
@@ -0,0 +1,24 @@
+/*
+ * host-signal.h: signal info dependent on the host architecture
+ *
+ * Copyright (C) 2021 Linaro Limited
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef X86_64_HOST_SIGNAL_H
+#define X86_64_HOST_SIGNAL_H
+
+static inline uintptr_t host_signal_pc(ucontext_t *uc)
+{
+    return uc->uc_mcontext.gregs[REG_RIP];
+}
+
+static inline bool host_sigsegv_write(siginfo_t *info, ucontext_t *uc)
+{
+    return uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe
+        && (uc->uc_mcontext.gregs[REG_ERR] & 0x2);
+}
+
+#endif
diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c
index ad6b4f6abf..39635cbea2 100644
--- a/accel/tcg/user-exec.c
+++ b/accel/tcg/user-exec.c
@@ -29,23 +29,8 @@
 #include "trace/trace-root.h"
 #include "trace/mem.h"
 
-#undef EAX
-#undef ECX
-#undef EDX
-#undef EBX
-#undef ESP
-#undef EBP
-#undef ESI
-#undef EDI
-#undef EIP
-#ifdef __linux__
-#include <sys/ucontext.h>
-#endif
-
 __thread uintptr_t helper_retaddr;
 
-//#define DEBUG_SIGNAL
-
 /**
  * adjust_signal_pc:
  * @pc: raw pc from the host signal ucontext_t.
@@ -154,69 +139,6 @@ bool handle_sigsegv_accerr_write(CPUState *cpu, sigset_t *old_set,
     }
 }
 
-/* 'pc' is the host PC at which the exception was raised. 'address' is
-   the effective address of the memory exception. 'is_write' is 1 if a
-   write caused the exception and otherwise 0'. 'old_set' is the
-   signal set which should be restored */
-static inline int handle_cpu_signal(uintptr_t pc, siginfo_t *info,
-                                    int is_write, sigset_t *old_set)
-{
-    CPUState *cpu = current_cpu;
-    CPUClass *cc;
-    unsigned long address = (unsigned long)info->si_addr;
-    MMUAccessType access_type;
-
-    if (is_write) {
-        access_type = MMU_DATA_STORE;
-    } else if (helper_retaddr == 1) {
-        access_type = MMU_INST_FETCH;
-    } else {
-        access_type = MMU_DATA_LOAD;
-    }
-    pc = adjust_signal_pc(pc);
-
-    /* For synchronous signals we expect to be coming from the vCPU
-     * thread (so current_cpu should be valid) and either from running
-     * code or during translation which can fault as we cross pages.
-     *
-     * If neither is true then something has gone wrong and we should
-     * abort rather than try and restart the vCPU execution.
-     */
-    if (!cpu || !cpu->running) {
-        printf("qemu:%s received signal outside vCPU context @ pc=0x%"
-               PRIxPTR "\n",  __func__, pc);
-        abort();
-    }
-
-#if defined(DEBUG_SIGNAL)
-    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
-           pc, address, is_write, *(unsigned long *)old_set);
-#endif
-
-    /* XXX: locking issue */
-    if (is_write &&
-        info->si_signo == SIGSEGV &&
-        info->si_code == SEGV_ACCERR &&
-        handle_sigsegv_accerr_write(cpu, old_set, pc, address)) {
-        return 1;
-    }
-
-    /* Convert forcefully to guest address space, invalid addresses
-       are still valid segv ones */
-    address = h2g_nocheck(address);
-
-    /*
-     * There is no way the target can handle this other than raising
-     * an exception.  Undo signal and retaddr state prior to longjmp.
-     */
-    sigprocmask(SIG_SETMASK, old_set, NULL);
-
-    cc = CPU_GET_CLASS(cpu);
-    cc->tcg_ops->tlb_fill(cpu, address, 0, access_type,
-                          MMU_USER_IDX, false, pc);
-    g_assert_not_reached();
-}
-
 static int probe_access_internal(CPUArchState *env, target_ulong addr,
                                  int fault_size, MMUAccessType access_type,
                                  bool nonfault, uintptr_t ra)
@@ -275,640 +197,6 @@ void *probe_access(CPUArchState *env, target_ulong addr, int size,
     return size ? g2h(env_cpu(env), addr) : NULL;
 }
 
-#if defined(__i386__)
-
-#if defined(__NetBSD__)
-#include <ucontext.h>
-#include <machine/trap.h>
-
-#define EIP_sig(context)     ((context)->uc_mcontext.__gregs[_REG_EIP])
-#define TRAP_sig(context)    ((context)->uc_mcontext.__gregs[_REG_TRAPNO])
-#define ERROR_sig(context)   ((context)->uc_mcontext.__gregs[_REG_ERR])
-#define MASK_sig(context)    ((context)->uc_sigmask)
-#define PAGE_FAULT_TRAP      T_PAGEFLT
-#elif defined(__FreeBSD__) || defined(__DragonFly__)
-#include <ucontext.h>
-#include <machine/trap.h>
-
-#define EIP_sig(context)  (*((unsigned long *)&(context)->uc_mcontext.mc_eip))
-#define TRAP_sig(context)    ((context)->uc_mcontext.mc_trapno)
-#define ERROR_sig(context)   ((context)->uc_mcontext.mc_err)
-#define MASK_sig(context)    ((context)->uc_sigmask)
-#define PAGE_FAULT_TRAP      T_PAGEFLT
-#elif defined(__OpenBSD__)
-#include <machine/trap.h>
-#define EIP_sig(context)     ((context)->sc_eip)
-#define TRAP_sig(context)    ((context)->sc_trapno)
-#define ERROR_sig(context)   ((context)->sc_err)
-#define MASK_sig(context)    ((context)->sc_mask)
-#define PAGE_FAULT_TRAP      T_PAGEFLT
-#else
-#define EIP_sig(context)     ((context)->uc_mcontext.gregs[REG_EIP])
-#define TRAP_sig(context)    ((context)->uc_mcontext.gregs[REG_TRAPNO])
-#define ERROR_sig(context)   ((context)->uc_mcontext.gregs[REG_ERR])
-#define MASK_sig(context)    ((context)->uc_sigmask)
-#define PAGE_FAULT_TRAP      0xe
-#endif
-
-int cpu_signal_handler(int host_signum, void *pinfo,
-                       void *puc)
-{
-    siginfo_t *info = pinfo;
-#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
-    ucontext_t *uc = puc;
-#elif defined(__OpenBSD__)
-    struct sigcontext *uc = puc;
-#else
-    ucontext_t *uc = puc;
-#endif
-    unsigned long pc;
-    int trapno;
-
-#ifndef REG_EIP
-/* for glibc 2.1 */
-#define REG_EIP    EIP
-#define REG_ERR    ERR
-#define REG_TRAPNO TRAPNO
-#endif
-    pc = EIP_sig(uc);
-    trapno = TRAP_sig(uc);
-    return handle_cpu_signal(pc, info,
-                             trapno == PAGE_FAULT_TRAP ?
-                             (ERROR_sig(uc) >> 1) & 1 : 0,
-                             &MASK_sig(uc));
-}
-
-#elif defined(__x86_64__)
-
-#ifdef __NetBSD__
-#include <machine/trap.h>
-#define PC_sig(context)       _UC_MACHINE_PC(context)
-#define TRAP_sig(context)     ((context)->uc_mcontext.__gregs[_REG_TRAPNO])
-#define ERROR_sig(context)    ((context)->uc_mcontext.__gregs[_REG_ERR])
-#define MASK_sig(context)     ((context)->uc_sigmask)
-#define PAGE_FAULT_TRAP       T_PAGEFLT
-#elif defined(__OpenBSD__)
-#include <machine/trap.h>
-#define PC_sig(context)       ((context)->sc_rip)
-#define TRAP_sig(context)     ((context)->sc_trapno)
-#define ERROR_sig(context)    ((context)->sc_err)
-#define MASK_sig(context)     ((context)->sc_mask)
-#define PAGE_FAULT_TRAP       T_PAGEFLT
-#elif defined(__FreeBSD__) || defined(__DragonFly__)
-#include <ucontext.h>
-#include <machine/trap.h>
-
-#define PC_sig(context)  (*((unsigned long *)&(context)->uc_mcontext.mc_rip))
-#define TRAP_sig(context)     ((context)->uc_mcontext.mc_trapno)
-#define ERROR_sig(context)    ((context)->uc_mcontext.mc_err)
-#define MASK_sig(context)     ((context)->uc_sigmask)
-#define PAGE_FAULT_TRAP       T_PAGEFLT
-#else
-#define PC_sig(context)       ((context)->uc_mcontext.gregs[REG_RIP])
-#define TRAP_sig(context)     ((context)->uc_mcontext.gregs[REG_TRAPNO])
-#define ERROR_sig(context)    ((context)->uc_mcontext.gregs[REG_ERR])
-#define MASK_sig(context)     ((context)->uc_sigmask)
-#define PAGE_FAULT_TRAP       0xe
-#endif
-
-int cpu_signal_handler(int host_signum, void *pinfo,
-                       void *puc)
-{
-    siginfo_t *info = pinfo;
-    unsigned long pc;
-#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
-    ucontext_t *uc = puc;
-#elif defined(__OpenBSD__)
-    struct sigcontext *uc = puc;
-#else
-    ucontext_t *uc = puc;
-#endif
-
-    pc = PC_sig(uc);
-    return handle_cpu_signal(pc, info,
-                             TRAP_sig(uc) == PAGE_FAULT_TRAP ?
-                             (ERROR_sig(uc) >> 1) & 1 : 0,
-                             &MASK_sig(uc));
-}
-
-#elif defined(_ARCH_PPC)
-
-/***********************************************************************
- * signal context platform-specific definitions
- * From Wine
- */
-#ifdef linux
-/* All Registers access - only for local access */
-#define REG_sig(reg_name, context)              \
-    ((context)->uc_mcontext.regs->reg_name)
-/* Gpr Registers access  */
-#define GPR_sig(reg_num, context)              REG_sig(gpr[reg_num], context)
-/* Program counter */
-#define IAR_sig(context)                       REG_sig(nip, context)
-/* Machine State Register (Supervisor) */
-#define MSR_sig(context)                       REG_sig(msr, context)
-/* Count register */
-#define CTR_sig(context)                       REG_sig(ctr, context)
-/* User's integer exception register */
-#define XER_sig(context)                       REG_sig(xer, context)
-/* Link register */
-#define LR_sig(context)                        REG_sig(link, context)
-/* Condition register */
-#define CR_sig(context)                        REG_sig(ccr, context)
-
-/* Float Registers access  */
-#define FLOAT_sig(reg_num, context)                                     \
-    (((double *)((char *)((context)->uc_mcontext.regs + 48 * 4)))[reg_num])
-#define FPSCR_sig(context) \
-    (*(int *)((char *)((context)->uc_mcontext.regs + (48 + 32 * 2) * 4)))
-/* Exception Registers access */
-#define DAR_sig(context)                       REG_sig(dar, context)
-#define DSISR_sig(context)                     REG_sig(dsisr, context)
-#define TRAP_sig(context)                      REG_sig(trap, context)
-#endif /* linux */
-
-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
-#include <ucontext.h>
-#define IAR_sig(context)               ((context)->uc_mcontext.mc_srr0)
-#define MSR_sig(context)               ((context)->uc_mcontext.mc_srr1)
-#define CTR_sig(context)               ((context)->uc_mcontext.mc_ctr)
-#define XER_sig(context)               ((context)->uc_mcontext.mc_xer)
-#define LR_sig(context)                ((context)->uc_mcontext.mc_lr)
-#define CR_sig(context)                ((context)->uc_mcontext.mc_cr)
-/* Exception Registers access */
-#define DAR_sig(context)               ((context)->uc_mcontext.mc_dar)
-#define DSISR_sig(context)             ((context)->uc_mcontext.mc_dsisr)
-#define TRAP_sig(context)              ((context)->uc_mcontext.mc_exc)
-#endif /* __FreeBSD__|| __FreeBSD_kernel__ */
-
-int cpu_signal_handler(int host_signum, void *pinfo,
-                       void *puc)
-{
-    siginfo_t *info = pinfo;
-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
-    ucontext_t *uc = puc;
-#else
-    ucontext_t *uc = puc;
-#endif
-    unsigned long pc;
-    int is_write;
-
-    pc = IAR_sig(uc);
-    is_write = 0;
-#if 0
-    /* ppc 4xx case */
-    if (DSISR_sig(uc) & 0x00800000) {
-        is_write = 1;
-    }
-#else
-    if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000)) {
-        is_write = 1;
-    }
-#endif
-    return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
-}
-
-#elif defined(__alpha__)
-
-int cpu_signal_handler(int host_signum, void *pinfo,
-                           void *puc)
-{
-    siginfo_t *info = pinfo;
-    ucontext_t *uc = puc;
-    uint32_t *pc = uc->uc_mcontext.sc_pc;
-    uint32_t insn = *pc;
-    int is_write = 0;
-
-    /* XXX: need kernel patch to get write flag faster */
-    switch (insn >> 26) {
-    case 0x0d: /* stw */
-    case 0x0e: /* stb */
-    case 0x0f: /* stq_u */
-    case 0x24: /* stf */
-    case 0x25: /* stg */
-    case 0x26: /* sts */
-    case 0x27: /* stt */
-    case 0x2c: /* stl */
-    case 0x2d: /* stq */
-    case 0x2e: /* stl_c */
-    case 0x2f: /* stq_c */
-        is_write = 1;
-    }
-
-    return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
-}
-#elif defined(__sparc__)
-
-int cpu_signal_handler(int host_signum, void *pinfo,
-                       void *puc)
-{
-    siginfo_t *info = pinfo;
-    int is_write;
-    uint32_t insn;
-#if !defined(__arch64__) || defined(CONFIG_SOLARIS)
-    uint32_t *regs = (uint32_t *)(info + 1);
-    void *sigmask = (regs + 20);
-    /* XXX: is there a standard glibc define ? */
-    unsigned long pc = regs[1];
-#else
-#ifdef __linux__
-    struct sigcontext *sc = puc;
-    unsigned long pc = sc->sigc_regs.tpc;
-    void *sigmask = (void *)sc->sigc_mask;
-#elif defined(__OpenBSD__)
-    struct sigcontext *uc = puc;
-    unsigned long pc = uc->sc_pc;
-    void *sigmask = (void *)(long)uc->sc_mask;
-#elif defined(__NetBSD__)
-    ucontext_t *uc = puc;
-    unsigned long pc = _UC_MACHINE_PC(uc);
-    void *sigmask = (void *)&uc->uc_sigmask;
-#endif
-#endif
-
-    /* XXX: need kernel patch to get write flag faster */
-    is_write = 0;
-    insn = *(uint32_t *)pc;
-    if ((insn >> 30) == 3) {
-        switch ((insn >> 19) & 0x3f) {
-        case 0x05: /* stb */
-        case 0x15: /* stba */
-        case 0x06: /* sth */
-        case 0x16: /* stha */
-        case 0x04: /* st */
-        case 0x14: /* sta */
-        case 0x07: /* std */
-        case 0x17: /* stda */
-        case 0x0e: /* stx */
-        case 0x1e: /* stxa */
-        case 0x24: /* stf */
-        case 0x34: /* stfa */
-        case 0x27: /* stdf */
-        case 0x37: /* stdfa */
-        case 0x26: /* stqf */
-        case 0x36: /* stqfa */
-        case 0x25: /* stfsr */
-        case 0x3c: /* casa */
-        case 0x3e: /* casxa */
-            is_write = 1;
-            break;
-        }
-    }
-    return handle_cpu_signal(pc, info, is_write, sigmask);
-}
-
-#elif defined(__arm__)
-
-#if defined(__NetBSD__)
-#include <ucontext.h>
-#include <sys/siginfo.h>
-#endif
-
-int cpu_signal_handler(int host_signum, void *pinfo,
-                       void *puc)
-{
-    siginfo_t *info = pinfo;
-#if defined(__NetBSD__)
-    ucontext_t *uc = puc;
-    siginfo_t *si = pinfo;
-#else
-    ucontext_t *uc = puc;
-#endif
-    unsigned long pc;
-    uint32_t fsr;
-    int is_write;
-
-#if defined(__NetBSD__)
-    pc = uc->uc_mcontext.__gregs[_REG_R15];
-#elif defined(__GLIBC__) && (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
-    pc = uc->uc_mcontext.gregs[R15];
-#else
-    pc = uc->uc_mcontext.arm_pc;
-#endif
-
-#ifdef __NetBSD__
-    fsr = si->si_trap;
-#else
-    fsr = uc->uc_mcontext.error_code;
-#endif
-    /*
-     * In the FSR, bit 11 is WnR, assuming a v6 or
-     * later processor.  On v5 we will always report
-     * this as a read, which will fail later.
-     */
-    is_write = extract32(fsr, 11, 1);
-    return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
-}
-
-#elif defined(__aarch64__)
-
-#if defined(__NetBSD__)
-
-#include <ucontext.h>
-#include <sys/siginfo.h>
-
-int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
-{
-    ucontext_t *uc = puc;
-    siginfo_t *si = pinfo;
-    unsigned long pc;
-    int is_write;
-    uint32_t esr;
-
-    pc = uc->uc_mcontext.__gregs[_REG_PC];
-    esr = si->si_trap;
-
-    /*
-     * siginfo_t::si_trap is the ESR value, for data aborts ESR.EC
-     * is 0b10010x: then bit 6 is the WnR bit
-     */
-    is_write = extract32(esr, 27, 5) == 0x12 && extract32(esr, 6, 1) == 1;
-    return handle_cpu_signal(pc, si, is_write, &uc->uc_sigmask);
-}
-
-#else
-
-#ifndef ESR_MAGIC
-/* Pre-3.16 kernel headers don't have these, so provide fallback definitions */
-#define ESR_MAGIC 0x45535201
-struct esr_context {
-    struct _aarch64_ctx head;
-    uint64_t esr;
-};
-#endif
-
-static inline struct _aarch64_ctx *first_ctx(ucontext_t *uc)
-{
-    return (struct _aarch64_ctx *)&uc->uc_mcontext.__reserved;
-}
-
-static inline struct _aarch64_ctx *next_ctx(struct _aarch64_ctx *hdr)
-{
-    return (struct _aarch64_ctx *)((char *)hdr + hdr->size);
-}
-
-int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
-{
-    siginfo_t *info = pinfo;
-    ucontext_t *uc = puc;
-    uintptr_t pc = uc->uc_mcontext.pc;
-    bool is_write;
-    struct _aarch64_ctx *hdr;
-    struct esr_context const *esrctx = NULL;
-
-    /* Find the esr_context, which has the WnR bit in it */
-    for (hdr = first_ctx(uc); hdr->magic; hdr = next_ctx(hdr)) {
-        if (hdr->magic == ESR_MAGIC) {
-            esrctx = (struct esr_context const *)hdr;
-            break;
-        }
-    }
-
-    if (esrctx) {
-        /* For data aborts ESR.EC is 0b10010x: then bit 6 is the WnR bit */
-        uint64_t esr = esrctx->esr;
-        is_write = extract32(esr, 27, 5) == 0x12 && extract32(esr, 6, 1) == 1;
-    } else {
-        /*
-         * Fall back to parsing instructions; will only be needed
-         * for really ancient (pre-3.16) kernels.
-         */
-        uint32_t insn = *(uint32_t *)pc;
-
-        is_write = ((insn & 0xbfff0000) == 0x0c000000   /* C3.3.1 */
-                    || (insn & 0xbfe00000) == 0x0c800000   /* C3.3.2 */
-                    || (insn & 0xbfdf0000) == 0x0d000000   /* C3.3.3 */
-                    || (insn & 0xbfc00000) == 0x0d800000   /* C3.3.4 */
-                    || (insn & 0x3f400000) == 0x08000000   /* C3.3.6 */
-                    || (insn & 0x3bc00000) == 0x39000000   /* C3.3.13 */
-                    || (insn & 0x3fc00000) == 0x3d800000   /* ... 128bit */
-                    /* Ignore bits 10, 11 & 21, controlling indexing.  */
-                    || (insn & 0x3bc00000) == 0x38000000   /* C3.3.8-12 */
-                    || (insn & 0x3fe00000) == 0x3c800000   /* ... 128bit */
-                    /* Ignore bits 23 & 24, controlling indexing.  */
-                    || (insn & 0x3a400000) == 0x28000000); /* C3.3.7,14-16 */
-    }
-    return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
-}
-#endif
-
-#elif defined(__s390__)
-
-int cpu_signal_handler(int host_signum, void *pinfo,
-                       void *puc)
-{
-    siginfo_t *info = pinfo;
-    ucontext_t *uc = puc;
-    unsigned long pc;
-    uint16_t *pinsn;
-    int is_write = 0;
-
-    pc = uc->uc_mcontext.psw.addr;
-
-    /*
-     * ??? On linux, the non-rt signal handler has 4 (!) arguments instead
-     * of the normal 2 arguments.  The 4th argument contains the "Translation-
-     * Exception Identification for DAT Exceptions" from the hardware (aka
-     * "int_parm_long"), which does in fact contain the is_write value.
-     * The rt signal handler, as far as I can tell, does not give this value
-     * at all.  Not that we could get to it from here even if it were.
-     * So fall back to parsing instructions.  Treat read-modify-write ones as
-     * writes, which is not fully correct, but for tracking self-modifying code
-     * this is better than treating them as reads.  Checking si_addr page flags
-     * might be a viable improvement, albeit a racy one.
-     */
-    /* ??? This is not even close to complete.  */
-    pinsn = (uint16_t *)pc;
-    switch (pinsn[0] >> 8) {
-    case 0x50: /* ST */
-    case 0x42: /* STC */
-    case 0x40: /* STH */
-    case 0xba: /* CS */
-    case 0xbb: /* CDS */
-        is_write = 1;
-        break;
-    case 0xc4: /* RIL format insns */
-        switch (pinsn[0] & 0xf) {
-        case 0xf: /* STRL */
-        case 0xb: /* STGRL */
-        case 0x7: /* STHRL */
-            is_write = 1;
-        }
-        break;
-    case 0xc8: /* SSF format insns */
-        switch (pinsn[0] & 0xf) {
-        case 0x2: /* CSST */
-            is_write = 1;
-        }
-        break;
-    case 0xe3: /* RXY format insns */
-        switch (pinsn[2] & 0xff) {
-        case 0x50: /* STY */
-        case 0x24: /* STG */
-        case 0x72: /* STCY */
-        case 0x70: /* STHY */
-        case 0x8e: /* STPQ */
-        case 0x3f: /* STRVH */
-        case 0x3e: /* STRV */
-        case 0x2f: /* STRVG */
-            is_write = 1;
-        }
-        break;
-    case 0xeb: /* RSY format insns */
-        switch (pinsn[2] & 0xff) {
-        case 0x14: /* CSY */
-        case 0x30: /* CSG */
-        case 0x31: /* CDSY */
-        case 0x3e: /* CDSG */
-        case 0xe4: /* LANG */
-        case 0xe6: /* LAOG */
-        case 0xe7: /* LAXG */
-        case 0xe8: /* LAAG */
-        case 0xea: /* LAALG */
-        case 0xf4: /* LAN */
-        case 0xf6: /* LAO */
-        case 0xf7: /* LAX */
-        case 0xfa: /* LAAL */
-        case 0xf8: /* LAA */
-            is_write = 1;
-        }
-        break;
-    }
-
-    return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
-}
-
-#elif defined(__mips__)
-
-#if defined(__misp16) || defined(__mips_micromips)
-#error "Unsupported encoding"
-#endif
-
-int cpu_signal_handler(int host_signum, void *pinfo,
-                       void *puc)
-{
-    siginfo_t *info = pinfo;
-    ucontext_t *uc = puc;
-    uintptr_t pc = uc->uc_mcontext.pc;
-    uint32_t insn = *(uint32_t *)pc;
-    int is_write = 0;
-
-    /* Detect all store instructions at program counter. */
-    switch((insn >> 26) & 077) {
-    case 050: /* SB */
-    case 051: /* SH */
-    case 052: /* SWL */
-    case 053: /* SW */
-    case 054: /* SDL */
-    case 055: /* SDR */
-    case 056: /* SWR */
-    case 070: /* SC */
-    case 071: /* SWC1 */
-    case 074: /* SCD */
-    case 075: /* SDC1 */
-    case 077: /* SD */
-#if !defined(__mips_isa_rev) || __mips_isa_rev < 6
-    case 072: /* SWC2 */
-    case 076: /* SDC2 */
-#endif
-        is_write = 1;
-        break;
-    case 023: /* COP1X */
-        /* Required in all versions of MIPS64 since
-           MIPS64r1 and subsequent versions of MIPS32r2. */
-        switch (insn & 077) {
-        case 010: /* SWXC1 */
-        case 011: /* SDXC1 */
-        case 015: /* SUXC1 */
-            is_write = 1;
-        }
-        break;
-    }
-
-    return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
-}
-
-#elif defined(__riscv)
-
-int cpu_signal_handler(int host_signum, void *pinfo,
-                       void *puc)
-{
-    siginfo_t *info = pinfo;
-    ucontext_t *uc = puc;
-    greg_t pc = uc->uc_mcontext.__gregs[REG_PC];
-    uint32_t insn = *(uint32_t *)pc;
-    int is_write = 0;
-
-    /* Detect store by reading the instruction at the program
-       counter. Note: we currently only generate 32-bit
-       instructions so we thus only detect 32-bit stores */
-    switch (((insn >> 0) & 0b11)) {
-    case 3:
-        switch (((insn >> 2) & 0b11111)) {
-        case 8:
-            switch (((insn >> 12) & 0b111)) {
-            case 0: /* sb */
-            case 1: /* sh */
-            case 2: /* sw */
-            case 3: /* sd */
-            case 4: /* sq */
-                is_write = 1;
-                break;
-            default:
-                break;
-            }
-            break;
-        case 9:
-            switch (((insn >> 12) & 0b111)) {
-            case 2: /* fsw */
-            case 3: /* fsd */
-            case 4: /* fsq */
-                is_write = 1;
-                break;
-            default:
-                break;
-            }
-            break;
-        default:
-            break;
-        }
-    }
-
-    /* Check for compressed instructions */
-    switch (((insn >> 13) & 0b111)) {
-    case 7:
-        switch (insn & 0b11) {
-        case 0: /*c.sd */
-        case 2: /* c.sdsp */
-            is_write = 1;
-            break;
-        default:
-            break;
-        }
-        break;
-    case 6:
-        switch (insn & 0b11) {
-        case 0: /* c.sw */
-        case 3: /* c.swsp */
-            is_write = 1;
-            break;
-        default:
-            break;
-        }
-        break;
-    default:
-        break;
-    }
-
-    return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
-}
-
-#else
-
-#error host CPU specific signal handler needed
-
-#endif
-
 /* The softmmu versions of these helpers are in cputlb.c.  */
 
 uint32_t cpu_ldub_data(CPUArchState *env, abi_ptr ptr)
diff --git a/linux-user/signal.c b/linux-user/signal.c
index 73c0f9066b..509dad7850 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -24,6 +24,7 @@
 #include "qemu.h"
 #include "trace.h"
 #include "signal-common.h"
+#include "host-signal.h"
 
 static struct target_sigaction sigact_table[TARGET_NSIG];
 
@@ -753,59 +754,85 @@ static inline void rewind_if_in_safe_syscall(void *puc)
 }
 #endif
 
-static void host_signal_handler(int host_signum, siginfo_t *info,
-                                void *puc)
+static void host_signal_handler(int host_sig, siginfo_t *info, void *puc)
 {
     CPUArchState *env = thread_cpu->env_ptr;
     CPUState *cpu = env_cpu(env);
     TaskState *ts = cpu->opaque;
-
-    int sig;
+    bool sync_sig = false;
     target_siginfo_t tinfo;
     ucontext_t *uc = puc;
     struct emulated_sigtable *k;
+    uintptr_t pc = 0;
+    int guest_sig;
 
-    /* the CPU emulator uses some host signals to detect exceptions,
-       we forward to it some signals */
-    if ((host_signum == SIGSEGV || host_signum == SIGBUS)
-        && info->si_code > 0) {
-        if (cpu_signal_handler(host_signum, info, puc))
+    /*
+     * Non-spoofed SIGSEGV and SIGBUS are synchronous, and need special
+     * handling wrt signal blocking and unwinding.  SIGSEGV may need to
+     * remove write-protection and restart the instruction.
+     */
+    if ((host_sig == SIGSEGV || host_sig == SIGBUS) && info->si_code > 0) {
+        pc = adjust_signal_pc(host_signal_pc(uc));
+        if (host_sig == SIGSEGV &&
+            info->si_code == SEGV_ACCERR &&
+            host_sigsegv_write(info, uc) &&
+            handle_sigsegv_accerr_write(cpu, &uc->uc_sigmask, pc,
+                                        (uintptr_t)info->si_addr)) {
             return;
+        }
+        sync_sig = true;
+    } else {
+        rewind_if_in_safe_syscall(puc);
+
+        /*
+         * Block host signals until target signal handler entered.
+         * We can't block SIGSEGV or SIGBUS while we're executing
+         * guest code in case the guest code provokes one in the
+         * window between now and it getting out to the main loop.
+         * Signals will be unblocked again in process_pending_signals().
+         *
+         * WARNING: we cannot use sigfillset() here because the uc_sigmask
+         * field is a kernel sigset_t, which is much smaller than the
+         * libc sigset_t which sigfillset() operates on. Using sigfillset()
+         * would write 0xff bytes off the end of the structure and trash
+         * data on the struct.
+         * We can't use sizeof(uc->uc_sigmask) either, because the libc
+         * headers define the struct field with the wrong (too large) type.
+         */
+        memset(&uc->uc_sigmask, 0xff, SIGSET_T_SIZE);
+        sigdelset(&uc->uc_sigmask, SIGSEGV);
+        sigdelset(&uc->uc_sigmask, SIGBUS);
     }
 
     /* get target signal number */
-    sig = host_to_target_signal(host_signum);
-    if (sig < 1 || sig > TARGET_NSIG)
+    guest_sig = host_to_target_signal(host_sig);
+    if (guest_sig < 1 || guest_sig > TARGET_NSIG) {
         return;
-    trace_user_host_signal(env, host_signum, sig);
-
-    rewind_if_in_safe_syscall(puc);
+    }
+    trace_user_host_signal(env, host_sig, guest_sig);
 
     host_to_target_siginfo_noswap(&tinfo, info);
-    k = &ts->sigtab[sig - 1];
+    k = &ts->sigtab[guest_sig - 1];
     k->info = tinfo;
-    k->pending = sig;
+    k->pending = guest_sig;
     ts->signal_pending = 1;
 
-    /* Block host signals until target signal handler entered. We
-     * can't block SIGSEGV or SIGBUS while we're executing guest
-     * code in case the guest code provokes one in the window between
-     * now and it getting out to the main loop. Signals will be
-     * unblocked again in process_pending_signals().
-     *
-     * WARNING: we cannot use sigfillset() here because the uc_sigmask
-     * field is a kernel sigset_t, which is much smaller than the
-     * libc sigset_t which sigfillset() operates on. Using sigfillset()
-     * would write 0xff bytes off the end of the structure and trash
-     * data on the struct.
-     * We can't use sizeof(uc->uc_sigmask) either, because the libc
-     * headers define the struct field with the wrong (too large) type.
+    /*
+     * For synchronous signals, unwind the cpu state to the faulting
+     * insn and then exit back to the main loop so that the signal
+     * is delivered immediately.
      */
-    memset(&uc->uc_sigmask, 0xff, SIGSET_T_SIZE);
-    sigdelset(&uc->uc_sigmask, SIGSEGV);
-    sigdelset(&uc->uc_sigmask, SIGBUS);
+    if (sync_sig) {
+        clear_helper_retaddr();
+        sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
+        cpu->exception_index = EXCP_INTERRUPT;
+        cpu_loop_exit_restore(cpu, pc);
+    }
 
-    /* interrupt the virtual CPU as soon as possible */
+    /*
+     * Interrupt the virtual CPU as soon as possible, but for now
+     * return to continue with the current TB.
+     */
     cpu_exit(thread_cpu);
 }
 
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [RFC PATCH 0/7] linux-user: Streamline handling of SIGSEGV/SIGBUS
  2021-09-13 22:05 [RFC PATCH 0/7] linux-user: Streamline handling of SIGSEGV/SIGBUS Richard Henderson
                   ` (6 preceding siblings ...)
  2021-09-13 22:05 ` [RFC PATCH 7/7] linux-user: Reorg cpu_signal_handler Richard Henderson
@ 2021-09-14  1:18 ` Richard Henderson
  7 siblings, 0 replies; 18+ messages in thread
From: Richard Henderson @ 2021-09-14  1:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, laurent, imp

On 9/13/21 3:05 PM, Richard Henderson wrote:
> All of the really tcg-specific portions are still in user-exec.c,
> and all of the really host-specific portions are now ditributed
> across linux-user/host/<arch>/.  Importantly, SEGV_MAPERR and
> SEGV_ACCERR are now passed through from the host kernel -- or at
> least there's a single place from which to manage it [1].

Hum.  And then there's the special case of s390x, where the hw does not provide the exact 
address on faults, but only the page.  We have code for that in cpu_loop, but I have to 
invent some new hook in this new scheme.


r~


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [RFC PATCH 1/7] include/exec: Move cpu_signal_handler declaration
  2021-09-13 22:05 ` [RFC PATCH 1/7] include/exec: Move cpu_signal_handler declaration Richard Henderson
@ 2021-09-14  6:03   ` Philippe Mathieu-Daudé
  2021-09-15 16:09   ` Warner Losh
  1 sibling, 0 replies; 18+ messages in thread
From: Philippe Mathieu-Daudé @ 2021-09-14  6:03 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel
  Cc: peter.maydell, Alistair Francis, laurent, imp

On 9/14/21 12:05 AM, Richard Henderson wrote:
> There is nothing target specific about this.  The implementation
> is host specific, but the declaration is 100% common.

Same as v3 ;)
https://www.mail-archive.com/qemu-devel@nongnu.org/msg830412.html

Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>

> Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>  include/exec/exec-all.h | 13 +++++++++++++
>  target/alpha/cpu.h      |  6 ------
>  target/arm/cpu.h        |  7 -------
>  target/avr/cpu.h        |  2 --
>  target/cris/cpu.h       |  8 --------
>  target/hexagon/cpu.h    |  3 ---
>  target/hppa/cpu.h       |  3 ---
>  target/i386/cpu.h       |  7 -------
>  target/m68k/cpu.h       |  8 --------
>  target/microblaze/cpu.h |  7 -------
>  target/mips/cpu.h       |  3 ---
>  target/mips/internal.h  |  2 --
>  target/nios2/cpu.h      |  2 --
>  target/openrisc/cpu.h   |  2 --
>  target/ppc/cpu.h        |  7 -------
>  target/riscv/cpu.h      |  2 --
>  target/rx/cpu.h         |  4 ----
>  target/s390x/cpu.h      |  7 -------
>  target/sh4/cpu.h        |  3 ---
>  target/sparc/cpu.h      |  2 --
>  target/tricore/cpu.h    |  2 --
>  target/xtensa/cpu.h     |  2 --
>  22 files changed, 13 insertions(+), 89 deletions(-)


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [RFC PATCH 2/7] accel/tcg: Split out adjust_signal_pc
  2021-09-13 22:05 ` [RFC PATCH 2/7] accel/tcg: Split out adjust_signal_pc Richard Henderson
@ 2021-09-14  6:07   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 18+ messages in thread
From: Philippe Mathieu-Daudé @ 2021-09-14  6:07 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: peter.maydell, laurent, imp

On 9/14/21 12:05 AM, Richard Henderson wrote:
> Split out a function to adjust the raw signal pc into a
> value that could be passed to cpu_restore_state.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>  include/exec/exec-all.h |  8 +++++++
>  accel/tcg/user-exec.c   | 50 ++++++++++++++++++++++++++---------------
>  2 files changed, 40 insertions(+), 18 deletions(-)

> -/* 'pc' is the host PC at which the exception was raised. 'address' is
> -   the effective address of the memory exception. 'is_write' is 1 if a
> -   write caused the exception and otherwise 0'. 'old_set' is the
> -   signal set which should be restored */
> -static inline int handle_cpu_signal(uintptr_t pc, siginfo_t *info,
> -                                    int is_write, sigset_t *old_set)

> +/* 'pc' is the host PC at which the exception was raised. 'address' is
> +   the effective address of the memory exception. 'is_write' is 1 if a
> +   write caused the exception and otherwise 0'. 'old_set' is the
> +   signal set which should be restored */
Pre-existing extra "'" in "otherwise 0."

Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [RFC PATCH 3/7] accel/tcg: Split out handle_sigsegv_accerr_write
  2021-09-13 22:05 ` [RFC PATCH 3/7] accel/tcg: Split out handle_sigsegv_accerr_write Richard Henderson
@ 2021-09-14  6:58   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 18+ messages in thread
From: Philippe Mathieu-Daudé @ 2021-09-14  6:58 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: peter.maydell, laurent, imp

On 9/14/21 12:05 AM, Richard Henderson wrote:
> This is the major portion of handle_cpu_signal which is specific
> to tcg, handling the page protections for the translations.
> Most of the rest will migrate to linux-user/ shortly.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>  include/exec/exec-all.h | 12 ++++++
>  accel/tcg/user-exec.c   | 96 +++++++++++++++++++++++++----------------
>  2 files changed, 72 insertions(+), 36 deletions(-)

Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [RFC PATCH 1/7] include/exec: Move cpu_signal_handler declaration
  2021-09-13 22:05 ` [RFC PATCH 1/7] include/exec: Move cpu_signal_handler declaration Richard Henderson
  2021-09-14  6:03   ` Philippe Mathieu-Daudé
@ 2021-09-15 16:09   ` Warner Losh
  1 sibling, 0 replies; 18+ messages in thread
From: Warner Losh @ 2021-09-15 16:09 UTC (permalink / raw)
  To: Richard Henderson
  Cc: Peter Maydell, Alistair Francis, QEMU Developers, Laurent Vivier

[-- Attachment #1: Type: text/plain, Size: 19698 bytes --]

On Mon, Sep 13, 2021 at 4:05 PM Richard Henderson <
richard.henderson@linaro.org> wrote:

> There is nothing target specific about this.  The implementation
> is host specific, but the declaration is 100% common.
>
> Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>  include/exec/exec-all.h | 13 +++++++++++++
>  target/alpha/cpu.h      |  6 ------
>  target/arm/cpu.h        |  7 -------
>  target/avr/cpu.h        |  2 --
>  target/cris/cpu.h       |  8 --------
>  target/hexagon/cpu.h    |  3 ---
>  target/hppa/cpu.h       |  3 ---
>  target/i386/cpu.h       |  7 -------
>  target/m68k/cpu.h       |  8 --------
>  target/microblaze/cpu.h |  7 -------
>  target/mips/cpu.h       |  3 ---
>  target/mips/internal.h  |  2 --
>  target/nios2/cpu.h      |  2 --
>  target/openrisc/cpu.h   |  2 --
>  target/ppc/cpu.h        |  7 -------
>  target/riscv/cpu.h      |  2 --
>  target/rx/cpu.h         |  4 ----
>  target/s390x/cpu.h      |  7 -------
>  target/sh4/cpu.h        |  3 ---
>  target/sparc/cpu.h      |  2 --
>  target/tricore/cpu.h    |  2 --
>  target/xtensa/cpu.h     |  2 --
>  22 files changed, 13 insertions(+), 89 deletions(-)
>

Reviewed-By: Warner Losh <imp@bsdimp.com>

Warner


> diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
> index 5d1b6d80fb..9d5987ba04 100644
> --- a/include/exec/exec-all.h
> +++ b/include/exec/exec-all.h
> @@ -662,6 +662,19 @@ static inline tb_page_addr_t
> get_page_addr_code_hostp(CPUArchState *env,
>      }
>      return addr;
>  }
> +
> +/**
> + * cpu_signal_handler
> + * @signum: host signal number
> + * @pinfo: host siginfo_t
> + * @puc: host ucontext_t
> + *
> + * To be called from the SIGBUS and SIGSEGV signal handler to inform the
> + * virtual cpu of exceptions.  Returns true if the signal was handled by
> + * the virtual CPU.
> + */
> +int cpu_signal_handler(int signum, void *pinfo, void *puc);
> +
>  #else
>  static inline void mmap_lock(void) {}
>  static inline void mmap_unlock(void) {}
> diff --git a/target/alpha/cpu.h b/target/alpha/cpu.h
> index 4e993bd15b..ce9ec32199 100644
> --- a/target/alpha/cpu.h
> +++ b/target/alpha/cpu.h
> @@ -287,7 +287,6 @@ void alpha_cpu_do_unaligned_access(CPUState *cpu,
> vaddr addr,
>                                     int mmu_idx, uintptr_t retaddr);
>
>  #define cpu_list alpha_cpu_list
> -#define cpu_signal_handler cpu_alpha_signal_handler
>
>  typedef CPUAlphaState CPUArchState;
>  typedef AlphaCPU ArchCPU;
> @@ -440,11 +439,6 @@ void alpha_translate_init(void);
>  #define CPU_RESOLVING_TYPE TYPE_ALPHA_CPU
>
>  void alpha_cpu_list(void);
> -/* you can call this signal handler from your SIGBUS and SIGSEGV
> -   signal handlers to inform the virtual CPU of exceptions. non zero
> -   is returned if the signal was handled by the virtual CPU.  */
> -int cpu_alpha_signal_handler(int host_signum, void *pinfo,
> -                             void *puc);
>  bool alpha_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
>                          MMUAccessType access_type, int mmu_idx,
>                          bool probe, uintptr_t retaddr);
> diff --git a/target/arm/cpu.h b/target/arm/cpu.h
> index cfd755cff9..6c78957e54 100644
> --- a/target/arm/cpu.h
> +++ b/target/arm/cpu.h
> @@ -1121,12 +1121,6 @@ static inline bool is_a64(CPUARMState *env)
>      return env->aarch64;
>  }
>
> -/* you can call this signal handler from your SIGBUS and SIGSEGV
> -   signal handlers to inform the virtual CPU of exceptions. non zero
> -   is returned if the signal was handled by the virtual CPU.  */
> -int cpu_arm_signal_handler(int host_signum, void *pinfo,
> -                           void *puc);
> -
>  /**
>   * pmu_op_start/finish
>   * @env: CPUARMState
> @@ -3015,7 +3009,6 @@ bool write_cpustate_to_list(ARMCPU *cpu, bool
> kvm_sync);
>  #define ARM_CPU_TYPE_NAME(name) (name ARM_CPU_TYPE_SUFFIX)
>  #define CPU_RESOLVING_TYPE TYPE_ARM_CPU
>
> -#define cpu_signal_handler cpu_arm_signal_handler
>  #define cpu_list arm_cpu_list
>
>  /* ARM has the following "translation regimes" (as the ARM ARM calls
> them):
> diff --git a/target/avr/cpu.h b/target/avr/cpu.h
> index 93e3faa0a9..dceacf3cd7 100644
> --- a/target/avr/cpu.h
> +++ b/target/avr/cpu.h
> @@ -175,7 +175,6 @@ static inline void set_avr_feature(CPUAVRState *env,
> int feature)
>  }
>
>  #define cpu_list avr_cpu_list
> -#define cpu_signal_handler cpu_avr_signal_handler
>  #define cpu_mmu_index avr_cpu_mmu_index
>
>  static inline int avr_cpu_mmu_index(CPUAVRState *env, bool ifetch)
> @@ -187,7 +186,6 @@ void avr_cpu_tcg_init(void);
>
>  void avr_cpu_list(void);
>  int cpu_avr_exec(CPUState *cpu);
> -int cpu_avr_signal_handler(int host_signum, void *pinfo, void *puc);
>  int avr_cpu_memory_rw_debug(CPUState *cs, vaddr address, uint8_t *buf,
>                              int len, bool is_write);
>
> diff --git a/target/cris/cpu.h b/target/cris/cpu.h
> index be021899ae..6603565f83 100644
> --- a/target/cris/cpu.h
> +++ b/target/cris/cpu.h
> @@ -199,12 +199,6 @@ int crisv10_cpu_gdb_read_register(CPUState *cpu,
> GByteArray *buf, int reg);
>  int cris_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
>  int cris_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
>
> -/* you can call this signal handler from your SIGBUS and SIGSEGV
> -   signal handlers to inform the virtual CPU of exceptions. non zero
> -   is returned if the signal was handled by the virtual CPU.  */
> -int cpu_cris_signal_handler(int host_signum, void *pinfo,
> -                           void *puc);
> -
>  void cris_initialize_tcg(void);
>  void cris_initialize_crisv10_tcg(void);
>
> @@ -250,8 +244,6 @@ enum {
>  #define CRIS_CPU_TYPE_NAME(name) (name CRIS_CPU_TYPE_SUFFIX)
>  #define CPU_RESOLVING_TYPE TYPE_CRIS_CPU
>
> -#define cpu_signal_handler cpu_cris_signal_handler
> -
>  /* MMU modes definitions */
>  #define MMU_USER_IDX 1
>  static inline int cpu_mmu_index (CPUCRISState *env, bool ifetch)
> diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h
> index 2855dd3881..f7d043865b 100644
> --- a/target/hexagon/cpu.h
> +++ b/target/hexagon/cpu.h
> @@ -129,9 +129,6 @@ typedef struct HexagonCPU {
>
>  #include "cpu_bits.h"
>
> -#define cpu_signal_handler cpu_hexagon_signal_handler
> -int cpu_hexagon_signal_handler(int host_signum, void *pinfo, void *puc);
> -
>  static inline void cpu_get_tb_cpu_state(CPUHexagonState *env,
> target_ulong *pc,
>                                          target_ulong *cs_base, uint32_t
> *flags)
>  {
> diff --git a/target/hppa/cpu.h b/target/hppa/cpu.h
> index 7854675b90..d3cb7a279f 100644
> --- a/target/hppa/cpu.h
> +++ b/target/hppa/cpu.h
> @@ -319,9 +319,6 @@ static inline void
> cpu_hppa_change_prot_id(CPUHPPAState *env) { }
>  void cpu_hppa_change_prot_id(CPUHPPAState *env);
>  #endif
>
> -#define cpu_signal_handler cpu_hppa_signal_handler
> -
> -int cpu_hppa_signal_handler(int host_signum, void *pinfo, void *puc);
>  hwaddr hppa_cpu_get_phys_page_debug(CPUState *cs, vaddr addr);
>  int hppa_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
>  int hppa_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
> diff --git a/target/i386/cpu.h b/target/i386/cpu.h
> index 7dd664791a..c2954c71ea 100644
> --- a/target/i386/cpu.h
> +++ b/target/i386/cpu.h
> @@ -1947,12 +1947,6 @@ void cpu_x86_frstor(CPUX86State *s, target_ulong
> ptr, int data32);
>  void cpu_x86_fxsave(CPUX86State *s, target_ulong ptr);
>  void cpu_x86_fxrstor(CPUX86State *s, target_ulong ptr);
>
> -/* you can call this signal handler from your SIGBUS and SIGSEGV
> -   signal handlers to inform the virtual CPU of exceptions. non zero
> -   is returned if the signal was handled by the virtual CPU.  */
> -int cpu_x86_signal_handler(int host_signum, void *pinfo,
> -                           void *puc);
> -
>  /* cpu.c */
>  void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1,
>                                uint32_t vendor2, uint32_t vendor3);
> @@ -2020,7 +2014,6 @@ uint64_t cpu_get_tsc(CPUX86State *env);
>  #define TARGET_DEFAULT_CPU_TYPE X86_CPU_TYPE_NAME("qemu32")
>  #endif
>
> -#define cpu_signal_handler cpu_x86_signal_handler
>  #define cpu_list x86_cpu_list
>
>  /* MMU modes definitions */
> diff --git a/target/m68k/cpu.h b/target/m68k/cpu.h
> index 550eb028b6..a3423729ef 100644
> --- a/target/m68k/cpu.h
> +++ b/target/m68k/cpu.h
> @@ -177,13 +177,6 @@ int m68k_cpu_gdb_write_register(CPUState *cpu,
> uint8_t *buf, int reg);
>
>  void m68k_tcg_init(void);
>  void m68k_cpu_init_gdb(M68kCPU *cpu);
> -/*
> - * you can call this signal handler from your SIGBUS and SIGSEGV
> - * signal handlers to inform the virtual CPU of exceptions. non zero
> - * is returned if the signal was handled by the virtual CPU.
> - */
> -int cpu_m68k_signal_handler(int host_signum, void *pinfo,
> -                           void *puc);
>  uint32_t cpu_m68k_get_ccr(CPUM68KState *env);
>  void cpu_m68k_set_ccr(CPUM68KState *env, uint32_t);
>  void cpu_m68k_set_sr(CPUM68KState *env, uint32_t);
> @@ -563,7 +556,6 @@ enum {
>  #define M68K_CPU_TYPE_NAME(model) model M68K_CPU_TYPE_SUFFIX
>  #define CPU_RESOLVING_TYPE TYPE_M68K_CPU
>
> -#define cpu_signal_handler cpu_m68k_signal_handler
>  #define cpu_list m68k_cpu_list
>
>  /* MMU modes definitions */
> diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h
> index 40401c33b7..13ed3cd4dd 100644
> --- a/target/microblaze/cpu.h
> +++ b/target/microblaze/cpu.h
> @@ -385,16 +385,9 @@ static inline void mb_cpu_write_msr(CPUMBState *env,
> uint32_t val)
>  }
>
>  void mb_tcg_init(void);
> -/* you can call this signal handler from your SIGBUS and SIGSEGV
> -   signal handlers to inform the virtual CPU of exceptions. non zero
> -   is returned if the signal was handled by the virtual CPU.  */
> -int cpu_mb_signal_handler(int host_signum, void *pinfo,
> -                          void *puc);
>
>  #define CPU_RESOLVING_TYPE TYPE_MICROBLAZE_CPU
>
> -#define cpu_signal_handler cpu_mb_signal_handler
> -
>  /* MMU modes definitions */
>  #define MMU_NOMMU_IDX   0
>  #define MMU_KERNEL_IDX  1
> diff --git a/target/mips/cpu.h b/target/mips/cpu.h
> index 1dfe69c6c0..56b1cbd091 100644
> --- a/target/mips/cpu.h
> +++ b/target/mips/cpu.h
> @@ -1193,7 +1193,6 @@ struct MIPSCPU {
>
>  void mips_cpu_list(void);
>
> -#define cpu_signal_handler cpu_mips_signal_handler
>  #define cpu_list mips_cpu_list
>
>  extern void cpu_wrdsp(uint32_t rs, uint32_t mask_num, CPUMIPSState *env);
> @@ -1277,8 +1276,6 @@ enum {
>   */
>  #define CPU_INTERRUPT_WAKE CPU_INTERRUPT_TGT_INT_0
>
> -int cpu_mips_signal_handler(int host_signum, void *pinfo, void *puc);
> -
>  #define MIPS_CPU_TYPE_SUFFIX "-" TYPE_MIPS_CPU
>  #define MIPS_CPU_TYPE_NAME(model) model MIPS_CPU_TYPE_SUFFIX
>  #define CPU_RESOLVING_TYPE TYPE_MIPS_CPU
> diff --git a/target/mips/internal.h b/target/mips/internal.h
> index eecdd10116..daddb05fd4 100644
> --- a/target/mips/internal.h
> +++ b/target/mips/internal.h
> @@ -156,8 +156,6 @@ extern const VMStateDescription vmstate_mips_cpu;
>
>  #endif /* !CONFIG_USER_ONLY */
>
> -#define cpu_signal_handler cpu_mips_signal_handler
> -
>  static inline bool cpu_mips_hw_interrupts_enabled(CPUMIPSState *env)
>  {
>      return (env->CP0_Status & (1 << CP0St_IE)) &&
> diff --git a/target/nios2/cpu.h b/target/nios2/cpu.h
> index 2ab82fdc71..88a511209c 100644
> --- a/target/nios2/cpu.h
> +++ b/target/nios2/cpu.h
> @@ -193,7 +193,6 @@ struct Nios2CPU {
>
>  void nios2_tcg_init(void);
>  void nios2_cpu_do_interrupt(CPUState *cs);
> -int cpu_nios2_signal_handler(int host_signum, void *pinfo, void *puc);
>  void dump_mmu(CPUNios2State *env);
>  void nios2_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
>  hwaddr nios2_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
> @@ -206,7 +205,6 @@ void do_nios2_semihosting(CPUNios2State *env);
>  #define CPU_RESOLVING_TYPE TYPE_NIOS2_CPU
>
>  #define cpu_gen_code cpu_nios2_gen_code
> -#define cpu_signal_handler cpu_nios2_signal_handler
>
>  #define CPU_SAVE_VERSION 1
>
> diff --git a/target/openrisc/cpu.h b/target/openrisc/cpu.h
> index be6df81a81..187a4a114e 100644
> --- a/target/openrisc/cpu.h
> +++ b/target/openrisc/cpu.h
> @@ -320,11 +320,9 @@ void openrisc_translate_init(void);
>  bool openrisc_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
>                             MMUAccessType access_type, int mmu_idx,
>                             bool probe, uintptr_t retaddr);
> -int cpu_openrisc_signal_handler(int host_signum, void *pinfo, void *puc);
>  int print_insn_or1k(bfd_vma addr, disassemble_info *info);
>
>  #define cpu_list cpu_openrisc_list
> -#define cpu_signal_handler cpu_openrisc_signal_handler
>
>  #ifndef CONFIG_USER_ONLY
>  extern const VMStateDescription vmstate_openrisc_cpu;
> diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
> index 362e7c4c5c..01d3773bc7 100644
> --- a/target/ppc/cpu.h
> +++ b/target/ppc/cpu.h
> @@ -1278,12 +1278,6 @@ extern const VMStateDescription vmstate_ppc_cpu;
>
>
>  /*****************************************************************************/
>  void ppc_translate_init(void);
> -/*
> - * you can call this signal handler from your SIGBUS and SIGSEGV
> - * signal handlers to inform the virtual CPU of exceptions. non zero
> - * is returned if the signal was handled by the virtual CPU.
> - */
> -int cpu_ppc_signal_handler(int host_signum, void *pinfo, void *puc);
>  bool ppc_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
>                        MMUAccessType access_type, int mmu_idx,
>                        bool probe, uintptr_t retaddr);
> @@ -1371,7 +1365,6 @@ int ppc_dcr_write(ppc_dcr_t *dcr_env, int dcrn,
> uint32_t val);
>  #define POWERPC_CPU_TYPE_NAME(model) model POWERPC_CPU_TYPE_SUFFIX
>  #define CPU_RESOLVING_TYPE TYPE_POWERPC_CPU
>
> -#define cpu_signal_handler cpu_ppc_signal_handler
>  #define cpu_list ppc_cpu_list
>
>  /* MMU modes definitions */
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index e735e53e26..465142616a 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -356,7 +356,6 @@ void riscv_cpu_do_transaction_failed(CPUState *cs,
> hwaddr physaddr,
>  char *riscv_isa_string(RISCVCPU *cpu);
>  void riscv_cpu_list(void);
>
> -#define cpu_signal_handler riscv_cpu_signal_handler
>  #define cpu_list riscv_cpu_list
>  #define cpu_mmu_index riscv_cpu_mmu_index
>
> @@ -372,7 +371,6 @@ void riscv_cpu_set_rdtime_fn(CPURISCVState *env,
> uint64_t (*fn)(uint32_t),
>  void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv);
>
>  void riscv_translate_init(void);
> -int riscv_cpu_signal_handler(int host_signum, void *pinfo, void *puc);
>  void QEMU_NORETURN riscv_raise_exception(CPURISCVState *env,
>                                           uint32_t exception, uintptr_t
> pc);
>
> diff --git a/target/rx/cpu.h b/target/rx/cpu.h
> index faa3606f52..4ac71aec37 100644
> --- a/target/rx/cpu.h
> +++ b/target/rx/cpu.h
> @@ -134,13 +134,9 @@ int rx_cpu_gdb_write_register(CPUState *cpu, uint8_t
> *buf, int reg);
>  hwaddr rx_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
>
>  void rx_translate_init(void);
> -int cpu_rx_signal_handler(int host_signum, void *pinfo,
> -                           void *puc);
> -
>  void rx_cpu_list(void);
>  void rx_cpu_unpack_psw(CPURXState *env, uint32_t psw, int rte);
>
> -#define cpu_signal_handler cpu_rx_signal_handler
>  #define cpu_list rx_cpu_list
>
>  #include "exec/cpu-all.h"
> diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h
> index b26ae8fff2..3153d053e9 100644
> --- a/target/s390x/cpu.h
> +++ b/target/s390x/cpu.h
> @@ -809,13 +809,6 @@ void s390_set_qemu_cpu_model(uint16_t type, uint8_t
> gen, uint8_t ec_ga,
>  #define S390_CPU_TYPE_NAME(name) (name S390_CPU_TYPE_SUFFIX)
>  #define CPU_RESOLVING_TYPE TYPE_S390_CPU
>
> -/* you can call this signal handler from your SIGBUS and SIGSEGV
> -   signal handlers to inform the virtual CPU of exceptions. non zero
> -   is returned if the signal was handled by the virtual CPU.  */
> -int cpu_s390x_signal_handler(int host_signum, void *pinfo, void *puc);
> -#define cpu_signal_handler cpu_s390x_signal_handler
> -
> -
>  /* interrupt.c */
>  #define RA_IGNORED                  0
>  void s390_program_interrupt(CPUS390XState *env, uint32_t code, uintptr_t
> ra);
> diff --git a/target/sh4/cpu.h b/target/sh4/cpu.h
> index 017a770214..56f7c32df9 100644
> --- a/target/sh4/cpu.h
> +++ b/target/sh4/cpu.h
> @@ -213,8 +213,6 @@ void superh_cpu_do_unaligned_access(CPUState *cpu,
> vaddr addr,
>                                      int mmu_idx, uintptr_t retaddr);
>
>  void sh4_translate_init(void);
> -int cpu_sh4_signal_handler(int host_signum, void *pinfo,
> -                           void *puc);
>  bool superh_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
>                           MMUAccessType access_type, int mmu_idx,
>                           bool probe, uintptr_t retaddr);
> @@ -250,7 +248,6 @@ void cpu_load_tlb(CPUSH4State * env);
>  #define SUPERH_CPU_TYPE_NAME(model) model SUPERH_CPU_TYPE_SUFFIX
>  #define CPU_RESOLVING_TYPE TYPE_SUPERH_CPU
>
> -#define cpu_signal_handler cpu_sh4_signal_handler
>  #define cpu_list sh4_cpu_list
>
>  /* MMU modes definitions */
> diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h
> index ff8ae73002..6b40d02237 100644
> --- a/target/sparc/cpu.h
> +++ b/target/sparc/cpu.h
> @@ -649,13 +649,11 @@ hwaddr cpu_get_phys_page_nofault(CPUSPARCState *env,
> target_ulong addr,
>                                             int mmu_idx);
>  #endif
>  #endif
> -int cpu_sparc_signal_handler(int host_signum, void *pinfo, void *puc);
>
>  #define SPARC_CPU_TYPE_SUFFIX "-" TYPE_SPARC_CPU
>  #define SPARC_CPU_TYPE_NAME(model) model SPARC_CPU_TYPE_SUFFIX
>  #define CPU_RESOLVING_TYPE TYPE_SPARC_CPU
>
> -#define cpu_signal_handler cpu_sparc_signal_handler
>  #define cpu_list sparc_cpu_list
>
>  /* MMU modes definitions */
> diff --git a/target/tricore/cpu.h b/target/tricore/cpu.h
> index 4b61a2c03f..c461387e71 100644
> --- a/target/tricore/cpu.h
> +++ b/target/tricore/cpu.h
> @@ -362,7 +362,6 @@ void fpu_set_state(CPUTriCoreState *env);
>
>  void tricore_cpu_list(void);
>
> -#define cpu_signal_handler cpu_tricore_signal_handler
>  #define cpu_list tricore_cpu_list
>
>  static inline int cpu_mmu_index(CPUTriCoreState *env, bool ifetch)
> @@ -377,7 +376,6 @@ typedef TriCoreCPU ArchCPU;
>
>  void cpu_state_reset(CPUTriCoreState *s);
>  void tricore_tcg_init(void);
> -int cpu_tricore_signal_handler(int host_signum, void *pinfo, void *puc);
>
>  static inline void cpu_get_tb_cpu_state(CPUTriCoreState *env,
> target_ulong *pc,
>                                          target_ulong *cs_base, uint32_t
> *flags)
> diff --git a/target/xtensa/cpu.h b/target/xtensa/cpu.h
> index cbb720e7cc..646965f379 100644
> --- a/target/xtensa/cpu.h
> +++ b/target/xtensa/cpu.h
> @@ -584,7 +584,6 @@ void xtensa_cpu_do_unaligned_access(CPUState *cpu,
> vaddr addr,
>                                      MMUAccessType access_type,
>                                      int mmu_idx, uintptr_t retaddr);
>
> -#define cpu_signal_handler cpu_xtensa_signal_handler
>  #define cpu_list xtensa_cpu_list
>
>  #define XTENSA_CPU_TYPE_SUFFIX "-" TYPE_XTENSA_CPU
> @@ -613,7 +612,6 @@ void check_interrupts(CPUXtensaState *s);
>  void xtensa_irq_init(CPUXtensaState *env);
>  qemu_irq *xtensa_get_extints(CPUXtensaState *env);
>  qemu_irq xtensa_get_runstall(CPUXtensaState *env);
> -int cpu_xtensa_signal_handler(int host_signum, void *pinfo, void *puc);
>  void xtensa_cpu_list(void);
>  void xtensa_sync_window_from_phys(CPUXtensaState *env);
>  void xtensa_sync_phys_from_window(CPUXtensaState *env);
> --
> 2.25.1
>
>

[-- Attachment #2: Type: text/html, Size: 22648 bytes --]

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [RFC PATCH 6/7] linux-user: Handle SIGSEGV/SIGBUS in host_to_target_siginfo_noswap
  2021-09-13 22:05 ` [RFC PATCH 6/7] linux-user: Handle SIGSEGV/SIGBUS in host_to_target_siginfo_noswap Richard Henderson
@ 2021-09-15 16:23   ` Warner Losh
  2021-09-15 16:27     ` Richard Henderson
  0 siblings, 1 reply; 18+ messages in thread
From: Warner Losh @ 2021-09-15 16:23 UTC (permalink / raw)
  To: Richard Henderson; +Cc: Peter Maydell, QEMU Developers, Laurent Vivier

[-- Attachment #1: Type: text/plain, Size: 1510 bytes --]

On Mon, Sep 13, 2021 at 4:05 PM Richard Henderson <
richard.henderson@linaro.org> wrote:

> Remap the faulting address from the host address space into
> the guest address space.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>  linux-user/signal.c | 9 +++++++++
>  1 file changed, 9 insertions(+)
>

Reviewed-by: Warner Losh <imp@bsdimp.com>

If I'm understanding this right, the FreeBSD code in the bsd-user fork
won't be affected by this change.
(or conversely, it's so far behind the linux stuff that it will need to be
completely
revamped).

Warner


> diff --git a/linux-user/signal.c b/linux-user/signal.c
> index a8faea6f09..73c0f9066b 100644
> --- a/linux-user/signal.c
> +++ b/linux-user/signal.c
> @@ -405,6 +405,15 @@ static inline void
> host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
>              tinfo->_sifields._sigpoll._fd = info->si_fd;
>              si_type = QEMU_SI_POLL;
>              break;
> +        case TARGET_SIGSEGV:
> +        case TARGET_SIGBUS:
> +            /*
> +             * Remap the host address into the target space.
> +             * Even an invalid guest address is still valid for a fault.
> +             */
> +            tinfo->_sifields._sigfault._addr = h2g_nocheck(info->si_addr);
> +            si_type = QEMU_SI_FAULT;
> +            break;
>          default:
>              /* Assume a sigqueue()/mq_notify()/rt_sigqueueinfo() source.
> */
>              tinfo->_sifields._rt._pid = info->si_pid;
> --
> 2.25.1
>
>

[-- Attachment #2: Type: text/html, Size: 2385 bytes --]

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [RFC PATCH 6/7] linux-user: Handle SIGSEGV/SIGBUS in host_to_target_siginfo_noswap
  2021-09-15 16:23   ` Warner Losh
@ 2021-09-15 16:27     ` Richard Henderson
  0 siblings, 0 replies; 18+ messages in thread
From: Richard Henderson @ 2021-09-15 16:27 UTC (permalink / raw)
  To: Warner Losh; +Cc: Peter Maydell, QEMU Developers, Laurent Vivier

On 9/15/21 9:23 AM, Warner Losh wrote:
> 
> 
> On Mon, Sep 13, 2021 at 4:05 PM Richard Henderson <richard.henderson@linaro.org 
> <mailto:richard.henderson@linaro.org>> wrote:
> 
>     Remap the faulting address from the host address space into
>     the guest address space.
> 
>     Signed-off-by: Richard Henderson <richard.henderson@linaro.org
>     <mailto:richard.henderson@linaro.org>>
>     ---
>       linux-user/signal.c | 9 +++++++++
>       1 file changed, 9 insertions(+)
> 
> 
> Reviewed-by: Warner Losh <imp@bsdimp.com <mailto:imp@bsdimp.com>>
> 
> If I'm understanding this right, the FreeBSD code in the bsd-user fork won't be affected 
> by this change.
> (or conversely, it's so far behind the linux stuff that it will need to be completely
> revamped).

The converse, yes.  I haven't looked at your branch, but I assume that it'll be easier 
with this cleanup than without.  FWIW.


r~


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [RFC PATCH 7/7] linux-user: Reorg cpu_signal_handler
  2021-09-13 22:05 ` [RFC PATCH 7/7] linux-user: Reorg cpu_signal_handler Richard Henderson
@ 2021-09-15 16:43   ` Warner Losh
  2021-09-15 16:52     ` Richard Henderson
  2021-09-16  8:51   ` Philippe Mathieu-Daudé
  1 sibling, 1 reply; 18+ messages in thread
From: Warner Losh @ 2021-09-15 16:43 UTC (permalink / raw)
  To: Richard Henderson; +Cc: Peter Maydell, QEMU Developers, Laurent Vivier

[-- Attachment #1: Type: text/plain, Size: 51798 bytes --]

On Mon, Sep 13, 2021 at 4:06 PM Richard Henderson <
richard.henderson@linaro.org> wrote:

> Split out two functions into linux-user/host/arch/host-signal.h.
> Since linux-user requires a linux host, drop all of the BSD and
> Solaris ifdefs.  These should be recreated under bsd-user/ when
> the current blanks there are filled.
>

For some architectures, this code will be small and host specific (I'm
thinking
arm, i386, ppc* and x86_64) but for others, there's common code that can be
shared
to parse the instruction (aarch64, mips*, riscv*). Do you see any value in
sharing that instruction parsing code in some way?

Otherwise, this is mostly just code shuffling and figuring out which of
the long legacy of ifdefs are still relevant in the *BSD world. At the
moment, we only build bsd-user on FreeBSD since the scaffolding
for the other BSDs is absent. I can cope when I merge this into the
bsd-user fork and loop things back when those bits are up for inclusion
in future patch trains.

Warner


> Fold the remnants of handle_cpu_signal into host_signal_handler.
>
> Drop the call to cc->tcg_ops->tlb_fill.  This was simply an indirect
> method to raise SIGSEGV; it is far easier to pass the host siginfo_t
> along to the guest.  This fixes all of the guest cpu_loop code that
> currently fails to properly fill in SEGV_MAPERR vs SEGV_ACCERR.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>  include/exec/exec-all.h               |  12 -
>  linux-user/host/aarch64/host-signal.h |  73 +++
>  linux-user/host/alpha/host-signal.h   |  41 ++
>  linux-user/host/arm/host-signal.h     |  30 ++
>  linux-user/host/i386/host-signal.h    |  24 +
>  linux-user/host/mips/host-signal.h    |  61 +++
>  linux-user/host/ppc/host-signal.h     |  24 +
>  linux-user/host/ppc64/host-signal.h   |   1 +
>  linux-user/host/riscv32/host-signal.h |  57 +++
>  linux-user/host/riscv64/host-signal.h |   1 +
>  linux-user/host/s390/host-signal.h    |  92 ++++
>  linux-user/host/s390x/host-signal.h   |   1 +
>  linux-user/host/sparc/host-signal.h   |  53 ++
>  linux-user/host/sparc64/host-signal.h |   1 +
>  linux-user/host/x86_64/host-signal.h  |  24 +
>  accel/tcg/user-exec.c                 | 712 --------------------------
>  linux-user/signal.c                   |  93 ++--
>  17 files changed, 543 insertions(+), 757 deletions(-)
>  create mode 100644 linux-user/host/aarch64/host-signal.h
>  create mode 100644 linux-user/host/alpha/host-signal.h
>  create mode 100644 linux-user/host/arm/host-signal.h
>  create mode 100644 linux-user/host/i386/host-signal.h
>  create mode 100644 linux-user/host/mips/host-signal.h
>  create mode 100644 linux-user/host/ppc/host-signal.h
>  create mode 100644 linux-user/host/ppc64/host-signal.h
>  create mode 100644 linux-user/host/riscv32/host-signal.h
>  create mode 100644 linux-user/host/riscv64/host-signal.h
>  create mode 100644 linux-user/host/s390/host-signal.h
>  create mode 100644 linux-user/host/s390x/host-signal.h
>  create mode 100644 linux-user/host/sparc/host-signal.h
>  create mode 100644 linux-user/host/sparc64/host-signal.h
>  create mode 100644 linux-user/host/x86_64/host-signal.h
>
> diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
> index f582d3e688..addcec6381 100644
> --- a/include/exec/exec-all.h
> +++ b/include/exec/exec-all.h
> @@ -683,18 +683,6 @@ uintptr_t adjust_signal_pc(uintptr_t pc);
>  bool handle_sigsegv_accerr_write(CPUState *cpu, sigset_t *old_set,
>                                   uintptr_t host_pc, uintptr_t host_addr);
>
> -/**
> - * cpu_signal_handler
> - * @signum: host signal number
> - * @pinfo: host siginfo_t
> - * @puc: host ucontext_t
> - *
> - * To be called from the SIGBUS and SIGSEGV signal handler to inform the
> - * virtual cpu of exceptions.  Returns true if the signal was handled by
> - * the virtual CPU.
> - */
> -int cpu_signal_handler(int signum, void *pinfo, void *puc);
> -
>  #else
>  static inline void mmap_lock(void) {}
>  static inline void mmap_unlock(void) {}
> diff --git a/linux-user/host/aarch64/host-signal.h
> b/linux-user/host/aarch64/host-signal.h
> new file mode 100644
> index 0000000000..818da17a21
> --- /dev/null
> +++ b/linux-user/host/aarch64/host-signal.h
> @@ -0,0 +1,73 @@
> +/*
> + * host-signal.h: signal info dependent on the host architecture
> + *
> + * Copyright (C) 2021 Linaro Limited
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or
> later.
> + * See the COPYING file in the top-level directory.
> + */
> +
> +#ifndef AARCH64_HOST_SIGNAL_H
> +#define AARCH64_HOST_SIGNAL_H
> +
> +/* Pre-3.16 kernel headers don't have these, so provide fallback
> definitions */
> +#ifndef ESR_MAGIC
> +#define ESR_MAGIC 0x45535201
> +struct esr_context {
> +    struct _aarch64_ctx head;
> +    uint64_t esr;
> +};
> +#endif
> +
> +static inline struct _aarch64_ctx *first_ctx(ucontext_t *uc)
> +{
> +    return (struct _aarch64_ctx *)&uc->uc_mcontext.__reserved;
> +}
> +
> +static inline struct _aarch64_ctx *next_ctx(struct _aarch64_ctx *hdr)
> +{
> +    return (struct _aarch64_ctx *)((char *)hdr + hdr->size);
> +}
> +
> +static inline uintptr_t host_signal_pc(ucontext_t *uc)
> +{
> +    return uc->uc_mcontext.pc;
> +}
> +
> +static inline bool host_sigsegv_write(siginfo_t *info, ucontext_t *uc)
> +{
> +    struct _aarch64_ctx *hdr;
> +    uint32_t insn;
> +
> +    /* Find the esr_context, which has the WnR bit in it */
> +    for (hdr = first_ctx(uc); hdr->magic; hdr = next_ctx(hdr)) {
> +        if (hdr->magic == ESR_MAGIC) {
> +            struct esr_context const *esrctx = (struct esr_context const
> *)hdr;
> +            uint64_t esr = esrctx->esr;
> +
> +            /* For data aborts ESR.EC is 0b10010x: then bit 6 is the WnR
> bit */
> +            return extract32(esr, 27, 5) == 0x12 && extract32(esr, 6, 1)
> == 1;
> +        }
> +    }
> +
> +    /*
> +     * Fall back to parsing instructions; will only be needed
> +     * for really ancient (pre-3.16) kernels.
> +     */
> +    insn = *(uint32_t *)host_signal_pc(uc);
> +
> +    return (insn & 0xbfff0000) == 0x0c000000   /* C3.3.1 */
> +        || (insn & 0xbfe00000) == 0x0c800000   /* C3.3.2 */
> +        || (insn & 0xbfdf0000) == 0x0d000000   /* C3.3.3 */
> +        || (insn & 0xbfc00000) == 0x0d800000   /* C3.3.4 */
> +        || (insn & 0x3f400000) == 0x08000000   /* C3.3.6 */
> +        || (insn & 0x3bc00000) == 0x39000000   /* C3.3.13 */
> +        || (insn & 0x3fc00000) == 0x3d800000   /* ... 128bit */
> +        /* Ignore bits 10, 11 & 21, controlling indexing.  */
> +        || (insn & 0x3bc00000) == 0x38000000   /* C3.3.8-12 */
> +        || (insn & 0x3fe00000) == 0x3c800000   /* ... 128bit */
> +        /* Ignore bits 23 & 24, controlling indexing.  */
> +        || (insn & 0x3a400000) == 0x28000000; /* C3.3.7,14-16 */
> +}
> +
> +#endif
> diff --git a/linux-user/host/alpha/host-signal.h
> b/linux-user/host/alpha/host-signal.h
> new file mode 100644
> index 0000000000..eaf83added
> --- /dev/null
> +++ b/linux-user/host/alpha/host-signal.h
> @@ -0,0 +1,41 @@
> +/*
> + * host-signal.h: signal info dependent on the host architecture
> + *
> + * Copyright (C) 2021 Linaro Limited
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or
> later.
> + * See the COPYING file in the top-level directory.
> + */
> +
> +#ifndef ALPHA_HOST_SIGNAL_H
> +#define ALPHA_HOST_SIGNAL_H
> +
> +static inline uintptr_t host_signal_pc(ucontext_t *uc)
> +{
> +    return uc->uc_mcontext.sc_pc;
> +}
> +
> +static inline bool host_sigsegv_write(siginfo_t *info, ucontext_t *uc)
> +{
> +    uint32_t *pc = uc->uc_mcontext.sc_pc;
> +    uint32_t insn = *pc;
> +
> +    /* XXX: need kernel patch to get write flag faster */
> +    switch (insn >> 26) {
> +    case 0x0d: /* stw */
> +    case 0x0e: /* stb */
> +    case 0x0f: /* stq_u */
> +    case 0x24: /* stf */
> +    case 0x25: /* stg */
> +    case 0x26: /* sts */
> +    case 0x27: /* stt */
> +    case 0x2c: /* stl */
> +    case 0x2d: /* stq */
> +    case 0x2e: /* stl_c */
> +    case 0x2f: /* stq_c */
> +        return true;
> +    }
> +    return false;
> +}
> +
> +#endif
> diff --git a/linux-user/host/arm/host-signal.h
> b/linux-user/host/arm/host-signal.h
> new file mode 100644
> index 0000000000..ae6bcde6c1
> --- /dev/null
> +++ b/linux-user/host/arm/host-signal.h
> @@ -0,0 +1,30 @@
> +/*
> + * host-signal.h: signal info dependent on the host architecture
> + *
> + * Copyright (C) 2021 Linaro Limited
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or
> later.
> + * See the COPYING file in the top-level directory.
> + */
> +
> +#ifndef ARM_HOST_SIGNAL_H
> +#define ARM_HOST_SIGNAL_H
> +
> +static inline uintptr_t host_signal_pc(ucontext_t *uc)
> +{
> +    return uc->uc_mcontext.gregs[R15];
> +}
> +
> +static inline bool host_sigsegv_write(siginfo_t *info, ucontext_t *uc,
> +                                      uintptr_t pc)
> +{
> +    /*
> +     * In the FSR, bit 11 is WnR, assuming a v6 or
> +     * later processor.  On v5 we will always report
> +     * this as a read, which will fail later.
> +     */
> +    uint32_t fsr = uc->uc_mcontext.error_code;
> +    return extract32(fsr, 11, 1);
> +}
> +
> +#endif
> diff --git a/linux-user/host/i386/host-signal.h
> b/linux-user/host/i386/host-signal.h
> new file mode 100644
> index 0000000000..a8ca5e4a89
> --- /dev/null
> +++ b/linux-user/host/i386/host-signal.h
> @@ -0,0 +1,24 @@
> +/*
> + * host-signal.h: signal info dependent on the host architecture
> + *
> + * Copyright (C) 2021 Linaro Limited
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or
> later.
> + * See the COPYING file in the top-level directory.
> + */
> +
> +#ifndef I386_HOST_SIGNAL_H
> +#define I386_HOST_SIGNAL_H
> +
> +static inline uintptr_t host_signal_pc(ucontext_t *uc)
> +{
> +    return uc->uc_mcontext.gregs[REG_EIP];
> +}
> +
> +static inline bool host_sigsegv_write(siginfo_t *info, ucontext_t *uc)
> +{
> +    return uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe
> +        && (uc->uc_mcontext.gregs[REG_ERR] & 0x2);
> +}
> +
> +#endif
> diff --git a/linux-user/host/mips/host-signal.h
> b/linux-user/host/mips/host-signal.h
> new file mode 100644
> index 0000000000..815bbd61fa
> --- /dev/null
> +++ b/linux-user/host/mips/host-signal.h
> @@ -0,0 +1,61 @@
> +/*
> + * host-signal.h: signal info dependent on the host architecture
> + *
> + * Copyright (C) 2021 Linaro Limited
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or
> later.
> + * See the COPYING file in the top-level directory.
> + */
> +
> +#ifndef MIPS_HOST_SIGNAL_H
> +#define MIPS_HOST_SIGNAL_H
> +
> +static inline uintptr_t host_signal_pc(ucontext_t *uc)
> +{
> +    return uc->uc_mcontext.pc;
> +}
> +
> +#if defined(__misp16) || defined(__mips_micromips)
> +#error "Unsupported encoding"
> +#endif
> +
> +static inline bool host_sigsegv_write(siginfo_t *info, ucontext_t *uc)
> +{
> +    uint32_t *insn = *(uint32_t *)host_signal_pc(uc);
> +
> +    /* Detect all store instructions at program counter. */
> +    switch ((insn >> 26) & 077) {
> +    case 050: /* SB */
> +    case 051: /* SH */
> +    case 052: /* SWL */
> +    case 053: /* SW */
> +    case 054: /* SDL */
> +    case 055: /* SDR */
> +    case 056: /* SWR */
> +    case 070: /* SC */
> +    case 071: /* SWC1 */
> +    case 074: /* SCD */
> +    case 075: /* SDC1 */
> +    case 077: /* SD */
> +#if !defined(__mips_isa_rev) || __mips_isa_rev < 6
> +    case 072: /* SWC2 */
> +    case 076: /* SDC2 */
> +#endif
> +        return true;
> +    case 023: /* COP1X */
> +        /*
> +         * Required in all versions of MIPS64 since
> +         * MIPS64r1 and subsequent versions of MIPS32r2.
> +         */
> +        switch (insn & 077) {
> +        case 010: /* SWXC1 */
> +        case 011: /* SDXC1 */
> +        case 015: /* SUXC1 */
> +            return true;
> +        }
> +        break;
> +    }
> +    return false;
> +}
> +
> +#endif
> diff --git a/linux-user/host/ppc/host-signal.h
> b/linux-user/host/ppc/host-signal.h
> new file mode 100644
> index 0000000000..b8dce622b4
> --- /dev/null
> +++ b/linux-user/host/ppc/host-signal.h
> @@ -0,0 +1,24 @@
> +/*
> + * host-signal.h: signal info dependent on the host architecture
> + *
> + * Copyright (C) 2021 Linaro Limited
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or
> later.
> + * See the COPYING file in the top-level directory.
> + */
> +
> +#ifndef PPC_HOST_SIGNAL_H
> +#define PPC_HOST_SIGNAL_H
> +
> +static inline uintptr_t host_signal_pc(ucontext_t *uc)
> +{
> +    return uc->uc_mcontext.regs->nip;
> +}
> +
> +static inline bool host_sigsegv_write(siginfo_t *info, ucontext_t *uc)
> +{
> +    return uc->uc_mcontext.regs->trap != 0x400
> +        && (uc->uc_mcontext.regs->dsisr & 0x02000000);
> +}
> +
> +#endif
> diff --git a/linux-user/host/ppc64/host-signal.h
> b/linux-user/host/ppc64/host-signal.h
> new file mode 100644
> index 0000000000..a353c22a90
> --- /dev/null
> +++ b/linux-user/host/ppc64/host-signal.h
> @@ -0,0 +1 @@
> +#include "../ppc/host-signal.h"
> diff --git a/linux-user/host/riscv32/host-signal.h
> b/linux-user/host/riscv32/host-signal.h
> new file mode 100644
> index 0000000000..f877412f96
> --- /dev/null
> +++ b/linux-user/host/riscv32/host-signal.h
> @@ -0,0 +1,57 @@
> +/*
> + * host-signal.h: signal info dependent on the host architecture
> + *
> + * Copyright (C) 2021 Linaro Limited
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or
> later.
> + * See the COPYING file in the top-level directory.
> + */
> +
> +#ifndef RISCV_HOST_SIGNAL_H
> +#define RISCV_HOST_SIGNAL_H
> +
> +static inline uintptr_t host_signal_pc(ucontext_t *uc)
> +{
> +    return uc->uc_mcontext.__gregs[REG_PC];
> +}
> +
> +static inline bool host_sigsegv_write(siginfo_t *info, ucontext_t *uc)
> +{
> +    /*
> +     * Detect store by reading the instruction at the program counter.
> +     * Do not read more than 16 bits, because we have not yet determined
> +     * the size of the instruction.
> +     */
> +    const uint16_t *pinsn = (const uint16_t *)host_signal_pc(uc);
> +    uint16_t insn = pinsn[0];
> +
> +    /* 16-bit instructions */
> +    switch (insn & 0xe003) {
> +    case 0xa000: /* c.fsd */
> +    case 0xc000: /* c.sw */
> +    case 0xe000: /* c.sd (rv64) / c.fsw (rv32) */
> +    case 0xa002: /* c.fsdsp */
> +    case 0xc002: /* c.swsp */
> +    case 0xe002: /* c.sdsp (rv64) / c.fswsp (rv32) */
> +        return true;
> +    }
> +
> +    /* 32-bit instructions, major opcodes */
> +    switch (insn & 0x7f) {
> +    case 0x23: /* store */
> +    case 0x27: /* store-fp */
> +        return true;
> +    case 0x2f: /* amo */
> +        /*
> +         * The AMO function code is in bits 25-31, unread as yet.
> +         * The AMO functions are LR (read), SC (write), and the
> +         * rest are all read-modify-write.
> +         */
> +        insn = pinsn[1];
> +        return (insn >> 11) != 2; /* LR */
> +    }
> +
> +    return false;
> +}
> +
> +#endif
> diff --git a/linux-user/host/riscv64/host-signal.h
> b/linux-user/host/riscv64/host-signal.h
> new file mode 100644
> index 0000000000..6e27f725ab
> --- /dev/null
> +++ b/linux-user/host/riscv64/host-signal.h
> @@ -0,0 +1 @@
> +#include "../riscv32/host-signal.h"
> diff --git a/linux-user/host/s390/host-signal.h
> b/linux-user/host/s390/host-signal.h
> new file mode 100644
> index 0000000000..8d34b32b9f
> --- /dev/null
> +++ b/linux-user/host/s390/host-signal.h
> @@ -0,0 +1,92 @@
> +/*
> + * host-signal.h: signal info dependent on the host architecture
> + *
> + * Copyright (C) 2021 Linaro Limited
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or
> later.
> + * See the COPYING file in the top-level directory.
> + */
> +
> +#ifndef S390_HOST_SIGNAL_H
> +#define S390_HOST_SIGNAL_H
> +
> +static inline uintptr_t host_signal_pc(ucontext_t *uc)
> +{
> +    return uc->uc_mcontext.psw.addr;
> +}
> +
> +static inline bool host_sigsegv_write(siginfo_t *info, ucontext_t *uc)
> +{
> +    uint16_t *pinsn = (uint16_t *)host_signal_pc(uc);
> +
> +    /*
> +     * ??? On linux, the non-rt signal handler has 4 (!) arguments instead
> +     * of the normal 2 arguments.  The 4th argument contains the
> "Translation-
> +     * Exception Identification for DAT Exceptions" from the hardware (aka
> +     * "int_parm_long"), which does in fact contain the is_write value.
> +     * The rt signal handler, as far as I can tell, does not give this
> value
> +     * at all.  Not that we could get to it from here even if it were.
> +     * So fall back to parsing instructions.  Treat read-modify-write
> ones as
> +     * writes, which is not fully correct, but for tracking
> self-modifying code
> +     * this is better than treating them as reads.  Checking si_addr page
> flags
> +     * might be a viable improvement, albeit a racy one.
> +     */
> +    /* ??? This is not even close to complete.  */
> +    switch (pinsn[0] >> 8) {
> +    case 0x50: /* ST */
> +    case 0x42: /* STC */
> +    case 0x40: /* STH */
> +    case 0xba: /* CS */
> +    case 0xbb: /* CDS */
> +        return true;
> +    case 0xc4: /* RIL format insns */
> +        switch (pinsn[0] & 0xf) {
> +        case 0xf: /* STRL */
> +        case 0xb: /* STGRL */
> +        case 0x7: /* STHRL */
> +            return true;
> +        }
> +        break;
> +    case 0xc8: /* SSF format insns */
> +        switch (pinsn[0] & 0xf) {
> +        case 0x2: /* CSST */
> +            return true;
> +        }
> +        break;
> +    case 0xe3: /* RXY format insns */
> +        switch (pinsn[2] & 0xff) {
> +        case 0x50: /* STY */
> +        case 0x24: /* STG */
> +        case 0x72: /* STCY */
> +        case 0x70: /* STHY */
> +        case 0x8e: /* STPQ */
> +        case 0x3f: /* STRVH */
> +        case 0x3e: /* STRV */
> +        case 0x2f: /* STRVG */
> +            return true;
> +        }
> +        break;
> +    case 0xeb: /* RSY format insns */
> +        switch (pinsn[2] & 0xff) {
> +        case 0x14: /* CSY */
> +        case 0x30: /* CSG */
> +        case 0x31: /* CDSY */
> +        case 0x3e: /* CDSG */
> +        case 0xe4: /* LANG */
> +        case 0xe6: /* LAOG */
> +        case 0xe7: /* LAXG */
> +        case 0xe8: /* LAAG */
> +        case 0xea: /* LAALG */
> +        case 0xf4: /* LAN */
> +        case 0xf6: /* LAO */
> +        case 0xf7: /* LAX */
> +        case 0xfa: /* LAAL */
> +        case 0xf8: /* LAA */
> +            return true;
> +        }
> +        break;
> +    }
> +    return false;
> +}
> +
> +#endif
> diff --git a/linux-user/host/s390x/host-signal.h
> b/linux-user/host/s390x/host-signal.h
> new file mode 100644
> index 0000000000..0e83f9358d
> --- /dev/null
> +++ b/linux-user/host/s390x/host-signal.h
> @@ -0,0 +1 @@
> +#include "../s390/host-signal.h"
> diff --git a/linux-user/host/sparc/host-signal.h
> b/linux-user/host/sparc/host-signal.h
> new file mode 100644
> index 0000000000..47d3b1512e
> --- /dev/null
> +++ b/linux-user/host/sparc/host-signal.h
> @@ -0,0 +1,53 @@
> +/*
> + * host-signal.h: signal info dependent on the host architecture
> + *
> + * Copyright (C) 2021 Linaro Limited
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or
> later.
> + * See the COPYING file in the top-level directory.
> + */
> +
> +#ifndef SPARC_HOST_SIGNAL_H
> +#define SPARC_HOST_SIGNAL_H
> +
> +static inline uintptr_t host_signal_pc(ucontext_t *uc)
> +{
> +#ifdef __arch64__
> +    return uc->uc_mcontext.mc_gregs[MC_PC];
> +#else
> +    return uc->uc_mcontext.gregs[REG_PC];
> +#endif
> +}
> +
> +static inline bool host_sigsegv_write(siginfo_t *info, ucontext_t *uc)
> +{
> +    uint32_t insn = *(uint32_t *)host_signal_pc(uc);
> +
> +    if ((insn >> 30) == 3) {
> +        switch ((insn >> 19) & 0x3f) {
> +        case 0x05: /* stb */
> +        case 0x15: /* stba */
> +        case 0x06: /* sth */
> +        case 0x16: /* stha */
> +        case 0x04: /* st */
> +        case 0x14: /* sta */
> +        case 0x07: /* std */
> +        case 0x17: /* stda */
> +        case 0x0e: /* stx */
> +        case 0x1e: /* stxa */
> +        case 0x24: /* stf */
> +        case 0x34: /* stfa */
> +        case 0x27: /* stdf */
> +        case 0x37: /* stdfa */
> +        case 0x26: /* stqf */
> +        case 0x36: /* stqfa */
> +        case 0x25: /* stfsr */
> +        case 0x3c: /* casa */
> +        case 0x3e: /* casxa */
> +            return true;
> +        }
> +    }
> +    return false;
> +}
> +
> +#endif
> diff --git a/linux-user/host/sparc64/host-signal.h
> b/linux-user/host/sparc64/host-signal.h
> new file mode 100644
> index 0000000000..1191fe2d40
> --- /dev/null
> +++ b/linux-user/host/sparc64/host-signal.h
> @@ -0,0 +1 @@
> +#include "../sparc/host-signal.h"
> diff --git a/linux-user/host/x86_64/host-signal.h
> b/linux-user/host/x86_64/host-signal.h
> new file mode 100644
> index 0000000000..d5fb3e4484
> --- /dev/null
> +++ b/linux-user/host/x86_64/host-signal.h
> @@ -0,0 +1,24 @@
> +/*
> + * host-signal.h: signal info dependent on the host architecture
> + *
> + * Copyright (C) 2021 Linaro Limited
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or
> later.
> + * See the COPYING file in the top-level directory.
> + */
> +
> +#ifndef X86_64_HOST_SIGNAL_H
> +#define X86_64_HOST_SIGNAL_H
> +
> +static inline uintptr_t host_signal_pc(ucontext_t *uc)
> +{
> +    return uc->uc_mcontext.gregs[REG_RIP];
> +}
> +
> +static inline bool host_sigsegv_write(siginfo_t *info, ucontext_t *uc)
> +{
> +    return uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe
> +        && (uc->uc_mcontext.gregs[REG_ERR] & 0x2);
> +}
> +
> +#endif
> diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c
> index ad6b4f6abf..39635cbea2 100644
> --- a/accel/tcg/user-exec.c
> +++ b/accel/tcg/user-exec.c
> @@ -29,23 +29,8 @@
>  #include "trace/trace-root.h"
>  #include "trace/mem.h"
>
> -#undef EAX
> -#undef ECX
> -#undef EDX
> -#undef EBX
> -#undef ESP
> -#undef EBP
> -#undef ESI
> -#undef EDI
> -#undef EIP
> -#ifdef __linux__
> -#include <sys/ucontext.h>
> -#endif
> -
>  __thread uintptr_t helper_retaddr;
>
> -//#define DEBUG_SIGNAL
> -
>  /**
>   * adjust_signal_pc:
>   * @pc: raw pc from the host signal ucontext_t.
> @@ -154,69 +139,6 @@ bool handle_sigsegv_accerr_write(CPUState *cpu,
> sigset_t *old_set,
>      }
>  }
>
> -/* 'pc' is the host PC at which the exception was raised. 'address' is
> -   the effective address of the memory exception. 'is_write' is 1 if a
> -   write caused the exception and otherwise 0'. 'old_set' is the
> -   signal set which should be restored */
> -static inline int handle_cpu_signal(uintptr_t pc, siginfo_t *info,
> -                                    int is_write, sigset_t *old_set)
> -{
> -    CPUState *cpu = current_cpu;
> -    CPUClass *cc;
> -    unsigned long address = (unsigned long)info->si_addr;
> -    MMUAccessType access_type;
> -
> -    if (is_write) {
> -        access_type = MMU_DATA_STORE;
> -    } else if (helper_retaddr == 1) {
> -        access_type = MMU_INST_FETCH;
> -    } else {
> -        access_type = MMU_DATA_LOAD;
> -    }
> -    pc = adjust_signal_pc(pc);
> -
> -    /* For synchronous signals we expect to be coming from the vCPU
> -     * thread (so current_cpu should be valid) and either from running
> -     * code or during translation which can fault as we cross pages.
> -     *
> -     * If neither is true then something has gone wrong and we should
> -     * abort rather than try and restart the vCPU execution.
> -     */
> -    if (!cpu || !cpu->running) {
> -        printf("qemu:%s received signal outside vCPU context @ pc=0x%"
> -               PRIxPTR "\n",  __func__, pc);
> -        abort();
> -    }
> -
> -#if defined(DEBUG_SIGNAL)
> -    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
> -           pc, address, is_write, *(unsigned long *)old_set);
> -#endif
> -
> -    /* XXX: locking issue */
> -    if (is_write &&
> -        info->si_signo == SIGSEGV &&
> -        info->si_code == SEGV_ACCERR &&
> -        handle_sigsegv_accerr_write(cpu, old_set, pc, address)) {
> -        return 1;
> -    }
> -
> -    /* Convert forcefully to guest address space, invalid addresses
> -       are still valid segv ones */
> -    address = h2g_nocheck(address);
> -
> -    /*
> -     * There is no way the target can handle this other than raising
> -     * an exception.  Undo signal and retaddr state prior to longjmp.
> -     */
> -    sigprocmask(SIG_SETMASK, old_set, NULL);
> -
> -    cc = CPU_GET_CLASS(cpu);
> -    cc->tcg_ops->tlb_fill(cpu, address, 0, access_type,
> -                          MMU_USER_IDX, false, pc);
> -    g_assert_not_reached();
> -}
> -
>  static int probe_access_internal(CPUArchState *env, target_ulong addr,
>                                   int fault_size, MMUAccessType
> access_type,
>                                   bool nonfault, uintptr_t ra)
> @@ -275,640 +197,6 @@ void *probe_access(CPUArchState *env, target_ulong
> addr, int size,
>      return size ? g2h(env_cpu(env), addr) : NULL;
>  }
>
> -#if defined(__i386__)
> -
> -#if defined(__NetBSD__)
> -#include <ucontext.h>
> -#include <machine/trap.h>
> -
> -#define EIP_sig(context)     ((context)->uc_mcontext.__gregs[_REG_EIP])
> -#define TRAP_sig(context)    ((context)->uc_mcontext.__gregs[_REG_TRAPNO])
> -#define ERROR_sig(context)   ((context)->uc_mcontext.__gregs[_REG_ERR])
> -#define MASK_sig(context)    ((context)->uc_sigmask)
> -#define PAGE_FAULT_TRAP      T_PAGEFLT
> -#elif defined(__FreeBSD__) || defined(__DragonFly__)
> -#include <ucontext.h>
> -#include <machine/trap.h>
> -
> -#define EIP_sig(context)  (*((unsigned long
> *)&(context)->uc_mcontext.mc_eip))
> -#define TRAP_sig(context)    ((context)->uc_mcontext.mc_trapno)
> -#define ERROR_sig(context)   ((context)->uc_mcontext.mc_err)
> -#define MASK_sig(context)    ((context)->uc_sigmask)
> -#define PAGE_FAULT_TRAP      T_PAGEFLT
> -#elif defined(__OpenBSD__)
> -#include <machine/trap.h>
> -#define EIP_sig(context)     ((context)->sc_eip)
> -#define TRAP_sig(context)    ((context)->sc_trapno)
> -#define ERROR_sig(context)   ((context)->sc_err)
> -#define MASK_sig(context)    ((context)->sc_mask)
> -#define PAGE_FAULT_TRAP      T_PAGEFLT
> -#else
> -#define EIP_sig(context)     ((context)->uc_mcontext.gregs[REG_EIP])
> -#define TRAP_sig(context)    ((context)->uc_mcontext.gregs[REG_TRAPNO])
> -#define ERROR_sig(context)   ((context)->uc_mcontext.gregs[REG_ERR])
> -#define MASK_sig(context)    ((context)->uc_sigmask)
> -#define PAGE_FAULT_TRAP      0xe
> -#endif
> -
> -int cpu_signal_handler(int host_signum, void *pinfo,
> -                       void *puc)
> -{
> -    siginfo_t *info = pinfo;
> -#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
> -    ucontext_t *uc = puc;
> -#elif defined(__OpenBSD__)
> -    struct sigcontext *uc = puc;
> -#else
> -    ucontext_t *uc = puc;
> -#endif
> -    unsigned long pc;
> -    int trapno;
> -
> -#ifndef REG_EIP
> -/* for glibc 2.1 */
> -#define REG_EIP    EIP
> -#define REG_ERR    ERR
> -#define REG_TRAPNO TRAPNO
> -#endif
> -    pc = EIP_sig(uc);
> -    trapno = TRAP_sig(uc);
> -    return handle_cpu_signal(pc, info,
> -                             trapno == PAGE_FAULT_TRAP ?
> -                             (ERROR_sig(uc) >> 1) & 1 : 0,
> -                             &MASK_sig(uc));
> -}
> -
> -#elif defined(__x86_64__)
> -
> -#ifdef __NetBSD__
> -#include <machine/trap.h>
> -#define PC_sig(context)       _UC_MACHINE_PC(context)
> -#define TRAP_sig(context)
>  ((context)->uc_mcontext.__gregs[_REG_TRAPNO])
> -#define ERROR_sig(context)    ((context)->uc_mcontext.__gregs[_REG_ERR])
> -#define MASK_sig(context)     ((context)->uc_sigmask)
> -#define PAGE_FAULT_TRAP       T_PAGEFLT
> -#elif defined(__OpenBSD__)
> -#include <machine/trap.h>
> -#define PC_sig(context)       ((context)->sc_rip)
> -#define TRAP_sig(context)     ((context)->sc_trapno)
> -#define ERROR_sig(context)    ((context)->sc_err)
> -#define MASK_sig(context)     ((context)->sc_mask)
> -#define PAGE_FAULT_TRAP       T_PAGEFLT
> -#elif defined(__FreeBSD__) || defined(__DragonFly__)
> -#include <ucontext.h>
> -#include <machine/trap.h>
> -
> -#define PC_sig(context)  (*((unsigned long
> *)&(context)->uc_mcontext.mc_rip))
> -#define TRAP_sig(context)     ((context)->uc_mcontext.mc_trapno)
> -#define ERROR_sig(context)    ((context)->uc_mcontext.mc_err)
> -#define MASK_sig(context)     ((context)->uc_sigmask)
> -#define PAGE_FAULT_TRAP       T_PAGEFLT
> -#else
> -#define PC_sig(context)       ((context)->uc_mcontext.gregs[REG_RIP])
> -#define TRAP_sig(context)     ((context)->uc_mcontext.gregs[REG_TRAPNO])
> -#define ERROR_sig(context)    ((context)->uc_mcontext.gregs[REG_ERR])
> -#define MASK_sig(context)     ((context)->uc_sigmask)
> -#define PAGE_FAULT_TRAP       0xe
> -#endif
> -
> -int cpu_signal_handler(int host_signum, void *pinfo,
> -                       void *puc)
> -{
> -    siginfo_t *info = pinfo;
> -    unsigned long pc;
> -#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
> -    ucontext_t *uc = puc;
> -#elif defined(__OpenBSD__)
> -    struct sigcontext *uc = puc;
> -#else
> -    ucontext_t *uc = puc;
> -#endif
> -
> -    pc = PC_sig(uc);
> -    return handle_cpu_signal(pc, info,
> -                             TRAP_sig(uc) == PAGE_FAULT_TRAP ?
> -                             (ERROR_sig(uc) >> 1) & 1 : 0,
> -                             &MASK_sig(uc));
> -}
> -
> -#elif defined(_ARCH_PPC)
> -
> -/***********************************************************************
> - * signal context platform-specific definitions
> - * From Wine
> - */
> -#ifdef linux
> -/* All Registers access - only for local access */
> -#define REG_sig(reg_name, context)              \
> -    ((context)->uc_mcontext.regs->reg_name)
> -/* Gpr Registers access  */
> -#define GPR_sig(reg_num, context)              REG_sig(gpr[reg_num],
> context)
> -/* Program counter */
> -#define IAR_sig(context)                       REG_sig(nip, context)
> -/* Machine State Register (Supervisor) */
> -#define MSR_sig(context)                       REG_sig(msr, context)
> -/* Count register */
> -#define CTR_sig(context)                       REG_sig(ctr, context)
> -/* User's integer exception register */
> -#define XER_sig(context)                       REG_sig(xer, context)
> -/* Link register */
> -#define LR_sig(context)                        REG_sig(link, context)
> -/* Condition register */
> -#define CR_sig(context)                        REG_sig(ccr, context)
> -
> -/* Float Registers access  */
> -#define FLOAT_sig(reg_num, context)                                     \
> -    (((double *)((char *)((context)->uc_mcontext.regs + 48 *
> 4)))[reg_num])
> -#define FPSCR_sig(context) \
> -    (*(int *)((char *)((context)->uc_mcontext.regs + (48 + 32 * 2) * 4)))
> -/* Exception Registers access */
> -#define DAR_sig(context)                       REG_sig(dar, context)
> -#define DSISR_sig(context)                     REG_sig(dsisr, context)
> -#define TRAP_sig(context)                      REG_sig(trap, context)
> -#endif /* linux */
> -
> -#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
> -#include <ucontext.h>
> -#define IAR_sig(context)               ((context)->uc_mcontext.mc_srr0)
> -#define MSR_sig(context)               ((context)->uc_mcontext.mc_srr1)
> -#define CTR_sig(context)               ((context)->uc_mcontext.mc_ctr)
> -#define XER_sig(context)               ((context)->uc_mcontext.mc_xer)
> -#define LR_sig(context)                ((context)->uc_mcontext.mc_lr)
> -#define CR_sig(context)                ((context)->uc_mcontext.mc_cr)
> -/* Exception Registers access */
> -#define DAR_sig(context)               ((context)->uc_mcontext.mc_dar)
> -#define DSISR_sig(context)             ((context)->uc_mcontext.mc_dsisr)
> -#define TRAP_sig(context)              ((context)->uc_mcontext.mc_exc)
> -#endif /* __FreeBSD__|| __FreeBSD_kernel__ */
> -
> -int cpu_signal_handler(int host_signum, void *pinfo,
> -                       void *puc)
> -{
> -    siginfo_t *info = pinfo;
> -#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
> -    ucontext_t *uc = puc;
> -#else
> -    ucontext_t *uc = puc;
> -#endif
> -    unsigned long pc;
> -    int is_write;
> -
> -    pc = IAR_sig(uc);
> -    is_write = 0;
> -#if 0
> -    /* ppc 4xx case */
> -    if (DSISR_sig(uc) & 0x00800000) {
> -        is_write = 1;
> -    }
> -#else
> -    if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000)) {
> -        is_write = 1;
> -    }
> -#endif
> -    return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
> -}
> -
> -#elif defined(__alpha__)
> -
> -int cpu_signal_handler(int host_signum, void *pinfo,
> -                           void *puc)
> -{
> -    siginfo_t *info = pinfo;
> -    ucontext_t *uc = puc;
> -    uint32_t *pc = uc->uc_mcontext.sc_pc;
> -    uint32_t insn = *pc;
> -    int is_write = 0;
> -
> -    /* XXX: need kernel patch to get write flag faster */
> -    switch (insn >> 26) {
> -    case 0x0d: /* stw */
> -    case 0x0e: /* stb */
> -    case 0x0f: /* stq_u */
> -    case 0x24: /* stf */
> -    case 0x25: /* stg */
> -    case 0x26: /* sts */
> -    case 0x27: /* stt */
> -    case 0x2c: /* stl */
> -    case 0x2d: /* stq */
> -    case 0x2e: /* stl_c */
> -    case 0x2f: /* stq_c */
> -        is_write = 1;
> -    }
> -
> -    return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
> -}
> -#elif defined(__sparc__)
> -
> -int cpu_signal_handler(int host_signum, void *pinfo,
> -                       void *puc)
> -{
> -    siginfo_t *info = pinfo;
> -    int is_write;
> -    uint32_t insn;
> -#if !defined(__arch64__) || defined(CONFIG_SOLARIS)
> -    uint32_t *regs = (uint32_t *)(info + 1);
> -    void *sigmask = (regs + 20);
> -    /* XXX: is there a standard glibc define ? */
> -    unsigned long pc = regs[1];
> -#else
> -#ifdef __linux__
> -    struct sigcontext *sc = puc;
> -    unsigned long pc = sc->sigc_regs.tpc;
> -    void *sigmask = (void *)sc->sigc_mask;
> -#elif defined(__OpenBSD__)
> -    struct sigcontext *uc = puc;
> -    unsigned long pc = uc->sc_pc;
> -    void *sigmask = (void *)(long)uc->sc_mask;
> -#elif defined(__NetBSD__)
> -    ucontext_t *uc = puc;
> -    unsigned long pc = _UC_MACHINE_PC(uc);
> -    void *sigmask = (void *)&uc->uc_sigmask;
> -#endif
> -#endif
> -
> -    /* XXX: need kernel patch to get write flag faster */
> -    is_write = 0;
> -    insn = *(uint32_t *)pc;
> -    if ((insn >> 30) == 3) {
> -        switch ((insn >> 19) & 0x3f) {
> -        case 0x05: /* stb */
> -        case 0x15: /* stba */
> -        case 0x06: /* sth */
> -        case 0x16: /* stha */
> -        case 0x04: /* st */
> -        case 0x14: /* sta */
> -        case 0x07: /* std */
> -        case 0x17: /* stda */
> -        case 0x0e: /* stx */
> -        case 0x1e: /* stxa */
> -        case 0x24: /* stf */
> -        case 0x34: /* stfa */
> -        case 0x27: /* stdf */
> -        case 0x37: /* stdfa */
> -        case 0x26: /* stqf */
> -        case 0x36: /* stqfa */
> -        case 0x25: /* stfsr */
> -        case 0x3c: /* casa */
> -        case 0x3e: /* casxa */
> -            is_write = 1;
> -            break;
> -        }
> -    }
> -    return handle_cpu_signal(pc, info, is_write, sigmask);
> -}
> -
> -#elif defined(__arm__)
> -
> -#if defined(__NetBSD__)
> -#include <ucontext.h>
> -#include <sys/siginfo.h>
> -#endif
> -
> -int cpu_signal_handler(int host_signum, void *pinfo,
> -                       void *puc)
> -{
> -    siginfo_t *info = pinfo;
> -#if defined(__NetBSD__)
> -    ucontext_t *uc = puc;
> -    siginfo_t *si = pinfo;
> -#else
> -    ucontext_t *uc = puc;
> -#endif
> -    unsigned long pc;
> -    uint32_t fsr;
> -    int is_write;
> -
> -#if defined(__NetBSD__)
> -    pc = uc->uc_mcontext.__gregs[_REG_R15];
> -#elif defined(__GLIBC__) && (__GLIBC__ < 2 || (__GLIBC__ == 2 &&
> __GLIBC_MINOR__ <= 3))
> -    pc = uc->uc_mcontext.gregs[R15];
> -#else
> -    pc = uc->uc_mcontext.arm_pc;
> -#endif
> -
> -#ifdef __NetBSD__
> -    fsr = si->si_trap;
> -#else
> -    fsr = uc->uc_mcontext.error_code;
> -#endif
> -    /*
> -     * In the FSR, bit 11 is WnR, assuming a v6 or
> -     * later processor.  On v5 we will always report
> -     * this as a read, which will fail later.
> -     */
> -    is_write = extract32(fsr, 11, 1);
> -    return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
> -}
> -
> -#elif defined(__aarch64__)
> -
> -#if defined(__NetBSD__)
> -
> -#include <ucontext.h>
> -#include <sys/siginfo.h>
> -
> -int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
> -{
> -    ucontext_t *uc = puc;
> -    siginfo_t *si = pinfo;
> -    unsigned long pc;
> -    int is_write;
> -    uint32_t esr;
> -
> -    pc = uc->uc_mcontext.__gregs[_REG_PC];
> -    esr = si->si_trap;
> -
> -    /*
> -     * siginfo_t::si_trap is the ESR value, for data aborts ESR.EC
> -     * is 0b10010x: then bit 6 is the WnR bit
> -     */
> -    is_write = extract32(esr, 27, 5) == 0x12 && extract32(esr, 6, 1) == 1;
> -    return handle_cpu_signal(pc, si, is_write, &uc->uc_sigmask);
> -}
> -
> -#else
> -
> -#ifndef ESR_MAGIC
> -/* Pre-3.16 kernel headers don't have these, so provide fallback
> definitions */
> -#define ESR_MAGIC 0x45535201
> -struct esr_context {
> -    struct _aarch64_ctx head;
> -    uint64_t esr;
> -};
> -#endif
> -
> -static inline struct _aarch64_ctx *first_ctx(ucontext_t *uc)
> -{
> -    return (struct _aarch64_ctx *)&uc->uc_mcontext.__reserved;
> -}
> -
> -static inline struct _aarch64_ctx *next_ctx(struct _aarch64_ctx *hdr)
> -{
> -    return (struct _aarch64_ctx *)((char *)hdr + hdr->size);
> -}
> -
> -int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
> -{
> -    siginfo_t *info = pinfo;
> -    ucontext_t *uc = puc;
> -    uintptr_t pc = uc->uc_mcontext.pc;
> -    bool is_write;
> -    struct _aarch64_ctx *hdr;
> -    struct esr_context const *esrctx = NULL;
> -
> -    /* Find the esr_context, which has the WnR bit in it */
> -    for (hdr = first_ctx(uc); hdr->magic; hdr = next_ctx(hdr)) {
> -        if (hdr->magic == ESR_MAGIC) {
> -            esrctx = (struct esr_context const *)hdr;
> -            break;
> -        }
> -    }
> -
> -    if (esrctx) {
> -        /* For data aborts ESR.EC is 0b10010x: then bit 6 is the WnR bit
> */
> -        uint64_t esr = esrctx->esr;
> -        is_write = extract32(esr, 27, 5) == 0x12 && extract32(esr, 6, 1)
> == 1;
> -    } else {
> -        /*
> -         * Fall back to parsing instructions; will only be needed
> -         * for really ancient (pre-3.16) kernels.
> -         */
> -        uint32_t insn = *(uint32_t *)pc;
> -
> -        is_write = ((insn & 0xbfff0000) == 0x0c000000   /* C3.3.1 */
> -                    || (insn & 0xbfe00000) == 0x0c800000   /* C3.3.2 */
> -                    || (insn & 0xbfdf0000) == 0x0d000000   /* C3.3.3 */
> -                    || (insn & 0xbfc00000) == 0x0d800000   /* C3.3.4 */
> -                    || (insn & 0x3f400000) == 0x08000000   /* C3.3.6 */
> -                    || (insn & 0x3bc00000) == 0x39000000   /* C3.3.13 */
> -                    || (insn & 0x3fc00000) == 0x3d800000   /* ... 128bit
> */
> -                    /* Ignore bits 10, 11 & 21, controlling indexing.  */
> -                    || (insn & 0x3bc00000) == 0x38000000   /* C3.3.8-12 */
> -                    || (insn & 0x3fe00000) == 0x3c800000   /* ... 128bit
> */
> -                    /* Ignore bits 23 & 24, controlling indexing.  */
> -                    || (insn & 0x3a400000) == 0x28000000); /*
> C3.3.7,14-16 */
> -    }
> -    return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
> -}
> -#endif
> -
> -#elif defined(__s390__)
> -
> -int cpu_signal_handler(int host_signum, void *pinfo,
> -                       void *puc)
> -{
> -    siginfo_t *info = pinfo;
> -    ucontext_t *uc = puc;
> -    unsigned long pc;
> -    uint16_t *pinsn;
> -    int is_write = 0;
> -
> -    pc = uc->uc_mcontext.psw.addr;
> -
> -    /*
> -     * ??? On linux, the non-rt signal handler has 4 (!) arguments instead
> -     * of the normal 2 arguments.  The 4th argument contains the
> "Translation-
> -     * Exception Identification for DAT Exceptions" from the hardware (aka
> -     * "int_parm_long"), which does in fact contain the is_write value.
> -     * The rt signal handler, as far as I can tell, does not give this
> value
> -     * at all.  Not that we could get to it from here even if it were.
> -     * So fall back to parsing instructions.  Treat read-modify-write
> ones as
> -     * writes, which is not fully correct, but for tracking
> self-modifying code
> -     * this is better than treating them as reads.  Checking si_addr page
> flags
> -     * might be a viable improvement, albeit a racy one.
> -     */
> -    /* ??? This is not even close to complete.  */
> -    pinsn = (uint16_t *)pc;
> -    switch (pinsn[0] >> 8) {
> -    case 0x50: /* ST */
> -    case 0x42: /* STC */
> -    case 0x40: /* STH */
> -    case 0xba: /* CS */
> -    case 0xbb: /* CDS */
> -        is_write = 1;
> -        break;
> -    case 0xc4: /* RIL format insns */
> -        switch (pinsn[0] & 0xf) {
> -        case 0xf: /* STRL */
> -        case 0xb: /* STGRL */
> -        case 0x7: /* STHRL */
> -            is_write = 1;
> -        }
> -        break;
> -    case 0xc8: /* SSF format insns */
> -        switch (pinsn[0] & 0xf) {
> -        case 0x2: /* CSST */
> -            is_write = 1;
> -        }
> -        break;
> -    case 0xe3: /* RXY format insns */
> -        switch (pinsn[2] & 0xff) {
> -        case 0x50: /* STY */
> -        case 0x24: /* STG */
> -        case 0x72: /* STCY */
> -        case 0x70: /* STHY */
> -        case 0x8e: /* STPQ */
> -        case 0x3f: /* STRVH */
> -        case 0x3e: /* STRV */
> -        case 0x2f: /* STRVG */
> -            is_write = 1;
> -        }
> -        break;
> -    case 0xeb: /* RSY format insns */
> -        switch (pinsn[2] & 0xff) {
> -        case 0x14: /* CSY */
> -        case 0x30: /* CSG */
> -        case 0x31: /* CDSY */
> -        case 0x3e: /* CDSG */
> -        case 0xe4: /* LANG */
> -        case 0xe6: /* LAOG */
> -        case 0xe7: /* LAXG */
> -        case 0xe8: /* LAAG */
> -        case 0xea: /* LAALG */
> -        case 0xf4: /* LAN */
> -        case 0xf6: /* LAO */
> -        case 0xf7: /* LAX */
> -        case 0xfa: /* LAAL */
> -        case 0xf8: /* LAA */
> -            is_write = 1;
> -        }
> -        break;
> -    }
> -
> -    return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
> -}
> -
> -#elif defined(__mips__)
> -
> -#if defined(__misp16) || defined(__mips_micromips)
> -#error "Unsupported encoding"
> -#endif
> -
> -int cpu_signal_handler(int host_signum, void *pinfo,
> -                       void *puc)
> -{
> -    siginfo_t *info = pinfo;
> -    ucontext_t *uc = puc;
> -    uintptr_t pc = uc->uc_mcontext.pc;
> -    uint32_t insn = *(uint32_t *)pc;
> -    int is_write = 0;
> -
> -    /* Detect all store instructions at program counter. */
> -    switch((insn >> 26) & 077) {
> -    case 050: /* SB */
> -    case 051: /* SH */
> -    case 052: /* SWL */
> -    case 053: /* SW */
> -    case 054: /* SDL */
> -    case 055: /* SDR */
> -    case 056: /* SWR */
> -    case 070: /* SC */
> -    case 071: /* SWC1 */
> -    case 074: /* SCD */
> -    case 075: /* SDC1 */
> -    case 077: /* SD */
> -#if !defined(__mips_isa_rev) || __mips_isa_rev < 6
> -    case 072: /* SWC2 */
> -    case 076: /* SDC2 */
> -#endif
> -        is_write = 1;
> -        break;
> -    case 023: /* COP1X */
> -        /* Required in all versions of MIPS64 since
> -           MIPS64r1 and subsequent versions of MIPS32r2. */
> -        switch (insn & 077) {
> -        case 010: /* SWXC1 */
> -        case 011: /* SDXC1 */
> -        case 015: /* SUXC1 */
> -            is_write = 1;
> -        }
> -        break;
> -    }
> -
> -    return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
> -}
> -
> -#elif defined(__riscv)
> -
> -int cpu_signal_handler(int host_signum, void *pinfo,
> -                       void *puc)
> -{
> -    siginfo_t *info = pinfo;
> -    ucontext_t *uc = puc;
> -    greg_t pc = uc->uc_mcontext.__gregs[REG_PC];
> -    uint32_t insn = *(uint32_t *)pc;
> -    int is_write = 0;
> -
> -    /* Detect store by reading the instruction at the program
> -       counter. Note: we currently only generate 32-bit
> -       instructions so we thus only detect 32-bit stores */
> -    switch (((insn >> 0) & 0b11)) {
> -    case 3:
> -        switch (((insn >> 2) & 0b11111)) {
> -        case 8:
> -            switch (((insn >> 12) & 0b111)) {
> -            case 0: /* sb */
> -            case 1: /* sh */
> -            case 2: /* sw */
> -            case 3: /* sd */
> -            case 4: /* sq */
> -                is_write = 1;
> -                break;
> -            default:
> -                break;
> -            }
> -            break;
> -        case 9:
> -            switch (((insn >> 12) & 0b111)) {
> -            case 2: /* fsw */
> -            case 3: /* fsd */
> -            case 4: /* fsq */
> -                is_write = 1;
> -                break;
> -            default:
> -                break;
> -            }
> -            break;
> -        default:
> -            break;
> -        }
> -    }
> -
> -    /* Check for compressed instructions */
> -    switch (((insn >> 13) & 0b111)) {
> -    case 7:
> -        switch (insn & 0b11) {
> -        case 0: /*c.sd */
> -        case 2: /* c.sdsp */
> -            is_write = 1;
> -            break;
> -        default:
> -            break;
> -        }
> -        break;
> -    case 6:
> -        switch (insn & 0b11) {
> -        case 0: /* c.sw */
> -        case 3: /* c.swsp */
> -            is_write = 1;
> -            break;
> -        default:
> -            break;
> -        }
> -        break;
> -    default:
> -        break;
> -    }
> -
> -    return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
> -}
> -
> -#else
> -
> -#error host CPU specific signal handler needed
> -
> -#endif
> -
>  /* The softmmu versions of these helpers are in cputlb.c.  */
>
>  uint32_t cpu_ldub_data(CPUArchState *env, abi_ptr ptr)
> diff --git a/linux-user/signal.c b/linux-user/signal.c
> index 73c0f9066b..509dad7850 100644
> --- a/linux-user/signal.c
> +++ b/linux-user/signal.c
> @@ -24,6 +24,7 @@
>  #include "qemu.h"
>  #include "trace.h"
>  #include "signal-common.h"
> +#include "host-signal.h"
>
>  static struct target_sigaction sigact_table[TARGET_NSIG];
>
> @@ -753,59 +754,85 @@ static inline void rewind_if_in_safe_syscall(void
> *puc)
>  }
>  #endif
>
> -static void host_signal_handler(int host_signum, siginfo_t *info,
> -                                void *puc)
> +static void host_signal_handler(int host_sig, siginfo_t *info, void *puc)
>  {
>      CPUArchState *env = thread_cpu->env_ptr;
>      CPUState *cpu = env_cpu(env);
>      TaskState *ts = cpu->opaque;
> -
> -    int sig;
> +    bool sync_sig = false;
>      target_siginfo_t tinfo;
>      ucontext_t *uc = puc;
>      struct emulated_sigtable *k;
> +    uintptr_t pc = 0;
> +    int guest_sig;
>
> -    /* the CPU emulator uses some host signals to detect exceptions,
> -       we forward to it some signals */
> -    if ((host_signum == SIGSEGV || host_signum == SIGBUS)
> -        && info->si_code > 0) {
> -        if (cpu_signal_handler(host_signum, info, puc))
> +    /*
> +     * Non-spoofed SIGSEGV and SIGBUS are synchronous, and need special
> +     * handling wrt signal blocking and unwinding.  SIGSEGV may need to
> +     * remove write-protection and restart the instruction.
> +     */
> +    if ((host_sig == SIGSEGV || host_sig == SIGBUS) && info->si_code > 0)
> {
> +        pc = adjust_signal_pc(host_signal_pc(uc));
> +        if (host_sig == SIGSEGV &&
> +            info->si_code == SEGV_ACCERR &&
> +            host_sigsegv_write(info, uc) &&
> +            handle_sigsegv_accerr_write(cpu, &uc->uc_sigmask, pc,
> +                                        (uintptr_t)info->si_addr)) {
>              return;
> +        }
> +        sync_sig = true;
> +    } else {
> +        rewind_if_in_safe_syscall(puc);
> +
> +        /*
> +         * Block host signals until target signal handler entered.
> +         * We can't block SIGSEGV or SIGBUS while we're executing
> +         * guest code in case the guest code provokes one in the
> +         * window between now and it getting out to the main loop.
> +         * Signals will be unblocked again in process_pending_signals().
> +         *
> +         * WARNING: we cannot use sigfillset() here because the uc_sigmask
> +         * field is a kernel sigset_t, which is much smaller than the
> +         * libc sigset_t which sigfillset() operates on. Using
> sigfillset()
> +         * would write 0xff bytes off the end of the structure and trash
> +         * data on the struct.
> +         * We can't use sizeof(uc->uc_sigmask) either, because the libc
> +         * headers define the struct field with the wrong (too large)
> type.
> +         */
> +        memset(&uc->uc_sigmask, 0xff, SIGSET_T_SIZE);
> +        sigdelset(&uc->uc_sigmask, SIGSEGV);
> +        sigdelset(&uc->uc_sigmask, SIGBUS);
>      }
>
>      /* get target signal number */
> -    sig = host_to_target_signal(host_signum);
> -    if (sig < 1 || sig > TARGET_NSIG)
> +    guest_sig = host_to_target_signal(host_sig);
> +    if (guest_sig < 1 || guest_sig > TARGET_NSIG) {
>          return;
> -    trace_user_host_signal(env, host_signum, sig);
> -
> -    rewind_if_in_safe_syscall(puc);
> +    }
> +    trace_user_host_signal(env, host_sig, guest_sig);
>
>      host_to_target_siginfo_noswap(&tinfo, info);
> -    k = &ts->sigtab[sig - 1];
> +    k = &ts->sigtab[guest_sig - 1];
>      k->info = tinfo;
> -    k->pending = sig;
> +    k->pending = guest_sig;
>      ts->signal_pending = 1;
>
> -    /* Block host signals until target signal handler entered. We
> -     * can't block SIGSEGV or SIGBUS while we're executing guest
> -     * code in case the guest code provokes one in the window between
> -     * now and it getting out to the main loop. Signals will be
> -     * unblocked again in process_pending_signals().
> -     *
> -     * WARNING: we cannot use sigfillset() here because the uc_sigmask
> -     * field is a kernel sigset_t, which is much smaller than the
> -     * libc sigset_t which sigfillset() operates on. Using sigfillset()
> -     * would write 0xff bytes off the end of the structure and trash
> -     * data on the struct.
> -     * We can't use sizeof(uc->uc_sigmask) either, because the libc
> -     * headers define the struct field with the wrong (too large) type.
> +    /*
> +     * For synchronous signals, unwind the cpu state to the faulting
> +     * insn and then exit back to the main loop so that the signal
> +     * is delivered immediately.
>       */
> -    memset(&uc->uc_sigmask, 0xff, SIGSET_T_SIZE);
> -    sigdelset(&uc->uc_sigmask, SIGSEGV);
> -    sigdelset(&uc->uc_sigmask, SIGBUS);
> +    if (sync_sig) {
> +        clear_helper_retaddr();
> +        sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
> +        cpu->exception_index = EXCP_INTERRUPT;
> +        cpu_loop_exit_restore(cpu, pc);
> +    }
>
> -    /* interrupt the virtual CPU as soon as possible */
> +    /*
> +     * Interrupt the virtual CPU as soon as possible, but for now
> +     * return to continue with the current TB.
> +     */
>      cpu_exit(thread_cpu);
>  }
>
> --
> 2.25.1
>
>

[-- Attachment #2: Type: text/html, Size: 61790 bytes --]

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [RFC PATCH 7/7] linux-user: Reorg cpu_signal_handler
  2021-09-15 16:43   ` Warner Losh
@ 2021-09-15 16:52     ` Richard Henderson
  0 siblings, 0 replies; 18+ messages in thread
From: Richard Henderson @ 2021-09-15 16:52 UTC (permalink / raw)
  To: Warner Losh; +Cc: Peter Maydell, QEMU Developers, Laurent Vivier

On 9/15/21 9:43 AM, Warner Losh wrote:
>     Split out two functions into linux-user/host/arch/host-signal.h.
>     Since linux-user requires a linux host, drop all of the BSD and
>     Solaris ifdefs.  These should be recreated under bsd-user/ when
>     the current blanks there are filled.
> 
> For some architectures, this code will be small and host specific (I'm thinking
> arm, i386, ppc* and x86_64) but for others, there's common code that can be shared
> to parse the instruction (aarch64, mips*, riscv*). Do you see any value in
> sharing that instruction parsing code in some way?

Yes, that would be ideal.  Although even more ideal would be for all kernels to actually 
provide detail to the signal handler so that we don't need to parse instructions. 
(AArch64 being the example where they did finally fix that, though we've still got for for 
pre-3.16 kernels still hanging about.)  How are the BSDs in this respect?

Anyway, I'm not sure how to organize such sharing, but I'm open to suggestion.


r~


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [RFC PATCH 7/7] linux-user: Reorg cpu_signal_handler
  2021-09-13 22:05 ` [RFC PATCH 7/7] linux-user: Reorg cpu_signal_handler Richard Henderson
  2021-09-15 16:43   ` Warner Losh
@ 2021-09-16  8:51   ` Philippe Mathieu-Daudé
  1 sibling, 0 replies; 18+ messages in thread
From: Philippe Mathieu-Daudé @ 2021-09-16  8:51 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: peter.maydell, laurent, imp

Hi Richard,

On 9/14/21 12:05 AM, Richard Henderson wrote:
> Split out two functions into linux-user/host/arch/host-signal.h.
> Since linux-user requires a linux host, drop all of the BSD and
> Solaris ifdefs.  These should be recreated under bsd-user/ when
> the current blanks there are filled.
> 
> Fold the remnants of handle_cpu_signal into host_signal_handler.
> 
> Drop the call to cc->tcg_ops->tlb_fill.  This was simply an indirect
> method to raise SIGSEGV; it is far easier to pass the host siginfo_t
> along to the guest.  This fixes all of the guest cpu_loop code that
> currently fails to properly fill in SEGV_MAPERR vs SEGV_ACCERR.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>  include/exec/exec-all.h               |  12 -
>  linux-user/host/aarch64/host-signal.h |  73 +++
>  linux-user/host/alpha/host-signal.h   |  41 ++
>  linux-user/host/arm/host-signal.h     |  30 ++
>  linux-user/host/i386/host-signal.h    |  24 +
>  linux-user/host/mips/host-signal.h    |  61 +++
>  linux-user/host/ppc/host-signal.h     |  24 +
>  linux-user/host/ppc64/host-signal.h   |   1 +
>  linux-user/host/riscv32/host-signal.h |  57 +++
>  linux-user/host/riscv64/host-signal.h |   1 +
>  linux-user/host/s390/host-signal.h    |  92 ++++
>  linux-user/host/s390x/host-signal.h   |   1 +
>  linux-user/host/sparc/host-signal.h   |  53 ++
>  linux-user/host/sparc64/host-signal.h |   1 +
>  linux-user/host/x86_64/host-signal.h  |  24 +
>  accel/tcg/user-exec.c                 | 712 --------------------------
>  linux-user/signal.c                   |  93 ++--
>  17 files changed, 543 insertions(+), 757 deletions(-)
>  create mode 100644 linux-user/host/aarch64/host-signal.h
>  create mode 100644 linux-user/host/alpha/host-signal.h
>  create mode 100644 linux-user/host/arm/host-signal.h
>  create mode 100644 linux-user/host/i386/host-signal.h
>  create mode 100644 linux-user/host/mips/host-signal.h
>  create mode 100644 linux-user/host/ppc/host-signal.h
>  create mode 100644 linux-user/host/ppc64/host-signal.h
>  create mode 100644 linux-user/host/riscv32/host-signal.h
>  create mode 100644 linux-user/host/riscv64/host-signal.h
>  create mode 100644 linux-user/host/s390/host-signal.h
>  create mode 100644 linux-user/host/s390x/host-signal.h
>  create mode 100644 linux-user/host/sparc/host-signal.h
>  create mode 100644 linux-user/host/sparc64/host-signal.h
>  create mode 100644 linux-user/host/x86_64/host-signal.h

> diff --git a/linux-user/signal.c b/linux-user/signal.c
> index 73c0f9066b..509dad7850 100644
> --- a/linux-user/signal.c
> +++ b/linux-user/signal.c

> -static void host_signal_handler(int host_signum, siginfo_t *info,
> -                                void *puc)
> +static void host_signal_handler(int host_sig, siginfo_t *info, void *puc)
>  {
>      CPUArchState *env = thread_cpu->env_ptr;
>      CPUState *cpu = env_cpu(env);
>      TaskState *ts = cpu->opaque;
> -
> -    int sig;
> +    bool sync_sig = false;
>      target_siginfo_t tinfo;
>      ucontext_t *uc = puc;
>      struct emulated_sigtable *k;
> +    uintptr_t pc = 0;
> +    int guest_sig;
>  
> -    /* the CPU emulator uses some host signals to detect exceptions,
> -       we forward to it some signals */
> -    if ((host_signum == SIGSEGV || host_signum == SIGBUS)
> -        && info->si_code > 0) {
> -        if (cpu_signal_handler(host_signum, info, puc))
> +    /*
> +     * Non-spoofed SIGSEGV and SIGBUS are synchronous, and need special
> +     * handling wrt signal blocking and unwinding.  SIGSEGV may need to
> +     * remove write-protection and restart the instruction.
> +     */
> +    if ((host_sig == SIGSEGV || host_sig == SIGBUS) && info->si_code > 0) {
> +        pc = adjust_signal_pc(host_signal_pc(uc));
> +        if (host_sig == SIGSEGV &&
> +            info->si_code == SEGV_ACCERR &&
> +            host_sigsegv_write(info, uc) &&
> +            handle_sigsegv_accerr_write(cpu, &uc->uc_sigmask, pc,
> +                                        (uintptr_t)info->si_addr)) {
>              return;
> +        }
> +        sync_sig = true;
> +    } else {
> +        rewind_if_in_safe_syscall(puc);
> +
> +        /*
> +         * Block host signals until target signal handler entered.
> +         * We can't block SIGSEGV or SIGBUS while we're executing
> +         * guest code in case the guest code provokes one in the
> +         * window between now and it getting out to the main loop.
> +         * Signals will be unblocked again in process_pending_signals().
> +         *
> +         * WARNING: we cannot use sigfillset() here because the uc_sigmask
> +         * field is a kernel sigset_t, which is much smaller than the
> +         * libc sigset_t which sigfillset() operates on. Using sigfillset()
> +         * would write 0xff bytes off the end of the structure and trash
> +         * data on the struct.
> +         * We can't use sizeof(uc->uc_sigmask) either, because the libc
> +         * headers define the struct field with the wrong (too large) type.
> +         */
> +        memset(&uc->uc_sigmask, 0xff, SIGSET_T_SIZE);
> +        sigdelset(&uc->uc_sigmask, SIGSEGV);
> +        sigdelset(&uc->uc_sigmask, SIGBUS);
>      }
>  
>      /* get target signal number */
> -    sig = host_to_target_signal(host_signum);
> -    if (sig < 1 || sig > TARGET_NSIG)
> +    guest_sig = host_to_target_signal(host_sig);
> +    if (guest_sig < 1 || guest_sig > TARGET_NSIG) {
>          return;
> -    trace_user_host_signal(env, host_signum, sig);
> -
> -    rewind_if_in_safe_syscall(puc);
> +    }
> +    trace_user_host_signal(env, host_sig, guest_sig);
>  
>      host_to_target_siginfo_noswap(&tinfo, info);
> -    k = &ts->sigtab[sig - 1];
> +    k = &ts->sigtab[guest_sig - 1];
>      k->info = tinfo;
> -    k->pending = sig;
> +    k->pending = guest_sig;
>      ts->signal_pending = 1;
>  
> -    /* Block host signals until target signal handler entered. We
> -     * can't block SIGSEGV or SIGBUS while we're executing guest
> -     * code in case the guest code provokes one in the window between
> -     * now and it getting out to the main loop. Signals will be
> -     * unblocked again in process_pending_signals().
> -     *
> -     * WARNING: we cannot use sigfillset() here because the uc_sigmask
> -     * field is a kernel sigset_t, which is much smaller than the
> -     * libc sigset_t which sigfillset() operates on. Using sigfillset()
> -     * would write 0xff bytes off the end of the structure and trash
> -     * data on the struct.
> -     * We can't use sizeof(uc->uc_sigmask) either, because the libc
> -     * headers define the struct field with the wrong (too large) type.
> +    /*
> +     * For synchronous signals, unwind the cpu state to the faulting
> +     * insn and then exit back to the main loop so that the signal
> +     * is delivered immediately.
>       */
> -    memset(&uc->uc_sigmask, 0xff, SIGSET_T_SIZE);
> -    sigdelset(&uc->uc_sigmask, SIGSEGV);
> -    sigdelset(&uc->uc_sigmask, SIGBUS);
> +    if (sync_sig) {
> +        clear_helper_retaddr();
> +        sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
> +        cpu->exception_index = EXCP_INTERRUPT;
> +        cpu_loop_exit_restore(cpu, pc);
> +    }
>  
> -    /* interrupt the virtual CPU as soon as possible */
> +    /*
> +     * Interrupt the virtual CPU as soon as possible, but for now
> +     * return to continue with the current TB.
> +     */
>      cpu_exit(thread_cpu);
>  }

Is it possible to split this patch per architectures,
doing for the first arch:

  #if ARCH1

  new host_signal_handler() {}

  #else

  old unmodified host_signal_handler() {}

  #endif

Then for the second:

  #if ARCH1 || ARCH2

  new host_signal_handler() {}

  #else

  old unmodified host_signal_handler() {}

  #endif

Last patch being cleaning the transition:

- #if ARCH1 || ARCH2 || ...

  new host_signal_handler() {}

- #else
-
- old unmodified host_signal_handler() {}
-
- #endif

?


^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2021-09-16  8:53 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-09-13 22:05 [RFC PATCH 0/7] linux-user: Streamline handling of SIGSEGV/SIGBUS Richard Henderson
2021-09-13 22:05 ` [RFC PATCH 1/7] include/exec: Move cpu_signal_handler declaration Richard Henderson
2021-09-14  6:03   ` Philippe Mathieu-Daudé
2021-09-15 16:09   ` Warner Losh
2021-09-13 22:05 ` [RFC PATCH 2/7] accel/tcg: Split out adjust_signal_pc Richard Henderson
2021-09-14  6:07   ` Philippe Mathieu-Daudé
2021-09-13 22:05 ` [RFC PATCH 3/7] accel/tcg: Split out handle_sigsegv_accerr_write Richard Henderson
2021-09-14  6:58   ` Philippe Mathieu-Daudé
2021-09-13 22:05 ` [RFC PATCH 4/7] accel/tcg: Move clear_helper_retaddr to cpu loop Richard Henderson
2021-09-13 22:05 ` [RFC PATCH 5/7] accel/tcg: Fold cpu_exit_tb_from_sighandler into caller Richard Henderson
2021-09-13 22:05 ` [RFC PATCH 6/7] linux-user: Handle SIGSEGV/SIGBUS in host_to_target_siginfo_noswap Richard Henderson
2021-09-15 16:23   ` Warner Losh
2021-09-15 16:27     ` Richard Henderson
2021-09-13 22:05 ` [RFC PATCH 7/7] linux-user: Reorg cpu_signal_handler Richard Henderson
2021-09-15 16:43   ` Warner Losh
2021-09-15 16:52     ` Richard Henderson
2021-09-16  8:51   ` Philippe Mathieu-Daudé
2021-09-14  1:18 ` [RFC PATCH 0/7] linux-user: Streamline handling of SIGSEGV/SIGBUS Richard Henderson

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.