When a Multiboot 2-compliant boot loader like GRUB invokes a 32-bit x86 operating system, it provides a magic number in the EAX register (
0x36d76289) and the physical address of a boot information table in EBX.
These values will eventually be useful to Georgix, so the first thing its bootstrap code does is push them onto the stack (in reverse order, so they can be popped off in order):
# Set up the stack.
movl $boot.stack.high, %esp
# The bootloader provides:
# * A magic number in EAX
# * The physical address of the boot information record in EBX
# Save these values on the stack to pass to the Rust entrypoint later.
After a bit of setup, the bootstrap code jumps to the Rust entrypoint, passing the magic number and boot information table pointer as arguments. Per the C calling convention, the first two arguments are passed in the EDI and ESI registers:
ljmp $boot.global_descriptor_table.code, $main
The bootstrap code didn’t always work this way. Until recently, it saved the magic number and boot information table pointer in EDI and ESI rather than on the stack. I wanted to use the stack from the start—to clarify that these values aren’t needed for setup, and to free up EDI and ESI for other purposes—but ran into some trouble.