Hey Fredrik!

On 2026-10-29 20:18, Pierrick Bouvier wrote:
On 10/29/2026 10:23 AM, Fredrik Noring wrote:
Hi Philippe, Maciej,

[ Maciej, a post [*] from you in 2021 is referenced in the following. ]

On 28 October 2026, Philippe Mathieu-Daudé wrote:
There is no libc for the R5900, so its tests can not run in user
mode [*].


I think that Philippe meant "there is no *prebuilt* libc for the r5900".

Both Glibc and Musl are available for the R5900.[1][2] In fact, we also
compile Gentoo for it. I believe the -mfix-r5900 option is used for the
official Gentoo MIPS downloads.[3]


If precompiled glibc or musl with companion toolchain are available from
a .tar, yes it could be used.

For now I deliberately kept user-mode emulation out, focusing on system
emulation which is less invasive.

I got user-emulation working but this add another QEMU binary and last
time Laurent as linux-user maintainer was not motivated to add a new
binary / target for 2 users :/

I have these changes on top of what I posted so far this week, but
building a r5900 cross-compiler on a x86 container running on an
aarch64 host takes age...:

-- >8 --
diff --git a/meson_options.txt b/meson_options.txt
index c9247e9de1..a48f2fcb7c 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -461,6 +461,10 @@ option('tcg_tests_cross_cc_mips32r5el', type: 'string',
        description: 'cc for mips32r5el tcg tests')
 option('tcg_tests_cross_cflags_mips32r5el', type: 'string',
        description: 'cflags for mips32r5el tcg tests')
+option('tcg_tests_cross_cc_mipsr5900el', type: 'string',
+       description: 'cc for mipsr5900el tcg tests')
+option('tcg_tests_cross_cflags_mipsr5900el', type: 'string',
+       description: 'cflags for mipsr5900el tcg tests')
 option('tcg_tests_cross_cc_or1k', type: 'string',
        description: 'cc for or1k tcg tests')
 option('tcg_tests_cross_cflags_or1k', type: 'string',
diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh
index 064e1429a4..69f203fa74 100644
--- a/scripts/meson-buildoptions.sh
+++ b/scripts/meson-buildoptions.sh
@@ -539,6 +539,7 @@ _meson_option_parse() {
--tcg-tests-cross-cc-m68k=*) quote_sh "-Dtcg_tests_cross_cc_m68k=$2" ;; --tcg-tests-cross-cc-mips=*) quote_sh "-Dtcg_tests_cross_cc_mips=$2" ;; --tcg-tests-cross-cc-mips32r5el=*) quote_sh "-Dtcg_tests_cross_cc_mips32r5el=$2" ;; + --tcg-tests-cross-cc-mipsr5900el=*) quote_sh "-Dtcg_tests_cross_cc_mipsr5900el=$2" ;; --tcg-tests-cross-cc-mips64=*) quote_sh "-Dtcg_tests_cross_cc_mips64=$2" ;; --tcg-tests-cross-cc-mips64el=*) quote_sh "-Dtcg_tests_cross_cc_mips64el=$2" ;; --tcg-tests-cross-cc-mips64r6=*) quote_sh "-Dtcg_tests_cross_cc_mips64r6=$2" ;;
@@ -565,6 +566,7 @@ _meson_option_parse() {
--tcg-tests-cross-cflags-m68k=*) quote_sh "-Dtcg_tests_cross_cflags_m68k=$2" ;; --tcg-tests-cross-cflags-mips=*) quote_sh "-Dtcg_tests_cross_cflags_mips=$2" ;; --tcg-tests-cross-cflags-mips32r5el=*) quote_sh "-Dtcg_tests_cross_cflags_mips32r5el=$2" ;; + --tcg-tests-cross-cflags-mipsr5900el=*) quote_sh "-Dtcg_tests_cross_cflags_mipsr5900el=$2" ;; --tcg-tests-cross-cflags-mips64=*) quote_sh "-Dtcg_tests_cross_cflags_mips64=$2" ;; --tcg-tests-cross-cflags-mips64el=*) quote_sh "-Dtcg_tests_cross_cflags_mips64el=$2" ;; --tcg-tests-cross-cflags-mips64r6=*) quote_sh "-Dtcg_tests_cross_cflags_mips64r6=$2" ;; diff --git a/tests/docker/dockerfiles/gentoo-mipsr5900el-cross.docker b/tests/docker/dockerfiles/gentoo-mipsr5900el-cross.docker
new file mode 100644
index 0000000000..f46c5a54b6
--- /dev/null
+++ b/tests/docker/dockerfiles/gentoo-mipsr5900el-cross.docker
@@ -0,0 +1,40 @@
+#
+# Docker mipsel (R5900) cross-compiler target
+#
+# The compiler is built with Gentoo crossdev because the regular Debian MIPS
+# toolchains do not provide the R5900-specific instruction set.
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+FROM docker.io/gentoo/stage3:latest
+
+RUN emerge-webrsync --quiet
+
+RUN mkdir -p /usr/local/portage-crossdev/{profiles,metadata} && \
+ printf '%s\n' crossdev > /usr/local/portage-crossdev/profiles/repo_name && \ + printf '%s\n' 'masters = gentoo' > /usr/local/portage-crossdev/metadata/layout.conf && \
+    chown -R portage:portage /usr/local/portage-crossdev && \
+    mkdir -p /etc/portage/repos.conf && \
+    printf '%s\n' \
+        '[crossdev]' \
+        'location = /usr/local/portage-crossdev' \
+        'priority = 10' \
+        'masters = gentoo' \
+        'auto-sync = no' \
+        > /etc/portage/repos.conf/crossdev.conf
+
+RUN emerge -qv \
+        dev-vcs/git \
+        '>=dev-libs/glib-2.0' \
+        sys-devel/crossdev \
+        sys-libs/zlib \
+        dev-lang/python
+
+RUN crossdev -s4 -t mipsr5900el-unknown-linux-gnu
+
+ENV QEMU_CONFIGURE_OPTS="--cross-prefix=mipsr5900el-unknown-linux-gnu-"
+
+ARG USER
+ARG UID
+RUN if [ "${USER}" ]; then \
+  id ${USER} 2>/dev/null || useradd -u ${UID} -U ${USER}; fi
diff --git a/tests/docker/dockerfiles/ubuntu2404-arm64-ps2dev.docker b/tests/docker/dockerfiles/ubuntu2404-arm64-ps2dev.docker
new file mode 100644
index 0000000000..8f2e9f2bd7
--- /dev/null
+++ b/tests/docker/dockerfiles/ubuntu2404-arm64-ps2dev.docker
@@ -0,0 +1,41 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+FROM docker.io/library/ubuntu:24.04
+
+RUN apt-get update && \
+ DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
+        ca-certificates \
+        bash \
+        make \
+        binutils \
+        file \
+        python3 \
+        libmpc3 && \
+    rm -rf /var/lib/apt/lists/*
+
+RUN python3 -c 'import urllib.request; urllib.request.urlretrieve("https://github.com/ps2dev/ps2dev/releases/download/v2.0.0/ps2dev-ubuntu-24.04-arm.tar.gz";, "/tmp/ps2dev.tar.gz")' && \
+    tar -xzf /tmp/ps2dev.tar.gz -C /usr/local && \
+    test -d /usr/local/ps2dev && \
+    rm -f /tmp/ps2dev.tar.gz
+
+ENV PS2DEV=/usr/local/ps2dev \
+    PS2SDK=/usr/local/ps2dev/ps2sdk \
+    GSKIT=/usr/local/ps2dev/gsKit \
+ PATH=/usr/local/ps2dev/bin:/usr/local/ps2dev/ee/bin:/usr/local/ps2dev/iop/bin:/usr/local/ps2dev/dvp/bin:/usr/local/ps2dev/ps2sdk/bin:$PATH
+
+RUN command -v mips64r5900el-ps2-elf-gcc && \
+ test "$(mips64r5900el-ps2-elf-gcc -dumpmachine)" = mips64r5900el-ps2-elf && \
+    mips64r5900el-ps2-elf-gcc --version && \
+    printf 'int test;\n' | mips64r5900el-ps2-elf-gcc \
+ -march=r5900 -mabi=eabi -mgp32 -mno-abicalls -ffreestanding -nostdlib \
+        -x c -c -o /tmp/r5900-assembler-check.o - && \
+    file /tmp/r5900-assembler-check.o && \
+    rm -f /tmp/r5900-assembler-check.o
+
+ARG USER
+ARG UID
+RUN if [ "${USER}" ]; then \
+        id "${USER}" 2>/dev/null || \
+        useradd -u "${UID}" -U "${USER}" 2>/dev/null || \
+        useradd -U "${USER}"; \
+    fi
diff --git a/tests/tcg/mips/meson.build b/tests/tcg/mips/meson.build
index 2164f143ea..5f640d13e8 100644
--- a/tests/tcg/mips/meson.build
+++ b/tests/tcg/mips/meson.build
@@ -1,3 +1,5 @@
+subdir('system')
+
 tests = []

 tests += tcg_tests['multiarch-linux-user']['tests']
diff --git a/tests/tcg/mips/system/boot.S b/tests/tcg/mips/system/boot.S
new file mode 100644
index 0000000000..ab5b799059
--- /dev/null
+++ b/tests/tcg/mips/system/boot.S
@@ -0,0 +1,32 @@
+/*
+ * Minimal R5900 bare-metal entry point.
+ *
+ * The MIPS UHI semihosting ABI uses $25 for the operation and $4 for its
+ * argument.  UHI_exit is selected by executing sdbbp with code 1 while
+ * semihosting is enabled in QEMU.
+ */
+
+       .set noreorder
+       .set noat
+
+       .section .text.boot, "ax", @progbits
+       .align 2
+       .globl _start
+       .ent _start
+_start:
+       /* Keep the stack away from the image loaded at address zero. */
+       lui     $sp, 0x0100
+
+       jal     test_main
+        nop
+
+       move    $a0, $v0
+       li      $t9, 1                  /* UHI_exit */
+ /* sdbbp 1 (SPECIAL2, code 1); the PS2Dev assembler lacks the mnemonic. */
+       .word   0x7000007f
+        nop
+
+1:
+       b       1b
+        nop
+       .end _start
diff --git a/tests/tcg/mips/system/meson.build b/tests/tcg/mips/system/meson.build
new file mode 100644
index 0000000000..d7b51711ec
--- /dev/null
+++ b/tests/tcg/mips/system/meson.build
@@ -0,0 +1,76 @@
+tests = []
+
+ps2_cc = find_program('mips64r5900el-ps2-elf-gcc', required: false)
+
+qemu_name = ''
+if 'qemu-system-mips64el' in emulators
+  qemu_name = 'qemu-system-mips64el'
+elif 'qemu-system-mipsel' in emulators
+  qemu_name = 'qemu-system-mipsel'
+endif
+
+if qemu_name != '' and (ps2_cc.found() or docker_supported)
+  qemu = emulators[qemu_name]
+  boot = files('boot.S')[0]
+  linker = files('linker.ld')[0]
+  smoke = files('r5900-smoke.c')[0]
+  runner = files('run-test.py')[0]
+
+  cflags = [
+    '-march=r5900',
+    '-mabi=eabi',
+    '-mgp32',
+    '-mno-abicalls',
+    '-mno-gpopt',
+    '-mno-extern-sdata',
+    '-fno-pic',
+    '-fno-builtin',
+    '-fno-stack-protector',
+    '-ffreestanding',
+    '-nostdlib',
+    '-nodefaultlibs',
+    '-nostartfiles',
+    '-Wl,--build-id=none',
+    '-Wl,-m,elf32lr5900',
+    '-Wl,-T', linker,
+  ]
+
+  elf_depends = []
+  if not ps2_cc.found()
+ dockerfile = files('../../../docker/dockerfiles/ubuntu2404-arm64-ps2dev.docker')
+    image = custom_target('image-ubuntu2404-arm64-ps2dev',
+ command: [docker_wrapper, 'build', '-f', dockerfile,
+                                    '-t', 'qemu/ubuntu2404-arm64-ps2dev',
+                                    '--platform', 'linux/arm64',
+                                    '--add-current-user'],
+                          build_by_default: false,
+                          console: true,
+ output: 'no_output_image-ubuntu2404-arm64-ps2dev')
+
+    mount = meson.project_source_root()
+    mount = mount + ':' + mount
+    here = meson.project_build_root()
+    ps2_cc = [docker_wrapper, 'run', '--run-as-current-user', '--',
+              '--security-opt', 'label=disable',
+              '--platform', 'linux/arm64',
+              '-w', here, '-v', here + ':' + here, '-v', mount,
+              'qemu/ubuntu2404-arm64-ps2dev',
+              'mips64r5900el-ps2-elf-gcc']
+    elf_depends += image
+  endif
+
+  elf = custom_target('mipsel-ps2-r5900-smoke',
+                      input: [smoke, boot],
+                      output: 'mipsel-ps2-r5900-smoke.elf',
+                      command: [ps2_cc, '@INPUT@', '-o', '@OUTPUT@',
+                                '-Wall', '-Werror', '-O0', '-g', cflags],
+                      depend_files: [linker, dockerfile],
+                      depends: elf_depends,
+                      build_by_default: false)
+
+  test('mipsel-ps2-r5900-smoke', python,
+       args: [runner, '--qemu', qemu.full_path(), '--elf', elf],
+       depends: [elf, qemu],
+       timeout: 120,
+ suite: ['tcg', 'tcg-' + qemu_name.replace('qemu-system-', '') + '-softmmu'])
+endif
diff --git a/tests/tcg/mips/system/run-test.py b/tests/tcg/mips/system/run-test.py
new file mode 100644
index 0000000000..912b6bb01b
--- /dev/null
+++ b/tests/tcg/mips/system/run-test.py
@@ -0,0 +1,30 @@
+#!/usr/bin/env python3
+"""Run a MIPS bare-metal ELF and propagate its UHI exit status."""
+
+import argparse
+import subprocess
+
+
+def main():
+    parser = argparse.ArgumentParser()
+    parser.add_argument('--qemu', required=True)
+    parser.add_argument('--elf', required=True)
+    args = parser.parse_args()
+
+    command = [
+        args.qemu,
+        '-M', 'none',
+        '-m', '16M',
+        '-cpu', 'R5900',
+        '-display', 'none',
+        '-device', f'loader,file={args.elf},cpu-num=0',
+        '-semihosting-config', 'enable=on,target=native',
+    ]
+
+    # Inherit stdout/stderr so diagnostics remain visible when the test
+    # fails.  UHI_exit makes QEMU's process status the test result.
+    return subprocess.run(command, check=False).returncode
+
+
+if __name__ == '__main__':
+    raise SystemExit(main())
diff --git a/tests/tcg/mips64/meson.build b/tests/tcg/mips64/meson.build
index c80a3716f5..0d3c44b643 100644
--- a/tests/tcg/mips64/meson.build
+++ b/tests/tcg/mips64/meson.build
@@ -6,6 +6,10 @@ tests += {
   '../mips64/octeon-insns.c': {
     'qemu_args': ['-cpu', 'Octeon68XX'],
   },
+  '../mips64/tx79-insns.c': {
+    'qemu_args': ['-cpu', 'R5900'],
+    'cflags': '-march=mips64r2',
+  },
 }
diff --git a/tests/tcg/mipsel/meson.build b/tests/tcg/mipsel/meson.build
index 3ac4711748..e69aff6211 100644
--- a/tests/tcg/mipsel/meson.build
+++ b/tests/tcg/mipsel/meson.build
@@ -215,3 +215,38 @@ if 'qemu-mipsel' in emulators
     }
   }
 endif
+
+tests = []
+
+tests_mips_r5900 = [
+  '../mips/user/isa/r5900/test_r5900_div1.c',
+  '../mips/user/isa/r5900/test_r5900_divu1.c',
+  '../mips/user/isa/r5900/test_r5900_madd.c',
+  '../mips/user/isa/r5900/test_r5900_maddu.c',
+  '../mips/user/isa/r5900/test_r5900_mflohi1.c',
+  '../mips/user/isa/r5900/test_r5900_mtlohi1.c',
+  '../mips/user/isa/r5900/test_r5900_mult.c',
+  '../mips/user/isa/r5900/test_r5900_multu.c',
+]
+
+foreach src: tests_mips_r5900
+  tests += {
+    src: {
+      'cflags': ['-mabi=32', '-march=r5900'],
+      'qemu_args': ['-cpu', 'R5900'],
+    }
+  }
+endforeach
+
+if 'qemu-mipsel' in emulators
+  tcg_tests += {
+    'mipsr5900el-linux-user': {
+      'cc': 'mipsr5900el-unknown-linux-gnu-gcc',
+      'cc_dockerfile': 'gentoo-mipsr5900el-cross',
+      'folder': 'mipsel',
+      'gdb_arch': 'mipsel',
+      'qemu': emulators['qemu-mipsel'],
+      'tests': tests,
+    }
+  }
+endif
---

As for QEMU, I maintain my own fork with R5900 user mode support since
2020, based on QEMU v5.2, as well as a corresponding Gentoo package,[4][5]
because later versions of QEMU became unfixable and unusable for R5900
user mode emulation.

A proper QEMU R5900 user mode must emulate the FPU like the Linux kernel
does, which is why QEMU 5.2 remains the latest usable version of QEMU for
the R5900.

It’s worth mentioning that there are discussions on introducing additional
FPU modes for the R5900 and Linux, which would allow use of FPU hardware,
despite its noncompliance with IEEE 754.[6][7]

[*] 
https://lore.kernel.org/qemu-devel/[email protected]/

Inspired-by: Maciej W. Rozycki <[email protected]>

Fredrik

[1] https://github.com/frno7/gentoo-mipsr5900el
[2] 
https://github.com/frno7/gentoo-mipsr5900el/blob/d84d04b2fd9d47d5cce9c1c0884026cc37d008cf/scripts/install-crossdev#L16-L17
[3] https://www.gentoo.org/downloads/mips/
[4] https://github.com/frno7/qemu
[5] 
https://github.com/frno7/gentoo.overlay/tree/main/app-emulation/qemu-mipsr5900el
[6] https://github.com/frno7/linux/wiki/R5900-floating-point-unit-(FPU)
[7] https://github.com/frno7/linux/issues/3



Reply via email to