George Claghorn

Discovering the D/B flag

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):

_start:
    # 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.
    pushl %ebx
    pushl %eax

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:

popl %edi
popl %esi
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.

Keep reading…

Switching from the legacy 8259 PIC to the modern APIC

The Writing an OS in Rust series covers enabling periodic timer interrupts with the 8259 PIC. As it explains, the 8259 is superseded by the APIC in modern x86-64 processors:

The Intel 8259 is a programmable interrupt controller (PIC) introduced in 1976. It has long been replaced by the newer APIC, but its interface is still supported on current systems for backwards compatibility reasons. The 8259 PIC is significantly easier to set up than the APIC, so we will use it to introduce ourselves to interrupts before we switch to the APIC in a later post.

Once I got timer interrupts working with the 8259 per the tutorial, I read up on using the APIC—particularly Xv6’s LAPIC initialization code—and decided to make the switch right away.

Keep reading…

Writing an operating system

If you follow me on Twitter, you may remember that I’m writing an x86-64 operating system in Rust to learn about operating systems. I learn best by doing and by writing. I’m sharing my work on GitHub. I’ll use this blog to share my writing.

So far, Georgix—that’s my operating system’s name, because I’m not creative enough to come up with something less obnoxious—boots, configures periodic timer interrupts, and handles them by printing dots to the screen. That’s not much, of course, but I’ve already learned a ton and I’m looking forward to learning more. Next up is memory allocation and paging.

Keep reading…