bunch of stuff idek
This commit is contained in:
7
bootler/CHANGELOG.md
Normal file
7
bootler/CHANGELOG.md
Normal file
@@ -0,0 +1,7 @@
|
||||
# Changelog
|
||||
|
||||
## [0.1.0] - 2026-03-06
|
||||
|
||||
### Added
|
||||
|
||||
- initialised CHANGELOG.md
|
||||
43
bootler/README.md
Normal file
43
bootler/README.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# bootler
|
||||
|
||||
hobby bootloader, 1-stage, legacy mode :p
|
||||
|
||||
run with `nix run git+https://git.mtgmonkey.net/andromeda/bootler#bootler`
|
||||
|
||||
### memory map
|
||||
|
||||
```
|
||||
. .
|
||||
: :
|
||||
| longmode kernel |
|
||||
+------ 0x00010000 ------+
|
||||
| |
|
||||
| |
|
||||
+------ 0x00009000 ------+
|
||||
| IDT |
|
||||
+------ 0x00008000 ------+
|
||||
| |
|
||||
| |
|
||||
+------ 0x00007E00 ------+
|
||||
| bootloader (boot.asm) |
|
||||
+------ 0x00007C00 ------+
|
||||
| stack |
|
||||
+------ 0x00005000 ------+
|
||||
| PT |
|
||||
+------ 0x00004000 ------+
|
||||
| PDT |
|
||||
+------ 0x00003000 ------+
|
||||
| PDPT |
|
||||
+------ 0x00002000 ------+
|
||||
| PML4T |
|
||||
+------ 0x00001000 ------+
|
||||
| |
|
||||
| |
|
||||
+------ 0x00000500 ------+
|
||||
| bios stuff |
|
||||
+------ 0x00000000 ------+
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
this project follows [Common Changelog](https://common-changelog.org) guidelines
|
||||
286
bootler/asm/boot.asm
Normal file
286
bootler/asm/boot.asm
Normal file
@@ -0,0 +1,286 @@
|
||||
; bootler
|
||||
; legacy bootloader in nasm-flavoured asm
|
||||
; 2026 Andromeda
|
||||
; GPL licensed
|
||||
|
||||
LOAD_ADDR equ 0x7C00
|
||||
|
||||
KERNEL_START equ 2 ; first sector on disk to load kernel from; 1 indexed
|
||||
KERNEL_SIZE equ 1 ; length of kernel in sectors
|
||||
KERNEL_LOAD_ADDR_ES equ 0x1000 ; kernel to be loaded at es * 0x10 + 0x0000
|
||||
|
||||
PAGE_TABLE_LOAD_ADDR equ 0x1000 ; start of page table; 4 * pt size
|
||||
PAGE_TABLE_SIZE equ 0x1000 ; size of page table in bytes
|
||||
|
||||
; 64 bit IDT stuff
|
||||
IDT_ADDR equ 0x8000 ; bottom of IDT
|
||||
IDT_SIZE equ 0x1000 ; size of IDT
|
||||
|
||||
IDT_SEGMENT equ 0x0008 ; gdt code segment to jump to for idt calls
|
||||
|
||||
; magic numbers and things
|
||||
A20_LINE_ENABLE equ 0x2401 ; magic number in ax to enable a20 line with 0x15
|
||||
BIOS_INT_DISK_OP equ 0x13
|
||||
BIOS_INT_MEMORY_OP equ 0x15
|
||||
|
||||
CR0_PE equ 1 << 0 ; Protected Mode Enabled
|
||||
CR0_PG equ 1 << 31 ; Paging
|
||||
|
||||
CR4_PAE equ 1 << 5 ; Physical Address Extension
|
||||
CR4_PGE equ 1 << 7 ; Page Global Enabled
|
||||
|
||||
MSR_IA32_EFER equ 0xC0000080 ; Extended Feature Enable model-specific Register
|
||||
|
||||
[bits 16]
|
||||
[org LOAD_ADDR]
|
||||
|
||||
jmp 0x0000:.cs_reset ; in case it loads us at 0x7C00:0x0000
|
||||
.cs_reset:
|
||||
|
||||
xor ax, ax
|
||||
mov ss, ax
|
||||
mov sp, LOAD_ADDR ; stack builds down, loader faces up
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
cld
|
||||
|
||||
; activate a20
|
||||
mov ax, A20_LINE_ENABLE
|
||||
int BIOS_INT_MEMORY_OP
|
||||
jc error
|
||||
mov si, msg_a20_line
|
||||
call print
|
||||
|
||||
; prep to read disk
|
||||
mov al, KERNEL_SIZE ; size in sectors, min. 1
|
||||
mov ch, 0 ; cylinder
|
||||
mov cl, KERNEL_START ; start sector, 1-indexed
|
||||
mov dh, 0 ; head
|
||||
; dl set by bios
|
||||
mov bx, KERNEL_LOAD_ADDR_ES ; load addr es:bx
|
||||
mov es, bx
|
||||
xor bx, bx
|
||||
|
||||
; read disk
|
||||
mov ah, 0x02
|
||||
int BIOS_INT_DISK_OP
|
||||
jc error
|
||||
mov si, msg_disk_read
|
||||
call print
|
||||
|
||||
; zero es
|
||||
push ax
|
||||
xor ax, ax
|
||||
mov es, ax
|
||||
pop ax
|
||||
|
||||
mov edi, PAGE_TABLE_LOAD_ADDR
|
||||
jmp lm_load
|
||||
|
||||
; expects:
|
||||
; es:edi -> 16kb for page table
|
||||
; ss:esp -> stack
|
||||
; heavily based on https://wiki.osdev.org/Entering_Long_Mode_Directly
|
||||
lm_load:
|
||||
; clear page table
|
||||
push di
|
||||
mov ecx, PAGE_TABLE_SIZE
|
||||
xor eax, eax
|
||||
cld
|
||||
rep stosd ; clear space for all 4 tables
|
||||
pop di
|
||||
|
||||
; PML4TE0
|
||||
lea eax, [es:di + PAGE_TABLE_SIZE]
|
||||
or eax, 11b
|
||||
mov [es:di], eax
|
||||
|
||||
; PDPT0E0
|
||||
lea eax, [es:di + 2 * PAGE_TABLE_SIZE]
|
||||
or eax, 11b
|
||||
mov [es:di + PAGE_TABLE_SIZE], eax
|
||||
|
||||
; PDT0E0
|
||||
lea eax, [es:di + 3 * PAGE_TABLE_SIZE]
|
||||
or eax, 11b
|
||||
mov [es:di + 2 * PAGE_TABLE_SIZE], eax
|
||||
|
||||
; PT0
|
||||
push di
|
||||
lea di, [di + 3 * PAGE_TABLE_SIZE]
|
||||
mov eax, 0x11
|
||||
|
||||
.set_pt_entry
|
||||
mov [es:di], eax
|
||||
add eax, 0x1000
|
||||
add di, 8
|
||||
cmp eax, 0x200000 ; size of page
|
||||
jb .set_pt_entry
|
||||
|
||||
pop di
|
||||
|
||||
; disable interrupts from PIC by masking all interrupts
|
||||
mov al, 0xFF ; mask
|
||||
out 0xA1, al
|
||||
out 0x21, al
|
||||
|
||||
; PAE, PGE
|
||||
mov eax, CR4_PAE | CR4_PGE
|
||||
mov cr4, eax
|
||||
|
||||
; cr3 -> PML4TE0
|
||||
mov edx, edi
|
||||
mov cr3, edx
|
||||
|
||||
; highs LME bit in EFER
|
||||
mov ecx, MSR_IA32_EFER
|
||||
rdmsr
|
||||
or eax, 0x00000100
|
||||
wrmsr
|
||||
|
||||
; activate long mode
|
||||
mov ebx, cr0
|
||||
or ebx, CR0_PG | CR0_PE
|
||||
mov cr0, ebx
|
||||
|
||||
cli
|
||||
lgdt [gdt_descriptor]
|
||||
|
||||
jmp 0x08:lm_start
|
||||
|
||||
error:
|
||||
mov si, .msg
|
||||
call print
|
||||
.msg db "err ", 0x00
|
||||
ret
|
||||
|
||||
done:
|
||||
hlt
|
||||
jmp done
|
||||
|
||||
print:
|
||||
pushad
|
||||
.loop
|
||||
lodsb
|
||||
test al, al
|
||||
je .done
|
||||
mov ah, 0x0E
|
||||
int 0x10
|
||||
jmp .loop
|
||||
.done
|
||||
popad
|
||||
ret
|
||||
|
||||
; TODO make readable (yoinked from https://wiki.osdev.org/Entering_Long_Mode_Directly)
|
||||
gdt_data:
|
||||
dq 0x0000000000000000
|
||||
dq 0x00209A0000000000
|
||||
dq 0x0000920000000000
|
||||
|
||||
gdt_descriptor:
|
||||
dw $ - gdt_data - 1 ; size
|
||||
dd gdt_data ; start
|
||||
|
||||
[bits 64]
|
||||
|
||||
; long mode entry
|
||||
lm_start:
|
||||
mov ax, 0x10
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
mov ss, ax
|
||||
|
||||
; set up serial device
|
||||
; TODO poll and whatnot (in rust??)
|
||||
mov dx, 0x3F8
|
||||
|
||||
; qemu -no-graphic overlaps serial and bios output without this
|
||||
mov al, 0x0D
|
||||
out dx, al
|
||||
mov al, 0x0A
|
||||
out dx, al
|
||||
|
||||
; initialize IDT at IDT_ADDR
|
||||
call idt_init
|
||||
|
||||
int3 ; silly test
|
||||
|
||||
jmp KERNEL_LOAD_ADDR_ES * 0x10
|
||||
|
||||
idt_init:
|
||||
; clear space for idt
|
||||
mov rdi, IDT_ADDR
|
||||
push di
|
||||
mov rcx, IDT_SIZE / 4
|
||||
xor rax, rax
|
||||
cld
|
||||
rep stosd ; clear double word for each rcx
|
||||
pop di
|
||||
|
||||
push rdx ; dx contains the output device
|
||||
; nothing between here and the `pop rdx` will be able to print
|
||||
|
||||
; breakpoint
|
||||
mov rdi, 0x8E ; present, no dpl, interrupt
|
||||
mov rsi, 0x03 ; breakpoint interrupt
|
||||
lea rdx, [int_hdl_dummy]
|
||||
call mk_idt_entry
|
||||
|
||||
pop rdx ; get back dx output device
|
||||
|
||||
lidt [idt_descriptor]
|
||||
|
||||
ret
|
||||
|
||||
int_hdl_dummy:
|
||||
mov rsi, .msg
|
||||
call lm_print
|
||||
iretq
|
||||
.msg db "INTdummy", 0x0D, 0x0A, 0x00
|
||||
|
||||
; rdi = flags
|
||||
; rsi = entry number
|
||||
; rdx -> handler
|
||||
mk_idt_entry:
|
||||
mov rax, rdx
|
||||
mov rcx, rsi
|
||||
|
||||
shl rcx, 4 ; offset = entry number * 16
|
||||
add rcx, IDT_ADDR
|
||||
|
||||
mov word [rcx + 0], ax ; offset
|
||||
mov word [rcx + 2], IDT_SEGMENT ; code segment
|
||||
mov word [rcx + 5], di
|
||||
mov byte [rcx + 4], 0 ; IST (0 = none)
|
||||
shr rax, 16
|
||||
mov word [rcx + 6], ax ; offset
|
||||
shr rax, 16
|
||||
mov dword [rcx + 8], eax ; offset
|
||||
mov dword [rcx + 12], 0 ; reserved
|
||||
ret
|
||||
|
||||
lm_print:
|
||||
.loop
|
||||
mov al, [rsi]
|
||||
test al, al
|
||||
jz .done
|
||||
out dx, al
|
||||
inc si
|
||||
jmp .loop
|
||||
.done:
|
||||
ret
|
||||
|
||||
idt_descriptor:
|
||||
dw IDT_SIZE - 1 ; size
|
||||
dq IDT_ADDR ; start
|
||||
|
||||
msg_a20_line db "a20 line", 0x0D, 0x0A, 0x00
|
||||
msg_disk_read db "disk", 0x0D, 0x0A, 0x00
|
||||
|
||||
times 510-($-$$) db 0 ; 2 bytes less now
|
||||
db 0x55
|
||||
db 0xAA
|
||||
23
bootler/asm/kernel.asm
Normal file
23
bootler/asm/kernel.asm
Normal file
@@ -0,0 +1,23 @@
|
||||
[bits 64]
|
||||
|
||||
mov al, 'K'
|
||||
out dx, al
|
||||
mov al, 'e'
|
||||
out dx, al
|
||||
mov al, 'r'
|
||||
out dx, al
|
||||
mov al, 'n'
|
||||
out dx, al
|
||||
mov al, 'e'
|
||||
out dx, al
|
||||
mov al, 'l'
|
||||
out dx, al
|
||||
mov al, 0x0D
|
||||
out dx, al
|
||||
mov al, 0x0A
|
||||
out dx, al
|
||||
mov al, 0x00
|
||||
out dx, al
|
||||
.done
|
||||
hlt
|
||||
jmp .done
|
||||
48
bootler/package.nix
Normal file
48
bootler/package.nix
Normal file
@@ -0,0 +1,48 @@
|
||||
{
|
||||
stdenv,
|
||||
nasm,
|
||||
qemu,
|
||||
...
|
||||
}: let
|
||||
bootImg = "boot";
|
||||
in
|
||||
stdenv.mkDerivation {
|
||||
pname = "bootler";
|
||||
version = "0.1.0";
|
||||
src = ./.;
|
||||
buildPhase = ''
|
||||
${nasm}/bin/nasm asm/boot.asm -o boot.bin
|
||||
${nasm}/bin/nasm asm/kernel.asm -o dummy.bin
|
||||
|
||||
dd if=/dev/zero of=${bootImg} bs=512 count=2880
|
||||
dd if=boot.bin of=${bootImg} conv=notrunc
|
||||
dd if=dummy.bin of=${bootImg} bs=512 seek=1 conv=notrunc
|
||||
'';
|
||||
installPhase = ''
|
||||
mkdir -p $out/bin
|
||||
cp boot.bin $out/bin
|
||||
cp ${bootImg} $out/bin
|
||||
|
||||
# create emulation binary
|
||||
cat<<EOF>$out/bin/bootler
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# create temp dir
|
||||
mkdir -p ./.bootler
|
||||
cp $(echo $out)/bin/${bootImg} ./.bootler/${bootImg}
|
||||
chmod a+w ./.bootler/${bootImg}
|
||||
|
||||
# run image
|
||||
${qemu}/bin/qemu-system-x86_64 \
|
||||
-nographic \
|
||||
-drive file=./.bootler/${bootImg},format=raw,index=0,media=disk
|
||||
|
||||
# clean up
|
||||
rm ./.bootler -r
|
||||
|
||||
EOF
|
||||
|
||||
chmod +x $out/bin/${bootImg}
|
||||
chmod +x $out/bin/bootler
|
||||
'';
|
||||
}
|
||||
Reference in New Issue
Block a user