:p
atchew
Login
From: Helge Deller <deller@gmx.de> The following changes since commit 759c456b1d22fe4083c8b384da27d3f56fd53f82: Merge tag 'linux-user-next-pull-request' of https://github.com/hdeller/qemu-hppa into staging (2026-04-27 12:57:33 -0400) are available in the Git repository at: https://github.com/hdeller/qemu-hppa.git tags/linux-user-next-pull-request for you to fetch changes up to 9667bf3249256788245c6ca07bc12106f3e4fa22: linux-user: Translate errno in IP_RECVERR and IPV6_RECVERR (2026-04-30 09:00:04 +0200) ---------------------------------------------------------------- Pull request for linux-user Please pull 4 fixes for the linux-user target. Two patches fix open bug reports regarding return error codes and allowed parameters. One adds missing CDROM ioctls (and fixes a few), and the last patch is a leftover from the previous pull request and helps flushing error strings at exit. ---------------------------------------------------------------- Helge Deller (4): linux-user: Add missing CDROM ioctls linux-user: Flush errors by using exit() instead of _exit() in error path linux-user: Allow getsockopt() with NULL optval address linux-user: Translate errno in IP_RECVERR and IPV6_RECVERR linux-user/ioctls.h | 29 +++++++++++++---------- linux-user/main.c | 2 +- linux-user/syscall.c | 56 +++++++++++++++++++++++++------------------- 3 files changed, 50 insertions(+), 37 deletions(-) -- 2.53.0
From: Helge Deller <deller@gmx.de> Add the missing CDROM ioctls and bring them in same order as documentation. Signed-off-by: Helge Deller <deller@gmx.de> --- linux-user/ioctls.h | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h index XXXXXXX..XXXXXXX 100644 --- a/linux-user/ioctls.h +++ b/linux-user/ioctls.h @@ -XXX,XX +XXX,XX @@ #endif IOCTL(CDROMPAUSE, 0, TYPE_NULL) - IOCTL(CDROMSTART, 0, TYPE_NULL) - IOCTL(CDROMSTOP, 0, TYPE_NULL) IOCTL(CDROMRESUME, 0, TYPE_NULL) - IOCTL(CDROMEJECT, 0, TYPE_NULL) - IOCTL(CDROMEJECT_SW, 0, TYPE_INT) - IOCTL(CDROMCLOSETRAY, 0, TYPE_NULL) - IOCTL(CDROMRESET, 0, TYPE_NULL) IOCTL(CDROMPLAYMSF, IOC_W, MK_PTR(TYPE_INT)) IOCTL(CDROMPLAYTRKIND, IOC_W, MK_PTR(TYPE_INT)) IOCTL(CDROMREADTOCHDR, IOC_R, MK_PTR(TYPE_INT)) IOCTL(CDROMREADTOCENTRY, IOC_RW, MK_PTR(TYPE_INT)) + IOCTL(CDROMSTOP, 0, TYPE_NULL) + IOCTL(CDROMSTART, 0, TYPE_NULL) + IOCTL(CDROMEJECT, 0, TYPE_NULL) IOCTL(CDROMVOLCTRL, IOC_W, MK_PTR(TYPE_INT)) IOCTL(CDROMSUBCHNL, IOC_RW, MK_PTR(TYPE_INT)) + IOCTL(CDROMEJECT_SW, IOC_W, TYPE_INT) + IOCTL(CDROMRESET, 0, TYPE_NULL) /* XXX: incorrect (need specific handling) */ IOCTL(CDROMREADAUDIO, IOC_W, MK_PTR(MK_STRUCT(STRUCT_cdrom_read_audio))) IOCTL(CDROMREADCOOKED, IOC_RW, MK_PTR(TYPE_INT)) @@ -XXX,XX +XXX,XX @@ IOCTL(CDROMREADALL, IOC_RW, MK_PTR(TYPE_INT)) IOCTL(CDROMMULTISESSION, IOC_RW, MK_PTR(TYPE_INT)) IOCTL(CDROM_GET_UPC, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(CDROM_LAST_WRITTEN, IOC_R, MK_PTR(TYPE_LONG)) IOCTL(CDROMVOLREAD, IOC_R, MK_PTR(TYPE_INT)) IOCTL(CDROMSEEK, IOC_W, MK_PTR(TYPE_INT)) IOCTL(CDROMPLAYBLK, IOC_W, MK_PTR(TYPE_INT)) - IOCTL(CDROM_MEDIA_CHANGED, 0, TYPE_NULL) - IOCTL(CDROM_SET_OPTIONS, 0, TYPE_INT) - IOCTL(CDROM_CLEAR_OPTIONS, 0, TYPE_INT) - IOCTL(CDROM_SELECT_SPEED, 0, TYPE_INT) - IOCTL(CDROM_SELECT_DISC, 0, TYPE_INT) - IOCTL(CDROM_DRIVE_STATUS, 0, TYPE_NULL) + IOCTL(CDROMCLOSETRAY, 0, TYPE_NULL) + IOCTL(CDROM_SET_OPTIONS, IOC_W, TYPE_INT) + IOCTL(CDROM_CLEAR_OPTIONS, IOC_W, TYPE_INT) + IOCTL(CDROM_SELECT_SPEED, IOC_W, TYPE_INT) + IOCTL(CDROM_SELECT_DISC, IOC_W, TYPE_INT) + IOCTL(CDROM_MEDIA_CHANGED, IOC_W, TYPE_INT) + IOCTL(CDROM_DRIVE_STATUS, IOC_W, TYPE_INT) IOCTL(CDROM_DISC_STATUS, 0, TYPE_NULL) + IOCTL(CDROM_CHANGER_NSLOTS, 0, TYPE_NULL) + IOCTL(CDROM_LOCKDOOR, IOC_W, TYPE_INT) + IOCTL(CDROM_DEBUG, IOC_W, TYPE_INT) + IOCTL(CDROM_GET_CAPABILITY, 0, TYPE_NULL) IOCTL(CDROMAUDIOBUFSIZ, 0, TYPE_INT) #if 0 -- 2.53.0
From: Helge Deller <deller@gmx.de> Similiar to previous patch - ensure that we always flush I/O by using exit() instead of _exit(). Reported by: Tobias Bergkvist <tobias@bergkv.ist> Reviewed-by: Warner Losh <imp@bsdimp.com> Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/2544 Signed-off-by: Helge Deller <deller@gmx.de> --- linux-user/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/main.c b/linux-user/main.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv, char **envp) info, &bprm); if (ret != 0) { printf("Error while loading %s: %s\n", exec_path, strerror(-ret)); - _exit(EXIT_FAILURE); + exit(EXIT_FAILURE); } for (wrk = target_environ; *wrk; wrk++) { -- 2.53.0
From: Helge Deller <deller@gmx.de> Some programs test availability of socket options by asking for the value with an NULL optval address, which currenrly always trigger an EFAULT in qemu. Fix it by allowing a NULL address, in the same manner as the Linux kernel on physical machines. Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/2390 Signed-off-by: Helge Deller <deller@gmx.de> Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com> --- linux-user/syscall.c | 50 +++++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -XXX,XX +XXX,XX @@ get_timeout: if (ret < 0) { return ret; } + /* special case: destination address is NULL, return 0 */ + if (optval_addr) { + len = 0; + } if (len == sizeof(struct target__kernel_sock_timeval)) { if (copy_to_user_timeval64(optval_addr, &tv)) { return -TARGET_EFAULT; @@ -XXX,XX +XXX,XX @@ get_timeout: } if (len > lv) len = lv; - if (len == 4) { + if (!optval_addr) { + /* writing to NULL does not give error */ + len = 0; + } else if (len == 4) { if (put_user_u32(val, optval_addr)) return -TARGET_EFAULT; } else { @@ -XXX,XX +XXX,XX @@ get_timeout: return -TARGET_EINVAL; lv = sizeof(lv); ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv)); +write_ret: if (ret < 0) return ret; - if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) { + if (!optval_addr) { + len = 0; + } else if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) { len = 1; - if (put_user_u32(len, optlen) - || put_user_u8(val, optval_addr)) + if (put_user_u8(val, optval_addr)) { return -TARGET_EFAULT; + } } else { if (len > sizeof(int)) len = sizeof(int); - if (put_user_u32(len, optlen) - || put_user_u32(val, optval_addr)) + if (put_user_u32(val, optval_addr)) { + return -TARGET_EFAULT; + } + } + if (put_user_u32(len, optlen)) { return -TARGET_EFAULT; } break; @@ -XXX,XX +XXX,XX @@ get_timeout: return -TARGET_EINVAL; lv = sizeof(lv); ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv)); - if (ret < 0) - return ret; - if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) { - len = 1; - if (put_user_u32(len, optlen) - || put_user_u8(val, optval_addr)) - return -TARGET_EFAULT; - } else { - if (len > sizeof(int)) - len = sizeof(int); - if (put_user_u32(len, optlen) - || put_user_u32(val, optval_addr)) - return -TARGET_EFAULT; - } + goto write_ret; break; default: ret = -TARGET_ENOPROTOOPT; @@ -XXX,XX +XXX,XX @@ get_timeout: if (ret < 0) { return ret; } - if (put_user_u32(lv, optlen) - || put_user_u32(val, optval_addr)) { + if (optval_addr) { + if (put_user_u32(val, optval_addr)) { + return -TARGET_EFAULT; + } + } else { + lv = 0; + } + if (put_user_u32(lv, optlen)) { return -TARGET_EFAULT; } break; -- 2.53.0
From: Helge Deller <deller@gmx.de> Translate host error codes of IP_RECVERR and IPV6_RECVERR control messages to target error codes before returning to the caller. For example, this is important for architectures (e.g. hppa, alpha, sparc, mips) on which the value of ECONNREFUSED is different to the value on a x86_64 host. Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/602 Signed-off-by: Helge Deller <deller@gmx.de> --- linux-user/syscall.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -XXX,XX +XXX,XX @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh, tgt_len != sizeof(struct errhdr_t)) { goto unimplemented; } - __put_user(errh->ee.ee_errno, &target_errh->ee.ee_errno); + __put_user(host_to_target_errno(errh->ee.ee_errno), + &target_errh->ee.ee_errno); __put_user(errh->ee.ee_origin, &target_errh->ee.ee_origin); __put_user(errh->ee.ee_type, &target_errh->ee.ee_type); __put_user(errh->ee.ee_code, &target_errh->ee.ee_code); @@ -XXX,XX +XXX,XX @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh, tgt_len != sizeof(struct errhdr6_t)) { goto unimplemented; } - __put_user(errh->ee.ee_errno, &target_errh->ee.ee_errno); + __put_user(host_to_target_errno(errh->ee.ee_errno), + &target_errh->ee.ee_errno); __put_user(errh->ee.ee_origin, &target_errh->ee.ee_origin); __put_user(errh->ee.ee_type, &target_errh->ee.ee_type); __put_user(errh->ee.ee_code, &target_errh->ee.ee_code); -- 2.53.0
The following changes since commit 2db91528542672cf0db78b3f2cc0e22b36302b38: Merge tag 'pull-vfio-20260527' of https://github.com/legoater/qemu into staging (2026-05-27 14:45:58 -0400) are available in the Git repository at: https://github.com/hdeller/qemu-hppa.git tags/linux-user-next-pull-request for you to fetch changes up to 07e701716b43da1a86c1045871c1eb613cf5e53a: linux-user: Move cpu_copy() to user-internals.h (2026-05-29 23:40:53 +0200) ---------------------------------------------------------------- linux user patches A series of patches for linux-user, specifically many FPU fixes in signal handling code for sh4, mips, ppc and s390x (from Matt Turner), a madvise() improvement (from me), and qemu header cleanups (from Peter Maydell). --- v3: Fix build failure due to unknown MADV_COLLAPSE constant in madivise() patch v2: Dropped the "ARM cortex-m55 program loading fix" and the FPU alpha patch ---------------------------------------------------------------- Helge Deller (2): linux-user: Implement finer grained madivse() syscall linux-user: Fix typo in function documentation for pgb_addr_set() Matt Turner (6): linux-user/ppc: restore fp_status from FPSCR on sigreturn linux-user/mips: save/restore FCSR across signal delivery linux-user/sh4: preserve T/M/Q bits across signal delivery linux-user/sh4: restore FP rounding mode on sigreturn target/sh4: sync fp_status when gdb writes FPSCR linux-user/s390x: restore fpu_status rounding mode from FPC on sigreturn Peter Maydell (2): linux-user: Move init_main_thread() prototype to user-internals.h linux-user: Move cpu_copy() to user-internals.h linux-user/elfload.c | 2 +- linux-user/mips/signal.c | 7 +++++++ linux-user/mmap.c | 34 +++++++++++++++++++++++++++++++++- linux-user/ppc/signal.c | 2 +- linux-user/qemu.h | 5 ----- linux-user/s390x/signal.c | 6 +++++- linux-user/sh4/signal.c | 19 ++++++++++++++++--- linux-user/user-internals.h | 18 ++++++++++++++++++ target/mips/cpu.h | 3 +++ target/mips/fpu.c | 5 +++++ target/s390x/cpu.h | 1 + target/s390x/tcg/fpu_helper.c | 20 ++++++++++++++------ target/sh4/cpu.h | 3 +++ target/sh4/gdbstub.c | 2 +- target/sh4/op_helper.c | 7 ++++++- tests/tcg/sh4/Makefile.target | 7 ------- 16 files changed, 114 insertions(+), 27 deletions(-) -- 2.54.0
From: Matt Turner <mattst88@gmail.com> restore_user_regs() restores the PPC FPSCR with a direct assignment: env->fpscr = (uint32_t) fpscr; ppc_store_fpscr() exists precisely to write FPSCR and keep the derived env->fp_status in sync: it calls fpscr_set_rounding_mode() to update the softfloat rounding mode, and set_float_rebias_overflow/underflow() to reflect the FP_OE/FP_UE enable bits. The direct assignment bypasses all of this. On sigreturn, interrupted code resumes with whatever rounding mode and overflow/underflow-rebias state the signal handler last installed in fp_status, rather than the state that was saved at signal delivery. Replace the direct assign with ppc_store_fpscr(). The FPSCR_MTFS_MASK applied inside ppc_store_fpscr() only excludes the computed FP_FEX and FP_VX bits, which it re-derives correctly from the exception and enable bits in the restored value. Fixes: bcd4933a23 ("linux-user: ppc signal handling") Cc: qemu-stable@nongnu.org Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Matt Turner <mattst88@gmail.com> Signed-off-by: Helge Deller <deller@gmx.de> --- linux-user/ppc/signal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/ppc/signal.c b/linux-user/ppc/signal.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/ppc/signal.c +++ b/linux-user/ppc/signal.c @@ -XXX,XX +XXX,XX @@ static void restore_user_regs(CPUPPCState *env, __get_user(*fpr, &frame->mc_fregs[i]); } __get_user(fpscr, &frame->mc_fregs[32]); - env->fpscr = (uint32_t) fpscr; + ppc_store_fpscr(env, (uint32_t) fpscr); } #if !defined(TARGET_PPC64) -- 2.54.0
From: Matt Turner <mattst88@gmail.com> QEMU keeps the MIPS FPU control/status register (FCSR, fcr31) in env->active_fpu.fcr31. The rounding mode, flush-to-zero (FS), and NaN-2008 mode bits in fcr31 are reflected into the derived env->active_fpu.fp_status via set_float_rounding_mode() and friends; every architectural write to FCSR goes through helper_ctc1() which calls restore_fp_status() to keep the two in sync. Both target_sigcontext variants (O32 and N32/N64) have an sc_fpc_csr field that holds FCSR, but setup_sigcontext() never wrote it and restore_sigcontext() never read it. As a result: - The signal frame always delivered sc_fpc_csr == 0 to the handler, so sigaction(SA_SIGINFO) handlers that inspect the interrupted context see the wrong FCSR. - On sigreturn, active_fpu.fcr31 retained whatever value the signal handler last installed (if any), and active_fpu.fp_status was never resynced. Interrupted code resumed with the wrong rounding mode, FS flag, and NaN-2008 semantics. Fix setup_sigcontext() to save fcr31 into sc_fpc_csr. Fix restore_sigcontext() to read it back (masked to fcr31_rw_bitmask as the kernel does) and call cpu_mips_restore_fp_status() to resync fp_status from the restored fcr31. Add cpu_mips_restore_fp_status() in target/mips/fpu.c (which already defines ieee_rm and includes fpu_helper.h), and declare it in cpu.h. Fixes: 084d0497a0 ("mips-linux-user: Save and restore fpu and dsp from sigcontext") Cc: qemu-stable@nongnu.org Signed-off-by: Matt Turner <mattst88@gmail.com> Signed-off-by: Helge Deller <deller@gmx.de> --- linux-user/mips/signal.c | 7 +++++++ target/mips/cpu.h | 3 +++ target/mips/fpu.c | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/linux-user/mips/signal.c b/linux-user/mips/signal.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/mips/signal.c +++ b/linux-user/mips/signal.c @@ -XXX,XX +XXX,XX @@ static inline void setup_sigcontext(CPUMIPSState *regs, for (i = 0; i < 32; ++i) { __put_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]); } + __put_user(regs->active_fpu.fcr31, &sc->sc_fpc_csr); } static inline void @@ -XXX,XX +XXX,XX @@ restore_sigcontext(CPUMIPSState *regs, struct target_sigcontext *sc) for (i = 0; i < 32; ++i) { __get_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]); } + { + uint32_t fcr31; + __get_user(fcr31, &sc->sc_fpc_csr); + regs->active_fpu.fcr31 = fcr31 & regs->active_fpu.fcr31_rw_bitmask; + cpu_mips_restore_fp_status(regs); + } } /* diff --git a/target/mips/cpu.h b/target/mips/cpu.h index XXXXXXX..XXXXXXX 100644 --- a/target/mips/cpu.h +++ b/target/mips/cpu.h @@ -XXX,XX +XXX,XX @@ void cpu_mips_clock_init(MIPSCPU *cpu); /* helper.c */ target_ulong exception_resume_pc(CPUMIPSState *env); +/* fpu.c */ +void cpu_mips_restore_fp_status(CPUMIPSState *env); + /** * mips_cpu_create_with_clock: * @typename: a MIPS CPU type. diff --git a/target/mips/fpu.c b/target/mips/fpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/mips/fpu.c +++ b/target/mips/fpu.c @@ -XXX,XX +XXX,XX @@ const FloatRoundMode ieee_rm[4] = { float_round_down }; +void cpu_mips_restore_fp_status(CPUMIPSState *env) +{ + restore_fp_status(env); +} + const char fregnames[32][4] = { "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", -- 2.54.0
From: Matt Turner <mattst88@gmail.com> QEMU keeps the SH4 T, M and Q status-register bits outside env->sr, in the dedicated env->sr_t, env->sr_m and env->sr_q fields; cpu_read_sr() folds them back into the architectural SR value and cpu_write_sr() splits them back out. setup_sigcontext() saved the bare env->sr (so the T/M/Q bits were always zero in the signal frame) and restore_sigcontext() wrote the value straight back into env->sr without updating sr_t/sr_m/sr_q. As a result the T bit was never preserved across signal delivery: on sigreturn the interrupted code resumed with whatever T value the signal handler last left behind. Any conditional branch (or addc/subc/rotcl/div1, etc.) immediately following the interrupted instruction could then take the wrong path. This is the cause of the long-standing intermittent failures of the tests/tcg/multiarch/signals.c test on sh4, which was marked BROKEN. With a SIGRTMIN timer firing every millisecond across many threads, the race was hit a few percent of the time and corrupted the guest heap, surfacing as a SIGSEGV in memset, a malloc assertion, or an rseq registration abort. Traced on a deterministic rr recording: a cmp/hi set T=0, the timer signal interrupted the very next instruction (a bf), the handler left T=1, and the resumed bf took glibc calloc's MORECORE_CLEARS branch, using the old top-chunk size as the clear length for a freshly split small chunk and running memset off the end of the heap. Fix setup_sigcontext()/restore_sigcontext() to use cpu_read_sr() and cpu_write_sr() so the T, M and Q bits round-trip correctly, and drop the BROKEN annotation on the sh4 signals test. Fixes: c3b5bc8ab3 ("SH4: Signal handling for the user space emulator, by Magnus Damm.") Cc: qemu-stable@nongnu.org Reviewed-by: Yoshinori Sato <yoshinori.sato@nifty.com> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Matt Turner <mattst88@gmail.com> Signed-off-by: Helge Deller <deller@gmx.de> --- linux-user/sh4/signal.c | 12 ++++++++++-- tests/tcg/sh4/Makefile.target | 7 ------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/linux-user/sh4/signal.c b/linux-user/sh4/signal.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/sh4/signal.c +++ b/linux-user/sh4/signal.c @@ -XXX,XX +XXX,XX @@ static void setup_sigcontext(struct target_sigcontext *sc, COPY(gregs[14]); COPY(gregs[15]); COPY(gbr); COPY(mach); COPY(macl); COPY(pr); - COPY(sr); COPY(pc); + COPY(pc); #undef COPY + /* The T, M and Q bits live outside env->sr; fold them back in. */ + __put_user(cpu_read_sr(regs), &sc->sc_sr); for (i=0; i<16; i++) { __put_user(regs->fregs[i], &sc->sc_fpregs[i]); @@ -XXX,XX +XXX,XX @@ static void restore_sigcontext(CPUSH4State *regs, struct target_sigcontext *sc) COPY(gregs[14]); COPY(gregs[15]); COPY(gbr); COPY(mach); COPY(macl); COPY(pr); - COPY(sr); COPY(pc); + COPY(pc); #undef COPY + /* The T, M and Q bits live outside env->sr; unfold them. */ + { + uint32_t sr; + __get_user(sr, &sc->sc_sr); + cpu_write_sr(regs, sr); + } for (i=0; i<16; i++) { __get_user(regs->fregs[i], &sc->sc_fpregs[i]); diff --git a/tests/tcg/sh4/Makefile.target b/tests/tcg/sh4/Makefile.target index XXXXXXX..XXXXXXX 100644 --- a/tests/tcg/sh4/Makefile.target +++ b/tests/tcg/sh4/Makefile.target @@ -XXX,XX +XXX,XX @@ # SuperH specific tweaks # -# This triggers failures for sh4-linux about 10% of the time. -# Random SIGSEGV at unpredictable guest address, cause unknown. -run-signals: signals - $(call skip-test, $<, "BROKEN") -run-plugin-signals-with-%: - $(call skip-test, $<, "BROKEN") - VPATH += $(SRC_PATH)/tests/tcg/sh4 test-macl: CFLAGS += -O -g -- 2.54.0
From: Matt Turner <mattst88@gmail.com> The SH4 FPSCR rounding-mode (RM) and denormal (DN) bits are not held only in env->fpscr: they are also reflected into the derived env->fp_status via set_float_rounding_mode()/set_flush_to_zero(). The guest keeps the two in sync by routing every write to FPSCR through helper_ld_fpscr(). restore_sigcontext() wrote the saved value straight into env->fpscr and never touched env->fp_status, so on sigreturn the interrupted code resumed with whatever FP rounding mode and flush-to-zero setting the signal handler last installed. (regs->flags = 0 forces the FR/SZ/PR TB flags to be recomputed, but fp_status is runtime float state, not a TB flag, so it was left stale.) This is the FP analogue of the T/M/Q bit problem just fixed for the integer status register. Factor the FPSCR -> fp_status synchronisation out of helper_ld_fpscr() into cpu_load_fpscr() and use it from restore_sigcontext() so the rounding mode round-trips correctly across signal delivery. Fixes: c3b5bc8ab3 ("SH4: Signal handling for the user space emulator, by Magnus Damm.") Cc: qemu-stable@nongnu.org Reviewed-by: Yoshinori Sato <yoshinori.sato@nifty.com> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Matt Turner <mattst88@gmail.com> Signed-off-by: Helge Deller <deller@gmx.de> --- linux-user/sh4/signal.c | 7 ++++++- target/sh4/cpu.h | 3 +++ target/sh4/op_helper.c | 7 ++++++- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/linux-user/sh4/signal.c b/linux-user/sh4/signal.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/sh4/signal.c +++ b/linux-user/sh4/signal.c @@ -XXX,XX +XXX,XX @@ static void restore_sigcontext(CPUSH4State *regs, struct target_sigcontext *sc) for (i=0; i<16; i++) { __get_user(regs->fregs[i], &sc->sc_fpregs[i]); } - __get_user(regs->fpscr, &sc->sc_fpscr); + /* Resync the derived float_status state, not just env->fpscr. */ + { + uint32_t fpscr; + __get_user(fpscr, &sc->sc_fpscr); + cpu_load_fpscr(regs, fpscr); + } __get_user(regs->fpul, &sc->sc_fpul); regs->tra = -1; /* disable syscall checks */ diff --git a/target/sh4/cpu.h b/target/sh4/cpu.h index XXXXXXX..XXXXXXX 100644 --- a/target/sh4/cpu.h +++ b/target/sh4/cpu.h @@ -XXX,XX +XXX,XX @@ static inline void cpu_write_sr(CPUSH4State *env, uint32_t sr) env->sr = sr & ~((1u << SR_M) | (1u << SR_Q) | (1u << SR_T)); } +/* Set FPSCR and the derived float_status rounding/flush-to-zero state. */ +void cpu_load_fpscr(CPUSH4State *env, uint32_t val); + #endif /* SH4_CPU_H */ diff --git a/target/sh4/op_helper.c b/target/sh4/op_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/sh4/op_helper.c +++ b/target/sh4/op_helper.c @@ -XXX,XX +XXX,XX @@ void helper_macw(CPUSH4State *env, int32_t arg0, int32_t arg1) } } -void helper_ld_fpscr(CPUSH4State *env, uint32_t val) +void cpu_load_fpscr(CPUSH4State *env, uint32_t val) { env->fpscr = val & FPSCR_MASK; if ((val & FPSCR_RM_MASK) == FPSCR_RM_ZERO) { @@ -XXX,XX +XXX,XX @@ void helper_ld_fpscr(CPUSH4State *env, uint32_t val) set_flush_to_zero((val & FPSCR_DN) != 0, &env->fp_status); } +void helper_ld_fpscr(CPUSH4State *env, uint32_t val) +{ + cpu_load_fpscr(env, val); +} + static void update_fpscr(CPUSH4State *env, uintptr_t retaddr) { int xcpt, cause, enable; -- 2.54.0
From: Matt Turner <mattst88@gmail.com> sh4_cpu_gdb_write_register() wrote the incoming FPSCR value straight into env->fpscr, leaving the derived env->fp_status (rounding mode and flush-to-zero) stale, so a gdb-initiated FPSCR change did not take effect for subsequent FP operations. Use cpu_load_fpscr() instead, the same way the adjacent case already uses cpu_write_sr() for SR. Cc: qemu-stable@nongnu.org Reviewed-by: Yoshinori Sato <yoshinori.sato@nifty.com> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Matt Turner <mattst88@gmail.com> Signed-off-by: Helge Deller <deller@gmx.de> --- target/sh4/gdbstub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/sh4/gdbstub.c b/target/sh4/gdbstub.c index XXXXXXX..XXXXXXX 100644 --- a/target/sh4/gdbstub.c +++ b/target/sh4/gdbstub.c @@ -XXX,XX +XXX,XX @@ int superh_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) env->fpul = ldl_p(mem_buf); break; case 24: - env->fpscr = ldl_p(mem_buf); + cpu_load_fpscr(env, ldl_p(mem_buf)); break; case 25 ... 40: if (env->fpscr & FPSCR_FR) { -- 2.54.0
From: Matt Turner <mattst88@gmail.com> QEMU keeps the s390x floating-point control register (FPC) in env->fpc. The rounding mode bits [2:0] of FPC are reflected into the derived env->fpu_status via set_float_rounding_mode(); every architectural write to FPC goes through HELPER(sfpc) which keeps the two in sync. restore_sigregs() restored FPC with a direct assignment: __get_user(env->fpc, &sc->fpregs.fpc); This wrote env->fpc correctly but never updated env->fpu_status, so on sigreturn the interrupted code resumed with whatever rounding mode the signal handler last installed in fpu_status. Factor the two-step "write fpc + sync fpu_status" logic out of HELPER(sfpc) into cpu_s390x_load_fpc(), declare it in cpu.h, and call it from restore_sigregs() in place of the direct assignment. cpu_s390x_load_fpc() partially reuses the sanity check from HELPER(sfpc): if the FPC value has an invalid rounding mode or reserved bits set, it falls back to 0, matching the kernel's fpu_lfpc_safe() behavior where a corrupt signal frame value causes a specification exception and 0 is used instead. HELPER(sfpc) now calls cpu_s390x_load_fpc() after its full specification-exception check, including the FEAT_FLOATING_POINT_EXT test that is not needed for the signal restore path. Fixes: 2941e0fa05 ("linux-user/s390x: Save/restore fpc when handling a signal") Cc: qemu-stable@nongnu.org Signed-off-by: Matt Turner <mattst88@gmail.com> Signed-off-by: Helge Deller <deller@gmx.de> --- linux-user/s390x/signal.c | 6 +++++- target/s390x/cpu.h | 1 + target/s390x/tcg/fpu_helper.c | 20 ++++++++++++++------ 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/linux-user/s390x/signal.c b/linux-user/s390x/signal.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/s390x/signal.c +++ b/linux-user/s390x/signal.c @@ -XXX,XX +XXX,XX @@ static void restore_sigregs(CPUS390XState *env, target_sigregs *sc) for (i = 0; i < 16; i++) { __get_user(env->aregs[i], &sc->regs.acrs[i]); } - __get_user(env->fpc, &sc->fpregs.fpc); + { + uint32_t fpc; + __get_user(fpc, &sc->fpregs.fpc); + cpu_s390x_load_fpc(env, fpc); + } for (i = 0; i < 16; i++) { __get_user(*get_freg(env, i), &sc->fpregs.fprs[i]); } diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h index XXXXXXX..XXXXXXX 100644 --- a/target/s390x/cpu.h +++ b/target/s390x/cpu.h @@ -XXX,XX +XXX,XX @@ void s390_init_sigp(void); /* helper.c */ void s390_cpu_set_psw(CPUS390XState *env, uint64_t mask, uint64_t addr); uint64_t s390_cpu_get_psw_mask(CPUS390XState *env); +void cpu_s390x_load_fpc(CPUS390XState *env, uint32_t fpc); /* outside of target/s390x/ */ S390CPU *s390_cpu_addr2state(uint16_t cpu_addr); diff --git a/target/s390x/tcg/fpu_helper.c b/target/s390x/tcg/fpu_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/s390x/tcg/fpu_helper.c +++ b/target/s390x/tcg/fpu_helper.c @@ -XXX,XX +XXX,XX @@ static const int fpc_to_rnd[8] = { float_round_to_odd, }; +void cpu_s390x_load_fpc(CPUS390XState *env, uint32_t fpc) +{ + /* + * Mimic kernel fpu_lfpc_safe(): a corrupt signal frame value that would + * trigger a specification exception instead results in FPC being set to 0. + */ + if (fpc_to_rnd[fpc & 0x7] == -1 || fpc & 0x03030088u) { + fpc = 0; + } + env->fpc = fpc; + set_float_rounding_mode(fpc_to_rnd[fpc & 0x7], &env->fpu_status); +} + /* set fpc */ void HELPER(sfpc)(CPUS390XState *env, uint64_t fpc) { @@ -XXX,XX +XXX,XX @@ void HELPER(sfpc)(CPUS390XState *env, uint64_t fpc) (!s390_has_feat(S390_FEAT_FLOATING_POINT_EXT) && fpc & 0x4)) { tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC()); } - - /* Install everything in the main FPC. */ - env->fpc = fpc; - - /* Install the rounding mode in the shadow fpu_status. */ - set_float_rounding_mode(fpc_to_rnd[fpc & 0x7], &env->fpu_status); + cpu_s390x_load_fpc(env, fpc); } /* set fpc and signal */ -- 2.54.0
Although most madvise() values are hints, some are important and are checked by userspace, especially by security-relevant applications like BoringSLL. So, return -EINVAL for those functions which we don't emulate. Signed-off-by: Helge Deller <deller@gmx.de> Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3489 --- linux-user/mmap.c | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/linux-user/mmap.c b/linux-user/mmap.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -XXX,XX +XXX,XX @@ abi_long target_madvise(abi_ulong start, abi_ulong len_in, int advice) case TARGET_MADV_KEEPONFORK: /* parisc */ advice = MADV_KEEPONFORK; break; - /* we do not care about the other MADV_xxx values yet */ + /* all other MADV_xxx values are the same across architectures */ } /* @@ -XXX,XX +XXX,XX @@ abi_long target_madvise(abi_ulong start, abi_ulong len_in, int advice) */ mmap_lock(); switch (advice) { + case MADV_NORMAL: + case MADV_RANDOM: + case MADV_SEQUENTIAL: + case MADV_WILLNEED: + case MADV_DOFORK: + case MADV_FREE: + case MADV_COLD: + case MADV_PAGEOUT: + ret = 0; /* OK */ + break; + case MADV_REMOVE: + ret = -EOPNOTSUPP; + break; case MADV_DONTDUMP: page_set_flags(start, start + len - 1, PAGE_DONTDUMP, 0); break; @@ -XXX,XX +XXX,XX @@ abi_long target_madvise(abi_ulong start, abi_ulong len_in, int advice) page_reset_target_data(start, start + len - 1); } } + break; + case MADV_DONTFORK: + case MADV_HWPOISON: + case MADV_MERGEABLE: + case MADV_UNMERGEABLE: + case MADV_HUGEPAGE: + case MADV_NOHUGEPAGE: + case MADV_POPULATE_READ: + case MADV_POPULATE_WRITE: +#ifdef MADV_COLLAPSE + case MADV_COLLAPSE: +#endif + case -1: /* BoringSSL uses -1 to check if the environment is broken */ + ret = -EINVAL; + break; + default: + qemu_log_mask(LOG_UNIMP, "Unhandled madvise(%d) call.\n", advice); + ret = -EINVAL; /* not yet known advise */ + break; } mmap_unlock(); -- 2.54.0
The third parameter is called guest_hiaddr. Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Alex Bennée <alex.bennee@linaro.org> Signed-off-by: Helge Deller <deller@gmx.de> --- linux-user/elfload.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -XXX,XX +XXX,XX @@ static bool pgb_try_mmap_set(const PGBAddrs *ga, uintptr_t base, uintptr_t brk) * pgb_addr_set: * @ga: output set of guest addrs * @guest_loaddr: guest image low address - * @guest_loaddr: guest image high address + * @guest_hiaddr: guest image high address * @identity: create for identity mapping * * Fill in @ga with the image, COMMPAGE and NULL page. -- 2.54.0
From: Peter Maydell <peter.maydell@linaro.org> The init_main_thread() prototype is needed only by code internal to linux-user/, so it doesn't need to be in qemu.h (which is also pulled in by various files outside linux-user/). Move the prototype to user-internals.h, and give it a documentation comment. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Helge Deller <deller@gmx.de> Signed-off-by: Helge Deller <deller@gmx.de> --- linux-user/qemu.h | 2 -- linux-user/user-internals.h | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/linux-user/qemu.h b/linux-user/qemu.h index XXXXXXX..XXXXXXX 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -XXX,XX +XXX,XX @@ void *lock_user_string(abi_ulong guest_addr); /* Clone cpu state */ CPUArchState *cpu_copy(CPUArchState *env); -void init_main_thread(CPUState *cs, struct image_info *info); - #endif /* QEMU_H */ diff --git a/linux-user/user-internals.h b/linux-user/user-internals.h index XXXXXXX..XXXXXXX 100644 --- a/linux-user/user-internals.h +++ b/linux-user/user-internals.h @@ -XXX,XX +XXX,XX @@ static inline void begin_parallel_context(CPUState *cs) } } +/** + * init_main_thread: Set CPU state for main thread + * @cs: CPU context to set + * @info: information about the image being loaded + * + * This function must be provided by the per-target code. It should + * set the initial CPU state based on the information about the + * starting binary in @image_info. This will be at a minimum setting + * the initial guest program counter and stack pointer; it should + * also set up any other guest register values where the Linux ABI + * defines that they start set to some other value than what the + * guest CPU architecture gives you out of reset. + */ +void init_main_thread(CPUState *cs, struct image_info *info); + /* * Include target-specific struct and function definitions; * they may need access to the target-independent structures -- 2.54.0
From: Peter Maydell <peter.maydell@linaro.org> We only use cpu_copy() inside linux-user, so we don't need to have the prototype in qemu.h available to code outside linux-user; move it to user-internals.h. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Helge Deller <deller@gmx.de> Signed-off-by: Helge Deller <deller@gmx.de> --- linux-user/qemu.h | 3 --- linux-user/user-internals.h | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/linux-user/qemu.h b/linux-user/qemu.h index XXXXXXX..XXXXXXX 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -XXX,XX +XXX,XX @@ void *lock_user_string(abi_ulong guest_addr); #define unlock_user_struct(host_ptr, guest_addr, copy) \ unlock_user(host_ptr, guest_addr, (copy) ? sizeof(*host_ptr) : 0) -/* Clone cpu state */ -CPUArchState *cpu_copy(CPUArchState *env); - #endif /* QEMU_H */ diff --git a/linux-user/user-internals.h b/linux-user/user-internals.h index XXXXXXX..XXXXXXX 100644 --- a/linux-user/user-internals.h +++ b/linux-user/user-internals.h @@ -XXX,XX +XXX,XX @@ static inline void begin_parallel_context(CPUState *cs) */ void init_main_thread(CPUState *cs, struct image_info *info); +/* Clone cpu state */ +CPUArchState *cpu_copy(CPUArchState *env); + /* * Include target-specific struct and function definitions; * they may need access to the target-independent structures -- 2.54.0