Hello everyone! hope you’re all doing well.
Lately I’ve been trying to develop real-time software on RISC-V (taking the official FreeRTOS QEMU demo ports as a starting point), but some very weird issues got in the way and made me decide to ask for help on the related forums.
TL:DR
FreeRTOS forums won’t allow me to paste the repository link here, but it basically goes like this: the program executes fine when a certain code snippet is encapsulated within a function, but “crashes” (i.e. hangs) when the same snippet is placed directly in the main code:
for(int i=0; i < NUMBER_OF_ITEMS; i++){
createAndPushItem(i);
// the function above does the exact same thing as the commented code below
// yet, the commented code does not work and will crash the program. but why??
// int index = priorities[i];
// void *value = (void *) getValue(i + 1);
// LinkedListItem_t *item = createItem(index, value);
// if(item){
// push(item, &list);
// }
}
The scope shouldn’t matter at all here, since there is no local variable being used or anything like that. Also, in favor of simplicity the sample code doesn’t even uses FreeRTOS’ tasks or scheduler, just the pvPortMalloc/vPortFree functions.
Context
It all started with me deciding to use Robin Kase’s ESFree library to append the EDF scheduler to the project, but the code didn’t work out-of-the-box on neither of the ‘virt’ ports. It ran OK on the ARM ports for QEMU, though, so I figured it should be some incompatibility issue on the RISC-V side. While investigating, I found the problem seemed to be related to the linked lists API, as the List_t uxNumberOfItems variable just seemed to go crazy on a certain point of the code that wasn’t even supposed to interact with it.
I then decided to create my own library for managing linked lists as a workaround and created a whole new sample project to test it, but my attempt of making it happen also went sideways with a new bug: the code would execute just fine when a certain snippet were placed inside a dedicated function, but not so much when placed directly on the main code. That is what I describe on the TL:DR section above.
This doesn’t really seem to me like a problem within FreeRTOS, as like I said there are no schedulers or tasks being used. The only resources provided by FreeRTOS which I actually use on the sample project are pvPortMalloc and vPortFree, but the problem happens anyway with regular malloc (as shown below). I can’t really cross FreeRTOS out of the equation, though, since the whole port setup (e.g. libraries, assembly files and makefile) has been provided by it.
Workarounds
These were my attempts of solving the problem so far:
- Tried using the other FreeRTOS RISC-V port meant for QEMU (RISC-V-Qemu-virt-GCC), but the problem persists.
- Tried building the project without compiler optimization (using -O0 instead of -Os in the makefile). The output is even worse, with the execution hanging even before printing the list items for the first time.
- Tested with other heap files provided by FreeRTOS (heap_1, heap_3 and heap_4). No success whatsoever.
- Tested with regular malloc() and free() from stdlib.h. Output shows same behavior as compiling without optimization (i.e. prints nothing on the terminal).
I suppose the next logical step would be to create my own RISC-V port for other QEMU supported boards such as SiFive HiFive Unleashed, but I am not very confident on this mission since I have little experience with developing ports for emulators, and there doesn’t seem to have many good guides about it online. I am familiar with many programming languages, but FreeRTOS/QEMU/compiler developing/debugging are definitely out of my league. Hence why I’m here asking for help from the clever ones.
I’ll be posting this issue on the RISC-V toolchain and QEMU forums aswell. Hopefully someone might help me out on this quest.
Thanks in advance.