User:Glauxosdev/Tutorials/Bootloader: Difference between revisions
m (Bootloader != Bootsector) |
m (Bot: Replace deprecated source tag with syntaxhighlight) |
||
Line 5: | Line 5: | ||
A bootloader is a [[Real Mode|real mode]] program that resides in the first sector of the disk; let it be on a hard disk or on a USB flash disk. The BIOS loads only the bootsector, so to start we have only 512 bytes, unless we load more sectors ourselves. The bootsector is loaded at address 0x00007C00, so using [[Real Mode|real mode]] [[Segmentation|segmentation]] the address is translated to 0x0000:0x7C00 or 0x07C0:0x0000. So for a start we have this code: |
A bootloader is a [[Real Mode|real mode]] program that resides in the first sector of the disk; let it be on a hard disk or on a USB flash disk. The BIOS loads only the bootsector, so to start we have only 512 bytes, unless we load more sectors ourselves. The bootsector is loaded at address 0x00007C00, so using [[Real Mode|real mode]] [[Segmentation|segmentation]] the address is translated to 0x0000:0x7C00 or 0x07C0:0x0000. So for a start we have this code: |
||
< |
<syntaxhighlight lang="asm"> |
||
bits 16 ; tell the assembler we want 16 bit code |
bits 16 ; tell the assembler we want 16 bit code |
||
org 0x7C00 ; tell the assembler to add 0x7C00 offset to labels, segments will be zeroed |
org 0x7C00 ; tell the assembler to add 0x7C00 offset to labels, segments will be zeroed |
||
Line 30: | Line 30: | ||
db 0x55 |
db 0x55 |
||
db 0xAA |
db 0xAA |
||
</syntaxhighlight> |
|||
</source> |
|||
Save this file as "boot.asm" and assemble it with nasm: |
Save this file as "boot.asm" and assemble it with nasm: |
||
< |
<syntaxhighlight lang="bash"> |
||
nasm -f bin -o boot.bin boot.asm |
nasm -f bin -o boot.bin boot.asm |
||
</syntaxhighlight> |
|||
</source> |
|||
Then copy the resulting binary to the first sector of a USB flash disk, where xxx indicates the block device corresponding to the USB flash disk. |
Then copy the resulting binary to the first sector of a USB flash disk, where xxx indicates the block device corresponding to the USB flash disk. |
||
< |
<syntaxhighlight lang="bash"> |
||
sudo dd if=boot.bin of=/dev/xxx |
sudo dd if=boot.bin of=/dev/xxx |
||
</syntaxhighlight> |
|||
</source> |
|||
'''Note:''' Don't try to copy the binary to the hard disk, as it will become unbootable. |
'''Note:''' Don't try to copy the binary to the hard disk, as it will become unbootable. |
||
Line 52: | Line 52: | ||
Let's add some more code so we can load a sector: |
Let's add some more code so we can load a sector: |
||
< |
<syntaxhighlight lang="asm"> |
||
bits 16 ; tell the assembler we want 16 bit code |
bits 16 ; tell the assembler we want 16 bit code |
||
org 0x7C00 ; tell the assembler to add 0x7C00 offset to labels, segments will be zeroed |
org 0x7C00 ; tell the assembler to add 0x7C00 offset to labels, segments will be zeroed |
||
Line 139: | Line 139: | ||
times 512 - ($ - next_sector) db 0 |
times 512 - ($ - next_sector) db 0 |
||
</syntaxhighlight> |
|||
</source> |
|||
If you assemble this file and boot a USB flash disk with the resulting binary, you will see a letter "A" at the top-left corner of the screen, except if your computer is such old so it doesn't support [[BIOS]] [[LBA]] extensions. |
If you assemble this file and boot a USB flash disk with the resulting binary, you will see a letter "A" at the top-left corner of the screen, except if your computer is such old so it doesn't support [[BIOS]] [[LBA]] extensions. |
Latest revision as of 06:28, 9 June 2024
In this tutorial we will learn how to create a bootloader that loads some sectors and executes them.
Take 0x01
A bootloader is a real mode program that resides in the first sector of the disk; let it be on a hard disk or on a USB flash disk. The BIOS loads only the bootsector, so to start we have only 512 bytes, unless we load more sectors ourselves. The bootsector is loaded at address 0x00007C00, so using real mode segmentation the address is translated to 0x0000:0x7C00 or 0x07C0:0x0000. So for a start we have this code:
bits 16 ; tell the assembler we want 16 bit code
org 0x7C00 ; tell the assembler to add 0x7C00 offset to labels, segments will be zeroed
start:
.setup_segments:
mov ax, 0 ; pass 0 value to ax, as segments can't be set with immediate values
mov ds, ax ; ds = ax = 0
mov es, ax ; es = ax = 0
mov fs, ax ; fs = ax = 0
mov gs, ax ; gs = ax = 0
mov ss, ax ; ss = ax = 0
.setup_stack:
mov sp, 0x7C00 ; stack grows downwards from the start of the bootloader
.hang:
jmp $ ; jump infinitely to the same instruction
end_boot_sector:
times 510 - ($ - $$) db 0
db 0x55
db 0xAA
Save this file as "boot.asm" and assemble it with nasm:
nasm -f bin -o boot.bin boot.asm
Then copy the resulting binary to the first sector of a USB flash disk, where xxx indicates the block device corresponding to the USB flash disk.
sudo dd if=boot.bin of=/dev/xxx
Note: Don't try to copy the binary to the hard disk, as it will become unbootable.
Reboot your computer and you will see a blinking cursor. Congratulations, you have made a bootable application. But it doesn't much. So, let's continue.
Take 0x02
Let's add some more code so we can load a sector:
bits 16 ; tell the assembler we want 16 bit code
org 0x7C00 ; tell the assembler to add 0x7C00 offset to labels, segments will be zeroed
start:
.setup_segments:
mov ax, 0 ; pass 0 value to ax, as segments can't be set with immediate values
mov ds, ax ; ds = ax = 0
mov es, ax ; es = ax = 0
mov fs, ax ; fs = ax = 0
mov gs, ax ; gs = ax = 0
mov ss, ax ; ss = ax = 0
.setup_stack:
mov sp, 0x7C00 ; stack grows downwards from the start of the bootloader
.save_boot_device_number:
mov byte [bootdev], dl ; boot device number is passed in dl by BIOS
.check_lba_extensions:
mov ah, 0x41
mov bx, 0x55AA
int 0x13
jc .hang ; carry flag is set if bios lba extensions don't exist
cmp bx, 0xAA55 ; bx = 0xAA55 if bios lba extensions exist
jne .hang
.load_next_sector:
mov eax, 1 ; load sector index 1
mov bx, next_sector ; at address indicated by next_sector label
mov cx, 1 ; load only 1 sector
call read_sectors ; call the routine to load sectors
jmp 0x7E00 ; jump to newly loaded sector
.hang:
jmp $ ; jump infinitely to the same instruction
read_sectors:
.save_registers:
pusha ; registers are preserved
.build_disk_address_packet:
mov si, 0x8000 ; disk address packet is at 0x00008000 (ds = 0)
mov word [ds:si], 0x10 ; size of packet is 16 bytes
mov word [ds:si + 2], cx ; sector count is in cx
mov word [ds:si + 4], bx ; memory offset is in bx
mov word [ds:si + 6], fs ; memory segment is in fs
mov dword [ds:si + 8], eax ; low starting lba sector is in eax
mov dword [ds:si + 12], 0
.invoke_disk_int:
mov ah, 0x42 ; bios extended read is used here
mov dl, byte [bootdev] ; boot device will be read
int 0x13 ; bios disk interrupt is invoked
.return:
popa ; registers are restored
ret ; return
variables:
bootdev db 0
end_boot_sector:
times 510 - ($ - $$) db 0
db 0x55
db 0xAA
; SECTOR 0x01 START ===================================================================
next_sector:
.print_letter_A:
mov bx, 0xB800 ; video memory resides at 0x000B8000
mov es, bx
mov bx, 0 ; print letter "A" at the first row and column
mov byte [es:bx], 65
.hang:
jmp $ ; jump infinitely to the same instruction
end_second_sector:
times 512 - ($ - next_sector) db 0
If you assemble this file and boot a USB flash disk with the resulting binary, you will see a letter "A" at the top-left corner of the screen, except if your computer is such old so it doesn't support BIOS LBA extensions.