This week, I had really a hard time with RISC-V Angel. It started with finding the bootloader code from the RISC-V Proxy Kernel, as the bootloader is the primary program/codes that needs to be load up before the main program actually runs. I searched all over the proxy kernel code and eventually I realized that the bootloader code is in one of the file name “pk.S”, which loads a bundle of assembly codes that initialize the stack pointer, global pointer and some memory storing, then jump to another address to start the kernel.
To extract the bootloader code that had been used up by the proxy kernel, I opened the proxy kernel executable file that had been build using
riscv32-unknown-elf-objdump command, and modify the jump address to my desired starting address. I compiled the file separately using the RISC-V GCC, and link the file manually using an external linker script that modified from the old linker script, to link the new object file on a new address and modified the entry point to this new address, as these codes should be run first before the main program. It took some time to learn about modifying the linker script, and I found this link to be useful on. I found that it is really necessary to understand every single line of the linker script before modifying it.
The Test for the Bootloader
I did the testing by simple compiling simple C program (just arithmetic) , and it seems to be working fine with the RISC-V Angel. However, it does not work fine with the addition of system calls related function such as <code> printf() </code> . This makes me wonder about the functionality of proxy kernel, whereby it does have bunch of system calls handling functions and initialization. I traced every instructions and I found that the memory loading is wrong at some point, as it loads a zero to the return address register, which lead to the execution of instruction at address zero, which contains undefined instructions. I am thinking that maybe some memory data should really be initialized before the program actually executes.
Then, I went to try out on the execution of simple C++ program with the bootloader, and it does not work well. The C++ executable file is extremely large compared with the C executable file, and it runs more initialization instructions and failed before entering the main section.
Review the Past of RISC-V Angel
While searching for solutions, I found something interesting. The RISC-V Angel ISA Simulator is not designed to boot a Linux Kernel initially, it started with running C programs as well. It is really a surprise when I discovered these in the past commits in GitHub, whereby the previous version does have a debugger that step in each instructions! Analyzing the previous code, I also realized that the RISC-V Angel actually loads the proxy kernel and the C program. It operates as loading the proxy kernel executable file that had been pre-compiled, and compile a new C code on the spot and generate an executable file that loads together with the proxy kernel, which is running similar to the way that RISC-V Spike (RISC-V ISA Simulator) executes the compiled C program.
I tried to port in the new proxy kernel along with a pre-compiled C program executable file, but it does not work well. The main problem that I found, that causes this failure is the running of instructions, as the previous commits codes are old codes, so as their ISA that had been written. It is not an up-to-date RISC-V ISA Simulator today, and therefore it cannot execute the instruction properly. For example, it could easily mistaken a store instruction as a jump instruction. These can be seen by making a compare in the GitHub, which compares the changes of the files from two commits.
Then, I tried out to port the new proxy kernel and C program executable file to the latest RISC-V Angel ISA, I found that there is another problem on the execution, which trigger system call handling function when running some instructions such as <code> csrw tohost, t0 </code> and ends up with error, which I think that the RISC-V Angel makes these functions that specifically written for the Linux Kernel codes. As I found that these instructions does not trigger any trap exception in the RISC-V Spike ISA Simulator, and they just run the instructions normally. Meanwhile, The RISC-V Spike has different way on the execution of the C program executable file, it will trigger exception traps on certain instructions, such as when entering the entry point of the C program executable file.
Maybe, the usage of proxy kernel is really necessary? I will find out the answer this week by just focusing on the C++ execution.