KimisOS/src/bootloader/main.s

915 lines
18 KiB
ArmAsm

; Kimi's Bootloader - Custom Booting solution for Kimi's OS
; (c) 2024 Notsomeidiot123 on Github
; Documentation available at https://github.com/notsomeidiot123/KimisOS
org 0x7c00
bits 16
%macro debug 0
mov ah, 0xe
mov al, 0x41
int 0x10
jmp $
%endmacro
;TODO:
;Enable A20 line |x|
;Enable unreal mode |x|
;Load GDT |x|
;Load part2 |x|
;Get video mode information |0|
;Set video mode |0|
;get memory map |0|
;enable paging |0|
;read filesystem |0|
;load kernel |0|
;parse ELF format |0|
;pass memory and video information to kernel|0|
;relocate and jump to kernel |0|
jump:
jmp short start
times 3-($-$$) db 0x90
fat_bpb:
.oem:
db "KIMI'SOS"
.bytes_per_sector:
dw 512
.sectors_per_cluster:
db 8
.reserved_sectors:
dw 32
.fat_count:
db 2
.root_dir_entries:
dw 0
.sectors_in_volume:
dw 0
.media_type:
db 0xf8
.sectors_per_fat:
dw 0
.sectors_per_track:
dw 63
.heads:
dw 8
.part_start:
dd 0
.large_sector_count:
dd 1048576
fat_ebpb32:
.sectors_per_fat:
dd 2048
.flags:
dw 0
.version:
db 0, 1
.root_dir_cluster:
dd 2
.fs_info_sector:
dw 1
.backup_boot:
dw 0
.reserved:
times 12 db 0
.drive_num:
db 0x80
.ntflags:
db 0
.sig:
db 0x29
.vid_Serial:
dd 0
.label:
db " Kimi's OS "
.sysid:
db "FAT32 "
start:
mov sp, 0x7000
mov bp, 0x7000
mov ax, ds
xor bx, bx
mov ds, bx
mov [data.part_seg], ax
mov [data.part_off], si
mov [data.boot_disc], dl
jmp 0:set_cs
set_cs:
xor cx, cx
check_a20:
inc cx
mov ax, 0xffff
mov es, ax
mov ax, [es:0x7e0e]
cmp ax, [ds:0x7dfe]
jne load_gdt
enable_a20:
cmp cx, 4
je no_a20
cmp cx, 3
je .fast_a20
cmp cx, 2
je .kb_en
.bios_en:
mov ax, 0x2401
int 0x15
jmp check_a20
.fast_a20:
in al, 0x92
or al, 2
out 0x92, al
mov ax, 10000
.lp:
dec ax
cmp ax, 0
jge .lp
jmp check_a20
.kb_en:
cli
mov al, 0xad
out 0x64, al
call .wait
mov al, 0xd0
out 0x64, al
call .wait2
in al, 0x60
push eax
call .wait
mov al, 0xd1
out 0x64, al
call .wait
pop eax
or al, 2
out 0x60, al
call .wait
mov al, 0xae
out 0x64, al
call .wait
sti
jmp check_a20
.wait:
in al, 0x64
test al,2
jnz .wait
ret
.wait2:
in al, 0x64
test al, 1
jnz .wait2
ret
load_gdt:
lgdt [GDT_desc]
push ds
mov eax, cr0
or al, 1
mov cr0, eax
jmp 0x8:.unreal
.unreal:
mov bx, 0x18
mov ds, bx
and al, 0xfe
mov cr0, eax
jmp 0x0:.real
.real:;no actual code here, just label for readability and organization
pop ds
load_part2:
mov ah, 0x42
xor edx, edx
mov dx, word [data.part_seg]
shl edx, 4
xor ecx, ecx
mov cx, word [data.part_off]
add edx, ecx
mov al, byte [edx]
and al, 0x80
jz .read
mov ecx, [edx + 0x8]
add [DAP.sector_start], ecx
.read:
mov dl, byte [data.boot_disc]
push 0
pop ds
mov si, DAP
int 0x13
jc load_fail
jmp part_2
jmp $
no_a20:
mov ah, 0xe
mov al, 'E'
int 0x10
mov al, '1'
int 0x10
jmp $
load_fail:
mov ah, 0xe
mov al, 'E'
int 0x10
mov al, '2'
int 0x10
jmp $
DAP:
.sz: db 0x10
.unused: db 0
.read_count: dw 7
.offset: dw 0x7e00
.segment: dw 0
.sector_start:
dd 1
dd 0
GDT_desc:
.size: dw GD_TABLE-GD_END - 1
.offset: dd GD_TABLE
GD_TABLE:
.null:
dd 0
dd 0
.kcode16:
dw 0xffff
dw 0x0000
db 0x00
db 0b10011010
db 0b00001111
db 0x00
.kcode32:
dw 0xffff
dw 0x0000
db 0x00
db 0b10011010
db 0b11001111
db 0x00
.kdata32:
dw 0xffff
dw 0x0000
db 0x00
db 0b10010010
db 0b11001111
db 0x00
.ucode32:
dw 0xffff
dw 0x0000
db 0x00
db 0b11111010
db 0b11001111
db 0x00
.udata32:
dw 0xffff
dw 0x0000
db 0x00
db 0b11110010
db 0b11001111
db 0x00
.tss:
dd 0
dd 0
.phony:
dw 0xaa55
dd 0
dw 0x55aa
GD_END:
data:
.boot_disc: db 0
.part_seg: dw 0
.part_off: dw 0
times 510-($-$$) db 0
db 0x55, 0xaa
fs_info:
.id: dd 0x41615252
.reserved0: times 480 db 0
.sig: dd 0x61417272
.last_known_free: dd 0xFFFFFFFF
.free_search_start: dd 3
.reserved: times 12 db 0
.trail: dd 0xAA550000
times 1024-($-$$) db 0
part_2:
call get_mmap
call paging_en
call set_video_mode
mov esi, 0
call cache_file_table
; debug
mov edi, kernel_file
call open_file
; debug
cmp eax, -1
je file_not_found
add edx, 0x40000;is 1mb enough for a filesystem diver and a disk driver?
call find_kpaddr
; debug
mov esi, eax
mov edi, [kload_paddr]
; debug
call read_file
; debug
jc load_fail
; debug
mov esi, [kload_paddr]
; jmp $
call load_elf
; debug
push eax
mov edi, disk_module_file
call open_file
; debug
cmp eax, -1
je .find_fs_driver_no_disk
mov [disk_module_struct.size], edx
mov esi, eax
and edx, 0xfffff000
add edx, 0x2000
add [kload_paddr], edx
; mov eax, [kload_paddr]
; jmp $
; debug
mov edi, [kload_paddr]
mov [disk_module_struct.ptr], edi
call read_file
jc load_fail
; mov esi, [kload_paddr]
; call load_elf
; debug
jc load_fail
jmp .find_fs_driver
.find_fs_driver_no_disk:
mov ax, 0xe44
int 0x10
.find_fs_driver:
; mov edi, fs_module_file
; call open_file
; cmp eax, -1
; je .start32_no_fs
; mov [fs_module_struct.size], edx
; mov eax, esi
; and edx, 0xfffffc00
; add edx, 0x1000
; add [kload_paddr], edx
; mov edi, [kload_paddr]
; mov [fs_module_struct.ptr], edi
; call read_file
; jc load_fail
;
mov edi, fs_module_file
call open_file
; debug
cmp eax, -1
je .start32_no_fs
mov [fs_module_struct.size], edx
mov esi, eax
and edx, 0xfffff000
add edx, 0x2000
add [kload_paddr], edx
; mov eax, [kload_paddr]
; jmp $
; debug
mov edi, [kload_paddr]
mov [fs_module_struct.ptr], edi
call read_file
jc load_fail
jmp .start32
;
.start32_no_fs:
mov ax, 0xe46
int 0x10
.start32:
; debug
; push eax
cli
mov eax, page_table
mov cr3, eax
mov eax, cr4
or eax, 1 << 4
mov cr4, eax
mov eax, cr0
or eax, 0x8000_0001
mov cr0, eax
jmp 0x10:protected_mode
protected_mode:
bits 32
mov bx, 0x18
mov ds, bx
mov es, bx
mov ss, bx
mov gs, bx
mov fs, bx
pop eax
mov esi, k_info
; jmp $
jmp eax
jmp $
bits 16
file_not_found:
mov ah, 0xe
mov al, 'E'
int 0x10
mov al, '5'
int 0x10
load_kernel:
get_mmap:
pushad
push ds
push es
push 0x200
pop es
mov di, 0
mov edx, 0x534D4150
xor ebx, ebx
xor esi, esi
.get_map:
mov eax, 0xe820
mov ecx, 24
int 0x15
jc .ret
mov eax, [es:di + 8]
or eax, [es:di + 16]
jz .get_map
inc si
or dword [es:di + 20], 1
add di, 24
cmp ebx, 0
je .ret
jmp .get_map
.ret:
cmp si, 0
je .ret_err
mov [es:di], dword 0
mov [k_info.memory_map_count], si
pop es
pop ds
popad
mov ax, 0
ret
.ret_err:
pop es
pop ds
popad
mov ax, 1
ret
set_video_mode:
mov ah, 0x0
mov al, 0x3
int 0x10
ret
paging_en:
mov eax, cr4
or eax, 0x00000010 ;enable 4mb pages
mov cr4, eax
mov eax, page_table;page table base
mov [eax], dword 0
or [eax], dword 0b0_0001_1000_1001;present, Write-through, page size 4mb, global, present
mov cr3, eax
;enable recursive paging
mov [eax + 1023*4], eax
or [eax + 1023*4], dword 0b0_0000_0000_0011
ret
open_file:
;only looks in the root directory
;edi = file_to_search
;esi = ptr to load file [TODO: IMPLEMENT]
;eax = return value (first cluster)
;edx = return value (file size)
push edi
xor esi, esi
xor ecx, ecx
xor edx, edx
mov esi, [fat_bpb.part_start];
add si, [fat_bpb.reserved_sectors]
mov cl, [fat_bpb.fat_count]
mov dx, [fat_ebpb32.sectors_per_fat]
mov ax, dx
xor dx, dx
mul cx
add si, ax
xor cx, cx
mov ax, [fat_ebpb32.root_dir_cluster]
sub ax, 2
mov cl, [fat_bpb.sectors_per_cluster]
mul cx
add si, ax
; jmp $
mov byte [DAP.segment], 0
mov [DAP.sector_start], esi
mov word [DAP.read_count], 8
mov word [DAP.offset], root_dir
mov si, DAP
mov ah, 0x42
mov dl, [data.boot_disc]
; jmp $
int 0x13
jc .not_found_ret
xor ecx, ecx
lea esi, [root_dir]
push word 0
pop es
.chklp:
; add esi, 0x20
mov edi, [esp]
cmp byte [esi], 0
mov ax, [esi]
je .not_found_ret
mov ecx, 11
push esi
repe cmpsb
pop esi
; jmp $
je .found
add esi, 0x20
jmp .chklp
.found:
pop edi
;eax = first cluster
;edx = file size
mov ax, [esi + 20]
shl eax, 16
mov ax, [esi + 26]
mov edx, [esi + 28]
; jmp $
ret
.not_found_ret:
pop edi
mov eax, -1
ret
jmp $
; debug
read_file:
;args: esi = first cluster in chain
;edi = pointer to data
push esi
sub esi, 2
xor ecx, ecx
xor edx, edx
mov eax, esi
mov cl, [fat_bpb.sectors_per_cluster]
mul ecx; eax = offset from file table
; jmp $
push eax
xor eax, eax
xor ecx, ecx
mov eax, [fat_ebpb32.sectors_per_fat]
xor edx, edx
mov cl, [fat_bpb.fat_count]
mul ecx
xor edx, edx
mov dx, [fat_bpb.reserved_sectors]
pop ecx
add eax, ecx
add eax, edx
mov [DAP.sector_start], eax
mov ecx, [fat_bpb.part_start]
add [DAP.sector_start], ecx
mov edx, [DAP.sector_start]
; cmp esi, 3
; je $
xor ecx, ecx
mov cl, [fat_bpb.sectors_per_cluster]
mov [DAP.read_count], cx
; push edi
; shr edi, 16
; mov [DAP.segment], di
; pop edi
; mov [DAP.offset], di
; jmp $
mov word [DAP.segment], 0
mov word [DAP.offset], file_buffer
mov ah, 0x42
mov dl, [data.boot_disc]
mov si, DAP
int 0x13
jc .exit_err
; debug
xor eax, eax
mov al, [fat_bpb.sectors_per_cluster]
xor edx, edx
xor ecx, ecx
mov cx, [fat_bpb.bytes_per_sector]
mul ecx
; push eax
mov esi, file_buffer
mov ebx, eax
call mmove
; debug
pop esi
call read_fat
; jmp $
; debug
cmp eax, 0xffffffff
je .exit_success
; jmp $
mov esi, eax
add edi, ebx
jmp read_file
.exit_err:
mov eax, 1
stc
ret
.exit_success:
mov eax, 0
clc
; debug
ret
jmp $
read_fat:
;args:
;esi: index
;return reg: eax
push esi
shr esi, 12
cmp esi, [loaded_fat_block]
mov eax, [loaded_fat_block]
je .read
call cache_file_table
; mov eax, [loaded_fat_block]
; mov esi, [file_table + 0x4 * 3]
.read:
pop esi
and esi, 0xfff
mov eax, [esi * 0x4 + file_table]
ret
cache_file_table:
;args:
;esi: fat block index (in 4kb)
;reads all data from file
mov eax, 4096
push edx
xor edx, edx
push ecx
xor ecx, ecx
mov cx, [fat_bpb.bytes_per_sector]
div ecx
push eax ;will be important for the DAP
mov [loaded_fat_block], esi
mov ecx, eax
mov eax, esi
xor edx, edx
mul ecx;eax = start sector
;sector_to_read = start_sector + fat_bpb.reserved_sectors
xor edx, edx
mov dx, [fat_bpb.reserved_sectors]
add eax, edx;sector_to_read
mov [DAP.sector_start], eax
pop eax
mov [DAP.read_count], ax
mov word [DAP.offset], file_table
mov ah, 0x42
mov si, DAP
mov dl, [data.boot_disc]
int 0x13
jc load_fail
pop ecx
pop edx
ret
jmp $
mmove:
;esi = src
;edi = dest
;ebx = count
; jmp $
push eax
push ecx
; debug
xor ecx, ecx
.mlp:
; jmp $
cmp ecx, ebx
jge .ret
mov al, [ds:esi + ecx]
mov [ds:edi + ecx], al
inc ecx
jmp .mlp
.ret:
; debug
pop ecx
pop eax
; jmp $
ret
find_kpaddr:
;edx = size of file in bytes
push edx
push esi
push eax
mov esi, [k_info.memory_map_ptr]
mov ecx, 24
.sloop:
mov eax, [esi + ecx + 8]
cmp eax, edx
jge .found
.sloop_next:
add ecx, 24
cmp [esi + ecx], dword 0
je .err
jmp .sloop
.found:
cmp [esi + ecx + 16], dword 1
jne .sloop_next
mov eax, [esi + ecx]
mov [kload_paddr], eax
pop eax
pop esi
pop edx
mov [kernel_physical_size], edx
ret
.err:
mov ax, 0xe45
int 0x10
mov al, '4'
int 0x10
jmp $
load_elf:
;parse elf and relocate each section to it's appropriate location
;esi: address of loaded kernel;
push ebp
mov ebp, esp
sub esp, 64; What could i possibly need 16 stack-allocated variables for???
mov [ebp - 8], esi;file_buffer
cmp dword [esi], elf_magic
jne .err
xor ebx, ebx
mov ebx, [esi + 28]
lea ebx, [esi + ebx]
.map_seg_l:
cmp dword [ebx], 0
je .exit
mov esi, [ebx + 8]
mov edi, [ebx + 4]
add edi, [ebp - 8]
mov ecx, [ebx + 20]
cmp ecx, 0
je .map_next
xor edx, edx
shr ecx, 12
add dword [kload_paddr], 0x1000
.mloop:
add dword [kload_paddr], 0x1000;
call map_addr
add edi, 0x1000
add esi, 0x1000
; jmp $
inc edx
cmp edx, ecx
jb .mloop
.map_next:
add ebx, 32
jmp .map_seg_l
.exit:
; jmp $
mov esi, [ebp - 8]
mov eax, [esi + 24]; entry address
; debug
add esp, 64
pop ebp
ret
jmp $
.err:
mov ah, 0xe
mov al, 'E'
int 0x10
mov al, '3'
int 0x10
jmp $
map_addr:
;map address in esi to physical address in edi
push ebp
mov ebp, esp
mov [ebp - 8], edi
mov [ebp - 12], esi
push edi
push esi
shr esi, 22
lea esi, [page_table + esi * 4]
mov eax, [esi]
and eax, 0xfffff000
cmp dword [esi], 0
jne .map
;create new page dir entry
mov eax, [last_allocated_pgtb]
add eax, 4096
mov [last_allocated_pgtb], eax
mov [esi], eax
or byte [esi], 1
.map:
mov esi, eax
mov eax, [ebp - 12]
shr eax, 12
and eax, 0x3ff
lea esi, [esi + eax * 4]
mov [esi], edi
or byte [esi], 1
pop esi
pop edi
pop ebp
ret
jmp $
map_pages_id:
;edx = page count
;eax = addr
push esi
push edi
push edx
cmp eax, 1 << 22
je .ret
mov esi, eax
.loop:
cmp edx, 0
je .ret
mov edi, esi
call map_addr
add esi, 0x1000
dec edx
jmp .loop
.ret:
pop edx
pop edi
pop esi
ret;
;kernel info
k_info:
.memory_map_ptr: dd 0x2000
.memory_map_count: dw 0
.padding: db 0
.bpp: db 0;if depth == 0 then video is text mode
.xres: dw 80
.yres: dw 25
.framebuffer_ptr: dd 0xb8000
.loaded_modules: dd disk_module_struct
;loaded_modules points to a struct array containing a ptr to the entry point of each pre-loaded module to be executed during startup
disk_module_struct:
.ptr: dd 0
.size: dd 0
.type: dd 1
.flags: db 0
.next_entry: dd fs_module_struct
fs_module_struct:
.ptr: dd 0
.size: dd 0
.type: dd 2
.flags: db 0
.next_entry: dd 0
kernel_file: db "kernel", 0x0, 0x0, "elf"
disk_module_file: db "idm", 0, 0, 0, 0, 0, "elf"
fs_module_file: db "ifsm", 0, 0, 0, 0, "elf"
loaded_fat_block: dd 0
last_allocated_pgtb: dd 0x10000
sacrifice1: dd 0
sacrifice0: dd 1
kernel_physical_size: dd 0
kload_paddr: dd 0x20000
elf_magic EQU 0x464c457f
file_buffer EQU 0xa000
root_dir EQU 0x1000
file_table EQU 0xf000
page_table EQU 0x00010000
times 4096-($-$$) db 0