forked from PoliEcho-holding-org/kern
Began work on new bootloader (KBOOT)
This commit is contained in:
+137
@@ -0,0 +1,137 @@
|
||||
; KBOOT - Kern Bootloader
|
||||
; Most of the code is taken from Limine (https://github.com/limine-bootloader/limine)
|
||||
; I tried to add more documentation than the Limine code had, but it's not everything
|
||||
; Any of my code is pretty bad, so i recommend using an existing bootloader
|
||||
|
||||
[org 0x7c00]
|
||||
[bits 16]
|
||||
|
||||
start:
|
||||
jmp .bpb_end
|
||||
|
||||
; Some BIOSes will override the FAT BPB area,
|
||||
; so we just fill it out to avoid pottentially
|
||||
; overriding bootloader code.
|
||||
; Source: https://github.com/limine-bootloader/limine/blob/trunk/stage1/hdd/bootsect.asm
|
||||
.bpb:
|
||||
times 3-($-$$) db 0
|
||||
.bpb_oem_id: db "KBOOT "
|
||||
.bpb_sector_size dw 512
|
||||
.bpb_sects_per_clust: db 0
|
||||
.bpb_reserved_sects: dw 0
|
||||
.bpb_fat_count: db 0
|
||||
.bpb_root_dir_entries: dw 0
|
||||
.bpb_sector_count: dw 0
|
||||
.bpb_media_type: db 0
|
||||
.bpb_sects_per_fat: dw 0
|
||||
.bpb_sects_per_track: dw 18
|
||||
.bpb_heads_count: dw 2
|
||||
.bpb_hidden_sects: dd 0
|
||||
.bpb_sect_count_big: dd 0
|
||||
.bpb_drive_num: db 0
|
||||
.bpb_reserved: db 0
|
||||
.bpb_signature: db 0
|
||||
.bpb_volume_id: dd 0
|
||||
.bpb_volume_label: db "KBOOT "
|
||||
.bpb_filesystem_type: times 8 db 0
|
||||
.bpb_end:
|
||||
cli
|
||||
cld
|
||||
jmp 0x0000:.init_codeseg ; Long jump to set CS = 0
|
||||
|
||||
; Zero out segment regs (Because segmentation is shit)
|
||||
.init_codeseg:
|
||||
xor si, si ; We cannot change segment regs directly
|
||||
mov ds, si ; Data Segment
|
||||
mov es, si ; Extra Segment
|
||||
mov ss, si ; Stack Segment
|
||||
mov sp, 0x7c00 ; Set Stack Pointer
|
||||
sti
|
||||
|
||||
; We probably won't be booting from a floppy, so
|
||||
; ignore if boot drive is < 0x80 and assume an error
|
||||
cmp dl, 0x80
|
||||
jl err.0
|
||||
; Also anything above 0x8f is "dubious" so we also
|
||||
; just assume an error
|
||||
cmp dl, 0x8f
|
||||
jg err.1
|
||||
|
||||
; Check that int 13h extensions are supported
|
||||
.int13chk:
|
||||
mov ah, 0x41
|
||||
mov bx, 0x55aa ; Expects bx to be this magic value
|
||||
int 0x13 ; Will se CF if unsupported
|
||||
jc err.2
|
||||
cmp bx, 0xaa55 ; Also sets bx to this magic
|
||||
jne err.3
|
||||
|
||||
; Load the stage 2 bootloader code to 0x70000
|
||||
.load_stage2:
|
||||
push 0x7000
|
||||
pop es ; ES = 0x7000
|
||||
xor bx, bx ; ES:BX = 0x70000
|
||||
mov eax, 512
|
||||
xor ebp, ebp
|
||||
mov ecx, 512
|
||||
call read_sectors
|
||||
jc err.4 ; CF was set -> failed to read from disk
|
||||
|
||||
.enable_protected:
|
||||
; Load GDT Pointer
|
||||
lgdt [gdtp]
|
||||
|
||||
; Set PE (Protected mode Enable) flag
|
||||
cli
|
||||
mov eax, cr0
|
||||
or eax, 1 ; Bit 1 - PE
|
||||
mov cr0, eax
|
||||
|
||||
; Far jump to protected mode
|
||||
jmp code_seg:vector
|
||||
|
||||
%include "disk.s" ; Disk I/O helper functions
|
||||
%include "gdt.s" ; Global Descriptor Table
|
||||
|
||||
; Handles an error
|
||||
err:
|
||||
; Error codes
|
||||
.4: inc si ; Failed to read stage2 from disk
|
||||
.3: inc si ; Int 13h extensions unsupported (BX wasn't magic)
|
||||
.2: inc si ; Int 13h extensions unsupported (CF was set)
|
||||
.1: inc si ; Invalid boot drive number (> 0x8f)
|
||||
.0: ; Invalid boot drive number (< 0x80)
|
||||
; Common error handler
|
||||
add si, '0' | (0x4f << 8) ; Store error code number char in SI, white on red
|
||||
push 0xb800 ; VGA Text mode video memory
|
||||
pop es ; ES = 0xb800
|
||||
mov word [es:0], si ; Write character
|
||||
|
||||
; Hang
|
||||
sti
|
||||
.h: hlt
|
||||
jmp .h
|
||||
|
||||
[bits 32]
|
||||
; Protected mode entry vector
|
||||
vector:
|
||||
mov eax, 0x10
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
mov ss, ax
|
||||
|
||||
and edx, 0xff
|
||||
|
||||
; Call stage 2 bootloader
|
||||
call 0x70000
|
||||
|
||||
; Padding and boot signature
|
||||
times 510-($-$$) db 0
|
||||
dw 0xaa55
|
||||
|
||||
; === STAGE 2 ===
|
||||
align 16
|
||||
incbin 'stage2.bin'
|
||||
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
; Reads sectors from disk
|
||||
; Args:
|
||||
; eax - LBA low 32 bits
|
||||
; ebp - LBA high 32 bits
|
||||
; dl - Drive number
|
||||
; es - Destination segment
|
||||
; bx - Destination offset
|
||||
; ecx - Byte count
|
||||
; Rets:
|
||||
; CF - Set on error
|
||||
read_sectors:
|
||||
pusha
|
||||
|
||||
; Fill out Disk Address Packet
|
||||
mov si, .da_packet
|
||||
mov word [si], 0x10 ; Packet Size and Unused
|
||||
mov word [si+2], 1 ; Sector count
|
||||
mov word [si+4], bx ; Dest. offset
|
||||
mov word [si+6], es ; Dest. segment
|
||||
|
||||
; Store some regs for later
|
||||
push dx
|
||||
push si
|
||||
push eax
|
||||
push ebp
|
||||
|
||||
; Get bytes per sector
|
||||
mov ah, 0x48 ; Extended read drive parameters
|
||||
mov si, .drive_params ; DS:SI - result buffer
|
||||
mov word [si], 0x1e ; Buffer size
|
||||
int 0x13
|
||||
jc .done ; CF set - error; we never pop ebp, eax, si & dx! (could cause issues)
|
||||
mov bp, word [si+24] ; Bytes per sector
|
||||
|
||||
; Convert byte count in ECX to sector count in CX
|
||||
mov ax, cx ; Low word
|
||||
shr ecx, 16 ; Shift high word into low word of ECX (therefore just CX)
|
||||
mov dx, cx ; High word
|
||||
xor cx, cx ; Clear CX
|
||||
div bp ; Divide byte count in ax (low word) by bytes per sector
|
||||
test dx, dx ; DX will contain remainder
|
||||
setnz cl ; (dx != 0) ? cl = 1 : cl = 0
|
||||
add cx, ax ; Add remaining sectors to cx
|
||||
|
||||
pop edx ; Restore pushed EBP to EDX
|
||||
pop eax ; Restore EAX
|
||||
pop si ; Restore SI
|
||||
|
||||
; Calculate destination LBA
|
||||
div ebp ; Divide EAX by EBP
|
||||
mov dword [si+8], eax ; LBA low
|
||||
mov dword [si+12], 0 ; LBA high
|
||||
|
||||
pop dx ; Restore DX
|
||||
|
||||
; Read sectors one by one
|
||||
.loop:
|
||||
mov ah, 0x42 ; Extended read
|
||||
clc ; Clear CF
|
||||
int 0x13
|
||||
jc .done ; Error
|
||||
|
||||
add word [si+4], bp ; Increment destination by sector byte count
|
||||
xor ebx, ebx ; EBX = 0
|
||||
inc dword [si+8] ; Increment LBA low
|
||||
seto bl ; Will set BL to 1 in case of overflow
|
||||
add dword [si+12], ebx ; Increment LBA high
|
||||
|
||||
loop .loop ; dec cx; jnz .loop
|
||||
|
||||
.done:
|
||||
popa
|
||||
ret
|
||||
|
||||
; Disk Address Packet
|
||||
.da_packet: equ 0x8000
|
||||
|
||||
; Drive Parameters from int 13h, ah = 0x48
|
||||
.drive_params: equ 0x8010
|
||||
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
; Global Descriptor Table
|
||||
gdt:
|
||||
.null_desc: ; Just zeros, no clue why it even exists
|
||||
dq 0
|
||||
.code_desc: ; 32-bit code
|
||||
dw 0xffff ; Limit (low 16-bits)
|
||||
dw 0x0000 ; Base (low 16 bits)
|
||||
db 0x00 ; Base (mid 8 bits)
|
||||
db 0b10011011 ; Access flags
|
||||
db 0b11001111 ; Low 4 bits - Granularity, High 4 bits - Limit (high 4 bits)
|
||||
db 0x00 ; Base (high 8 bits)
|
||||
.data_desc: ; 32-bit data
|
||||
dw 0xffff ; Limit (low 16-bits)
|
||||
dw 0x0000 ; Base (low 16 bits)
|
||||
db 0x00 ; Base (mid 8 bits)
|
||||
db 0b10010011 ; Access flags
|
||||
db 0b11001111 ; Low 4 bits - Granularity, High 4 bits - Limit (high 4 bits)
|
||||
db 0x00 ; Base (high 8 bits)
|
||||
.end:
|
||||
|
||||
; GDT Pointer
|
||||
gdtp:
|
||||
dw gdt.end - gdt - 1 ; Size
|
||||
dd gdt ; Pointer
|
||||
|
||||
; Segments
|
||||
code_seg equ gdt.code_desc - gdt
|
||||
data_seg equ gdt.data_desc - gdt
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
/* Third stage "prekernel" */
|
||||
OUTPUT_FORMAT("binary")
|
||||
|
||||
SECTIONS {
|
||||
.text 0x50000 : {
|
||||
*(entry);
|
||||
*(.text*);
|
||||
}
|
||||
.data : {
|
||||
*(.data*);
|
||||
}
|
||||
.rodata : {
|
||||
*(.rodata*);
|
||||
}
|
||||
.bss : {
|
||||
*(.bss*);
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
#
|
||||
# Bootloader
|
||||
#
|
||||
|
||||
include make.defaults
|
||||
|
||||
STAGE1 = $(BIN)/stage1.bin
|
||||
STAGE2 = $(BIN)/stage2.bin
|
||||
STAGE3 = $(BIN)/stage3.bin
|
||||
STAGE1_SRC = $(BOOT_DIR)/stage1.s
|
||||
STAGE2_SRC = $(BOOT_DIR)/stage2.s
|
||||
STAGE3_SRC = $(BOOT_DIR)/stage3.c
|
||||
STAGE3_OBJ = $(BIN)/boot/stage3.o
|
||||
|
||||
bootloader: $(STAGE1) $(STAGE2) $(STAGE3)
|
||||
|
||||
$(STAGE1): $(STAGE1_SRC)
|
||||
@echo "Assembling $<..."
|
||||
$(AS) -fbin -o $@ $< $(ASFLAGS)
|
||||
|
||||
$(STAGE2): $(STAGE2_SRC)
|
||||
@echo "Assembling $<..."
|
||||
$(AS) -fbin -o $@ $< $(ASFLAGS)
|
||||
|
||||
$(STAGE3): $(STAGE3_SRC)
|
||||
@echo "Compiling $(STAGE3_SRC)..."
|
||||
$(CC) $(CFLAGS) -I$(LIBK_INC) -I$(LIBC_INC) -o $(STAGE3_OBJ) -c $<
|
||||
$(LD) $(LDFLAGS) -T$(BOOT_DIR)/linker.ld -o $@ $(STAGE3_OBJ) $(LIBK)
|
||||
|
||||
-167
@@ -1,167 +0,0 @@
|
||||
[bits 16]
|
||||
[org 0x7c00]
|
||||
|
||||
%define SUPERBLOCK 0x8c00
|
||||
%define FIRST_INODE_BLOCK (SUPERBLOCK) + 18
|
||||
%define STAGE3_INODE 0xb000 + (2 * 64)
|
||||
%define EXTENT0 (STAGE3_INODE) + 14 ; Offset of extent[0] in inode_t
|
||||
|
||||
start:
|
||||
xor ax, ax
|
||||
mov es, ax
|
||||
mov ds, ax
|
||||
|
||||
mov byte [driveNum], dl
|
||||
|
||||
; Clear screen
|
||||
mov ax, 0x03
|
||||
int 0x10
|
||||
|
||||
;; Read in the boot block and the superblock to memory for 2nd stage bootloader
|
||||
mov al, 15 ; 8 - 1 for boot block - bootsector & 8 for super block
|
||||
mov bl, al
|
||||
dec bl ; Number of sectors - 1
|
||||
mov di, 0x7E00 ; Destination 0x7c00-0x8c00 = boot block, 0x8c00-0x9c00 = superblock
|
||||
|
||||
mov dx, 0x1F6 ; flags
|
||||
mov al, 0xE0 ; 0b0111 0000, bits: 0-3 = LBA bits 24-27, 4 = drive, 5 = always set, 6 = set for LBA, 7 = always set
|
||||
out dx, al
|
||||
|
||||
mov dx, 0x1F2 ; Sector count port
|
||||
mov al, 15 ; number of sectors to read
|
||||
out dx, al
|
||||
|
||||
inc dx ; 0x1F3 - LBA low
|
||||
mov al, 1 ; LBA 1 = 2nd disk sector (0-based), bits 0-7 of LBA
|
||||
out dx, al
|
||||
|
||||
inc dx ; 0x1F4 - LBA mid
|
||||
xor ax, ax ; bits 8-15 of LBA
|
||||
out dx, al
|
||||
|
||||
inc dx ; 0x1F5 - LBA high
|
||||
; xor ax, ax ; bits 16-23 of LBA
|
||||
out dx, al
|
||||
|
||||
inc dx
|
||||
inc dx ; 0x1F7 - Command port
|
||||
mov al, 0x20 ; Read with retry
|
||||
out dx, al
|
||||
|
||||
call loadSectorLoop
|
||||
|
||||
;; Parse superblock for first inode block, offset to reserved bootloader
|
||||
|
||||
;; Read first inode block to memory
|
||||
;; Each disk block is 4KB or 8 sectors of 512 bytes
|
||||
imul cx, [FIRST_INODE_BLOCK], 8 ; CX = disk sector/LBA of first inode block
|
||||
|
||||
mov bl, 7 ; 8 sectors for a block - 1
|
||||
mov di, 0xb000 ; Address to read into, first inode block = 0xB000-0xC000
|
||||
|
||||
mov dx, 0x1F6 ; flags
|
||||
mov al, 0xE0
|
||||
out dx, al
|
||||
|
||||
mov dx, 0x1F2
|
||||
mov al, 8
|
||||
out dx, al
|
||||
|
||||
inc dx
|
||||
mov al, cl
|
||||
out dx, al
|
||||
|
||||
inc dx
|
||||
mov al, ch
|
||||
out dx, al
|
||||
|
||||
inc dx
|
||||
xor ax, ax
|
||||
out dx, al
|
||||
|
||||
inc dx
|
||||
inc dx
|
||||
mov al, 0x20
|
||||
out dx, al
|
||||
|
||||
call loadSectorLoop
|
||||
|
||||
;; Read boot loader inode to memory
|
||||
;; inode 2, each inode is 64 bytes in size
|
||||
imul ecx, [EXTENT0], 8 ; first_block translated to disk sector/LBA
|
||||
imul ebx, [EXTENT0+4], 8 ; length_blocks translated to disk sectors/LBAs
|
||||
|
||||
mov dx, 0x1F2
|
||||
mov al, bl
|
||||
out dx, al
|
||||
|
||||
inc dx
|
||||
mov al, cl
|
||||
out dx, al
|
||||
|
||||
inc dx
|
||||
mov al, ch
|
||||
out dx, al
|
||||
|
||||
inc dx
|
||||
shr ecx, 16
|
||||
mov al, cl
|
||||
out dx, al
|
||||
|
||||
inc dx
|
||||
and ch, 0x0F
|
||||
mov al, ch
|
||||
or al, 0xE0
|
||||
out dx, al
|
||||
|
||||
inc dx
|
||||
mov al, 0x20
|
||||
out dx, al
|
||||
|
||||
dec bl
|
||||
mov ax, 0x5000
|
||||
mov es, ax
|
||||
xor di, di
|
||||
|
||||
call loadSectorLoop
|
||||
|
||||
xor ax, ax
|
||||
mov es, ax ; ES = 0x0000
|
||||
|
||||
;; Jump to 2nd stage bootloader here, does not return
|
||||
mov dl, [driveNum]
|
||||
jmp 0x0000:0x7E00
|
||||
|
||||
;; Poll status port after reading 1 sector
|
||||
loadSectorLoop:
|
||||
in al, dx ; Status register (reading port 1F7h)
|
||||
test al, 8 ; Sector buffer requires servicing
|
||||
je loadSectorLoop ; Keep trying until sector buffer is ready
|
||||
|
||||
mov cx, 256 ; # of words to read for 1 sector
|
||||
mov dx, 0x1F0 ; Data port, reading
|
||||
rep insw ; Read bytes from DX port # into DI, CX # of times
|
||||
|
||||
;; 400ns delay - Read alternate status register
|
||||
mov dx, 0x3F6
|
||||
in al, dx
|
||||
in al, dx
|
||||
in al, dx
|
||||
in al, dx
|
||||
|
||||
cmp bl, 0 ; Sector # to still read
|
||||
je .return
|
||||
|
||||
dec bl
|
||||
mov dx, 0x1F7
|
||||
jmp loadSectorLoop
|
||||
.return:
|
||||
ret
|
||||
|
||||
;; VARIABLES
|
||||
driveNum: db 0
|
||||
|
||||
;; Boot sector magic
|
||||
times 510-($-$$) db 0 ; Padding
|
||||
dw 0xaa55
|
||||
|
||||
-518
@@ -1,518 +0,0 @@
|
||||
[bits 16]
|
||||
[org 0x7e00]
|
||||
|
||||
%define STAGE3_LOC 0x50000
|
||||
%define MODE_INFO_BLOCK_LOC 0x6000
|
||||
|
||||
start:
|
||||
mov [driveNum], dl
|
||||
|
||||
; Physical memory map setup
|
||||
xor ax, ax
|
||||
mov es, ax
|
||||
|
||||
memMapEntries equ 0x7000
|
||||
getMemoryMap:
|
||||
mov di, memMapEntries + 4 ; 4 bytes after memMapEntries
|
||||
xor ebx, ebx
|
||||
xor bp, bp
|
||||
mov edx, "PAMS" ; SMAP in little endian
|
||||
mov eax, 0xe820
|
||||
mov dword [es:di+20], 1 ; Force valid ACPI 3.X entry
|
||||
mov ecx, 24
|
||||
int 0x15
|
||||
jc .error
|
||||
|
||||
cmp eax, "PAMS"
|
||||
jne .error
|
||||
test ebx, ebx
|
||||
jnz .start
|
||||
|
||||
.error:
|
||||
stc
|
||||
jmp inputGfx
|
||||
|
||||
.nextEntry:
|
||||
mov edx, "PAMS" ; In case BIOS messes with edx
|
||||
mov ecx, 24
|
||||
mov eax, 0xe820
|
||||
int 0x15
|
||||
|
||||
.start:
|
||||
jcxz .skipEntry
|
||||
mov ecx, [es:di+8] ; Low 32 bits of length
|
||||
or ecx, [es:di+12] ; High 32 bits of length
|
||||
jz .skipEntry
|
||||
|
||||
; Valid entry
|
||||
inc bp
|
||||
add di, 24 ; Next entry
|
||||
|
||||
.skipEntry:
|
||||
test ebx, ebx
|
||||
jz .done
|
||||
jmp .nextEntry
|
||||
|
||||
.done:
|
||||
mov [memMapEntries], bp
|
||||
clc
|
||||
|
||||
;; Get graphics values from user (resolution etc.)
|
||||
inputGfx:
|
||||
xor ecx, ecx
|
||||
cmp word [width], 0 ; Values already set
|
||||
jne vbeSetup
|
||||
mov si, gfxChooseMsg
|
||||
call print
|
||||
call getNumber ; Stores input value in bx
|
||||
mov [width], bx
|
||||
|
||||
mov si, gfxHeightMsg
|
||||
call print
|
||||
call getNumber
|
||||
mov [height], bx
|
||||
|
||||
mov si, gfxBppMsg
|
||||
call print
|
||||
call getNumber
|
||||
mov [bpp], bx
|
||||
|
||||
vbeSetup:
|
||||
; Setup VBE info
|
||||
xor ax, ax
|
||||
mov es, ax
|
||||
mov ax, 0x4f00
|
||||
mov di, vbeInfoBlock
|
||||
int 0x10
|
||||
|
||||
cmp ax, 0x4f
|
||||
jne error
|
||||
|
||||
mov ax, word [vbeInfoBlock.videoModePtr]
|
||||
mov [offset], ax
|
||||
mov ax, word [vbeInfoBlock.videoModePtr+2]
|
||||
mov [_segment], ax
|
||||
|
||||
mov fs, ax
|
||||
mov si, [offset]
|
||||
|
||||
;; Get next VBE mode
|
||||
.findMode:
|
||||
mov dx, [fs:si]
|
||||
inc si
|
||||
inc si
|
||||
mov [offset], si
|
||||
mov [mode], dx
|
||||
|
||||
cmp dx, 0xffff ; Indicates end of modes
|
||||
je .endOfModes
|
||||
|
||||
mov ax, 0x4f01 ; Get VBE mode info
|
||||
mov cx, [mode]
|
||||
mov di, modeInfoBlock
|
||||
int 0x10
|
||||
|
||||
cmp ax, 0x4f
|
||||
jne error
|
||||
|
||||
; Print values (Debug)
|
||||
; mov ax, [modeInfoBlock.xRes]
|
||||
; ror ax, 8
|
||||
; call printHex
|
||||
; ror ax, 8
|
||||
; call printHex
|
||||
; mov ax, 0x0e20
|
||||
; int 0x10
|
||||
; mov ax, [modeInfoBlock.yRes]
|
||||
; ror ax, 8
|
||||
; call printHex
|
||||
; ror ax, 8
|
||||
; call printHex
|
||||
; mov ax, 0x0e20
|
||||
; int 0x10
|
||||
; xor ax, ax
|
||||
; mov al, [modeInfoBlock.bpp]
|
||||
; call printHex
|
||||
; mov ax, 0x0e20
|
||||
; int 0x10
|
||||
; mov al, 0x0a
|
||||
; int 0x10
|
||||
; mov al, 0x0d
|
||||
; int 0x10
|
||||
|
||||
; Check if it is the right mode
|
||||
mov ax, [width]
|
||||
cmp ax, [modeInfoBlock.xRes]
|
||||
jne .nextMode
|
||||
|
||||
mov ax, [height]
|
||||
cmp ax, [modeInfoBlock.yRes]
|
||||
jne .nextMode
|
||||
|
||||
mov al, [bpp]
|
||||
cmp al, [modeInfoBlock.bpp]
|
||||
jne .nextMode
|
||||
|
||||
; Set VBE mode
|
||||
mov ax, 0x4f02
|
||||
mov bx, [mode]
|
||||
or bx, 0x4000 ; Set 14th bit to 1
|
||||
xor di, di
|
||||
int 0x10
|
||||
|
||||
cmp ax, 0x4f
|
||||
jne error
|
||||
|
||||
jmp checkA20
|
||||
|
||||
.nextMode:
|
||||
mov ax, [_segment]
|
||||
mov fs, ax
|
||||
mov si, [offset]
|
||||
jmp .findMode
|
||||
|
||||
.endOfModes:
|
||||
mov ax, 0x03
|
||||
int 0x10 ; Clear screen
|
||||
mov si, gfxModeNotFoundErr
|
||||
call print
|
||||
mov word [width], 0 ; Unset values
|
||||
jmp inputGfx
|
||||
|
||||
error:
|
||||
mov si, vbeErr
|
||||
call print
|
||||
cli
|
||||
hlt
|
||||
|
||||
;; Enables the A20 line
|
||||
enableA20:
|
||||
in al, 0x92
|
||||
or al, 2
|
||||
out 0x92, al
|
||||
|
||||
;; Check if the A20 line is enabled
|
||||
checkA20:
|
||||
push ds
|
||||
push es
|
||||
push di
|
||||
push si
|
||||
|
||||
cli
|
||||
xor ax, ax ; ax = 0
|
||||
mov es, ax ; es = 0
|
||||
not ax ; ax = 0xffff
|
||||
mov ds, ax ; ds = 0xffff
|
||||
|
||||
mov di, 0x0500
|
||||
mov si, 0x0510
|
||||
|
||||
mov al, byte [es:di]
|
||||
push ax
|
||||
mov al, byte [ds:si]
|
||||
push ax
|
||||
|
||||
mov byte [es:di], 0x00
|
||||
mov byte [ds:si], 0xff
|
||||
|
||||
cmp byte [es:di], 0xff
|
||||
|
||||
pop ax
|
||||
mov byte [ds:si], al
|
||||
pop ax
|
||||
mov byte [es:di], al
|
||||
|
||||
mov ax, 0
|
||||
jne enableA20
|
||||
|
||||
pop si
|
||||
pop di
|
||||
pop es
|
||||
pop ds
|
||||
|
||||
;; Load the global descriptor table (GDT)
|
||||
loadGDT:
|
||||
cli
|
||||
lgdt [GDT_Descriptor]
|
||||
; Enable protected mode
|
||||
mov eax, cr0
|
||||
or eax, 1
|
||||
mov cr0, eax
|
||||
|
||||
; Far jump to 32 bit mode!!
|
||||
jmp CODE_SEG:protected_start
|
||||
|
||||
|
||||
;;
|
||||
;; Prints a hex byte
|
||||
;; al - value to print
|
||||
;;
|
||||
printHex:
|
||||
push ax
|
||||
push bx
|
||||
|
||||
mov bh, 2
|
||||
mov bl, al
|
||||
and al, 0xf0
|
||||
ror al, 4
|
||||
mov ah, 0x0e ; For printing
|
||||
.printNibble:
|
||||
cmp al, 10
|
||||
jl .print
|
||||
add al, 39
|
||||
.print:
|
||||
add al, 48 ; ASCII Char
|
||||
int 0x10
|
||||
dec bh
|
||||
jz .done
|
||||
mov al, bl
|
||||
and al, 0x0f
|
||||
jmp .printNibble
|
||||
.done:
|
||||
pop bx
|
||||
pop ax
|
||||
ret
|
||||
|
||||
;;
|
||||
;; Prints a null terminated string
|
||||
;; si - pointer to string
|
||||
;;
|
||||
print:
|
||||
push ax
|
||||
mov ah, 0x0e
|
||||
.loop:
|
||||
lodsb ; mov al, [si] inc si
|
||||
cmp al, 0
|
||||
je .done
|
||||
int 0x10
|
||||
jmp .loop
|
||||
.done:
|
||||
pop ax
|
||||
ret
|
||||
|
||||
;;
|
||||
;; Reads a base 10 number as input from user
|
||||
;; Returns:
|
||||
;; bx - number read
|
||||
;;
|
||||
getNumber: ; TODO: if user enters a number that overflows (n > 0xffff) shit breaks
|
||||
push cx
|
||||
push ax
|
||||
push dx
|
||||
xor bx, bx
|
||||
mov cx, 10
|
||||
.nextDigit:
|
||||
xor ah, ah
|
||||
int 0x16
|
||||
mov ah, 0x0e
|
||||
|
||||
cmp al, 0x08 ; Backspace
|
||||
je .backspace
|
||||
cmp al, 0x0d ; Enter
|
||||
je .enter
|
||||
|
||||
cmp al, '0' ; Make sure user entered a number
|
||||
jl .nextDigit
|
||||
cmp al, '9'
|
||||
jg .nextDigit
|
||||
|
||||
int 0x10 ; Print the digit
|
||||
|
||||
sub al, '0' ; Convert to integer
|
||||
mov ah, 0
|
||||
imul bx, bx, 10 ; bx *= 10
|
||||
add bx, ax ; bx += ax
|
||||
jmp .nextDigit
|
||||
|
||||
.backspace:
|
||||
cmp bx, 0 ; Check if we can backspace
|
||||
je .nextDigit
|
||||
int 0x10 ; go back one space
|
||||
|
||||
mov ax, bx
|
||||
xor dx, dx
|
||||
div cx ; dx:ax / cx -> ax = result, dx = remainder
|
||||
mov bx, ax
|
||||
|
||||
mov ah, 0x0e
|
||||
mov al, ' '
|
||||
int 0x10
|
||||
mov al, 0x08
|
||||
int 0x10
|
||||
|
||||
jmp .nextDigit
|
||||
|
||||
.enter:
|
||||
pop dx
|
||||
pop ax
|
||||
pop cx
|
||||
ret
|
||||
|
||||
;; 32 Bit entry code
|
||||
[bits 32]
|
||||
protected_start:
|
||||
; Set up data and stack segments
|
||||
mov ax, DATA_SEG
|
||||
mov ds, ax
|
||||
mov ss, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
|
||||
; Set up the stack pointer in protected mode
|
||||
mov ebp, 0x90000
|
||||
mov esp, ebp
|
||||
|
||||
; Store VBE Mode Info Block in memory
|
||||
mov esi, modeInfoBlock
|
||||
mov edi, MODE_INFO_BLOCK_LOC ; Destination
|
||||
mov ecx, 64 ; 64 * 4 = 256B (size of modeInfoBlock)
|
||||
rep movsd
|
||||
|
||||
; Perform The far jump
|
||||
jmp CODE_SEG:STAGE3_LOC
|
||||
|
||||
;; Data
|
||||
driveNum: db 0
|
||||
|
||||
vbeErr: db "VBE Error!", 0
|
||||
acpiFuncErr: db "ACPI Function not supported!", 0
|
||||
|
||||
gfxChooseMsg: db "Please enter desired values" ; No NULL terminator, we want to print gfxWidthMsg right after anyway
|
||||
gfxWidthMsg: db 0x0a, 0x0d, "Width: ", 0
|
||||
gfxHeightMsg: db 0x0a, 0x0d, "Height: ", 0
|
||||
gfxBppMsg: db 0x0a, 0x0d, "Bits Per Pixel: ", 0
|
||||
gfxModeNotFoundErr: db "Mode not found! ", 0
|
||||
|
||||
;; GDT
|
||||
GDT:
|
||||
.start:
|
||||
.nullDescriptor: ; No clue why this exists
|
||||
dd 0
|
||||
dd 0
|
||||
.codeDescriptor: ; Memory for code
|
||||
dw 0xffff ; First 16 bits of limit
|
||||
dw 0 ; 16 bits +
|
||||
db 0 ; + 8 bits = 24 bits
|
||||
db 0b10011010 ; p, dpl, s, type flags
|
||||
db 0b11001111 ; Other flags, last 4 bits of limit
|
||||
db 0 ; Base
|
||||
.dataDescriptor: ; Memory for data
|
||||
dw 0xffff ; First 16 bits of limit
|
||||
dw 0 ; 16 bits +
|
||||
db 0 ; + 8 bits = 24 bits
|
||||
db 0b10010010 ; p, dpl, s, type flags
|
||||
db 0b11001111 ; Other flags, last 4 bits of limit
|
||||
db 0 ; Base
|
||||
.end:
|
||||
|
||||
GDT_Descriptor:
|
||||
dw GDT.end - GDT.start - 1 ; Size
|
||||
dd GDT.start ; GDT Pointer
|
||||
|
||||
CODE_SEG equ GDT.codeDescriptor - GDT.start
|
||||
DATA_SEG equ GDT.dataDescriptor - GDT.start
|
||||
|
||||
;; VBE Stuff
|
||||
; Default width
|
||||
%ifndef DEF_W
|
||||
%define DEF_W 0
|
||||
%endif
|
||||
; Default height
|
||||
%ifndef DEF_H
|
||||
%define DEF_H 0
|
||||
%endif
|
||||
; Default bpp
|
||||
%ifndef DEF_BPP
|
||||
%define DEF_BPP 0
|
||||
%endif
|
||||
; Use defaults
|
||||
%ifdef DEF_RES
|
||||
width: dw DEF_W
|
||||
%else
|
||||
width: dw 0
|
||||
%endif
|
||||
height: dw DEF_H
|
||||
bpp: db DEF_BPP
|
||||
|
||||
offset: dw 0
|
||||
_segment: dw 0 ; segment is a keyword
|
||||
mode: dw 0
|
||||
|
||||
times (512*2)-($-$$) db 0 ; End Sector 2
|
||||
|
||||
;; Sector 2
|
||||
vbeInfoBlock:
|
||||
.vbeSigniture: db "VBE2"
|
||||
.vbeVersion: dw 0x0300 ; BCD Version
|
||||
.oemStringPtr: dd 0
|
||||
.capibilities: dd 0
|
||||
.videoModePtr: dd 0
|
||||
.totalMemory: dw 0
|
||||
.oemSoftwareRev: dw 0
|
||||
.oemVendorNamePtr: dd 0
|
||||
.oemProductNamePtr: dd 0
|
||||
.oemProductRevisionPtr: dd 0
|
||||
.reserved: times 222 db 0
|
||||
.oemData: times 256 db 0
|
||||
|
||||
;; Sector 3
|
||||
modeInfoBlock:
|
||||
;; Required by all VBE revisions
|
||||
.modeAttr: dw 0
|
||||
.windowAAtrr: db 0
|
||||
.windowBAttr: db 0
|
||||
.windowGranularity: dw 0
|
||||
.windowSize: dw 0
|
||||
.windowASegment: dw 0
|
||||
.windowBSegment: dw 0
|
||||
.windowFunctionPtr: dd 0
|
||||
.bytesPerScanline: dw 0
|
||||
|
||||
;; Required by VBE 1.2+
|
||||
.xRes: dw 0
|
||||
.yRes: dw 0
|
||||
.xCharSize: db 0
|
||||
.yCharSize: db 0
|
||||
.planeCount: db 0
|
||||
.bpp: db 0
|
||||
.bankCount: db 0
|
||||
.memoryModel: db 0
|
||||
.bankSize: db 0
|
||||
.imagePageCount: db 0
|
||||
.reserved1: db 1
|
||||
|
||||
;; Direct color fields
|
||||
.redMaskSize: db 0
|
||||
.redFieldPos: db 0
|
||||
.greenMaskSize: db 0
|
||||
.greenFieldPos: db 0
|
||||
.blueMaskSize: db 0
|
||||
.blueFieldPos: db 0
|
||||
.reservedMaskSize: db 0
|
||||
.reservedFieldPos: db 0
|
||||
.directColorModeInfo: db 0
|
||||
|
||||
;; Required by VBE 2.0+
|
||||
.physicalBasePtr: dd 0
|
||||
.reserved2: dd 0
|
||||
.reserved3: dw 0
|
||||
|
||||
;; Required by VBE 3.0+
|
||||
.linearBytesPerScanline: dw 0
|
||||
.bankImagePageCount: db 0
|
||||
.linearImagePageCount: db 0
|
||||
.linearRedMaskSize: db 0
|
||||
.linearRedFieldPos: db 0
|
||||
.linearGreenMaskSize: db 0
|
||||
.linearGreenFieldPos: db 0
|
||||
.linearBlueMaskSize: db 0
|
||||
.linearBlueFieldPos: db 0
|
||||
.linearReservedMaskSize: db 0
|
||||
.linearReservedFieldPos: db 0
|
||||
.maxPixelClock: dd 0
|
||||
|
||||
.reserved4: times 190 db 0
|
||||
|
||||
times (512*4)-($-$$) db 0
|
||||
|
||||
-138
@@ -1,138 +0,0 @@
|
||||
#include <memory/physical.h>
|
||||
#include <memory/virtual.h>
|
||||
#include <memory/addresses.h>
|
||||
#include <screen/gfxmode.h>
|
||||
#include <screen/text.h>
|
||||
#include <drivers/disk.h>
|
||||
#include <fs/kernfs.h>
|
||||
#include <fs/fs.h>
|
||||
|
||||
void bigError(uint32_t err);
|
||||
|
||||
__attribute__ ((section("entry")))
|
||||
void main() {
|
||||
// Physical memory manager setup
|
||||
uint32_t smapEntryCount = *(uint32_t*)SMAP_ENTRY_COUNT;
|
||||
smapEntry_t* smapEntries = (smapEntry_t*)SMAP_ENTRIES;
|
||||
smapEntries += smapEntryCount - 1;
|
||||
uint32_t totalMemory = smapEntries->baseAddress + smapEntries->length - 1;
|
||||
|
||||
setupPhysicalMemoryManager(MEMMAP_AREA, totalMemory);
|
||||
|
||||
smapEntries = (smapEntry_t*)SMAP_ENTRIES;
|
||||
for (uint32_t i = 0; i < smapEntryCount; i++) {
|
||||
if (smapEntries[i].type == 1) {
|
||||
initMemoryRegion(smapEntries[i].baseAddress, smapEntries[i].length);
|
||||
}
|
||||
}
|
||||
|
||||
deinitMemoryRegion(0x1000, 0x11fff); // Reserve kernel memory (under 0x12000)
|
||||
deinitMemoryRegion(MEMMAP_AREA, maxBlocks / BLOCKS_PER_BYTE);
|
||||
|
||||
// Load root dir, find kernel INode and parse it
|
||||
superblock_t* sb = (superblock_t*)SUPERBLOCK_LOC;
|
||||
sb->rootInodePtr = BOOT_FIRST_INODE_LOC + sizeof(inode_t);
|
||||
inode_t* root = (inode_t*)sb->rootInodePtr;
|
||||
loadFile(root, (void*)SCRATCH_BLOCK_LOC);
|
||||
|
||||
inode_t* inode;
|
||||
if ((inode = getInode("kernel.bin", (dirEntry_t*)SCRATCH_BLOCK_LOC)) == NULL) {
|
||||
// kernel.bin doesn't exist??? very bad -> error
|
||||
bigError(0xDEAD);
|
||||
} else { loadFile(inode, (void*)KERNEL_LOC); }
|
||||
|
||||
font_t* font = (font_t*)FONT_LOC;
|
||||
if ((inode = getInode("term16n.fnt", (dirEntry_t*)SCRATCH_BLOCK_LOC)) != NULL) {
|
||||
loadFile(inode, font);
|
||||
} else if ((inode = getInode("testfont.fnt", (dirEntry_t*)SCRATCH_BLOCK_LOC)) != NULL) {
|
||||
loadFile(inode, font);
|
||||
} else {
|
||||
// No font found, bad.
|
||||
bigError(0xBeef);
|
||||
}
|
||||
|
||||
// Virtual memory manager setup
|
||||
if (setupVirtualMemoryManager() != 0) {
|
||||
bigError(0xCafe);
|
||||
}
|
||||
|
||||
// Identity map VBE framebuffer
|
||||
uint32_t fbSize = (gfxMode->yRes * gfxMode->linearBytesPerScanline) / PAGE_SIZE;
|
||||
if (fbSize % PAGE_SIZE > 0) { fbSize++; }
|
||||
fbSize *= 2; // Double for hardware
|
||||
for (uint32_t i = 0, fbStart = gfxMode->physicalBasePtr; i < fbSize; i++, fbStart += PAGE_SIZE) {
|
||||
mapPage((void*)fbStart, (void*)fbStart);
|
||||
}
|
||||
deinitMemoryRegion(gfxMode->physicalBasePtr, fbSize * BLOCK_SIZE);
|
||||
|
||||
*(uint32_t*)PHYS_MEM_MAX_BLOCKS = maxBlocks;
|
||||
*(uint32_t*)PHYS_MEM_USED_BLOCKS = usedBlocks;
|
||||
|
||||
for (uint32_t virt = KERNEL_LOC; virt < 0x400000; virt += PAGE_SIZE) {
|
||||
unmapPage((void*)virt);
|
||||
}
|
||||
|
||||
__asm__ volatile ("movl %cr3, %ecx; movl %ecx, %cr3");
|
||||
|
||||
*(uint32_t*)CURRENT_PAGE_DIR_ADDR = (uint32_t)currentPd;
|
||||
|
||||
// Call/jump to kernel
|
||||
((void(*)(void))0xC0000000)();
|
||||
bigError(0xffffffff);
|
||||
}
|
||||
|
||||
void rect(uint32_t c, uint16_t x, uint16_t y, uint16_t w, uint16_t h) {
|
||||
uint8_t* vidmem = (uint8_t*)gfxMode->physicalBasePtr;
|
||||
uint8_t bytesPerPx = gfxMode->bpp / 8;
|
||||
uint32_t convColor = convertColor(c);
|
||||
|
||||
for (uint32_t dx = 0; dx < w; dx++) {
|
||||
for (uint32_t dy = 0; dy < h; dy++) {
|
||||
uint32_t offset = (((y + dy) * gfxMode->xRes) + (x + dx)) * bytesPerPx;
|
||||
|
||||
for (uint8_t i = 0; i < gfxMode->bpp; i++) {
|
||||
vidmem[offset + i] = (uint8_t)(convColor >> (i*8));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bigError(uint32_t err) {
|
||||
// Red BG
|
||||
rect(0x00ff0000, 0, 0, gfxMode->xRes, gfxMode->yRes);
|
||||
// E
|
||||
rect(0x00ffffff, 20, 10, 10, 50);
|
||||
rect(0x00ffffff, 30, 10, 30, 10);
|
||||
rect(0x00ffffff, 30, 30, 30, 10);
|
||||
rect(0x00ffffff, 30, 50, 30, 10);
|
||||
// R
|
||||
rect(0x00ffffff, 70, 10, 10, 50);
|
||||
rect(0x00ffffff, 70, 10, 30, 10);
|
||||
rect(0x00ffffff, 70, 30, 30, 10);
|
||||
rect(0x00ffffff, 90, 10, 10, 30);
|
||||
rect(0x00ffffff, 80, 40, 10, 10);
|
||||
rect(0x00ffffff, 90, 50, 10, 10);
|
||||
// R
|
||||
rect(0x00ffffff, 110, 10, 10, 50);
|
||||
rect(0x00ffffff, 110, 10, 30, 10);
|
||||
rect(0x00ffffff, 110, 30, 30, 10);
|
||||
rect(0x00ffffff, 130, 10, 10, 30);
|
||||
rect(0x00ffffff, 120, 40, 10, 10);
|
||||
rect(0x00ffffff, 130, 50, 10, 10);
|
||||
// O
|
||||
rect(0x00ffffff, 150, 10, 10, 50);
|
||||
rect(0x00ffffff, 170, 10, 10, 50);
|
||||
rect(0x00ffffff, 150, 10, 30, 10);
|
||||
rect(0x00ffffff, 150, 50, 30, 10);
|
||||
// R
|
||||
rect(0x00ffffff, 190, 10, 10, 50);
|
||||
rect(0x00ffffff, 190, 10, 30, 10);
|
||||
rect(0x00ffffff, 190, 30, 30, 10);
|
||||
rect(0x00ffffff, 210, 10, 10, 30);
|
||||
rect(0x00ffffff, 200, 40, 10, 10);
|
||||
rect(0x00ffffff, 210, 50, 10, 10);
|
||||
|
||||
__asm__ volatile ("cli; hlt" :: "a"(err));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user