use long mode, x86_64-unknown-none works now

This commit is contained in:
andromeda
2026-03-04 22:45:35 +01:00
parent 1b6f76488d
commit 094e8c288a
6 changed files with 211 additions and 133 deletions

View File

@@ -1,2 +1,5 @@
[build] [build]
target = "x86_64-unknown-none" target = "x86_64-unknown-none"
rustflags = [
"-Crelocation-model=static"
]

View File

@@ -16,7 +16,7 @@ run with `nix run git+https://git.mtgmonkey.net/andromeda/bootler#bootler`
+------ 0x00100000 ------+ +------ 0x00100000 ------+
| hardware, bios stuff | | hardware, bios stuff |
+------ 0x00080000 ------+ +------ 0x00080000 ------+
| pm stack (esp) | from boot.asm | free |
+------ 0x00010200 ------+ +------ 0x00010200 ------+
| kernel (kernel.asm) | | kernel (kernel.asm) |
+------ 0x00010000 ------+ +------ 0x00010000 ------+
@@ -24,7 +24,17 @@ run with `nix run git+https://git.mtgmonkey.net/andromeda/bootler#bootler`
+------ 0x00007E00 ------+ +------ 0x00007E00 ------+
| bootloader (boot.asm) | | bootloader (boot.asm) |
+------ 0x00007C00 ------+ +------ 0x00007C00 ------+
| real mode stack (sp) | from boot.asm | stack | TODO get real stack
+------ 0x00005000 ------+
| PT |
+------ 0x00004000 ------+
| PDT |
+------ 0x00003000 ------+
| PDPT |
+------ 0x00002000 ------+
| PML4T |
+------ 0x00001000 ------+
| free |
+------ 0x00000500 ------+ +------ 0x00000500 ------+
| bios stuff | | bios stuff |
+------ 0x00000000 ------+ +------ 0x00000000 ------+

View File

@@ -3,156 +3,210 @@
; 2026 Andromeda ; 2026 Andromeda
; GPL licensed ; 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
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] [bits 16]
[org 0x7C00] ; address where bootloader is loaded [org LOAD_ADDR]
jmp 0x0000:.cs_reset ; in case it loads us at 0x7C00:0x0000
.cs_reset:
xor ax, ax xor ax, ax
mov ss, ax
mov sp, LOAD_ADDR ; stack builds down, loader faces up
mov ds, ax mov ds, ax
mov es, ax mov es, ax
mov ss, ax mov fs, ax
mov sp, 0x7C00 mov gs, ax
cld
mov ah, 0x0E
mov al, 'R'
int 0x10
mov al, 'e'
int 0x10
mov al, 'a'
int 0x10
mov al, 'l'
int 0x10
mov al, 0x0D
int 0x10
mov al, 0x0A
int 0x10
mov al, 0x00 ; stops serial and bios output from overlapping in qemu -nographic
int 0x10 ; output
; activate a20 ; activate a20
mov ax, 0x2401 mov ax, A20_LINE_ENABLE
int 0x15 int BIOS_INT_MEMORY_OP
jc error jc error_a20_line
mov si, msg_a20_line
call print
; load kernel ; prep to read disk
; 'docs' from https://www.ctyme.com/intr/rb-0607.htm mov al, KERNEL_SIZE ; size in sectors, min. 1
mov ah, 0x02 mov ch, 0 ; cylinder
mov al, 1 ; number of sectors to read (must be nonzero) mov cl, KERNEL_START ; start sector, 1-indexed
mov ch, 0 ; low eight bits of cylinder number mov dh, 0 ; head
mov cl, 2 ; sector number 1-63 (bits 0-5); high two bits of cylinder (bits 6-7, ; dl set by bios
; hard disk only) mov bx, KERNEL_LOAD_ADDR_ES ; load addr es:bx
mov dh, 0 ; head number
; dl is already set by bios
mov bx, 0x1000 ; data buffer
mov es, bx mov es, bx
xor bx, bx xor bx, bx
int 0x13 ; read disk
jc error
; load gdt ; read disk
lgdt [gdt_descriptor] mov ah, 0x02
int BIOS_INT_DISK_OP
jc error_disk_read
mov si, msg_disk_read
call print
; jump to pm ; zero es
cli push ax
mov eax, cr0 xor ax, ax
or eax, 1 mov es, ax
mov cr0, eax pop ax
jmp 0x08:pm_start
error: mov edi, PAGE_TABLE_LOAD_ADDR
mov al, 'e' jmp lm_load
int 0x10
mov al, 'r'
int 0x10
mov al, 'r'
int 0x10
mov al, 'o'
int 0x10
mov al, 'r'
int 0x10
jmp $
; 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_a20_line:
mov si, .msg
call print
jmp done
.msg db "err a20 line", 0x00
error_disk_read:
mov si, .msg
call print
jmp done
.msg db "err disk read", 0x00
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 real idt
empty_idt:
dw 0 ; length
dd 0 ; base
; TODO make readable (yoinked from https://wiki.osdev.org/Entering_Long_Mode_Directly)
gdt_data: gdt_data:
; null segment
dq 0x0000000000000000 dq 0x0000000000000000
; code segment dq 0x00209A0000000000
dw 0xFFFF dq 0x0000920000000000
dw 0x0000
db 0x00
db 10011010b ; 32-bit code segment, present, ring 0
db 11001111b ; limit bits 16-19
db 0x00
; data segment
dw 0xFFFF
dw 0x0000
db 0x00
db 10010010b ; 32-bit data segment, present, ring 0
db 11001111b ; limit bits 16-19
db 0x00
gdt_descriptor: gdt_descriptor:
dw $ - gdt_data - 1 ; size dw $ - gdt_data - 1 ; size
dd gdt_data ; start dd gdt_data ; start
[bits 32] [bits 64]
; entry point ; long mode entry
pm_start: lm_start:
; data segment registers
mov ax, 0x10 mov ax, 0x10
mov ds, ax mov ds, ax
mov es, ax mov es, ax
mov fs, ax mov fs, ax
mov gs, ax mov gs, ax
mov ss, ax mov ss, ax
mov esp, 0x80000
; TODO actually configure COM1 ; set up serial device
mov dx, 0x3F8 ; COM1 ; TODO poll and whatnot (in rust??)
mov al, 'P' mov dx, 0x3F8
out dx, al
mov al, 'r'
out dx, al
mov al, 'o'
out dx, al
mov al, 't'
out dx, al
mov al, 'e'
out dx, al
mov al, 'c'
out dx, al
mov al, 't'
out dx, al
mov al, 'e'
out dx, al
mov al, 'd'
out dx, al
mov al, 0x0D
out dx, al
mov al, 0x0A
out dx, al
jmp 0x08:0x10000 jmp KERNEL_LOAD_ADDR_ES * 0x10
msg_a20_line db "a20 line", 0x0D, 0x0A, 0x00
msg_disk_read db "disk read", 0x0D, 0x0A, 0x00
pm_error:
mov al, 'p'
out dx, al
mov al, 'm'
out dx, al
mov al, 'e'
out dx, al
mov al, 'r'
out dx, al
mov al, 'r'
out dx, al
mov al, 'o'
out dx, al
mov al, 'r'
out dx, al
jmp $
times 510-($-$$) db 0 ; 2 bytes less now times 510-($-$$) db 0 ; 2 bytes less now
db 0x55 db 0x55
db 0xAA db 0xAA

View File

@@ -1,4 +1,4 @@
[bits 32] [bits 64]
mov al, 'K' mov al, 'K'
out dx, al out dx, al
@@ -18,6 +18,6 @@ mov al, 0x0A
out dx, al out dx, al
mov al, 0x00 mov al, 0x00
out dx, al out dx, al
jmp $ .done
hlt
times 512-($-$$) db 0 jmp .done

View File

@@ -23,7 +23,11 @@ in (naersk'.buildPackage {
release = true; release = true;
# build std # build std
cargoBuildOptions = x: x ++ ["-Zbuild-std=core,compiler_builtins,alloc" "-Zbuild-std-features=compiler-builtins-mem"]; cargoBuildOptions = x:
x
++ [
"-Zbuild-std=core,compiler_builtins"
];
postInstall = '' postInstall = ''
ld --oformat binary \ ld --oformat binary \

View File

@@ -6,15 +6,22 @@ use core::panic::PanicInfo;
#[unsafe(no_mangle)] #[unsafe(no_mangle)]
pub extern "C" fn _start() -> ! { pub extern "C" fn _start() -> ! {
// 'k' // 'k'
loop{unsafe {core::arch::asm!( print("kernel\n");
"out dx, al", in("al") 0x6Bu8 loop {}
)}} }
fn print(s: &str) {
let mut bytes = s.bytes();
while let Some(b) = bytes.next() {
unsafe {core::arch::asm!(
"out dx, al"
, in("al") b
)};
};
} }
#[panic_handler] #[panic_handler]
fn panic(_: &PanicInfo) -> ! { fn panic(_: &PanicInfo) -> ! {
// 'p' print("panicked");
loop{unsafe {core::arch::asm!( loop {}
"out dx, al", in("al") 0x70u8
)}}
} }