Introduction
This is what happens when a PC boots:
- The BIOS is executed
- The BIOS searches for a bootstrap
- When a bootstrap is found, it is loaded to memory address 07C00h
- The DL register is set to the drive number for the bootdrive.
- The Bootstrap, your code, is executed
A valid bootstrap MUST:
- .. be compiled into a plain binary file (COM)
- .. be located at the first sector on a disk.
- .. have the size 512 bytes (1 sector is 512 bytes)
- .. contain the word 0AA55h in the last byte
The Tools I use
These are the tools I use:
NASM - Assembler.
Helppc - Info about the interrupts.
Partcopy - To copy the bootstrap to the disk
These are all free of course.
Just hang...man!
This is a small example bootstrap. It just hangs:
hang:
jmp hang
times 512-($-$$)-2 db 0
dw 0AA55h
The "times.." line tells nasm that we want the file to be 512 bytes.
The last two bytes in all bootstraps must contain 0AA55h, that is why I wrote that last line.
Compile with:
nasm hang.asm -f bin -o hang.bin
If you want to test the bootstrap, you must transfer it to a disk. You will have to format the disk before you can use it again, so make sure there are no important information on it.
Transfer the file with:
partcopy hang.bin 0 200 -f0
Reboot the computer with the disk inserted, the computer hangs!
Hello Cyberspace!
There were much joy when the computer hanged, but I am not content with this.
Now I will extend the bootstrap slightly. The bootstrap will print a message, and then hang.
The following code shows my improved bootstrap:
org 0x7C00 ; This is where BIOS put me
; ---------------------------------------------------------
; Main program
; ---------------------------------------------------------
mov si, msg ; Print message
call putstr
hang: ; Hang!
jmp hang
; ---------------------------------------------------------
; Functions and variables used by our bootstrap
; ----------------------------------------------------------
msg db 'Hello Cyberspace!', 0
; Print a 0-terminated string on the screen
putstr:
lodsb ; AL = [DS:SI]
or al,al ; Set zero flag if al=0
jz putstrd ; Jump to putstrd if zero flag is set
mov ah,0x0E ; Video function 0Eh
mov bx,0x0007 ; Color
int 0x10
jmp putstr ; Load characters until AL=0
putstrd:
retn
times 512-($-$$)-2 db 0
dw 0AA55h
The code is pretty easy, and I don't think I have to explain it.
Compile and transfer the bootstrap with:
nasm hello.asm -f bin -o hello.bin
partcopy hello.bin 0 200 -f0
A real real mode bootloader
The boot sector above was pretty cool, but it wasn't too useful. You'll
want to create a boot sector that loads some program off the disk and
jumps to it. The boot sector below is a real mode boot sector that
loads stuff off the disk and jumps (the program is loaded to memory address 0x10000):
org 0x7C00 ; This is where BIOS put me
; ---------------------------------------------------------
; Main program
; ---------------------------------------------------------
start:
; Setup the stack.
; We can't allow interrupts while we setup the stack
cli ; Disable interrupts
mov ax, 0x9000 ; Put stack at 0x90000
mov ss, ax ; SS = 9000 and
mov sp, 0 ; SP = 0000 => Stack = 90000
sti ; Enable interrupts
; Remember the bootdrive information provided in DL
mov [bootdrv], dl
; Load a program
call load
; Jump to the loaded program
mov ax, 0x1000
mov es, ax
mov ds, ax
push ax
mov ax, 0
push ax
retf
; ---------------------------------------------------------
; Functions and variables used by our bootstrap
; ----------------------------------------------------------
bootdrv db 0 ; This variable will contain the bootdrive id
; Load a program from the bootdrive
load:
; Reset the diskdrive (Interrupt 13h, 0)
push ds ; Store DS
mov ax, 0 ; Select function (Reset Disk)
mov dl, [bootdrv] ; Drive to reset
int 13h ; Reset it!
pop ds ; Restore DS
jc loadfile ; Failed -> Try again
load1:
mov ax,0x1000 ; ES:BX = 10000
mov es,ax
mov bx, 0
; Read disksectors (Interrupt 13h, 2)
mov ah, 2 ; Select function (Read disk sectors)
mov al, 5 ; read 5 sectors
mov cx, 2 ; Cylinder=0, sector=2
mov dx, 0 ; head=0, drive=0
int 13h ; ES:BX = data from disk
jc load1 ; failed -> Try again
retn
times 512-($-$$)-2 db 0
dw 0AA55h
Now that our bootstrap loads and executes something, we _should_ write some code to load:
mov ax, 1000h ; Update segment registers
mov ds, ax
mov es, ax
mov si, msg ; Print a message
call putstr
hang: ; Just hang
jmp hang
; Print a 0-terminated string (SI=pointer to string)
putstr:
lodsb
or al,al
jz short putstrd
mov ah,0x0E
mov bx,0x0007
int 0x10
jmp putstr
putstrd:
retn
msg db 'JIPPIKAYE!',13,10,0
Compile and transfer with:
nasm bootload.asm -f bin -o bootload.bin
partcopy bootload.bin 0 200 -f0
nasm second.asm -f bin -o second.bin
partcopy second.bin 0 200 -f0 200
Done
That's it. I would really like some comments.