What is it about the Rust code that causes the same operation to not work?
I have genuinely no idea. Is it a toolchain problem? (I've had quite a few of those, so I wouldn't be surprised.) Is it me being an idiot and not understanding how to translate the operation in C into Rust syntax?
Edit: I figured out why it isn't displaying anything. In the "serial0" console in QEMU it's displaying a "Invalid Opcode" error. This sounds like a toolchain problem, but what it could be, I have no idea.
Here's a screenshot of the error:
I find it highly unlikely this is an abort, as in a second run I got a difference between the kernel address and the error RIP that was greater than the file size. Only 2 ways that I can think of that could cause that to occur would be execution somehow escaping the kernel, or the bootloader jumping to the wrong address. Which, since I had this bootloader working with the previous C kernel, I find unlikely.
pointer::offset() takes its argument in units of size_of::<T>().
You are multiplying by 4, i.e. size_of::<u32>(), apparently under the impression that the argument is a byte offset, no?
AFAICT, the framebuf.base_address in your C code is just a 64-bit integer, not even a pointer. So pointer arithmetic isn't even in play. The C is just treating a plain old int as a byte pointer. That won't work in Rust with pointer::offset(). The offset method arg is more like indexing an array of type T.
You could get away with it if you did the same "cast this int as a pointer" trick as in the C code. Not that it's recommended, but it's something that can be done with caution. ↩︎
Then this is much easier, all that mess of pointer arithmetic in the C version is to index a 1d array aligned to u8 offsets (direct access to RAM should behave as if it was that) as a 2d array aligned to u32 offsets. Even then, "Invalid Opcode" error mentioned couldn't have come from that, right? Having a wrong operation with no jumps in it shouldn't cause a "Invalid Opcode" error.
Ah yeah. I didn't read carefully enough and jumped from " drawing" to a computation kernel usually used in graphics programming ^^' in your case the kernel will obviously not kill the process.
You might however still run into some interrupt that gets called when an unknown instruction is executed or a different interrupt when read only memory is written to. Can you run the code with a debugger?
I actually tried that, I couldn't get GDB to trigger breakpoints anywhere near the error location for some reason. And I have no idea if it's possible to make it so GDB stops execution when int 6 is triggered, so I can backtrace and figure out how execution got there.
find out where the interrupt 6 is located on x86 (on arm this is standardized, I'm not sure about x86) and put a breakpoint there. From gdb perspective there shouldn't be a difference between a breakpoint in "normal" code and interrupts.
put a breakpoint into the entry point of the kernel and manually step through the code to find out where things go wrong.