Skip to content

Instantly share code, notes, and snippets.

@NSG650
Created January 20, 2023 10:52
Show Gist options
  • Save NSG650/1db6230997956bffbb03ade9377135f1 to your computer and use it in GitHub Desktop.
Save NSG650/1db6230997956bffbb03ade9377135f1 to your computer and use it in GitHub Desktop.
; this bootloader only loads and runs the kernel
; this does not load an initrd so the kernel will kernel panic stating it failed to mount the rootfs
; build instructions
; nasm -f bin slkboot.asm
; running instructions
; cat slkboot kernel_file > fun
; qemu-system-x86_64 -hda fun
[BITS 16]
ORG 0x7c00
jmp start
nop
; Fast A20 Enable
a20_enable:
in al, 0x92
or al, 0x0e
out 0x92, al
ret
highaddr dd 0x100000
high_move:
mov esi, 0x20000
mov edi, [highaddr]
shl eax, 9
.loop:
mov edx, [ds:esi]
mov [ds:edi], edx
add edi, 4
add esi, 4
sub eax, 4
jnz high_move.loop
mov [highaddr], edi
ret
; eax is the sector that need to be loaded in high addr
high_load:
shr eax, 9
inc eax
mov ecx, 0x7f
xor edx, edx
div ecx
push dx
.loop:
push ax
mov ax, 0x7f
mov bx, 0x2000
xor dx, dx
call disk_read
call high_move
pop ax
dec ax
jnz high_load.loop
pop ax
test ax, ax
jz high_load.done
mov bx, 0x2000
xor dx, dx
call disk_read
call high_move
.done:
ret
; extended disk read
disk_read:
push ax
mov word [dap.count], ax
mov word [dap.offset], dx
mov word [dap.segment], bx
mov ah, 0x42
mov dl, [bootdrive]
lea si, [dap]
int 0x13
; add newly read sectors
mov edx, [dap.lba]
movzx eax, word [dap.count]
add edx, eax
mov [dap.lba], edx
pop ax
ret
unreal_mode:
.protected_mode:
lgdt [gdt_desc]
mov eax, cr0
or al, 1
mov cr0, eax
mov bx, 0x8
mov ds, bx
mov es, bx
.enter_unreal:
mov eax, cr0
and al, 0xFE
mov cr0, eax
xor ax, ax ; new limits were cached, restore segment values
mov ds, ax
mov es, ax
ret
start:
mov [bootdrive], dl
cli
cld
xor ax, ax
mov ds, ax
mov ss, ax
mov sp, 0xe000
mov es, ax
; This segment helps us jump in unreal mode
; This is so we can still be in real mode but have 32 bit addressing
; Useful for loading the kernel at a high address
call a20_enable
call unreal_mode
; Command line parameters to pass to the kernel
lea si, [cmdline]
mov cx, cmdline_size
mov di, 0xff00
rep movsb ; we are literally doing a memcpy((char *)0xff00, cmdline, cmdline_size); here
; we are loading the kernel at 0x7e00
mov bx, 0x7e0
mov es, bx
xor dx, dx
mov ax, 1
call disk_read
mov al, [es:0x1f1] ; setup_sects
mov dx, 0x200 ; load in memory after 1 sectors
call disk_read
mov bx, [es:0x20e]
cmp bx, 0
jz load_params
load_params:
; The real mode kernel header
; Fill out the only ones needed
mov byte [es:0x210], 0xff ; type_of_loader
mov byte [es:0x211], 0x80 ; loadflags - CAN_USE_HEAP
mov word [es:0x224], 0xde00 ; heap_end_ptr
mov dword [es:0x228], 0xff00 ; cmd_line_ptr
mov eax, [es:0x1f4] ; syssize
shl eax, 4
call high_load
; **** RUNNING THE KERNEL
; The kernel is started by jumping to the kernel entry point, which is
; located at *segment* offset 0x20 from the start of the real mode
; kernel. This means that if you loaded your real-mode kernel code at
; 0x90000, the kernel entry point is 9020:0000.
; from Documentation/x86/boot.txt
; as we have loaded the kernel at 0x7e00 we have to jump to 0x8000
mov sp, 0xe000
mov ax, 0x7e0
mov es, ax
mov ds, ax
mov fs, ax
mov gs, ax
jmp 0x800:0
hlt
dap:
db 0x10 ; dap size
db 0 ; reserved
.count:
dw 0
.offset:
dw 0
.segment:
dw 0
.lba:
dd 1 ; LBA low bits
dd 0 ; LBA high bits
cmdline db "auto", 0x0
cmdline_size equ $-cmdline
bootdrive db 0x0
; Unreal mode GDT
gdt_desc:
dw gdt_end - gdt
dd gdt
gdt:
gdt_null:
dq 0
gdt_data:
dw 0xFFFF
dw 0
db 0
db 10010010b
db 11001111b
db 0
gdt_end:
times 510-($-$$) db 0
dw 0xAA55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment