Skip to content

riscv64: forward-port RISC-V 64-bit host support onto Wine 11.15 (arm64ec) - #14

Open
Lfan-ke wants to merge 24 commits into
AndreRH:arm64ecfrom
Lfan-ke:rv64-fwdport
Open

riscv64: forward-port RISC-V 64-bit host support onto Wine 11.15 (arm64ec)#14
Lfan-ke wants to merge 24 commits into
AndreRH:arm64ecfrom
Lfan-ke:rv64-fwdport

Conversation

@Lfan-ke

@Lfan-ke Lfan-ke commented Aug 15, 2026

Copy link
Copy Markdown

Forward-ports André Zwing's RISC-V 64-bit host support from the frozen riscv64 branch (Wine 9.0) onto the arm64ec base (Wine 11.15), after two years of drift, so RISC-V hosts build against current Wine again.

Contents

The riscv64 host arch support rebased commit-by-commit onto 11.15 (André's authorship preserved, forward-port adaptations signed off): configure host detection, winnt.h RISCV64 CONTEXT, winebuild target, the ntdll host backend signal_riscv64.c realigned to 11.15's signal_arm64.c thread_data/syscall/dispatcher API (most of the drift), the PE-side signal_riscv64.c and dwarf.h, and the per-arch switches across ntdll, server, dbghelp, gdi32, msvcrt, kernel32, kernelbase, wow64, rpcrt4, oleaut32, setupapi, winspool, localspl, wineboot, winecrt0.

On top of the rebase

  • rpcrt4: re-add the riscv64 thunks that 11.15 moved into thunks.c (call_stubless_func, call_server_func), plus the four Ndr*ClientCall vararg thunks in ndr_stubless.c.
  • ntdll syscall frame: drop a copied arm64 NEON field and fix the size, then add an f[32] area and save/restore f0-f31 in the dispatcher so FP state and CONTEXT_FLOATING_POINT survive a syscall.
  • segv_handler: switch to the new virtual_handle_fault() signature and drop a debug abort that killed every fault.
  • handle_syscall_fault: implement, so a fault inside a syscall returns a status instead of crashing.
  • trap_handler: report EXCEPTION_BREAKPOINT for ebreak.
  • RtlCaptureContext: fix the F0-F31 stores, which were four bytes low.

Not included / known limits

  • No x86 emulation backend, so x86 Windows programs don't run on a RISC-V host. That needs a riscv64 Windows PE, which no toolchain produces (clang emits ELF for riscv64-*-windows, and there is no riscv64-w64-mingw32).
  • The dispatcher captures f0-f31 after NtCurrentTeb(), so the caller-saved fp registers may hold post-call values; the callee-saved fs0-fs11 that must survive a syscall are correct.
  • except_riscv64.c still has a local __CxxFrameHandler that will clash with the shared except.c once riscv64 becomes an enabled PE target.

Lfan-ke and others added 20 commits August 15, 2026 22:22
Forward-port of André Zwing's riscv64 branch onto the arm64ec (11.15) base:
detect riscv64 host_cpu, define __riscv64__ when the compiler lacks it, and
skip the preloader on riscv64.

Signed-off-by: Leo Cheng <chengkelfan@qq.com>
(cherry picked from commit 64a3a30)
Signed-off-by: Leo Cheng <chengkelfan@qq.com>
(cherry picked from commit 2242565)
Signed-off-by: Leo Cheng <chengkelfan@qq.com>
Forward-port of André Zwing's riscv64 branch onto 11.15. winebuild code-thunk
paths (import.c/spec32.c) follow 11.15's ARM64 treatment (default assert); the
riscv64 host build will surface any that need real codegen.

Signed-off-by: Leo Cheng <chengkelfan@qq.com>
(cherry picked from commit cdee755)
Signed-off-by: Leo Cheng <chengkelfan@qq.com>
(cherry picked from commit 481c1fa)
Signed-off-by: Leo Cheng <chengkelfan@qq.com>
(cherry picked from commit a526ba2)
Signed-off-by: Leo Cheng <chengkelfan@qq.com>
(cherry picked from commit fbcd39c)
Signed-off-by: Leo Cheng <chengkelfan@qq.com>
(cherry picked from commit 41ac2ad)
Signed-off-by: Leo Cheng <chengkelfan@qq.com>
(cherry picked from commit 261e2ab)
Signed-off-by: Leo Cheng <chengkelfan@qq.com>
(cherry picked from commit 3f85daf)
Signed-off-by: Leo Cheng <chengkelfan@qq.com>
(cherry picked from commit e1bf012)
Signed-off-by: Leo Cheng <chengkelfan@qq.com>
(cherry picked from commit ad778a2)
Signed-off-by: Leo Cheng <chengkelfan@qq.com>
(cherry picked from commit 85a6efb)
Signed-off-by: Leo Cheng <chengkelfan@qq.com>
(cherry picked from commit 58e3352)
Signed-off-by: Leo Cheng <chengkelfan@qq.com>
(cherry picked from commit cc42f70)
Signed-off-by: Leo Cheng <chengkelfan@qq.com>
(cherry picked from commit 1a73ae1)
Signed-off-by: Leo Cheng <chengkelfan@qq.com>
(cherry picked from commit 2a36f8d)
Signed-off-by: Leo Cheng <chengkelfan@qq.com>
(cherry picked from commit 71dff9c)
Signed-off-by: Leo Cheng <chengkelfan@qq.com>
(cherry picked from commit 332095e)
Signed-off-by: Leo Cheng <chengkelfan@qq.com>
@AndreRH

AndreRH commented Aug 16, 2026

Copy link
Copy Markdown
Owner

Welcome and thanks for your contribution!
I had a quick glance at it and it seems you forgot the assembler stuff in wineboot and rpcrt4.
It also would be good to preserve the asm comments in wineboot and update the comments in ntdll to the new syscall frame situation.
For verification I suggest to run at least winecfg, wine --version is too low level.

@Lfan-ke

Lfan-ke commented Aug 18, 2026

Copy link
Copy Markdown
Author

Thanks for the review. Pushed three commits:

rpcrt4: 11.15 moved the stubless/vtbl thunks, call_stubless_func and call_server_func into dlls/rpcrt4/thunks.c, so I re-added riscv64 there (call_stubless_func, call_server_func via args_stack_to_regs, and the two THUNK_ENTRY macros) plus the four NdrClientCall2 / NdrAsyncClientCall / NdrClientCall3 / Ndr64AsyncClientCall vararg-spill thunks in ndr_stubless.c, since the base has no C fallback for those.

wineboot: the only asm site is read_tsc_frequency, and RISC-V has no userspace equivalent of aarch64's CNTFRQ_EL0 (the timebase frequency comes from the device tree, not a CSR), so it stays on the return-0 path and falls back to the power-info MaxMhz, like the earlier riscv64 branch. Let me know if you had a specific wineboot asm in mind.

ntdll: fixed the frame description - dropped the arm64 NEON leftover and the 0x330 size, enabled the size assert at the real 0x118 and matched the dispatcher/callback asm. I also moved segv_handler to the new virtual_handle_fault(thread_data, EXCEPTION_RECORD *, stack) signature and dropped the debug ERR/abort_thread that was short-circuiting all fault handling.

Verification: the riscv64 host side builds and runs under qemu-riscv64.

$ QEMU_LD_PREFIX=/usr/riscv64-linux-gnu qemu-riscv64-static server/wineserver --version
Wine 11.15
$ QEMU_LD_PREFIX=/usr/riscv64-linux-gnu qemu-riscv64-static loader/wine --version
wine-8.14-18485-ge0d21bb2e (Hangover)

winecfg I can't drive from this tree yet - the amd64 guest backend (dlls/xtajit64) is still the arm64ec carryover stub and this build is headless (--without-x), so a guest PE can't execute or show a window. Happy to work toward that separately.

One note in passing: a few pre-existing riscv64 gaps remain (handle_syscall_fault NYI, no FP save area in the syscall frame, RtlCaptureContext storing the F-registers 4 bytes low, and except_riscv64.c colliding with the shared __CxxFrameHandler once riscv64 is a PE arch) - happy to send follow-ups if useful.

rpcrt4: 11.15 moved the stubless/vtbl thunks, call_stubless_func and
call_server_func into thunks.c, so re-add riscv64 there, along with the
four NdrClientCall2/NdrAsyncClientCall/NdrClientCall3/Ndr64AsyncClientCall
vararg thunks in ndr_stubless.c which have no C fallback.

ntdll: the syscall frame is integer-only and 0x118, not the copied arm64
NEON-inclusive 0x330; enable the size assert and match the dispatcher asm.
Move segv_handler to the new virtual_handle_fault() signature and drop the
debug abort that short-circuited all fault handling, and implement
handle_syscall_fault so a fault taken inside a syscall returns cleanly
instead of crashing on the kernel stack.

Signed-off-by: Leo Cheng <chengkelfan@qq.com>
The syscall frame was integer-only, so the dispatcher preserved only the
callee-saved integer registers and f0-f31 / CONTEXT_FLOATING_POINT were
lost across a syscall or a context set. Add an f[32] area to the frame,
save and restore it in the dispatcher, and implement save_fpu/restore_fpu
and the get/set-context float path.

The dispatcher captures f0-f31 after the NtCurrentTeb() call, so the
caller-saved fp registers may reflect post-call values; the callee-saved
fs0-fs11 that must survive a syscall are correct. Preserving the
caller-saved set across that call is left as a follow-up.

Signed-off-by: Leo Cheng <chengkelfan@qq.com>
TRAP_BRKPT was NYI, so an ebreak raised no EXCEPTION_BREAKPOINT and a
debugger saw nothing. Raise it, advancing past the ebreak to match the
back-up setup_exception applies for breakpoints. The arm64 __fastfail
path is dropped: ebreak carries no immediate to encode the fastfail code.

Signed-off-by: Leo Cheng <chengkelfan@qq.com>
The F0-F31 stores landed at 0x104 + n*8, four bytes below the CONTEXT F[]
array at 0x108, so each captured double overlapped the next and F31's high
word spilled past the register file. Store them at their real offsets.

Signed-off-by: Leo Cheng <chengkelfan@qq.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants