Thursday, January 30, 2025

Let us create our first UEFI boot loader in assembly

Raam Raam ji (greeting with god's name :) ). Hello world. This is our first blog post in the operating system development series.

Today, we will try to address this fundamental question - "How does an OS (Operating System) boot? What happens first?"

Let's get our hands dirty. Let us learn by doing. So it is the "firmware", the UEFI firmware on modern systems that is responsible for loading and calling your OS boot loader's entry point.

If you don't know what is UEFI, it stands for "Unified Extensible Firmware Interface". You don't need to know what is it. Just know that it is both different and newer than BIOS (Basic Input/Output System). It's a firmware that loads your OS's boot loader into RAM and calls its entry point. Simple!

Now what is a boot loader? It is a boot program that performs some initialization tasks, loads the kernel file into memory, and provides the kernel with the information it needs to work correctly.

So the first system program that runs after booting by the firmware is your boot loader which in turns loads and jumps to your kernel's entry point. A kernel is the core and central component of an OS. The userspace program like your shell runs later.

1. Enough theory! Now let's create a simple boot loader that does nothing but goes into an infinite loop and you will test it on your real machine:


format pe64 efi

entry start

section '.text' code executable readable

start:
	; infinite loop
	jmp $

Open your favorite text editor (I like `vim`) and paste the above code. Save it as boot.asm and then on a 64-bit Ubuntu like machine, install fasm assembler with apt install fasm. Then run the following command:

fasm boot.asm BOOTx64.EFI

On successful passes, you will get the output file `BOOTx64.EFI`.


2. Now you need to format a pen drive in order to make it bootable and then we will copy this boot loader program into it.

Open `Disks` program on your Ubuntu-like machine and select your pen drive from the leftmost column. Now click on Drive Options (upper three dots) in the right and then on Format Disk.... Now select the options as below:



click Format.... Now click on the plus button (+) below the Volumes label, click Next, choose FAT and then finally click Create. Now mount this partition and create two directories viz. EFI/BOOT on it. Now copy the above boot loader executable to <mount point>/EFI/BOOT/BOOTx64.EFI .

Reboot.

Now when your machine powers on, press the key to select the boot options (just google for it), select your USB thumb drive, and voila... we got a steady blank screen because of the infinite loop!

The code that you had just typed and assembled is now working!

3. Now let us understand the above code a bit:

`format pe64 efi` tells your assembler that it is going to be a 64-bit Portable Executable output format, with UEFI as the target subsystem.

`entry start` tells that the entry point for this loader application is the `start` label.

`section '.text' code executable readable` tells the assembler about the text section where the instructions of the loader program goes and this section is both executable and readable by the processor.

`start:` is our start label (a label in assembly is a mnemonic for an address). It can be any name.

`; infinite loop` is a comment telling that the following line will execute an infinite loop.

Finally, `jmp $` tells the program control to jump to the present address (which is this line itself) and so it goes into an infinite loop.

No comments:

Post a Comment

Let us print text from the UEFI boot loader in assembly

1. Raam Raam ji (greeting with god's name :) ). This is our second blog post in the operating system development series. If yo...