Skip to content

mop.r / mop.rr preserve rd instead of trapping or zeroing it #305

Description

@carlosqwqqwq

mop.r / mop.rr preserve rd instead of trapping or zeroing it

Affected revision

RVVM staging snapshot used for this report, 2026-09-05, x86-64 host, RV64 guest user-mode execution.

Summary

In the SYSTEM instruction path (src/cpu/riscv_priv.c), the funct3 = 0b100 case contains:

case 0x04:
    if ((insn & 0xB0000000UL) == 0x80000000UL) { // mop.r.{0,31}, mop.rr.{0,7} (Zimop)
        return;
    }
    break;

For these code points RVVM returns without raising an illegal-instruction exception and without writing a value to rd. The RISC-V Zimop specification states that MOP.R.n and MOP.RR.n, unless redefined by another extension, write 0 to x[rd]. They are not pure no-ops.

Reproducer

Minimal Linux static guest:

#include <signal.h>
#include <setjmp.h>
#include <stdint.h>
#include <stdio.h>

static sigjmp_buf jb;
static volatile int trapped;

static void on_sigill(int sig, siginfo_t *si, void *ctx)
{
    (void)sig; (void)si; (void)ctx;
    trapped = 1;
    siglongjmp(jb, 1);
}

int main(void)
{
    struct sigaction sa = {0};
    sa.sa_sigaction = on_sigill;
    sa.sa_flags = SA_SIGINFO;
    sigaction(SIGILL, &sa, 0);

    uint64_t a0 = 0x1122334455667788ULL;
    if (sigsetjmp(jb, 1) == 0) {
        asm volatile(".word 0x81c04573" : "+r"(a0)); // mop.r.0 a0, a0
    }
    printf("trap=%d out=0x%016" PRIx64 "\n", trapped, a0);
    return 0;
}

The same raw words for mop.r.31, mop.rr.0, and mop.rr.7 reproduce the same behavior.

Environment

  • Native RV64 reference: native RV64 hardware, RV64 Linux, direct execution.
  • QEMU reference: qemu-riscv64 user mode.
  • RVVM: user-mode execution through the affected RVVM build.

Expected behavior

Either these code points should raise an illegal-instruction exception in a guest configuration that does not enable Zimop, or, if the default Zimop fallback is implemented, they should write 0 to rd.

Observed behavior

RVVM retires the instruction, preserves rd unchanged, and delivers no guest-visible trap:

trap=0 out=0x1122334455667788

On the native RV64 reference and on QEMU the same witness traps or writes zero:

native: trap=1
qemu:   trap=0 out=0

Cause

The mop.r/mop.rr decode branch returns immediately. It neither traps nor applies the architectural rd = 0 writeback.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions