riscvarchive / riscv-qemu

QEMU with RISC-V (RV64G, RV32G) Emulation Support
385 stars 154 forks source link

QEMU RISCV generates illegal instruction on csrrw #97

Closed rtcw50 closed 6 years ago

rtcw50 commented 6 years ago

Hello, RISCV QEMU seems unable to execute csrrw instructions. Assembly encoding seems ok to me. Thanks for the help.

ENVIRONMENT Ubuntu 1604 docker image (reproduced on Fedora 23 native as well)

QEMU:

qemu-riscv32 --version
qemu-riscv32 version 2.11.50 (-dirty)
Copyright (c) 2003-2017 Fabrice Bellard and the QEMU Projects

commit 73406e1213ee5a0ba29e7bd1a6b232a6811dc3a3
Author: Michael Clark <mjc@sifive.com>
Date:   Wed Jan 10 18:15:45 2018 -0800

RISCV gcc:

Using built-in specs.
COLLECT_GCC=riscv32-unknown-elf-gcc
COLLECT_LTO_WRAPPER=/opt/riscv/libexec/gcc/riscv32-unknown-elf/7.0.1/lto-wrapper
Target: riscv32-unknown-elf
Configured with: /mnt/riscv/rv-tools/riscv-gnu-toolchain/ubu1604-rv32-ilp32-build/../riscv-gcc/configure --target=riscv32-unknown-elf --prefix=/opt/riscv --disable-shared --disable-threads --enable-languages=c,c++ --with-system-zlib --enable-tls --with-newlib --with-headers=/opt/riscv/riscv32-unknown-elf/include --disable-libmudflap --disable-libssp --disable-libquadmath --disable-libgomp --disable-nls --enable-checking=yes --disable-multilib --with-abi=ilp32 --with-arch=rv32imafdc 'CFLAGS_FOR_TARGET=-Os  -mcmodel=medlow'
Thread model: single
gcc version 7.0.1 20170321 (experimental) (GCC)

RISCV Clang:

/mnt/riscv/llvm_riscv_github/build/bin/clang -v -O0  -isystem /opt/riscv/riscv32-unknown-elf/include -target riscv32-unknown-elf -march=rv32imafdc csrrw.c -o csrrw.elf
clang version 7.0.0 (https://github.com/llvm-mirror/clang 43e5d26a5656cb0fec35bee609c669e429699d7d) (https://github.com/llvm-mirror/llvm 23b4612e31598d3cd3edb6fbb337d61feea3dc93)
Target: riscv32-unknown--elf
Thread model: posix
InstalledDir: /mnt/riscv/llvm_riscv_github/build/bin
 "/mnt/riscv/llvm_riscv_github/build/bin/clang-6.0" -cc1 -triple riscv32-unknown--elf -emit-obj -mrelax-all -disable-free -main-file-name csrrw.c -mrelocation-model static -mthread-model posix -mdisable-fp-elim -fmath-errno -masm-verbose -mconstructor-aliases -target-feature +m -target-feature +a -target-feature +f -target-feature +d -target-feature +c -target-abi ilp32 -dwarf-column-info -debugger-tuning=gdb -v -resource-dir /mnt/riscv/llvm_riscv_github/build/lib/clang/7.0.0 -isystem /opt/riscv/riscv32-unknown-elf/include -O0 -fdebug-compilation-dir /mnt/riscv/llvm_riscv_github/local_tests/test3 -ferror-limit 19 -fmessage-length 114 -fno-signed-char -fobjc-runtime=gcc -fdiagnostics-show-option -fcolor-diagnostics -o /tmp/csrrw-fe7c5d.o -x c csrrw.c

Compile the following code with gcc or clang: riscv32-unknown-elf-gcc csrrw.c -o csrrw.elf

csrrw.c:

int gI;

int main() {
 unsigned cycles = 0;
 __asm __volatile(
    "csrw 0xc00," "%[cycles]\n\t"
      :[cycles]"+r"(cycles)
  );
 for (int i=0; i<1000; i++) {
        gI += i;
 }
 //printf ("Hello World %d\n", gI);
  __asm __volatile(
    "csrr %[cycles]," "0xc00" "\n\t"
      :[cycles]"=r"(cycles)
  );
  return cycles;
}

Execute in user mode: ... rv-tools/riscv-qemu/build/riscv32-linux-user/qemu-riscv32 csrrw.elf

Output: Illegal instruction (core dumped)

Debug Output:

``IN: main
0x0001015a:  addi            sp,sp,-32
0x0001015c:  sw              s0,28(sp)
0x0001015e:  addi            s0,sp,32
0x00010160:  sw              zero,-24(s0)
0x00010164:  lw              a5,-24(s0)
0x00010168:  csrrw           zero,cycle,a5

OUT: [size=119]
0x55d8ad76e400:  41 8b 6e ec              movl     -0x14(%r14), %ebp
0x55d8ad76e404:  85 ed                    testl    %ebp, %ebp
0x55d8ad76e406:  0f 8c 5f 00 00 00        jl       0x55d8ad76e46b
0x55d8ad76e40c:  41 8b 6e 08              movl     8(%r14), %ebp
0x55d8ad76e410:  83 c5 e0                 addl     $-0x20, %ebp
0x55d8ad76e413:  41 89 6e 08              movl     %ebp, 8(%r14)
0x55d8ad76e417:  8d 5d 1c                 leal     0x1c(%rbp), %ebx
0x55d8ad76e41a:  45 8b 66 20              movl     0x20(%r14), %r12d
0x55d8ad76e41e:  65 67 44 89 23           movl     %r12d, %gs:0(%ebx)
0x55d8ad76e423:  83 c5 20                 addl     $0x20, %ebp
0x55d8ad76e426:  41 89 6e 20              movl     %ebp, 0x20(%r14)
0x55d8ad76e42a:  8d 5d e8                 leal     -0x18(%rbp), %ebx
0x55d8ad76e42d:  45 33 e4                 xorl     %r12d, %r12d
0x55d8ad76e430:  65 67 44 89 23           movl     %r12d, %gs:0(%ebx)
0x55d8ad76e435:  83 c5 e8                 addl     $-0x18, %ebp
0x55d8ad76e438:  65 67 8b 6d 00           movl     %gs:0(%ebp), %ebp
0x55d8ad76e43d:  41 89 6e 3c              movl     %ebp, 0x3c(%r14)
0x55d8ad76e441:  41 c7 86 80 01 00 00 68  movl     $0x10168, 0x180(%r14)
0x55d8ad76e449:  01 01 00
0x55d8ad76e44c:  49 8b fe                 movq     %r14, %rdi
0x55d8ad76e44f:  8b f5                    movl     %ebp, %esi
0x55d8ad76e451:  ba 00 0c 00 00           movl     $0xc00, %edx
0x55d8ad76e456:  e8 fd 3b a9 ff           callq    0x55d8ad202058
0x55d8ad76e45b:  41 c7 86 80 01 00 00 6c  movl     $0x1016c, 0x180(%r14)
0x55d8ad76e463:  01 01 00
0x55d8ad76e466:  e9 ab db ff ff           jmp      0x55d8ad76c016
0x55d8ad76e46b:  48 8d 05 11 ff ff ff     leaq     -0xef(%rip), %rax
0x55d8ad76e472:  e9 a1 db ff ff           jmp      0x55d8ad76c018          
sorear commented 6 years ago

This behavior is, as far as I know, correct. The cycle counter is read-only in RISC-V (see the privileged specification), and so writes to it are decoded as illegal instructions; qemu-system-riscv32 will take an illegal instruction trap in the guest, while user emulation does the equivalent of a raise(SIGILL) to allow signal handlers within the emulated program to fire.

rtcw50 commented 6 years ago

OK, thanks, now that I think about it, that seems reasonable. Sorry for the interrupt.