01.Loading an External Program

Where do we get the external program from? Somehow we need to load the code we want to execute into memory. More feature-complete operating systems usually have drivers and file systems that enable them to load the software from a CD-ROM drive, a hard disk or other persistent media.

GRUB Modules

GRUB can load arbitrary files into memory from the ISO image, and these files are usually referred to as modules. To make GRUB load a module, edit the file iso/boot/grub/menu.lst and add the following line at the end of the file:

module /modules/program
mkdir -p iso/modules
; in file `loader.s`

MAGIC_NUMBER equ 0x1BADB002 ; define the magic number constant
ALIGN_MODULES equ 0x00000001 ; tell GRUB to align modules

; calculate the checksum (all options + checksum should equal 0)

section .text: ; start of the text (code) section
align 4 ; the code must be 4 byte aligned
dd MAGIC_NUMBER ; write the magic number
dd ALIGN_MODULES ; write the align modules instruction
dd CHECKSUM ; write the checksum

02.Executing a Program

A Very Simple Program

A program written at this stage can only perform a few actions. Therefore, a very short program that writes a value to a register suffices as a test program. Halting Bochs after a while and then check that register contains the correct number by looking in the Bochs log will verify that the program has run. This is an example of such a short program:

; set eax to some distinguishable number, to read from the log afterwards
mov eax, 0xDEADBEEF

; enter infinite loop, nothing more to do
; $ means "beginning of line", ie. the same instruction
jmp $


Since our kernel cannot parse advanced executable formats we need to compile the code into a flat binary. NASM can do this with the flag -f:

nasm -f bin program.s -o program

Finding the Program in Memory

Before jumping to the program we must find where it resides in memory. Assuming that the contents of ebx is passed as an argument to kmain, we can do this entirely from C.

int kmain(/* additional arguments */ unsigned int ebx)
multiboot_info_t *mbinfo = (multiboot_info_t *) ebx;
unsigned int address_of_module = mbinfo->mods_addr;

Jumping to the Code

The only thing left to do is to jump to the code loaded by GRUB. Since it is easier to parse the multiboot structure in C than assembly code, calling the code from C is more convenient (it can of course be done with jmp or call in assembly code as well). The C code could look like this:

    typedef void (*call_module_t)(void);
/* ... */
call_module_t start_program = (call_module_t) address_of_module;
/* we'll never get here, unless the module code returns */



Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store