:p
atchew
Login
From: Helge Deller <deller@gmx.de> The following changes since commit 98b060da3a4f92b2a994ead5b16a87e783baf77c: Update version for v11.0.0 release (2026-04-21 16:28:47 +0100) 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 0272032af5d7ad6e19305abcd494a5f4f8dd7d58: linux-user: Add missing CDROM ioctls (2026-04-27 22:56:07 +0200) ---------------------------------------------------------------- linux-user: Pull various patches This patch series adds myself as linux-user maintainer, and includes some patches which have piled up for linux-user during the last few weeks. v2: - added various Revied-by tags - fixed Reported-by tags - added second exit() call to "Flush errors by using exit() instead of _exit() in error path" patch - added missing CDROM ioctls patch ---------------------------------------------------------------- Alistair Francis (1): linux-user/strace: Use pointer type for read and write values Gyorgy Tamasi (1): linux-user: Don't define target_stat64 struct for loongarch64 Helge Deller (8): MAINTAINERS: Add myself as maintainer for linux-user linux-user: Define SO_TIMESTAMP*_NEW and SO_RCVTIMEIO_NEW linux-user: Add setsockopt() for SO_RCVTIMEO_NEW and SO_SNDTIMEO_NEW linux-user: Add getsockopt() for SO_RCVTIMEO_NEW and SO_SNDTIMEO_NEW linux-user: Fix CLONE_PARENT_SETTID when using fork-like clone linux-user: Use abi_int for imr_ifindex in ip_mreqn struct linux-user: Flush errors by using exit() instead of _exit() in error path linux-user: Add missing CDROM ioctls James Hilliard (1): linux-user/mips: sync k0 TLS for EF_MIPS_MACH_OCTEON userlands Matt Turner (1): linux-user/ppc: Fix ppc64 rt_sigframe stack offset Richard Henderson (2): linux-user/arm/nwfpe: Replace user_registers with current_cpu linux-user/arm/nwfpe: Use thread-local storage for qemufpa Yixin Wei (1): linux-user: fix off-by-one in host_to_target_for_each_rtattr() MAINTAINERS | 1 + linux-user/alpha/sockbits.h | 7 +++++ linux-user/arm/cpu_loop.c | 2 +- linux-user/arm/nwfpe/fpa11.c | 12 ++------- linux-user/arm/nwfpe/fpa11.h | 25 ++++++------------ linux-user/elfload.c | 3 +++ linux-user/fd-trans.c | 2 +- linux-user/generic/sockbits.h | 8 ++++++ linux-user/hppa/sockbits.h | 7 +++++ linux-user/ioctls.h | 29 ++++++++++++--------- linux-user/main.c | 4 +-- linux-user/mips/sockbits.h | 7 +++++ linux-user/mips/target_cpu.h | 5 ++++ linux-user/ppc/signal.c | 16 ++++++++++-- linux-user/qemu.h | 1 + linux-user/sparc/sockbits.h | 7 +++++ linux-user/strace.list | 4 +-- linux-user/syscall.c | 49 +++++++++++++++++++++++++++-------- linux-user/syscall_defs.h | 4 +-- 19 files changed, 133 insertions(+), 60 deletions(-) -- 2.53.0
From: Helge Deller <deller@gmx.de> I'd like to step up as maintainer for linux-user. I'm actively using linux-user to emulate a HP-PARISC (hppa) linux environment on my debian buildd servers, so I'm very much interested that linux-user is running good and stable. Signed-off-by: Helge Deller <deller@gmx.de> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com> Reviewed-by: Alex Bennée <alex.bennee@linaro.org> Reviewed-by: Laurent Vivier <laurent@vivier.eu> --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index XXXXXXX..XXXXXXX 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -XXX,XX +XXX,XX @@ T: git https://github.com/qemu-bsd-user/qemu-bsd-user bsd-user-rebase-3.1 Linux user M: Laurent Vivier <laurent@vivier.eu> +M: Helge Deller <deller@gmx.de> R: Pierrick Bouvier <pierrick.bouvier@linaro.org> S: Odd Fixes F: linux-user/ -- 2.53.0
From: Matt Turner <mattst88@gmail.com> The kernel's 64-bit signal delivery (signal_64.c) uses: newsp = frame - __SIGNAL_FRAMESIZE while the 32-bit path (signal_32.c) uses: newsp = frame - (__SIGNAL_FRAMESIZE + 16) The extra 16 bytes in the 32-bit case is to place siginfo and ucontext at the same offsets as older kernels (see the comment in signal_32.c). The 64-bit rt_sigframe starts with ucontext directly and does not need this adjustment. QEMU's setup_rt_frame() unconditionally used (SIGNAL_FRAMESIZE + 16) for both 32-bit and 64-bit, placing the handler's SP 16 bytes too low on ppc64. Signal delivery and return still worked because do_rt_sigreturn had the matching wrong offset, but the vDSO DWARF unwind info encodes the correct kernel offset. This caused any DWARF unwinder (libunwind, libgcc, etc.) to compute a CFA that is 16 bytes off, reading garbage register values from the signal frame. Define RT_SIGFRAME_ADJUST (0 on ppc64, 16 on ppc32) and use it in both setup_rt_frame and do_rt_sigreturn to match the kernel. This was verified by A/B testing with libunwind's test suite: ppc64le: Gtest-bt, Ltest-bt, Gtest-concurrent, Ltest-concurrent, and Ltest-sig-context all change from FAIL to PASS. ppc64be: Gtest-bt, Ltest-bt, and Ltest-sig-context all change from FAIL to PASS. Signed-off-by: Matt Turner <mattst88@gmail.com> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Helge Deller <deller@gmx.de> Cc: qemu-stable@nongnu.org --- linux-user/ppc/signal.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) 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 @@ QEMU_BUILD_BUG_ON(offsetof(struct target_rt_sigframe, uc.tuc_mcontext) #endif +#ifdef TARGET_PPC64 +#define RT_SIGFRAME_ADJUST 0 +#else +/* + * For 32-bit rt sigframes we have an extra 16 bytes of gap + * on top of __SIGNAL_FRAMESIZE; this is to get the siginfo + * and ucontext in the same positions as in older kernels. + * See Linux's arch/powerpc/kernel/signal_32.c. + */ +#define RT_SIGFRAME_ADJUST 16 +#endif + #if defined(TARGET_PPC64) struct target_func_ptr { @@ -XXX,XX +XXX,XX @@ void setup_rt_frame(int sig, struct target_sigaction *ka, env->fpscr = 0; /* Create a stack frame for the caller of the handler. */ - newsp = rt_sf_addr - (SIGNAL_FRAMESIZE + 16); + newsp = rt_sf_addr - (SIGNAL_FRAMESIZE + RT_SIGFRAME_ADJUST); err |= put_user(env->gpr[1], newsp, target_ulong); if (err) @@ -XXX,XX +XXX,XX @@ long do_rt_sigreturn(CPUPPCState *env) struct target_rt_sigframe *rt_sf = NULL; target_ulong rt_sf_addr; - rt_sf_addr = env->gpr[1] + SIGNAL_FRAMESIZE + 16; + rt_sf_addr = env->gpr[1] + SIGNAL_FRAMESIZE + RT_SIGFRAME_ADJUST; if (!lock_user_struct(VERIFY_READ, rt_sf, rt_sf_addr, 1)) goto sigsegv; -- 2.53.0
From: Yixin Wei <easonwei1998@gmail.com> host_to_target_for_each_rtattr() uses "len > sizeof(struct rtattr)" as its loop condition. When the last rtattr in a netlink message has exactly sizeof(struct rtattr) (4) bytes remaining, the loop exits without byte-swapping its rta_len and rta_type. A big-endian guest then reads rta_len in the wrong byte order and fails validation. The companion function target_to_host_for_each_rtattr() correctly uses ">=" (added in commit fa2229dbf8). The kernel's RTA_OK macro also uses ">=". Fix the host_to_target direction to match. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2485 Signed-off-by: Yixin Wei <yixinwei@meta.com> Fixes: 6c5b5645ae0 ("linux-user: add rtnetlink(7) support") Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Helge Deller <deller@gmx.de> Cc: qemu-stable@nongnu.org --- linux-user/fd-trans.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/fd-trans.c b/linux-user/fd-trans.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/fd-trans.c +++ b/linux-user/fd-trans.c @@ -XXX,XX +XXX,XX @@ static abi_long host_to_target_for_each_rtattr(struct rtattr *rtattr, unsigned short aligned_rta_len; abi_long ret; - while (len > sizeof(struct rtattr)) { + while (len >= sizeof(struct rtattr)) { rta_len = rtattr->rta_len; if (rta_len < sizeof(struct rtattr) || rta_len > len) { -- 2.53.0
From: Gyorgy Tamasi <gyorgy.tamasi@gmail.com> The kernel defines 'struct stat64' only if __BITS_PER_LONG != 64 || defined(__ARCH_WANT_STAT64). loongarch64 doesn't set __ARCH_WANT_STAT64, and it isn't 32-bit, so it won't get this struct. QEMU incorrectly does define a target_stat64 struct. However this isn't causing any guest-visible problems, because defining the target_stat64 struct and TARGET_HAS_STRUCT_STAT64 affects these syscalls: TARGET_NR_stat64 TARGET_NR_lstat64 TARGET_NR_fstat64 TARGET_NR_fstatat64 TARGET_NR_newfstatat For loongarch64 the only one of those we provide is newfstatat, and that is actually a separate QEMU bug, because the kernel does not provide that syscall for this architecture. No real guest code will be using a syscall that doesn't exist in the ABI. (Some of these syscalls are present in the loongarch64 "ABI1.0", but that ABI was never accepted in the upstream kernel, and QEMU does not model that ABI, only the "ABI2.0".) Stop defining TARGET_HAS_STRUCT_STAT64 anyway, for consistency with the kernel and to avoid confusion. Note: Commit message suggested by Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Gyorgy Tamasi <gyorgy.tamasi@gmail.com> Tested-by: Gyorgy Tamasi <gyorgy.tamasi@gmail.com> Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Helge Deller <deller@gmx.de> --- linux-user/syscall_defs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index XXXXXXX..XXXXXXX 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -XXX,XX +XXX,XX @@ struct target_stat { abi_uint __unused5; }; -#if !defined(TARGET_RISCV64) +#if !defined(TARGET_RISCV64) && !defined(TARGET_LOONGARCH64) #define TARGET_HAS_STRUCT_STAT64 struct target_stat64 { abi_ullong st_dev; -- 2.53.0
From: Richard Henderson <richard.henderson@linaro.org> Use the thread-local variable current_cpu instead of a global variable to access the general registers. This also means we don't need to pass env to EmulateAll. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Helge Deller <deller@gmx.de> --- linux-user/arm/cpu_loop.c | 2 +- linux-user/arm/nwfpe/fpa11.c | 9 +-------- linux-user/arm/nwfpe/fpa11.h | 23 +++++++---------------- 3 files changed, 9 insertions(+), 25 deletions(-) diff --git a/linux-user/arm/cpu_loop.c b/linux-user/arm/cpu_loop.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/arm/cpu_loop.c +++ b/linux-user/arm/cpu_loop.c @@ -XXX,XX +XXX,XX @@ static bool insn_is_linux_bkpt(uint32_t opcode, bool is_thumb) static bool emulate_arm_fpa11(CPUARMState *env, uint32_t opcode) { TaskState *ts = get_task_state(env_cpu(env)); - int rc = EmulateAll(opcode, &ts->fpa, env); + int rc = EmulateAll(opcode, &ts->fpa); int raise, enabled; if (rc == 0) { diff --git a/linux-user/arm/nwfpe/fpa11.c b/linux-user/arm/nwfpe/fpa11.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/arm/nwfpe/fpa11.c +++ b/linux-user/arm/nwfpe/fpa11.c @@ -XXX,XX +XXX,XX @@ FPA11* qemufpa = NULL; -CPUARMState* user_registers; /* Reset the FPA11 chip. Called to initialize and reset the emulator. */ void resetFPA11(void) @@ -XXX,XX +XXX,XX @@ void SetRoundingPrecision(const unsigned int opcode) /* Emulate the instruction in the opcode. */ /* ??? This is not thread safe. */ -unsigned int EmulateAll(unsigned int opcode, FPA11* qfpa, CPUARMState* qregs) +unsigned int EmulateAll(unsigned int opcode, FPA11* qfpa) { unsigned int nRc = 0; // unsigned long flags; @@ -XXX,XX +XXX,XX @@ unsigned int EmulateAll(unsigned int opcode, FPA11* qfpa, CPUARMState* qregs) } qemufpa=qfpa; - user_registers=qregs; - -#if 0 - fprintf(stderr,"emulating FP insn 0x%08x, PC=0x%08x\n", - opcode, qregs[ARM_REG_PC]); -#endif fpa11 = GET_FPA11(); if (fpa11->initflag == 0) /* good place for __builtin_expect */ diff --git a/linux-user/arm/nwfpe/fpa11.h b/linux-user/arm/nwfpe/fpa11.h index XXXXXXX..XXXXXXX 100644 --- a/linux-user/arm/nwfpe/fpa11.h +++ b/linux-user/arm/nwfpe/fpa11.h @@ -XXX,XX +XXX,XX @@ #define GET_FPA11() (qemufpa) -/* - * The processes registers are always at the very top of the 8K - * stack+task struct. Use the same method as 'current' uses to - * reach them. - */ -extern CPUARMState *user_registers; - -#define GET_USERREG() (user_registers) - /* Need task_struct */ //#include <linux/sched.h> @@ -XXX,XX +XXX,XX @@ void SetRoundingPrecision(const unsigned int); static inline unsigned int readRegister(unsigned int reg) { - return (user_registers->regs[(reg)]); + CPUARMState *env = cpu_env(current_cpu); + return env->regs[reg]; } static inline void writeRegister(unsigned int x, unsigned int y) { -#if 0 - printf("writing %d to r%d\n",y,x); -#endif - user_registers->regs[(x)]=(y); + CPUARMState *env = cpu_env(current_cpu); + env->regs[x] = y; } static inline void writeConditionCodes(unsigned int x) { - cpsr_write(user_registers, x, CPSR_NZCV, CPSRWriteByInstr); + CPUARMState *env = cpu_env(current_cpu); + cpsr_write(env, x, CPSR_NZCV, CPSRWriteByInstr); } #define ARM_REG_PC 15 -unsigned int EmulateAll(unsigned int opcode, FPA11* qfpa, CPUARMState* qregs); +unsigned int EmulateAll(unsigned int opcode, FPA11* qfpa); unsigned int EmulateCPDO(const unsigned int); unsigned int EmulateCPDT(const unsigned int); -- 2.53.0
From: Richard Henderson <richard.henderson@linaro.org> Fix the thread safety of the emulation by not storing a pointer in global storage. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Helge Deller <deller@gmx.de> --- linux-user/arm/nwfpe/fpa11.c | 3 +-- linux-user/arm/nwfpe/fpa11.h | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/linux-user/arm/nwfpe/fpa11.c b/linux-user/arm/nwfpe/fpa11.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/arm/nwfpe/fpa11.c +++ b/linux-user/arm/nwfpe/fpa11.c @@ -XXX,XX +XXX,XX @@ //#include <asm/system.h> -FPA11* qemufpa = NULL; +__thread FPA11* qemufpa = NULL; /* Reset the FPA11 chip. Called to initialize and reset the emulator. */ void resetFPA11(void) @@ -XXX,XX +XXX,XX @@ void SetRoundingPrecision(const unsigned int opcode) } /* Emulate the instruction in the opcode. */ -/* ??? This is not thread safe. */ unsigned int EmulateAll(unsigned int opcode, FPA11* qfpa) { unsigned int nRc = 0; diff --git a/linux-user/arm/nwfpe/fpa11.h b/linux-user/arm/nwfpe/fpa11.h index XXXXXXX..XXXXXXX 100644 --- a/linux-user/arm/nwfpe/fpa11.h +++ b/linux-user/arm/nwfpe/fpa11.h @@ -XXX,XX +XXX,XX @@ typedef struct tagFPA11 { float_status fp_status; /* QEMU float emulator status */ } FPA11; -extern FPA11* qemufpa; +extern __thread FPA11* qemufpa; void resetFPA11(void); void SetRoundingMode(const unsigned int); -- 2.53.0
From: Alistair Francis <alistair.francis@wdc.com> The stack pointer is being truncated as 32-bits for qemu-riscv64, so let's use %p to print the syscall pointer argument. Cc: qemu-stable@nongnu.org Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3238 Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Nutty Liu <nutty.liu@hotmail.com> Signed-off-by: Helge Deller <deller@gmx.de> --- linux-user/strace.list | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-user/strace.list b/linux-user/strace.list index XXXXXXX..XXXXXXX 100644 --- a/linux-user/strace.list +++ b/linux-user/strace.list @@ -XXX,XX +XXX,XX @@ { TARGET_NR_quotactl, "quotactl" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_read -{ TARGET_NR_read, "read" , "%s(%d,%#x,%d)", NULL, NULL }, +{ TARGET_NR_read, "read" , "%s(%d,%p,%d)", NULL, NULL }, #endif #ifdef TARGET_NR_readahead { TARGET_NR_readahead, "readahead" , NULL, NULL, NULL }, @@ -XXX,XX +XXX,XX @@ print_syscall_ret_waitpid }, #endif #ifdef TARGET_NR_write -{ TARGET_NR_write, "write" , "%s(%d,%#x,%d)", NULL, NULL }, +{ TARGET_NR_write, "write" , "%s(%d,%p,%d)", NULL, NULL }, #endif #ifdef TARGET_NR_writev { TARGET_NR_writev, "writev" , "%s(%d,%p,%#x)", NULL, NULL }, -- 2.53.0
From: James Hilliard <james.hilliard1@gmail.com> Cavium Octeon userspace is not following a generic MIPS Linux TLS ABI rule here. Older Octeon glibc uses the k0 register as the fast thread pointer, while newer Octeon2 and Octeon3 glibc variants use the normal rdhwr $29 path. linux-user already updates CP0_UserLocal for cpu_set_tls() and TARGET_NR_set_thread_area, but it does not keep gpr[26] synchronized. That leaves EF_MIPS_MACH_OCTEON userlands able to complete set_thread_area() and still reach pthread startup or pthread_self() with a stale k0 value. Use the existing MIPS ELF machine flags from linux-user/elfload.c and mirror CP0_UserLocal into gpr[26] only for EF_MIPS_MACH_OCTEON. Signed-off-by: James Hilliard <james.hilliard1@gmail.com> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Helge Deller <deller@gmx.de> --- linux-user/elfload.c | 3 +++ linux-user/mips/target_cpu.h | 5 +++++ linux-user/qemu.h | 1 + linux-user/syscall.c | 2 +- 4 files changed, 10 insertions(+), 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 void load_elf_image(const char *image_name, const ImageSource *src, /* Usual start for brk is after all sections of the main executable. */ info->brk = TARGET_PAGE_ALIGN(hiaddr + load_bias); info->elf_flags = ehdr->e_flags; +#ifdef TARGET_MIPS + info->use_k0_tls = (ehdr->e_flags & EF_MIPS_MACH) == EF_MIPS_MACH_OCTEON; +#endif prot_exec = PROT_EXEC; #ifdef TARGET_AARCH64 diff --git a/linux-user/mips/target_cpu.h b/linux-user/mips/target_cpu.h index XXXXXXX..XXXXXXX 100644 --- a/linux-user/mips/target_cpu.h +++ b/linux-user/mips/target_cpu.h @@ -XXX,XX +XXX,XX @@ static inline void cpu_clone_regs_parent(CPUMIPSState *env, unsigned flags) static inline void cpu_set_tls(CPUMIPSState *env, target_ulong newtls) { + TaskState *ts = get_task_state(env_cpu(env)); + env->active_tc.CP0_UserLocal = newtls; + if (ts->info->use_k0_tls) { + env->active_tc.gpr[26] = newtls; + } } static inline abi_ulong get_sp_from_cpustate(CPUMIPSState *state) 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 @@ struct image_info { uint32_t note_flags; #ifdef TARGET_MIPS + bool use_k0_tls; int fp_abi; int interp_fp_abi; #endif 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 abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, #ifdef TARGET_NR_set_thread_area case TARGET_NR_set_thread_area: #if defined(TARGET_MIPS) - cpu_env->active_tc.CP0_UserLocal = arg1; + cpu_set_tls(cpu_env, arg1); return 0; #elif defined(TARGET_I386) && defined(TARGET_ABI32) return do_set_thread_area(cpu_env, arg1); -- 2.53.0
From: Helge Deller <deller@gmx.de> Define the entries which always use the 64-bit timestamps. Signed-off-by: Helge Deller <deller@gmx.de> --- linux-user/alpha/sockbits.h | 7 +++++++ linux-user/generic/sockbits.h | 8 ++++++++ linux-user/hppa/sockbits.h | 7 +++++++ linux-user/mips/sockbits.h | 7 +++++++ linux-user/sparc/sockbits.h | 7 +++++++ 5 files changed, 36 insertions(+) diff --git a/linux-user/alpha/sockbits.h b/linux-user/alpha/sockbits.h index XXXXXXX..XXXXXXX 100644 --- a/linux-user/alpha/sockbits.h +++ b/linux-user/alpha/sockbits.h @@ -XXX,XX +XXX,XX @@ /* Instruct lower device to use last 4-bytes of skb data as FCS */ #define TARGET_SO_NOFCS 43 +#define TARGET_SO_TIMESTAMP_NEW 63 +#define TARGET_SO_TIMESTAMPNS_NEW 64 +#define TARGET_SO_TIMESTAMPING_NEW 65 + +#define TARGET_SO_RCVTIMEO_NEW 66 +#define TARGET_SO_SNDTIMEO_NEW 67 + /* TARGET_O_NONBLOCK clashes with the bits used for socket types. Therefore we * have to define SOCK_NONBLOCK to a different value here. */ diff --git a/linux-user/generic/sockbits.h b/linux-user/generic/sockbits.h index XXXXXXX..XXXXXXX 100644 --- a/linux-user/generic/sockbits.h +++ b/linux-user/generic/sockbits.h @@ -XXX,XX +XXX,XX @@ #define TARGET_SO_PROTOCOL 38 #define TARGET_SO_DOMAIN 39 + +#define TARGET_SO_TIMESTAMP_NEW 63 +#define TARGET_SO_TIMESTAMPNS_NEW 64 +#define TARGET_SO_TIMESTAMPING_NEW 65 + +#define TARGET_SO_RCVTIMEO_NEW 66 +#define TARGET_SO_SNDTIMEO_NEW 67 + #endif diff --git a/linux-user/hppa/sockbits.h b/linux-user/hppa/sockbits.h index XXXXXXX..XXXXXXX 100644 --- a/linux-user/hppa/sockbits.h +++ b/linux-user/hppa/sockbits.h @@ -XXX,XX +XXX,XX @@ #define TARGET_SO_CNX_ADVICE 0x402E +#define TARGET_SO_TIMESTAMP_NEW 0x4038 +#define TARGET_SO_TIMESTAMPNS_NEW 0x4039 +#define TARGET_SO_TIMESTAMPING_NEW 0x403A + +#define TARGET_SO_RCVTIMEO_NEW 0x4040 +#define TARGET_SO_SNDTIMEO_NEW 0x4041 + /* TARGET_O_NONBLOCK clashes with the bits used for socket types. Therefore we * have to define SOCK_NONBLOCK to a different value here. */ diff --git a/linux-user/mips/sockbits.h b/linux-user/mips/sockbits.h index XXXXXXX..XXXXXXX 100644 --- a/linux-user/mips/sockbits.h +++ b/linux-user/mips/sockbits.h @@ -XXX,XX +XXX,XX @@ #define TARGET_SO_RCVBUFFORCE 33 #define TARGET_SO_PASSSEC 34 +#define TARGET_SO_TIMESTAMP_NEW 63 +#define TARGET_SO_TIMESTAMPNS_NEW 64 +#define TARGET_SO_TIMESTAMPING_NEW 65 + +#define TARGET_SO_RCVTIMEO_NEW 66 +#define TARGET_SO_SNDTIMEO_NEW 67 + /** sock_type - Socket types * * Please notice that for binary compat reasons MIPS has to diff --git a/linux-user/sparc/sockbits.h b/linux-user/sparc/sockbits.h index XXXXXXX..XXXXXXX 100644 --- a/linux-user/sparc/sockbits.h +++ b/linux-user/sparc/sockbits.h @@ -XXX,XX +XXX,XX @@ #define TARGET_SO_TIMESTAMPING 0x0023 #define TARGET_SCM_TIMESTAMPING TARGET_SO_TIMESTAMPING +#define TARGET_SO_TIMESTAMP_NEW 0x0046 +#define TARGET_SO_TIMESTAMPNS_NEW 0x0042 +#define TARGET_SO_TIMESTAMPING_NEW 0x0043 + +#define TARGET_SO_RCVTIMEO_NEW 0x0044 +#define TARGET_SO_SNDTIMEO_NEW 0x0045 + #define TARGET_SO_RXQ_OVFL 0x0024 #define TARGET_SO_WIFI_STATUS 0x0025 -- 2.53.0
From: Helge Deller <deller@gmx.de> Add handlers for both sockopts which use 64-bit time_t from userspace. Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/885 Signed-off-by: Helge Deller <deller@gmx.de> --- linux-user/syscall.c | 21 +++++++++++++++++++-- 1 file changed, 19 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 copy_to_user_timeval(abi_ulong target_tv_addr, return 0; } -#if defined(TARGET_NR_clock_adjtime64) && defined(CONFIG_CLOCK_ADJTIME) static inline abi_long copy_from_user_timeval64(struct timeval *tv, abi_ulong target_tv_addr) { @@ -XXX,XX +XXX,XX @@ static inline abi_long copy_from_user_timeval64(struct timeval *tv, return 0; } -#endif static inline abi_long copy_to_user_timeval64(abi_ulong target_tv_addr, const struct timeval *tv) @@ -XXX,XX +XXX,XX @@ static abi_long do_setsockopt(int sockfd, int level, int optname, &tv, sizeof(tv))); return ret; } + case TARGET_SO_RCVTIMEO_NEW: + case TARGET_SO_SNDTIMEO_NEW: + { + struct timeval tv; + + if (optlen != sizeof(struct target__kernel_sock_timeval)) { + return -TARGET_EINVAL; + } + + if (copy_from_user_timeval64(&tv, optval_addr)) { + return -TARGET_EFAULT; + } + + ret = get_errno(setsockopt(sockfd, SOL_SOCKET, + optname == TARGET_SO_RCVTIMEO_NEW ? + SO_RCVTIMEO : SO_SNDTIMEO, + &tv, sizeof(tv))); + return ret; + } case TARGET_SO_ATTACH_FILTER: { struct target_sock_fprog *tfprog; -- 2.53.0
From: Helge Deller <deller@gmx.de> Add handlers for both sockopts which use 64-bit time_t from userspace. Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/885 Signed-off-by: Helge Deller <deller@gmx.de> --- linux-user/syscall.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 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 abi_long do_getsockopt(int sockfd, int level, int optname, /* These don't just return a single integer */ case TARGET_SO_PEERNAME: goto unimplemented; - case TARGET_SO_RCVTIMEO: { + case TARGET_SO_RCVTIMEO: + case TARGET_SO_RCVTIMEO_NEW: { struct timeval tv; socklen_t tvlen; @@ -XXX,XX +XXX,XX @@ get_timeout: if (ret < 0) { return ret; } - if (len > sizeof(struct target_timeval)) { - len = sizeof(struct target_timeval); - } - if (copy_to_user_timeval(optval_addr, &tv)) { - return -TARGET_EFAULT; + if (len == sizeof(struct target__kernel_sock_timeval)) { + if (copy_to_user_timeval64(optval_addr, &tv)) { + return -TARGET_EFAULT; + } + } else { + if (len >= sizeof(struct target_timeval)) { + len = sizeof(struct target_timeval); + if (copy_to_user_timeval(optval_addr, &tv)) { + return -TARGET_EFAULT; + } + } } if (put_user_u32(len, optlen)) { return -TARGET_EFAULT; @@ -XXX,XX +XXX,XX @@ get_timeout: break; } case TARGET_SO_SNDTIMEO: + case TARGET_SO_SNDTIMEO_NEW: optname = SO_SNDTIMEO; goto get_timeout; case TARGET_SO_PEERCRED: { -- 2.53.0
From: Helge Deller <deller@gmx.de> The CLONE_PARENT_SETTID option requires the implementation to store the child thread ID at the location pointed to by parent_tid in the parent's memory. Fix our implementation and move the code from the client side (where fork returned 0), to the parent side and store the return value from the fork call (which is the client TID) in the parent_tid pointer. Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3340 Signed-off-by: Helge Deller <deller@gmx.de> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> --- linux-user/syscall.c | 4 ++-- 1 file changed, 2 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 int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp, the child process gets its own copy of the lock. */ if (flags & CLONE_CHILD_SETTID) put_user_u32(sys_gettid(), child_tidptr); - if (flags & CLONE_PARENT_SETTID) - put_user_u32(sys_gettid(), parent_tidptr); ts = get_task_state(cpu); if (flags & CLONE_SETTLS) cpu_set_tls (env, newtls); @@ -XXX,XX +XXX,XX @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp, ts->child_tidptr = child_tidptr; } else { cpu_clone_regs_parent(env, flags); + if (flags & CLONE_PARENT_SETTID) + put_user_u32(ret, parent_tidptr); if (flags & CLONE_PIDFD) { int pid_fd = 0; #if defined(__NR_pidfd_open) && defined(TARGET_NR_pidfd_open) -- 2.53.0
From: Helge Deller <deller@gmx.de> Peter Hartley noticed, that in the qemu code the imr_ifindex member of struct target_ip_mreq needs to be of type "int" instead of "long", which is what the Linux kernel uses on all architectures. Adjust the type accordingly, and add a QEMU_BUILD_BUG_ON() checker to prevent such issues in the future. This change should fix multicast issues when using hosts and guests with different endianess or bit size. Reported-by: Peter Hartley <peter@talesfromthearmchair.net> Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/2553 Signed-off-by: Helge Deller <deller@gmx.de> --- linux-user/syscall.c | 2 ++ linux-user/syscall_defs.h | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) 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 abi_long do_setsockopt(int sockfd, int level, int optname, QEMU_BUILD_BUG_ON(sizeof(struct ip_mreq) != sizeof(struct target_ip_mreq)); + QEMU_BUILD_BUG_ON(sizeof(struct ip_mreqn) != + sizeof(struct target_ip_mreqn)); if (optname == IP_MULTICAST_IF) { min_size = sizeof(struct in_addr); diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index XXXXXXX..XXXXXXX 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -XXX,XX +XXX,XX @@ struct target_ip_mreq { struct target_ip_mreqn { struct target_in_addr imr_multiaddr; struct target_in_addr imr_address; - abi_long imr_ifindex; + abi_int imr_ifindex; }; struct target_ip_mreq_source { -- 2.53.0
From: Helge Deller <deller@gmx.de> Qemu user mode does not properly flushes error messages related to bad arguments when exiting (at least when the output is piped to a file instead of running on a terminal). Ensure that we always flush 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 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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) execfd = open(exec_path, O_RDONLY); if (execfd < 0) { printf("Error while loading %s: %s\n", exec_path, strerror(errno)); - _exit(EXIT_FAILURE); + exit(EXIT_FAILURE); } } @@ -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> 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
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