Community of non stanford students to work on https://web.stanford.edu/class/cs140e/ Theres a seperate room for sharing code. Just mention you need an invite
My current problem is tough to debug. If I use bump allocator, I can read the root directory (assignment 2, phase 3b). However, if I use my 'bin' allocator, I get a hang. Tracked it down to this line of code:
kprintln!(" bb ");
let a = 0 as *mut u8;
kprintln!(" bbb {:?}",a);
kprintln!(" bbb {:?}",(*block).next);
(*block).next = a;which prints
bb
bbb 0x0
bbb'block' here is a local struct representing a bin block. My first hang was creating a 'std::ptr::null_mut::<u8>', so I replaced that with casting zero as an experiment. No panic. I may need to install aarch64 exception handlers to see if I'm triggering an invalid op or something.
Pretty basic: my "bin allocator" was creating blocks based on minimum required alloc size, aligned as required, and then padding it with room for my header. That passed all the "alloc" unit tests just fine. However, on the Pi it keels over quickly because I can have cases where my pointers are not 8 byte aligned. First deref of an unaligned pointer will kick in an aarch64 unaligned fault, kicking us to the nonexistant fault handler. Death.
Easy enough to fix! Onward.
For people working on Filesystem stuff:
Anyplace where you create a struct (MBR, EBPB, etc) by casting it from an array of bytes, realize that those bytes can/will have any alignment. Example: bytes_per_sector in EBPB is a u16 with offset of 11 bytes from beginning of struct. Giving that struct member type u16 seemed to work fine on x86 (passed all tests), but fails hard on aarch64 (kprintf!("{}",ebpb.bytes_per_sector hangs, likely heading off to the ARM abort handler with an alignment fault).
You could have a "raw" version of the struct, and copy over to a 'safe' version (no #reprc) (similar to how ATAGs was handled), but that is kind of a pain, and will fail the unit tests (which check the exact size of the EBPB/MBR structs). What I did: everything in those structs is either a single u8 or an array of u8s. No alignment required. All fields are 'private', and any field that is used outside has a 'getter' function that does (a[0] as u16 + (a[1] as u16)<<8) (or u32 equivalent) to turn the data into the expected type. Works, relatively simple, only needs to be implemented for the fields you actually use.
You should be watching for this with any struct that has #[repr(C, packed)].
One thing that really helped me, I created a new version of 'transmit_with_progress' called 'transmit_with_debug'. It took an extra argument: a function that took a fn(&str, int), but otherwise it looked like the progressfn. I could then send debug messages with a number back to the ttywrite program to print out. On the Pi I did the same thing with receive_with_debug(), and I had 8 LEDs wired up on the Pi so I could send byte values and byte messages out on the pi side. Enough to let me know how far I was getting in the code before it died.
the basic xxx_with_progress() function just called the xxx_with_debug() function, using a noop debug function.
At least for me, if I don't have some equivalent to 'printf debugging' deep in the code, I'm lost.