exceptionassemblyriscvinterrupt-handlingriscv32

how to get details about an "Environment call from M-mode" exception for ecall handler?


we are integrating a new core (from pulpino to cv32). I have no issues compiling and running code on my target, except when calling time() or srand() or rand() (but not div() for instance), where the default exception handler is called back and I have the following CSR values:

mcause : 0x0000000b
mstatus : 0x00001880 (mstatus.MPP : 03, mstatus.MIE : 01)
mepc : 0x00003476
mtval : 0x00000000
mip : 0x00000000
mie : 0xffff0000
misa : 0x40101104

I compiled and ran a very simple test (which is just/only a call to rand() that triggers the exception) and then I display the CSR in the default exception handler with printfs.

as you can see, mcause = 0xB which is "Environment call from M-mode" (see p29)

The ECALL instruction is used to make a request to a higher privilege level. The binary interface to the execution environment will define how parameters for the request are passed, but usually these will be in defined locations in the integer register file. Executing an ECALL instruction causes an Environment Call exception.

What I understand that ecall is used to call for instance linux. and by disassembling the binary, I found that ecall was called in the time and rand functions, but not the div. This proves that the ecall is triggering the exception.

1/ What could explain that ecall triggers an exception?

Executing an ECALL instruction causes an Environment Call exception.

OK, so I guess I should be handling the ecall exception, but how?

here is my crt0.S:

 .section .vectors, "ax"
  .option norvc;
  .global intvec
intvec:
  .org 0x00
  jal x0, default_exception_handler_c
  [...]

  .org 0x88
  jal x0, ecall_insn_handler

2/ Why the ecall triggers the default_exception_handler_c and not the ecall_insn_handler? bad hw wiring?



details:

I am working with the riscv COREV toolchain configured with:


riscv32-corev-elf-gcc -v
[...]
Target: riscv32-corev-elf
Configured with: ../../gcc/configure --target=riscv32-corev-elf --prefix=/build/workspace/corev-gcc-centos7/install --with-sysroot=/build/workspace/corev-gcc-centos7/install/riscv32-corev-elf --with-native-system-header-dir=/include --with-newlib --disable-shared --enable-languages=c,c++ --enable-tls --disable-werror --disable-libmudflap --disable-libssp --disable-quadmath --disable-libgomp --disable-nls --enable-multilib --with-arch=rv32imac --with-abi=ilp32 --with-bugurl=''\''https://www.embecosm.com'\''' --with-pkgversion=''\''corev-openhw-gcc-centos7-20200913'\'''
Thread model: single
Supported LTO compression algorithms: zlib
gcc version 11.0.0 20200813 (experimental) ('corev-openhw-gcc-centos7-20200913') 

compilation flags include:

-Os -Wa,-march=rv32ic -Wall -Wdouble-promotion -Wextra -Wformat=2 -fdata-sections -ffunction-sections -fno-builtin -fno-builtin-printf -fno-merge-all-constants -g0 -march=rv32ic -s -std=gnu11

Solution

  • What could explain that ecall triggers an exception?

    I am a bit confused by this question. ECALL is documented to trigger an exception, indeed that is the purpose of that operation, akin to SYSENTER / SYSCALL on x86/x64.

    The idea here is to facilitate a context switch. Functions like div() can be resolved in unpriviledged mode, others like time() cannot (for example, because unpriviledged mode does not allow access to the system clock). So their implementation sets certain registers in a certain way ("please give me the clock's status"), and then triggers an exception (ECALL). The exception handler -- which runs at a higher priviledge level -- checks the value of those registers, which tell it which functionality was required by the caller. The functionality is performed, results are stored in registers, and control is returned to the (unpriviledged) caller.

    Why the ecall triggers the default_exception_handler_c and not the ecall_insn_handler? bad hw wiring?

    I very much doubt that, because it is elementary functionality. It is much more likely that your exception handling is incorrectly implemented.