Clean-up and conveniance for mbr and loader

This commit is contained in:
Adrien Bourmault 2018-12-22 23:58:46 +01:00
parent bcff95e6d0
commit a805431f7c
8 changed files with 55 additions and 343 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -29,7 +29,7 @@ SYSTDIR=kaleid/system
all: bootloader all: bootloader
boot.mbr.s: $(BOOTDIR)/mbr.s boot.mbr.s: $(BOOTDIR)/mbr.s $(BOOTDIR)/mbr.inc
$(ASM) $(BOOTFLAGS) $(BOOTDIR)/mbr.s -o $(OBJDIR)/boot/mbr.bin $(ASM) $(BOOTFLAGS) $(BOOTDIR)/mbr.s -o $(OBJDIR)/boot/mbr.bin
boot.loader.s: $(BOOTDIR)/loader.s boot.loader.s: $(BOOTDIR)/loader.s

View File

@ -7,8 +7,12 @@
; Desc: Kernel (second stage) Loader for OS/K ; ; Desc: Kernel (second stage) Loader for OS/K ;
; (x86_64 architecture only) ; ; (x86_64 architecture only) ;
;=----------------------------------------------------------------------------=; ;=----------------------------------------------------------------------------=;
;;VIDEO
%define TRAM 0x0B8000 ; [T]ext[RAM] %define TRAM 0x0B8000 ; [T]ext[RAM]
%define VRAM 0x0A0000 ; [V]ideo[RAM] %define VRAM 0x0A0000 ; [V]ideo[RAM]
;; BPB
%define OEMName bp+0x03 ; Disk label %define OEMName bp+0x03 ; Disk label
%define bytesPerSector bp+0x0b ; Bytes per sector %define bytesPerSector bp+0x0b ; Bytes per sector
%define sectorsPerCluster bp+0x0d ; Sectors per cluster %define sectorsPerCluster bp+0x0d ; Sectors per cluster
@ -32,9 +36,9 @@
[BITS 16] [BITS 16]
[ORG 0x1000] [ORG 0x1000]
mov ax, cs mov ax, cs ; correcting cs after the horrible far jump
mov ds, ax mov ds, ax ; hm... And ds too
mov es, ax mov es, ax ; And es because it is jealous
mov [Bootdrv], dl mov [Bootdrv], dl
jmp 0x0000:main jmp 0x0000:main
@ -52,8 +56,8 @@ GDT64:
dw GDT64 ; linear address of GDT dw GDT64 ; linear address of GDT
dd 0x0 dd 0x0
CODE_SELECTOR: ;; 32-bit code selector (ring 0) CODE_SELECTOR: ;; 32-bit code selector (ring 0)
dw 0x0FFFF ; Segment Limit 15:00 dw 0x0FFFF ; Segment Limit
db 0x0, 0x0, 0x0 ; Base Address 23:00 db 0x0, 0x0, 0x0 ; Base Address
db 10011010b ; |7|6|5|4|3|2|1|0| db 10011010b ; |7|6|5|4|3|2|1|0|
; | | | | | | | `----- 1 when segment used. ; | | | | | | | `----- 1 when segment used.
; | | | | | | `------ 1 when writable. ; | | | | | | `------ 1 when writable.
@ -72,11 +76,11 @@ GDT64:
; | | `---------- 0 always ; | | `---------- 0 always
; | `----------- size of data. 1 for 32bits ; | `----------- size of data. 1 for 32bits
; `------------ 0 if limit is in Bytes, 1 if it's in pages (4ko) ; `------------ 0 if limit is in Bytes, 1 if it's in pages (4ko)
db 0x0 ; Base Address 31:24 db 0x0 ; Base Address
DATA_SELECTOR: ;; flat data selector (ring 0) DATA_SELECTOR: ;; flat data selector (ring 0)
dw 0x0FFFF ; Segment Limit 15:00 dw 0x0FFFF ; Segment Limit
db 0x0, 0x0, 0x0 ; Base Address 23:00 db 0x0, 0x0, 0x0 ; Base Address
db 10010010b ; |7|6|5|4|3|2|1|0| db 10010010b ; |7|6|5|4|3|2|1|0|
; | | | | | | | `----- 1 when segment used. ; | | | | | | | `----- 1 when segment used.
; | | | | | | `------ 1 when writable. ; | | | | | | `------ 1 when writable.
@ -95,11 +99,11 @@ GDT64:
; | | `---------- 0 always ; | | `---------- 0 always
; | `----------- size of data. 1 for 32bits ; | `----------- size of data. 1 for 32bits
; `------------ 0 if limit is in Bytes, 1 if it's in pages (4ko) ; `------------ 0 if limit is in Bytes, 1 if it's in pages (4ko)
db 0x0 ; Base Address 31:24 db 0x0 ; Base Address
LONG_SELECTOR: ;; 64-bit code selector (ring 0) LONG_SELECTOR: ;; 64-bit code selector (ring 0)
dw 0x0FFFF ; Segment Limit 15:00 dw 0x0FFFF ; Segment Limit
db 0x0, 0x0, 0x0 ; Base Address 23:00 db 0x0, 0x0, 0x0 ; Base Address
db 10011010b ; |7|6|5|4|3|2|1|0| db 10011010b ; |7|6|5|4|3|2|1|0|
; | | | | | | | `----- 1 when segment used. ; | | | | | | | `----- 1 when segment used.
; | | | | | | `------ 1 when writable. ; | | | | | | `------ 1 when writable.
@ -118,89 +122,10 @@ GDT64:
; | | `---------- 0 always ; | | `---------- 0 always
; | `----------- size of data. 1 for 32bits ; | `----------- size of data. 1 for 32bits
; `------------ 0 if limit is in Bytes, 1 if it's in pages (4ko) ; `------------ 0 if limit is in Bytes, 1 if it's in pages (4ko)
db 0x0 ; Base Address 31:24 db 0x0 ; Base Address
GDT_LENGTH: GDT_LENGTH:
disable_cursor: %include "boot/loader16.inc"
pushf
push eax
push edx
mov dx, 0x3D4
mov al, 0xA ; low cursor shape register
out dx, al
inc dx
mov al, 0x20 ; bits 6-7 unused, bit 5 disables the cursor, bits 0-4 control the cursor shape
out dx, al
pop edx
pop eax
popf
ret
get_dimensions:
push eax
push ebx
mov ah, 0x0F
int 0x10
mov [VGA_HEIGHT], ah
mov [VIDEO_MODE], al
pop ebx
pop eax
ret
;-----------------------------------------------------------------------;
; Checks if the CPU is compatible with 64-bits operating systems ;
; If the 21th bit of the eax register is set, then CPUID is supported ;
; We then test CPUID's result to see if long mode is supported ;
;-----------------------------------------------------------------------;
Is64bits:
pushfd ; recovering the flags in eax
pop eax
mov ecx, eax
xor eax, 0x200000
push eax
popfd
pushfd
pop eax
xor eax, ecx
shr eax, 21
and eax, 1 ; magical spell of murta
push ecx
popfd
test eax, eax
jz .NonCompat ; if (CPUID non supporté) goto NonCompat
mov eax, 0x80000000
cpuid
cmp eax, 0x80000001
jb .NonCompat ; if (eax <= 0x80000001) goto NonCompat
mov eax, 0x80000001
cpuid
test edx, 1 << 29
jz .NonCompat ; if (edx != 1 << 29) goto NonCompat
ret ; back to mbr.s
.NonCompat:
stc
ret
PrintB:
;---------------------------------------------------;
; Print out a simple string. ;
; ;
; Expects: DS:SI = String to print ;
; ;
; Returns: None ;
; ;
;---------------------------------------------------;
lodsb ; Load byte from ds:si to al
or al, al ; If al is empty stop looping
jz .done ; Done looping and return
mov ah, 0x0e ; Teletype output
int 0x10 ; Video interupt
jmp PrintB ; Loop untill string is null
.done:
ret
main: main:
;; compatibility check ;; compatibility check
@ -309,73 +234,11 @@ main32:
jmp (LONG_SELECTOR-GDT64):main64 jmp (LONG_SELECTOR-GDT64):main64
[BITS 64] [BITS 64]
;; FUNCTIONS
clear:
;-----------------------------------------------------------------------;
; x64/LM Clear Text Screen Function ;
;-----------------------------------------------------------------------;
mov qword [NextTRAM], TRAM
mov edi, TRAM
push rsi
push rdi
push rcx
mov ah, 0
mov al, 0
mov rcx, 0x4000 ; traditionnal value
rep stosw ; fill screen with al while cx > 0
pop rcx
pop rsi
pop rdi
ret
write: %include "boot/loader64.inc"
;-----------------------------------------------------------------------;
; x64/LM Text Printing Functions ;
; bl : color code ;
; esi : string address ;
;-----------------------------------------------------------------------;
mov edi, [NextTRAM] ;TRAM ADDRESS
push rsi
push rdi
.pLoop:
lodsb
cmp al, 0 ; while @al, i.e. while we're not hitting '\0'
je .pEnd
cmp al, 0x0A ; LF
je .lf
cmp al, 0x0D ; CR
je .cr
stosb ; text subpixel
mov al, bl
stosb ; color subpixel
add qword [NextTRAM], 0x2 ; Cursor moving
add qword [VGA_X], 0x2 ; coord + 2 because 2 subpixels
jmp .pLoop
.pEnd:
pop rdi
pop rsi
ret
.lf:
mov rax, [VGA_HEIGHT64]
add [NextTRAM], rax ; Cursor moving
add [NextTRAM], rax
add edi, eax ; Address moving
add edi, eax
jmp .pLoop
.cr:
push rax
mov rax, qword [VGA_X]
sub qword [NextTRAM], rax ; pos = X + Y * VGA_HEIGHT64. Donc pos - X = début de ligne
sub edi, edx
mov qword [VGA_X], 0
pop rax
jmp .pLoop
.scroll:
jmp .pLoop
;; DATA ;; DATA
txt db 0x09, " Switching to Long Mode... OK", 0x0A, 0x0D, 0 txt db 0x09, " Switching to Long Mode... ", 0
Init db "Booting OS/K !", 0x0D, 0x0A, 0x0D, 0x0A, 0x09, " Checking CPUID...",0 Init db "Booting OS/K !", 0x0D, 0x0A, 0x0D, 0x0A, 0x09, " Checking CPUID...",0
Reinit db "Booting OS/K !", 0x0D, 0x0A, 0x0D, 0x0A, 0 Reinit db "Booting OS/K !", 0x0D, 0x0A, 0x0D, 0x0A, 0
CPUIDD db 0x09, " Checking CPUID...", 0 CPUIDD db 0x09, " Checking CPUID...", 0
@ -417,10 +280,14 @@ main64:
mov esi, Pass mov esi, Pass
call write call write
mov bl, 0x0A mov bl, 0x0F
mov esi, txt mov esi, txt
call write call write
mov bl, 0x0A
mov esi, Pass
call write
mov bl, 0x0D mov bl, 0x0D
mov esi, msg mov esi, msg
call write call write
@ -434,5 +301,4 @@ ErrorNo64:
Die: Die:
cli cli
hlt ; die nooooow hlt ; die nooooow
retf jmp 0xF000:0xFFF0
KERNEL:

View File

@ -26,14 +26,14 @@
[BITS 16] ; Ensure 16-bit code (because fuck UEFI) [BITS 16] ; Ensure 16-bit code (because fuck UEFI)
;---------------------------------------------------;
; Disk description table ;
;---------------------------------------------------;
Intro: Intro:
jmp short _start ; Jump over the BIOS PARAMETER BLOCK jmp short _start ; Jump over the BIOS PARAMETER BLOCK
nop ; Required by BIOS to recognize the Disk nop ; Required by BIOS to recognize the Disk loul
BPB: BPB:
;---------------------------------------------------;
; Disk description table ;
;---------------------------------------------------;
%define OEMName bp+0x03 ; Disk label %define OEMName bp+0x03 ; Disk label
%define bytesPerSector bp+0x0b ; Bytes per sector %define bytesPerSector bp+0x0b ; Bytes per sector
%define sectorsPerCluster bp+0x0d ; Sectors per cluster %define sectorsPerCluster bp+0x0d ; Sectors per cluster
@ -53,7 +53,8 @@ BPB:
%define volumeId bp+0x27 ; Volume ID %define volumeId bp+0x27 ; Volume ID
%define volumeLabel bp+0x2b ; Volume Label %define volumeLabel bp+0x2b ; Volume Label
%define fatTypeLabel bp+0x36 ; File system type %define fatTypeLabel bp+0x36 ; File system type
times 0x3b db 0x00
times 0x3b db 0x00 ; ALLOCATE THE SECTORS FOR THE BPB
;; ENTRY POINT ;; ENTRY POINT
_start: _start:
@ -63,11 +64,11 @@ bootstrap:
jmp go jmp go
;; LOVELY DATA ;; LOVELY DATA
FileNotFound db "FStage ERR : NO LOADER", 0 ; File was not found FileNotFound db "First Stage ERROR : NO LOADER", 0
DiskError db "FStage ERR : DISK", 0 ; Error while reading from the disk DiskError db "First Stage ERROR : DISK", 0
UserData dw 0 ; Start of the data sectors UserData dw 0
Bootdrv db 0 ; Boot Bootdrv number Bootdrv db 0
filename db "LOADER BIN" ; Filename filename db "LOADER BIN"
;; GO ! ;; GO !
@ -82,7 +83,7 @@ go:
mov ss, ax ; Continue init the staaaaaaaack mov ss, ax ; Continue init the staaaaaaaack
mov sp, STACK_OFF ; Ok man, the stack is in 4K :O mov sp, STACK_OFF ; Ok man, the stack is in 4K :O
sti sti
mov bp, (0x7c0-STACK_SEG) << 4 ; Correct bp for the disk description table ! mov bp, (0x7c0-STACK_SEG) << 4 ; Correct bp (the disk description table)
;; INITIALIZE BOOT DISK ;; INITIALIZE BOOT DISK
or dl, dl ; Verifying dl points actually to the boot drive or dl, dl ; Verifying dl points actually to the boot drive
@ -137,20 +138,7 @@ search_root:
;; ERROR... ;; ERROR...
mov si, FileNotFound ; Could not find the file mov si, FileNotFound ; Could not find the file
call print call print
call reboot
;; REBOOT
reboot:
xor ax, ax
int 0x16 ; Get a single keypress
mov ah, 0x0e ; Teletype output
mov al, 0x0d ; Carriage return
int 0x10 ; Video interupt
mov al, 0x0a ; Line feed
int 0x10 ; Video interupt
mov al, 0x0a ; Line feed
int 0x10 ; Video interupt
xor ax, ax
int 0x19 ; Reboot the system
;; LOAD THE FAT FROM THE FILE ;; LOAD THE FAT FROM THE FILE
load_fat: load_fat:
@ -178,152 +166,10 @@ load_fat:
; ... ; ...
; I hope.... ; I hope....
; ... ; ...
call reboot
%include "boot/mbr.inc"
;---------------------------------------------------;
; FUNCTIONS ;
;---------------------------------------------------;
read_clusters:
;---------------------------------------------------;
; Read file clusters, starting at the given cluster,;
; expects FAT to be loaded into the disk buffer. ;
; Please note that this may allocate up to 128KB ;
; of ram. ;
; ;
; Expects: AX = Starting cluster ;
; ES:DI = Location to load clusters ;
; ;
; Returns: None ;
; ;
;---------------------------------------------------;
pusha
push es
.cluster_loop:
xor bh, bh
xor dx, dx
push ax ; Get the cluster start = (cluster - 2) * sectorsPerCluster + UserData
sub ax, 2 ; Subtract 2
mov bl, byte [sectorsPerCluster] ; Sectors per cluster is a byte value
mul bx ; multiply (cluster - 2) * sectorsPerCluster
add ax, word [UserData] ; add the UserData
xor ch, ch
mov cl, byte [sectorsPerCluster] ; Sectors to read
call read_sectors ; Read the sectors
pop ax ; Current cluster number
xor dx, dx
;; Calculate next sector for FAT16 (cluster * 2)
mov bx, 2 ; Multiply the cluster by two (cluster is in ax)
mul bx
;; Load sector in RAM
push ds
push si
mov si, BUFFER_SEG
mov ds, si ; Temporarly set ds:si to the FAT buffer
mov si, BUFFER_OFF
add si, ax ; Point to the next cluster in the FAT entry
mov ax, word [ds:si] ; Load ax to the next cluster in FAT
pop si
pop ds
;; Next
cmp ax, 0xfff8 ; Check if we are at the end of the file?
jae .done
add di, 512 ; Add to the pointer offset
jnc .cluster_loop
;; Correct the buffer because an error will occur if the buffer in memory
mov dx, es ; overlaps a 64k page boundry, when di overflows
add dh, 0x10 ; it will trigger the carry flag, so correct
mov es, dx ; extra segment by 0x1000
jmp .cluster_loop ; Load the next file cluster
.done:
pop es
popa
ret
read_sectors:
;---------------------------------------------------;
; Read sectors starting at a given sector by ;
; the given times and load into a buffer. Please ;
; note that this may allocate up to 128KB of ram. ;
; ;
; Expects: AX = Starting sector ;
; CX = Number of sectors to read ;
; ES:DI = Location to load sectors ;
; ;
; Returns: None ;
; ;
;---------------------------------------------------;
pusha
push es
mov bx, di ; Convert es:di to es:bx for int 13h
.sector_loop:
push ax
push cx
xor dx, dx
div word [sectorsPerTrack] ; Divide the lba (value in ax) by sectorsPerTrack
mov cx, dx ; Save the absolute sector value
inc cx
xor dx, dx ; Divide by the number of heads
div word [heads] ; to get absolute head and track values
mov dh, dl ; Move the absolute head into dh
mov ch, al ; Low 8 bits of absolute track
shl ah, 1 ; High 2 bits of absolute track
shl ah, 1
shl ah, 1
shl ah, 1
shl ah, 1
shl ah, 1
or cl, ah ; Now cx is set with respective track and sector numbers
mov dl, byte [Bootdrv] ; Set correct Bootdrv for int 13h
mov di, 5 ; Try five times to read the sector because i love 5
.attempt_read:
mov ax, 0x0201 ; Read Sectors func of int 13h, read one sector
int 0x13 ; Call int 13h (BIOS disk I/O)
jnc .read_ok ; If no carry set, the sector has been read
xor ah, ah ; Reset Bootdrv func of int 13h
int 0x13 ; Call int 13h (BIOS disk I/O)
dec di ; Decrease read attempt counter
jnz .attempt_read ; Try to read the sector again
mov si, DiskError ; Error reading the disk :/
call print
jmp reboot
.read_ok:
pop cx
pop ax
inc ax ; Increase the next sector to read
add bx, word [bytesPerSector] ; Add to the buffer address for the next sector
jnc .next_sector
;; Fixing buffer because an error will occur if the buffer in memory
mov dx, es ; overlaps a 64k page boundry, when bx overflows
add dh, 0x10 ; it will trigger the carry flag, so correct
mov es, dx ; es segment by 0x1000
.next_sector:
loop .sector_loop
pop es
popa
ret
print:
;---------------------------------------------------;
; Print out a simple string. ;
; ;
; Expects: DS:SI = String to print ;
; ;
; Returns: None ;
; ;
;---------------------------------------------------;
lodsb ; Load byte from ds:si to al
or al, al ; If al is empty stop looping
jz .done ; Done looping and return
mov ah, 0x0e ; Teletype output
int 0x10 ; Video interupt
jmp print ; Loop untill string is null
.done:
ret
;; END ;; END
times 510 - ($ - $$) db 0 ; Pad remainder of boot sector with zeros times 510 - ($ - $$) db 0 ; Pad remainder of boot sector with zeros
dw 0xaa55 ; Boot signature dw 0xaa55 ; Boot signature