You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
344 lines
6.6 KiB
344 lines
6.6 KiB
bits 16
|
|
org 0x8000
|
|
|
|
xor ax, ax
|
|
mov ds, ax
|
|
mov es, ax
|
|
mov ss, ax
|
|
mov sp, 0x7000
|
|
|
|
FIRST_PARTITION_SECTOR equ 2048 ; TODO Read MBR.
|
|
STAGE_BUFFER_SEGMENT equ 0x0900
|
|
STAGE_BUFFER_OFFSET equ 0x0000
|
|
KERNEL_BUFFER_SEGMENT equ 0x2000
|
|
|
|
jmp prepare_kernel
|
|
|
|
dap:
|
|
.dap_size: db 16
|
|
.reserved: db 0
|
|
.src_sectors: dw 1
|
|
.dst_offset: dw 0
|
|
.dst_segment: dw 0
|
|
.src_lba: dq 0
|
|
dap_end:
|
|
|
|
bpb:
|
|
.bytes_per_sector: dw 0
|
|
.sectors_per_cluster: db 0
|
|
.reserved_sectors: dw 0
|
|
.fats_count: db 0
|
|
.root_entry_count: dw 0
|
|
.total_sectors_16: dw 0
|
|
.media_type: db 0
|
|
.sectors_per_fat: dw 0
|
|
bpb_end:
|
|
|
|
fat_start: dw 0
|
|
root_start: dw 0
|
|
root_size: dw 0
|
|
data_start: dw 0
|
|
|
|
kernel_filename: db 'KERNEL BIN'
|
|
kernel_cluster: dw 0
|
|
kernel_buffer_offset: dw 0
|
|
|
|
read_sectors:
|
|
xor bx, bx
|
|
mov ds, bx
|
|
|
|
mov [dap.src_lba], eax
|
|
mov [dap.src_sectors], cx
|
|
mov [dap.dst_segment], es
|
|
mov [dap.dst_offset], di
|
|
mov ah, 0x42
|
|
mov dl, 0x80
|
|
mov si, dap
|
|
int 0x13
|
|
jc disk_error
|
|
ret
|
|
|
|
disk_error:
|
|
mov ah, 0x0E
|
|
mov al, 'E'
|
|
int 0x10
|
|
jmp $
|
|
|
|
prepare_kernel:
|
|
load_bpb:
|
|
xor bx, bx
|
|
mov ds, bx
|
|
|
|
mov eax, FIRST_PARTITION_SECTOR
|
|
mov cx, 1
|
|
mov bx, STAGE_BUFFER_SEGMENT
|
|
mov es, bx
|
|
mov di, STAGE_BUFFER_OFFSET
|
|
call read_sectors
|
|
|
|
mov bx, STAGE_BUFFER_SEGMENT
|
|
mov ds, bx
|
|
|
|
mov si, STAGE_BUFFER_OFFSET + 11
|
|
xor bx, bx
|
|
mov es, bx
|
|
mov di, bpb
|
|
mov cx, bpb_end - bpb
|
|
rep movsb
|
|
|
|
find_data_start:
|
|
xor bx, bx
|
|
mov ds, bx
|
|
|
|
mov ax, FIRST_PARTITION_SECTOR
|
|
add ax, [bpb.reserved_sectors]
|
|
mov [fat_start], ax
|
|
|
|
xor ax, ax
|
|
mov al, [bpb.fats_count]
|
|
mul word [bpb.sectors_per_fat]
|
|
add ax, [fat_start]
|
|
mov [root_start], ax ; dx should be zero for sane FAT16 values
|
|
|
|
mov ax, [bpb.root_entry_count]
|
|
shl ax, 5 ; * 32
|
|
shr ax, 9 ; / 512 ; there should be at least 512 entries, so safe
|
|
mov [root_size], ax
|
|
|
|
mov ax, [root_start]
|
|
add ax, [root_size]
|
|
mov [data_start], ax
|
|
|
|
find_kernel:
|
|
xor bx, bx
|
|
mov ds, bx
|
|
|
|
xor eax, eax
|
|
mov ax, [root_start]
|
|
mov cx, [root_size]
|
|
mov bx, STAGE_BUFFER_SEGMENT
|
|
mov es, bx
|
|
mov di, STAGE_BUFFER_OFFSET
|
|
call read_sectors
|
|
|
|
mov cx, [bpb.root_entry_count]
|
|
mov bx, STAGE_BUFFER_SEGMENT
|
|
mov ds, bx
|
|
mov si, STAGE_BUFFER_OFFSET
|
|
|
|
.check_entry:
|
|
mov bx, STAGE_BUFFER_SEGMENT
|
|
mov ds, bx
|
|
|
|
cmp byte [si], 0x00
|
|
je .no_more_entries
|
|
cmp byte [si], 0xE5
|
|
je .continue
|
|
|
|
push si
|
|
push cx
|
|
xor bx, bx
|
|
mov es, bx
|
|
mov di, kernel_filename
|
|
mov cx, 11
|
|
rep cmpsb
|
|
pop cx
|
|
pop si
|
|
je .found
|
|
|
|
.continue:
|
|
add si, 32
|
|
loop .check_entry
|
|
|
|
.no_more_entries:
|
|
mov ah, 0x0E
|
|
mov al, 'K'
|
|
int 0x10
|
|
jmp $
|
|
|
|
.found:
|
|
mov bx, STAGE_BUFFER_SEGMENT
|
|
mov ds, bx
|
|
|
|
mov ax, [si + 26]
|
|
|
|
xor bx, bx
|
|
mov ds, bx
|
|
|
|
mov [kernel_cluster], ax
|
|
|
|
load_fat:
|
|
xor bx, bx
|
|
mov ds, bx
|
|
|
|
xor eax, eax
|
|
mov ax, [fat_start]
|
|
mov cx, [bpb.sectors_per_fat]
|
|
mov bx, STAGE_BUFFER_SEGMENT
|
|
mov es, bx
|
|
mov di, STAGE_BUFFER_OFFSET
|
|
call read_sectors
|
|
|
|
load_kernel_cluster:
|
|
xor bx, bx
|
|
mov ds, bx
|
|
|
|
xor eax, eax
|
|
mov ax, [kernel_cluster]
|
|
sub ax, 2
|
|
xor bx, bx
|
|
mov bl, [bpb.sectors_per_cluster]
|
|
mul bx
|
|
add ax, [data_start]
|
|
xor cx, cx
|
|
mov cl, [bpb.sectors_per_cluster]
|
|
mov bx, KERNEL_BUFFER_SEGMENT
|
|
mov es, bx
|
|
mov di, [kernel_buffer_offset]
|
|
call read_sectors
|
|
|
|
mov ax, [bpb.sectors_per_cluster]
|
|
shl ax, 9 ; * 512
|
|
add ax, [kernel_buffer_offset]
|
|
mov [kernel_buffer_offset], ax
|
|
|
|
find_next_kernel_cluster:
|
|
xor bx, bx
|
|
mov ds, bx
|
|
|
|
mov si, [kernel_cluster]
|
|
shl si, 1 ; * 2
|
|
add si, STAGE_BUFFER_OFFSET
|
|
mov bx, STAGE_BUFFER_SEGMENT
|
|
mov ds, bx
|
|
mov ax, [si]
|
|
xor bx, bx
|
|
mov ds, bx
|
|
mov [kernel_cluster], ax
|
|
cmp ax, 0xFFF8
|
|
jb load_kernel_cluster
|
|
|
|
; ------------------------------------------------------------------------------
|
|
|
|
jmp load_gdt
|
|
|
|
gdt_start:
|
|
gdt_0: dq 0x0000000000000000
|
|
gdt_32_code:
|
|
.limit_low: dw 0xFFFF
|
|
.base_low: dw 0x0000
|
|
.base_middle: db 0x00
|
|
.access: db 10011010b ; present, ring 0, code, executable, readable
|
|
.flags: db 11001111b ; 32-bit, 4KB granularity
|
|
.base_high: db 0x00
|
|
gdt_32_code_end:
|
|
gdt_64_code:
|
|
.limit_low: dw 0xFFFF
|
|
.base_low: dw 0x0000
|
|
.base_middle: db 0x00
|
|
.access: db 10011010b ; present, ring 0, code, executable, readable
|
|
.flags: db 10101111b ; long mode (L bit)
|
|
.base_high: db 0x00
|
|
gdt_64_code_end:
|
|
gdt_data:
|
|
.limit_low: dw 0xFFFF
|
|
.base_low: dw 0x0000
|
|
.base_middle: db 0x00
|
|
.access: db 10010010b ; present, ring 0, data, writable
|
|
.flags: db 00000000b
|
|
.base_high: db 0x00
|
|
gdt_data_end:
|
|
gdt_end:
|
|
|
|
gdt_descriptor:
|
|
.size: dw gdt_end - gdt_start - 1
|
|
.offset: dd gdt_start
|
|
gdt_descriptor_end:
|
|
|
|
load_gdt:
|
|
cli
|
|
|
|
lgdt [gdt_descriptor]
|
|
|
|
mov eax, cr0
|
|
or eax, 0x00000001
|
|
mov cr0, eax
|
|
|
|
jmp 0x0008:protected_mode
|
|
|
|
; ------------------------------------------------------------------------------
|
|
|
|
bits 32
|
|
protected_mode:
|
|
mov ax, 0x0018 ; data segment is now third entry = 0x18
|
|
mov ds, ax
|
|
mov es, ax
|
|
mov ss, ax
|
|
mov esp, 0x00090000
|
|
|
|
; zero page table memory
|
|
mov edi, 0x00010000
|
|
mov ecx, 256 * 5
|
|
xor eax, eax
|
|
rep stosd
|
|
|
|
; PML4[0] -> PDPT at 0x00011000
|
|
mov dword [0x00010000], 0x00011003
|
|
; PML4[511] -> PDPT at 0x00012000
|
|
mov dword [0x00010FF8], 0x00012003
|
|
; PML4[0].PDPT[0] -> PD at 0x00013000
|
|
mov dword [0x00011000], 0x00013003
|
|
; PML4[511].PDPT[510] -> PD at 0x00014000
|
|
mov dword [0x00012FF0], 0x00014003
|
|
; PD: fill 64 entries, each mapping 2MB
|
|
mov edi, 0x00013000
|
|
mov eax, 0x00000083 ; present, writable, huge page, base 0
|
|
mov ecx, 64
|
|
|
|
.fill_pd:
|
|
mov ebx, edi
|
|
add ebx, 0x1000
|
|
mov dword [edi], eax
|
|
mov dword [ebx], eax
|
|
add edi, 8
|
|
add eax, 0x00200000 ; next 2MB
|
|
loop .fill_pd
|
|
|
|
; load PML4 into CR3
|
|
mov eax, 0x00010000
|
|
mov cr3, eax
|
|
|
|
; enable PAE
|
|
mov eax, cr4
|
|
or eax, 0x00000020
|
|
mov cr4, eax
|
|
|
|
; enable long mode in EFER MSR
|
|
mov ecx, 0xC0000080
|
|
rdmsr
|
|
or eax, 0x00000100
|
|
wrmsr
|
|
|
|
; enable paging (and keep protection enabled)
|
|
mov eax, cr0
|
|
or eax, 0x80000000
|
|
mov cr0, eax
|
|
|
|
jmp 0x0010:long_mode ; 0x10 = second entry = 64-bit code segment
|
|
|
|
; ------------------------------------------------------------------------------
|
|
|
|
bits 64
|
|
long_mode:
|
|
mov ax, 0x0018 ; data segment
|
|
mov ds, ax
|
|
mov es, ax
|
|
mov ss, ax
|
|
mov rsp, 0xFFFFFFFF80090000
|
|
|
|
xor rax, rax
|
|
xor rbx, rbx
|
|
xor rcx, rcx
|
|
xor rdx, rdx
|
|
|
|
jmp 0xFFFFFFFF80020000
|
|
|