You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
User mode is what builds half the world's cross-architecture container images through binfmt_misc. It is a different product from system emulation with the same JIT underneath.
Slice 1 merged in #197: qemu-x86_64 runs static and dynamic x86_64 programs on an x86_64 Linux host. It covers the guest address space and mmap engine in user-common, the ELF loader, the x86_64 cpu loop on the TCG JIT, and the common syscalls. Its stdout, stderr and exit codes matched QEMU 11.1 qemu-x86_64 on 46 programs: hello (static and dynamic), busybox applets, coreutils, dash, and fault and abort cases. No box is ticked yet, because the first one also needs signals, threads and /proc, which are slice 2.
Signal delivery for x86_64 guests landed in #203 (rt_sigframe, rt_sigreturn, safe_syscall, fault signals), compared against qemu-x86_64 11.1. Threads and /proc are next for this item.
Slice 2, threads: #207 is merged (c88dcf0). It adds guest threads for qemu-x86_64: clone with CLONE_VM, set_tid_address, CHILD_CLEARTID futex wake on exit, exit vs exit_group, and the jit's parallel mode. A pthread test and coreutils sort --parallel match qemu-x86_64 11.1. The /proc emulation is next, then the first box.
Slice 2, /proc: #209 is merged (5644f73). /proc/self/maps, smaps, stat, auxv and cmdline now describe the guest as QEMU's open_self_* functions write them, also as /proc// and through relative names. A property test, static and dynamic, matches qemu-x86_64 11.1 except that MAP_SHARED anonymous memory shows as private; a small follow-up makes it shared. With #203 (signals), #207 (threads) and #209, the first box is done and ticked. Next is slice 3: aarch64 and riscv64 guests.
Follow-up to #209: #211 is merged. MAP_SHARED anonymous memory is now shared on the host as well, so a guest's forked children share it as they do under Linux and QEMU. A fork test matches qemu-x86_64 11.1 and the native run. The /proc test from #209 now matches QEMU on every line.
The aarch64 guest landed in #216: target, sigframes, hwcaps, cpuinfo, generic syscall numbering and the target-arm user mode switch. It was compared against qemu-aarch64 11.1 with static and dynamic cross-built programs, busybox, and the signal, frame, thread, /proc and shm suites. The outputs match apart from the max model's feature set and QEMU's core dump line. A follow-up removes a sysconf unsafe that went over the linux-user budget. riscv64 is next.
#218 merged (f4268f9): /proc/cpuinfo now counts online CPUs from /sys/devices/system/cpu/online instead of calling sysconf, so ruvm-linux-user is back to 4 unsafe items, within its budget. riscv64 is next.
#228 merged (1b57a64): riscv64 guest. It adds the cpu loop with ecall, hwprobe and flush_icache, the rt_sigframe and ucontext with the F/D state, the riscv64 ELF hwcap and /proc/cpuinfo, -cpu, and the riscv sigaction layout. Static and dynamic hello, crash, signal, thread, fork and shm programs, a frame test, and busybox were run under ruvm and under qemu-riscv64 built from the 11.1 source, and their output was compared. It also fixes a shared GuestSpace bug: when ELF_ET_DYN_BASE fell outside the reservation, QEMU's fallback put it right on TASK_UNMAPPED_BASE, so both bases now fall back together. One difference is known: the isa string in /proc/cpuinfo leaves out zicfilp, zicfiss, zvfbfa, smctr, ssctr and ssdbltrp, because target-riscv does not implement them. Next is the direct guest_base memory path.
Merged #238 (f4e1080): the x86-64 backend now inlines 128-bit atomic guest loads and stores as one VMOVDQA or VMOVDQU, as QEMU does on hosts where that access is atomic, instead of sending every one of them through the slow path when the guest runs threads. On server2, sort of a 2 million line file under qemu-x86_64 went from 5148 ms to 1379 ms (QEMU 1417 ms), and a small CPU benchmark went from 4422 ms to 4044 ms (QEMU 2727 ms). The rest of that gap is the TLB lookup on every access, which the direct guest_base path is meant to remove next.
Merged #245 (2c2baad): two linux-user mremap fixes found while testing the direct guest_base path. A moving mremap of part of a merged mapping now splits the range at both ends first, and a failed host move_pages maps zero pages back over the destination the kernel already unmapped. New tests in user-common and sys. The x86-64 mremap programs and the x86-64 comparison suite give the same output as qemu-x86_64 11.1.
The direct guest_base memory path for user mode merged as #292 (679991e). On an x86_64 host each guest load and store in the JIT is now a host access at guest_base plus the address when it is in bounds and aligned enough, and falls back to the old slow path otherwise. Host faults on direct accesses resume in that slow path, and pages with translated code stay read only on the host, as QEMU's page_protect does.
Benchmarks on server2, best of 5 runs over three rounds, wall time in ms, all under qemu-x86_64 or ruvm as qemu-x86_64:
Sort is within about 7% of QEMU, and sort -k is level with it. The CPU benchmark is still about 30% behind; that gap is in the generated code, not in memory accesses. The x86_64, aarch64 and riscv64 comparison suites and the thread suite give the same results as before against QEMU.
Plan for the remaining M7 guests (arm, i386, ppc64le, s390x).
i386 runs on the existing x86 frontend, but the other three have no frontend in ruvm yet. target-arm is AArch64 only, and target-ppc and target-s390x are empty crates. Each of those needs a translator before linux-user can run its programs, so this is a series of PRs per target, not one PR per guest. In order:
i386: the 32-bit guest in linux-user, with a compat layer that converts system call arguments and structures between a 32-bit guest and the 64-bit host (stat64, iovec, timespec in both widths, msghdr, sigaction and the rest). It also covers int 0x80, set_thread_area, the 32-bit signal frames and a 4 GiB guest space.
arm: AArch32 in target-arm, starting with the A32 and T32 decoders and the integer instructions, then VFP, then Neon, each a PR. Then qemu-arm on the compat layer from step 1, with the kuser helper page and the Arm signal frames. Every target-arm PR also runs the AArch64 tests and the system-mode boot tests, so the AArch64 side does not regress.
ppc64le: target-ppc for 64-bit little endian user mode, integer and branch first, then FP, then Altivec and VSX. Then the linux-user guest with the ppc system call numbers and constants.
s390x: target-s390x for z/Architecture user mode, integer first, then FP and the vector facility. Then the linux-user guest, the first big-endian one, which byte swaps every structure that crosses the guest boundary.
Each step is compared against QEMU 11.1 linux-user on the test servers, with small programs and risu-style instruction sequences for the frontends, and I'll comment here after each guest merges.
#297 is merged: -g now works for aarch64 and riscv64 programs. The register features match QEMU's user-mode gdbstub (core, FPU or SVE, pauth and TPIDR on aarch64; core, FPU, vector, privilege level and user CSRs on riscv64), and gdb-multiarch gives the same output as against qemu-aarch64 and qemu-riscv64 11.1 over breakpoints, register reads and writes, catch syscall, stepping, fork following and the target description. Still missing: aarch64's org.qemu.gdb.arm.sys.regs feature, and riscv64's cycle/time/instret, which read ruvm's counters rather than the host TSC.
Next is i386 with the 32-bit compat syscall layer.
#313 is merged: qemu-i386 now runs static and dynamic i386 programs through the new 32-bit compat system call layer. Its output matches qemu-i386 11.1 on the tests/tcg i386 and multiarch programs, except for the documented one-page mmap offset from the missing vDSO. Signal frames for i386 come next, followed by sockets, IPC and timers.
#327 merged: the first AArch32 slice. target-arm decodes A32, T32 and T16 with the integer instructions, plus the VFP moves, loads and stores glibc needs at start-up. qemu-arm runs a static armhf hello with the same output as QEMU 11.1. The target-arm and machine-arm tests still pass.
Next for AArch32: VFP arithmetic, the kuser helpers and commpage, and signal frames. Neon comes after that.
#331 merged: qemu-i386 delivers signals now, with the old and rt frames, the alternate stack and the old signal calls. A signal test and the tests/tcg signal and thread programs give the same output as QEMU 11.1. linux-test and signals still stop at socket() and timer_create(), which are ENOSYS on i386 for now.
#332 merged (6187b2d): AArch32 VFP arithmetic and conversions. It covers half, single and double precision arithmetic, the fused forms, compares, VRINT, every VCVT form (integer, fixed point, f16, precision) and the v8 VSEL, VMAXNM/VMINNM and directed rounding. A static armhf test sweeps 19 special values through every form and checks FPSCR flags under each rounding mode and FZ, DN and AHP. Its output matches QEMU 11.1's qemu-arm exactly, built both as Thumb-2 and as A32. Still UNDEF: Neon, the BF16 VCVT and VJCVT. Next is the kuser helpers, the commpage and signal frames for qemu-arm.
M7 arm: #333 merged (320c580). qemu-arm now has the commpage and kuser helpers (version 5, barrier, cmpxchg, get_tls, cmpxchg64) and the sigframe and rt_sigframe signal frames, including the VFP frame and the Thumb return trampolines on the page where QEMU puts its vDSO. A static armhf signal and kuser test gives the same output as QEMU 11.1 qemu-arm, built for both Thumb and A32. Next is Neon.
M7 arm: #346 merged (d9f4ea1). This is AArch32 Neon slice 1, for A32 and T32. It has the integer data processing groups, every VLDn/VSTn form with QEMU's alignment checks, VMOV scalar, and VDUP. 10714 generated single instruction tests, run as A32 and as Thumb, match QEMU 11.1 qemu-arm exactly, and so does an intrinsics program at -O1 and -O3. The FP ops, VRECPE/VRSQRTE and crypto still UNDEF, and HWCAP_NEON is still clear.
Signal test note: the signal tests still differ from QEMU, as they already did at #333. The CPSR GE bits differ, and the fault address can move by 0x10 with the environment size. ruvm doesn't provide AT_SYSINFO_EHDR yet, so the stack sits 8 bytes higher. Its masked HWCAP also makes glibc pick other string routines. Next is Neon slice 2: the FP ops, VRECPE/VRSQRTE, HWCAP_NEON and AT_SYSINFO_EHDR, so the signal tests match.
Activity
tamnd commentedon Oct 9, 2026
Slice 1 merged in #197:
qemu-x86_64runs static and dynamic x86_64 programs on an x86_64 Linux host. It covers the guest address space and mmap engine in user-common, the ELF loader, the x86_64 cpu loop on the TCG JIT, and the common syscalls. Its stdout, stderr and exit codes matched QEMU 11.1 qemu-x86_64 on 46 programs: hello (static and dynamic), busybox applets, coreutils, dash, and fault and abort cases. No box is ticked yet, because the first one also needs signals, threads and /proc, which are slice 2.tamnd commentedon Oct 9, 2026
Signal delivery for x86_64 guests landed in #203 (rt_sigframe, rt_sigreturn, safe_syscall, fault signals), compared against qemu-x86_64 11.1. Threads and /proc are next for this item.
tamnd commentedon Oct 9, 2026
Slice 2, threads: #207 is merged (c88dcf0). It adds guest threads for qemu-x86_64: clone with CLONE_VM, set_tid_address, CHILD_CLEARTID futex wake on exit, exit vs exit_group, and the jit's parallel mode. A pthread test and coreutils sort --parallel match qemu-x86_64 11.1. The /proc emulation is next, then the first box.
tamnd commentedon Oct 9, 2026
Slice 2, /proc: #209 is merged (5644f73). /proc/self/maps, smaps, stat, auxv and cmdline now describe the guest as QEMU's open_self_* functions write them, also as /proc// and through relative names. A property test, static and dynamic, matches qemu-x86_64 11.1 except that MAP_SHARED anonymous memory shows as private; a small follow-up makes it shared. With #203 (signals), #207 (threads) and #209, the first box is done and ticked. Next is slice 3: aarch64 and riscv64 guests.
tamnd commentedon Oct 9, 2026
Follow-up to #209: #211 is merged. MAP_SHARED anonymous memory is now shared on the host as well, so a guest's forked children share it as they do under Linux and QEMU. A fork test matches qemu-x86_64 11.1 and the native run. The /proc test from #209 now matches QEMU on every line.
tamnd commentedon Oct 9, 2026
The aarch64 guest landed in #216: target, sigframes, hwcaps, cpuinfo, generic syscall numbering and the target-arm user mode switch. It was compared against qemu-aarch64 11.1 with static and dynamic cross-built programs, busybox, and the signal, frame, thread, /proc and shm suites. The outputs match apart from the max model's feature set and QEMU's core dump line. A follow-up removes a sysconf unsafe that went over the linux-user budget. riscv64 is next.
tamnd commentedon Oct 10, 2026
#218 merged (f4268f9): /proc/cpuinfo now counts online CPUs from /sys/devices/system/cpu/online instead of calling sysconf, so ruvm-linux-user is back to 4 unsafe items, within its budget. riscv64 is next.
tamnd commentedon Oct 10, 2026
#228 merged (1b57a64): riscv64 guest. It adds the cpu loop with ecall, hwprobe and flush_icache, the rt_sigframe and ucontext with the F/D state, the riscv64 ELF hwcap and /proc/cpuinfo, -cpu, and the riscv sigaction layout. Static and dynamic hello, crash, signal, thread, fork and shm programs, a frame test, and busybox were run under ruvm and under qemu-riscv64 built from the 11.1 source, and their output was compared. It also fixes a shared GuestSpace bug: when ELF_ET_DYN_BASE fell outside the reservation, QEMU's fallback put it right on TASK_UNMAPPED_BASE, so both bases now fall back together. One difference is known: the isa string in /proc/cpuinfo leaves out zicfilp, zicfiss, zvfbfa, smctr, ssctr and ssdbltrp, because target-riscv does not implement them. Next is the direct guest_base memory path.
tamnd commentedon Oct 10, 2026
Merged #238 (f4e1080): the x86-64 backend now inlines 128-bit atomic guest loads and stores as one VMOVDQA or VMOVDQU, as QEMU does on hosts where that access is atomic, instead of sending every one of them through the slow path when the guest runs threads. On server2, sort of a 2 million line file under qemu-x86_64 went from 5148 ms to 1379 ms (QEMU 1417 ms), and a small CPU benchmark went from 4422 ms to 4044 ms (QEMU 2727 ms). The rest of that gap is the TLB lookup on every access, which the direct guest_base path is meant to remove next.
tamnd commentedon Oct 10, 2026
Merged #245 (2c2baad): two linux-user mremap fixes found while testing the direct guest_base path. A moving mremap of part of a merged mapping now splits the range at both ends first, and a failed host move_pages maps zero pages back over the destination the kernel already unmapped. New tests in user-common and sys. The x86-64 mremap programs and the x86-64 comparison suite give the same output as qemu-x86_64 11.1.
2 remaining items
tamnd commentedon Oct 13, 2026
Ticked the strace and gdbstub box.
-stracelanded in #280 and-g, the user mode gdbstub, in #288, both compared against QEMU's linux-user on server2.tamnd commentedon Oct 13, 2026
The direct guest_base memory path for user mode merged as #292 (679991e). On an x86_64 host each guest load and store in the JIT is now a host access at guest_base plus the address when it is in bounds and aligned enough, and falls back to the old slow path otherwise. Host faults on direct accesses resume in that slow path, and pages with translated code stay read only on the host, as QEMU's page_protect does.
Benchmarks on server2, best of 5 runs over three rounds, wall time in ms, all under qemu-x86_64 or ruvm as qemu-x86_64:
Sort is within about 7% of QEMU, and sort -k is level with it. The CPU benchmark is still about 30% behind; that gap is in the generated code, not in memory accesses. The x86_64, aarch64 and riscv64 comparison suites and the thread suite give the same results as before against QEMU.
tamnd commentedon Oct 13, 2026
Plan for the remaining M7 guests (arm, i386, ppc64le, s390x).
i386 runs on the existing x86 frontend, but the other three have no frontend in ruvm yet. target-arm is AArch64 only, and target-ppc and target-s390x are empty crates. Each of those needs a translator before linux-user can run its programs, so this is a series of PRs per target, not one PR per guest. In order:
Each step is compared against QEMU 11.1 linux-user on the test servers, with small programs and risu-style instruction sequences for the frontends, and I'll comment here after each guest merges.
tamnd commentedon Oct 13, 2026
#297 is merged:
-gnow works for aarch64 and riscv64 programs. The register features match QEMU's user-mode gdbstub (core, FPU or SVE, pauth and TPIDR on aarch64; core, FPU, vector, privilege level and user CSRs on riscv64), and gdb-multiarch gives the same output as against qemu-aarch64 and qemu-riscv64 11.1 over breakpoints, register reads and writes, catch syscall, stepping, fork following and the target description. Still missing: aarch64'sorg.qemu.gdb.arm.sys.regsfeature, and riscv64's cycle/time/instret, which read ruvm's counters rather than the host TSC.Next is i386 with the 32-bit compat syscall layer.
linux-user: i386 guests and the 32-bit compat system call layer (#313)
tamnd commentedon Oct 14, 2026
#313 is merged:
qemu-i386now runs static and dynamic i386 programs through the new 32-bit compat system call layer. Its output matches qemu-i386 11.1 on the tests/tcg i386 and multiarch programs, except for the documented one-page mmap offset from the missing vDSO. Signal frames for i386 come next, followed by sockets, IPC and timers.target-arm, linux-user: AArch32 integer translator and qemu-arm (#327)
tamnd commentedon Oct 14, 2026
#327 merged: the first AArch32 slice. target-arm decodes A32, T32 and T16 with the integer instructions, plus the VFP moves, loads and stores glibc needs at start-up.
qemu-armruns a static armhf hello with the same output as QEMU 11.1. The target-arm and machine-arm tests still pass.Next for AArch32: VFP arithmetic, the kuser helpers and commpage, and signal frames. Neon comes after that.
linux-user: signal delivery for i386 guests (#331)
tamnd commentedon Oct 14, 2026
#331 merged:
qemu-i386delivers signals now, with the old and rt frames, the alternate stack and the old signal calls. A signal test and the tests/tcg signal and thread programs give the same output as QEMU 11.1.linux-testandsignalsstill stop atsocket()andtimer_create(), which are ENOSYS on i386 for now.Next is AArch32 VFP arithmetic.
target-arm: AArch32 VFP arithmetic and conversions (#332)
tamnd commentedon Oct 14, 2026
#332 merged (6187b2d): AArch32 VFP arithmetic and conversions. It covers half, single and double precision arithmetic, the fused forms, compares, VRINT, every VCVT form (integer, fixed point, f16, precision) and the v8 VSEL, VMAXNM/VMINNM and directed rounding. A static armhf test sweeps 19 special values through every form and checks FPSCR flags under each rounding mode and FZ, DN and AHP. Its output matches QEMU 11.1's qemu-arm exactly, built both as Thumb-2 and as A32. Still UNDEF: Neon, the BF16 VCVT and VJCVT. Next is the kuser helpers, the commpage and signal frames for qemu-arm.
tamnd commentedon Oct 14, 2026
M7 arm: #333 merged (320c580). qemu-arm now has the commpage and kuser helpers (version 5, barrier, cmpxchg, get_tls, cmpxchg64) and the sigframe and rt_sigframe signal frames, including the VFP frame and the Thumb return trampolines on the page where QEMU puts its vDSO. A static armhf signal and kuser test gives the same output as QEMU 11.1 qemu-arm, built for both Thumb and A32. Next is Neon.
target-arm: AArch32 Neon integer data processing and loads and stores (…
tamnd commentedon Oct 15, 2026
M7 arm: #346 merged (d9f4ea1). This is AArch32 Neon slice 1, for A32 and T32. It has the integer data processing groups, every VLDn/VSTn form with QEMU's alignment checks, VMOV scalar, and VDUP. 10714 generated single instruction tests, run as A32 and as Thumb, match QEMU 11.1 qemu-arm exactly, and so does an intrinsics program at -O1 and -O3. The FP ops, VRECPE/VRSQRTE and crypto still UNDEF, and HWCAP_NEON is still clear.
Signal test note: the signal tests still differ from QEMU, as they already did at #333. The CPSR GE bits differ, and the fault address can move by 0x10 with the environment size. ruvm doesn't provide AT_SYSINFO_EHDR yet, so the stack sits 8 bytes higher. Its masked HWCAP also makes glibc pick other string routines. Next is Neon slice 2: the FP ops, VRECPE/VRSQRTE, HWCAP_NEON and AT_SYSINFO_EHDR, so the signal tests match.