Closed tvlad1234 closed 1 year ago
I tried the file-backed RAM approach on an x86 Linux system (same code, only difference being file access as I use FatFS on the Pico) and it worked. I am pretty sure that the RAM access on the Pico works properly, as I've tried multiple approaches and all of them had the same result (same access fault at the same address every time). The project I am working on can be found here: pico-rv32ima
I tried compiling and running mini-rv32ima (the regular version provided in this repository) on a Pi 4 running Pi OS Lite. The emulator crashed in the exact same way as it did with my version on the Pi Pico. I suspect there's some code in mini-rv32ima.h that behaves differently on ARM than it does on x86.
Would you mind running it in valgrind
by saying valgrind ./minir....
Additionally, can you build the kernel + image to see where the call stack is actually failing?
I'm building the kernel right now. On a side note, I also compiled and ran mini-rv32ima on 64-bit ARM (a Mac and an Oracle Cloud VM) and it worked without any issues, so I'm guessing it's 32-bit ARM related. I also compiled with clang on ARM32, with the same issues.
I've rebuilt the image and ran mini-rv32ima in Valgrind. I'm getting a different error message in the kernel with this image (but it's still the same every time I run the emulator). After looking at the assembly listing, it seems that it faults at an ebreak
in init_pwq
. Also, if I run the emulator with the -d
parameter, it faults and exits at the address the kernel is reporting in the panic message.
I am attaching the Valgrind output, kernel listing and kernel image below. valgrindOutput.txt imageAndListing.zip
I have added a printf in the emulator code which prints the memory address it loads from when it executes the instruction that triggers the access fault in the provided prebuilt image:
case 0b0000011: // Load
{
uint32_t rs1 = REG((ir >> 15) & 0x1f);
uint32_t imm = ir >> 20;
int32_t imm_se = imm | (( imm & 0x800 )?0xfffff000:0);
uint32_t rsval = rs1 + imm_se;
// vlads modification
// see what address we try to access at the instruction which fails
if(pc == 0x8006f1fc){
printf("\n\nrsval = %08x", rsval); getchar(); }
On x86 the emulator outputs:
[ 0.000000] Memory: 61936K/65532K available (1346K kernel code, 271K rwdata, 149K rodata, 1105K init, 108K bss, 3596K reserved, 0K cma-reserved)
rsval = 83f84d88
rsval = 83f84da8[ 0.000000] NR_IRQS: 64, nr_irqs: 64, preallocated irqs: 0
[ 0.000000] riscv-intc: 32 local interrupts mapped
[ 0.000000] clint: clint@11000000: timer running at 1000000 Hz
[ 0.000000] clocksource: clint_clocksource: mask: 0xffffffffffffffff max_cycles: 0x1d854df40, max_idle_ns: 3526361616960 ns
[ 0.000000] sched_clock: 64 bits at 1000kHz, resolution 1000ns, wraps every 2199023255500ns
rsval = 83f84dc8[ 0.443526] Console: colour dummy device 80x25
[ 0.443855] Calibrating delay loop (skipped), value calculated using timer frequency.. 2.00 BogoMIPS (lpj=4000)
[ 0.444364] pid_max: default: 4096 minimum: 301
rsval = 83f84de8
On ARM32 it outputs:
GNU nano 6.4 on_arm.txt
[ 0.000000] Memory: 61936K/65532K available (1346K kernel code, 271K rwdata, 149K rodata, 1105K init, 108K bss, 3596K reserved, 0K cma-reserved)
rsval = 83ffba48
rsval = 83ffbce8[ 0.000000] NR_IRQS: 64, nr_irqs: 64, preallocated irqs: 0
[ 0.000000] riscv-intc: 32 local interrupts mapped
[ 0.000000] clint: clint@11000000: timer running at 1000000 Hz
[ 0.000000] clocksource: clint_clocksource: mask: 0xffffffffffffffff max_cycles: 0x1d854df40, max_idle_ns: 3526361616960 ns
[ 0.000000] sched_clock: 64 bits at 1000kHz, resolution 1000ns, wraps every 2199023255500ns
rsval = 83ffba08[ 2.711267] Console: colour dummy device 80x25
[ 2.716250] Calibrating delay loop (skipped), value calculated using timer frequency.. 2.00 BogoMIPS (lpj=4000)
[ 2.725399] pid_max: default: 4096 minimum: 301
rsval = 00000004
After a lot of debugging, it turns out that the following lines in mini-rv32ima.h behave differently on x86 and ARM: https://github.com/cnlohr/mini-rv32ima/blob/ec3267e3327d9ad6f3d6da3309c52ead6ba7a214/mini-rv32ima/mini-rv32ima.h#L311 https://github.com/cnlohr/mini-rv32ima/blob/ec3267e3327d9ad6f3d6da3309c52ead6ba7a214/mini-rv32ima/mini-rv32ima.h#L315
This is due to the fact that shifts on x86 are automatically limited to 5bit values, but on ARM they aren't. In this case, there is a chance that the shift result might get fully zeroed, even though it's not supposed to be.
This issue seems to be solved by and'ing the rs2 value with 0x1F before using it in the bitshift.
Thank you for doing all this work. It is all resolved now.
I am currently trying to use this emulator core to run Linux on the Raspberry Pi Pico. I have managed to solve the lack of RAM by storing memory contents on an SD card and using about 128K of internal SRAM as cache. It is quite slow, but seems to be working, it takes the emulator 30 seconds to get to the point where the kernel panics. I am using the provided precompiled Buildroot images. It always panics in the same spot, with the exact trace. I don't have any experience working with RISC-V so far, so I don't know where to start troubleshooting. This is what the kernel panic shows: