Skip to content

Booting

Booting

Steps:
1. POST (Power On Self Test)
2. BIOS Firmware
- Initialize CPU, Memory, etc.
- Check for hardware errors
- Search for boot loader
3. Boot loader
- In the MBR (Master Boot Record)/Boot Sector. The first 512 bytes of the device. The last bytes of this sector must end in 55AA.
- Transfer from 16 bit to real mode

Boot loader

References:
- Common functions

Custom Boot loader:

[BITS 16] ; Start in 16 bit mode
[ORG 0x7c00] ; Start Code at this address

CODE_OFFSET equ 0x8
DATA_OFFSET equ 0x10

start:
	cli ; Clear Interrupts
	mov ax, 0x00
	mov ds, ax
	mov es, ax
	mov ss, ax
	mov sp, 0x7c00 ; Start the stack at 0x7c00 going up to 0x0000
	sti ; Enable Interrupts
	jmp load_PM

	mov si, message ; Move message address into the SI register
print:

	lodsb ; Deference address at SI and load into the AL register. Then increment the SI register
	cmp al, 0 ; Check if reached the end of the string
	je done
	mov ah, 0x0E ; Set the "display char" argument
	int 0x10 ; Send the common/video Interrupt command
	jmp print ; Continue the print loop


done:
	cli ; Clear Interrupts
	hlt ; Stop the CPU

load_PM:
	cli ; Clear Interrupts
	lgdt[gdt_descriptor] ; Load the GDT from the descriptor
	mov eax, cr0   ; Clear the CR0 register 
	or al, 1    ; Set the Protected Mode enable
	mov cr0, eax
	jmp CODE_OFFSET:pmode_main


message:
db "Hello World", 0


; GDT Implementation https://wiki.osdev.org/Global_Descriptor_Table
gdt_start:
	db 0x00000000 ; NULL entry
	db 0x00000000 ; GDT Entry 1

	; Code Segment Descriptor https://wiki.osdev.org/Global_Descriptor_Table#Segment_Descriptor
	dw 0xFFFF    ; Limit 
	dw 0x0000    ; Base
	db 0x00      ; Base
	db 10011010b ; Access Byte: Present Bit, Code Segment Bit, Executable Bit, Read Bit 
	db 11001111b ; Flags and Limit Byte: Granularity Flag, 4KB Blocks, 32bit segment
	db 0x00      ; Base


	; Data Segment Descriptor https://wiki.osdev.org/Global_Descriptor_Table#Segment_Descriptor
	dw 0xFFFF    ; Limit 
	dw 0x0000    ; Base
	db 0x00      ; Base
	db 10010010b ; Access Byte: Present Bit, Code Segment Bit, Read Bit 
	db 11001111b ; Flags and Limit Byte: Granularity Flag, 4KB Blocks, 32bit segment
	db 0x00      ; Base

gdt_end:
gdt_descriptor:
	dw gdt_end - gdt_start - 1; Size of GDT
	dd gdt_start ; Start of GDT Address

[BITS 32]
pmode_main:
	mov ax, DATA_OFFSET ; Setup 32 bit registers
	mov ds, ax
	mov es, ax
	mov fs, ax
	mov gs, ax 
	mov ebp, 0x9C00 ; Setup stack 
	mov esp, ebp

	in al, 0x92 ;
	or al, 2 ; 
	out 0x92, al ;

times 510 - ($ -$$) db 0 ; Pad the data so that we can have the full 512 block 


db 0x55 ; Ending data
db 0xAA

Build & Run:

>>> nasm -f bin boot.asm -o boot.bin
>>> hexyl boot.bin
┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐
│00000000│ fa b8 00 00 8e d8 8e c0  8e d0 bc 00 7c fb be 1e │××⋄⋄××××┊×××⋄|×ו│
│00000010│ 7c ac 3c 00 74 06 b4 0e  cd 10 eb f5 fa f4 48 65 |×<⋄t•×•┊ו××××He│
│00000020│ 6c 6c 6f 20 57 6f 72 6c  64 00 00 00 00 00 00 00 │llo Worl┊d⋄⋄⋄⋄⋄⋄⋄│
│00000030│ 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 │⋄⋄⋄⋄⋄⋄⋄⋄┊⋄⋄⋄⋄⋄⋄⋄⋄│
│*                                                                         │
│000001f0│ 00 00 00 00 00 00 00 00  00 00 00 00 00 00 55 aa │⋄⋄⋄⋄⋄⋄⋄⋄┊⋄⋄⋄⋄⋄⋄U×│
└────────┴─────────────────────────┴─────────────────────────┴────────┴────────┘
>>> qemu-system-x86_64 -hda ./boot.bin

Linux

Booting modern Intel CPUs
https://binarydebt.wordpress.com/2018/10/06/how-does-an-x86-processor-boot/
ArchLinux Boot process
Linux Insides Booting

  1. Real Mode
  2. Start executing commands from 8086 reset vector
    3.

Linux Bootloaders:
- BIOS
- MBR
- GRUB
- Kernel
- INIT/Systemd

Mac Booting

Booting on the Apple T2
Mac Secure Boot
AsahiLinux Boot Process
- https://github.com/AsahiLinux/docs/wiki/SW%3ABoot
- https://support.apple.com/guide/security/boot-process-secac71d5623/web