Hero Alom is the greatest super hero of the world.
Assembly Level Language is intimidating. This implementation and development guide is primarily for those who have some experience with programming in general. However, I don't expect any expertise. Heck, I am also learning. This is the associative learning model that I am trying to follow here (the term is all mine, I guess).
In any case, this project - Hero Alom OS has a simple goal. To help you understand how Assembly Level Languages can be used to create bootloaders. And then, eventually, full fledged operating systems. Though, in all fairness, a bootloader is also an OS of sorts. But you get my drift.
I will go slow here. Primarily because I am learning myself.
And why did I choose this name?
Well, you need to google this guy - Hero Alom and research a bit about him. If he is able to reach stardom with his 'talent' so can you. Great things can be done with hard work, perseverence and some luck. Don't get me wrong. I am not trying to make fun of this super hero here. My point is - be optimistic. There is a chance that good things will happen.
org 0x7c00 ; Set the origin of the code to 0x7c00 (the location where boot sector is loaded)
boot:
mov si, hello ; Load the memory location of the string "hello" into SI register
mov ah, 0x0e ; Set AH register to 0x0e (write character in tty mode)
.loop:
lodsb ; Load byte at address pointed by SI into AL and increment SI
or al, al ; Logical OR operation of AL with itself (checks if AL is zero)
jz halt ; If AL is zero (end of string), jump to halt
int 0x10 ; Call BIOS interrupt 0x10 (video services) to print character in AL
jmp .loop ; Jump back to loop to process the next character
halt:
cli ; Clear interrupt flag to disable interrupts
hlt ; Halt CPU execution
hello: db "Hello world, this is the lighter version of a 16 bit HAOS", 0 ; Define a null-terminated string "hello"
times 510 - ($-$$) db 0 ; Fill the remaining bytes in the boot sector with zeros
dw 0xaa55 ; Boot signature to mark the sector as bootable
The code starts at the label boot.
- It sets up the SI register to point to the memory location of the string "Hello world...".
- Then, it enters a loop where it loads a byte from the memory location pointed by SI into the AL register using lodsb, checks if it's null-terminated (end of the string), prints the character using BIOS interrupt 0x10 if it's not null, and repeats until it reaches the end of the string.
- After printing the string, it halts the CPU by clearing interrupts with cli and executing hlt.
- The hello label defines the string "Hello world...".
- Finally, the boot sector is padded with zeros until byte 510, and the boot signature 0xaa55 is added to mark it as bootable.
This code effectively prints "Hello world, this is the lighter version of a 16 bit HAOS" to the screen and then halts the CPU.
Then you call the shell script - bootlite.sh
#/bin/sh
nasm -f bin -o bootlite.bin bootlite.asm
dd status=noxfer conv=notrunc if=bootlite.bin of=bootlite.flp
qemu-system-i386 -fda bootlite.flp
BITS 16
start:
mov ax, 07C0h ; Set up 4K stack space after this bootloader
add ax, 288 ; (4096 + 512) / 16 bytes per paragraph
mov ss, ax
mov sp, 4096
mov ax, 07C0h ; Set data segment to where we're loaded
mov ds, ax
mov si, text_string ; Put string position into SI
call print_string ; Call our string-printing routine
jmp $ ; Jump here - infinite loop!
text_string db 'Welcome to Hero Alom Operating System', 0
print_string: ; Routine: output string in SI to screen
mov ah, 0Eh ; int 10h 'print char' function
.repeat:
lodsb ; Get character from string
cmp al, 0
je .done ; If char is zero, end of string
int 10h ; Otherwise, print it
jmp .repeat
.done:
ret
times 510-($-$$) db 0 ; Pad remainder of boot sector with 0s
dw 0xAA55 ; The standard PC boot signature
- The code begins at the start label.
- It sets up a 4K stack space after the bootloader and initializes the stack pointer (SP) accordingly.
- Then it sets the data segment (DS) to where the bootloader is loaded.
- It loads the address of the string "Welcome to Hero Alom Operating System" into the SI register and calls the print_string routine.
- The print_string routine prints the string character by character using BIOS interrupt 0x10.
- It ends when a null terminator is encountered in the string.
- Finally, the boot sector is padded with zeros, and the boot signature 0xAA55 is added.
- This bootloader prints the message "Welcome to Hero Alom Operating System" and then enters an infinite loop.
org 0x7c00
boot:
mov ax, 0x2401 ; Function 0x24 of int 0x15 returns the amount of extended memory in kilobytes
int 0x15 ; Call BIOS interrupt 0x15
mov ax, 0x3 ; Function 0x03 of int 0x10 sets video mode (80x25 text mode)
int 0x10 ; Call BIOS interrupt 0x10
cli ; Clear interrupts
lgdt [gdt_pointer] ; Load Global Descriptor Table (GDT) pointer
mov eax, cr0 ; Move the value of Control Register 0 into EAX
or eax, 0x1 ; Set the first bit of CR0 to enable protected mode
mov cr0, eax ; Move the modified value back into CR0
jmp CODE_SEG:boot2 ; Jump to code segment (in protected mode)
gdt_start:
dq 0x0 ; Null descriptor
gdt_code:
dw 0xFFFF ; Limit (0 to 0xFFFF)
dw 0x0 ; Base (0)
db 0x0 ; Base (0)
db 10011010b ; Access byte
db 11001111b ; Granularity
db 0x0 ; Base (0)
gdt_data:
dw 0xFFFF ; Limit (0 to 0xFFFF)
dw 0x0 ; Base (0)
db 0x0 ; Base (0)
db 10010010b ; Access byte
db 11001111b ; Granularity
db 0x0 ; Base (0)
gdt_end:
gdt_pointer:
dw gdt_end - gdt_start ; GDT size
dd gdt_start ; GDT base address
CODE_SEG equ gdt_code - gdt_start
DATA_SEG equ gdt_data - gdt_start
bits 32
boot2:
mov ax, DATA_SEG ; Load data segment with data descriptor
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax ; Load stack segment with data descriptor
mov esi, hello ; Set ESI to point to the hello string
mov ebx, 0xb8000 ; Set EBX to the video memory address
.loop:
lodsb ; Load byte from SI into AL and increment SI
or al, al ; Check if AL is zero
jz halt ; If zero, jump to halt
or eax, 0x0100 ; Set attribute byte (color) to white on black
mov word [ebx], ax ; Store character and attribute at video memory address
add ebx, 2 ; Move to the next character cell in video memory
jmp .loop ; Repeat loop
halt:
cli ; Disable interrupts
hlt ; Halt execution
hello: db "Hello world!", 0 ; Define the hello string
times 510 - ($-$$) db 0 ; Fill the rest of the sector with zeros
dw 0xaa55 ; Boot signature
- The bootloader starts in 16-bit mode.
- It performs some basic initialization, such as setting up the video mode, clearing interrupts, and loading the GDT (Global Descriptor Table).
- Then it switches to 32-bit protected mode by setting the first bit of the CR0 register.
- The bootloader defines a GDT with null, code, and data descriptors.
- It jumps to the code segment in protected mode and continues execution from there.
- In protected mode, it sets up the data segment registers and initializes a loop to print "Hello world!" to the screen.
- After printing the message, it halts the CPU.
- This bootloader switches the CPU to protected mode and prints "Hello world!" to the screen using the BIOS video services.