Experimental bootloader update
This commit is contained in:
parent
960a949d9c
commit
21c3dd64e0
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -14,4 +14,6 @@
|
|||
2018/12/06 - Actually started project, began MBR, decided directories organization, created this file and others
|
||||
2018/12/08 - MBR actually supports Long Mode Compatibility Verification
|
||||
- Added A20 line Enabling to MBR
|
||||
2018/12/21 - Boot is now in two stages. First stage is 512 MBR code that loads second stage loader from FAT16.
|
||||
That second stage loader enables A20, switches into long mode and write colored text =D
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ SYSTDIR=kaleid/system
|
|||
|
||||
all: bootloader
|
||||
|
||||
boot.mbr.s: $(BOOTDIR)/mbr.s $(BOOTDIR)/mbr.inc
|
||||
boot.mbr.s: $(BOOTDIR)/mbr.s
|
||||
$(ASM) $(BOOTFLAGS) $(BOOTDIR)/mbr.s -o $(OBJDIR)/boot/mbr.bin
|
||||
|
||||
boot.loader.s: $(BOOTDIR)/loader.s
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
;=----------------------------------------------------------------------------=;
|
||||
; GNU GPL OS/K ;
|
||||
; ;
|
||||
; Authors: spectral` ;
|
||||
; NeoX ;
|
||||
; ;
|
||||
; Desc: Functions for the OS/K loaders ;
|
||||
; (x86_64 architecture only) ;
|
||||
;=----------------------------------------------------------------------------=;
|
||||
|
||||
;-------------------------------------------------------------------;
|
||||
; Prints the (null-terminated) string at address @es:@si ;
|
||||
;-------------------------------------------------------------------;
|
||||
PrintB:
|
||||
pushad ; saving context
|
||||
.pLoop:
|
||||
lodsb ; loads the character at @es:@si in @al
|
||||
mov bh, 0x00
|
||||
mov bl, 0x07
|
||||
cmp al,0
|
||||
je .pEnd ; while @al, i.e. while we're not hitting '\0'
|
||||
mov ah, 0x0E
|
||||
int 0x10 ; print character @al in color @bl (BIOS interrupt)
|
||||
jmp .pLoop
|
||||
.pEnd:
|
||||
popad ; restores context
|
||||
ret
|
|
@ -7,114 +7,119 @@
|
|||
; Desc: Kernel (second stage) Loader for OS/K ;
|
||||
; (x86_64 architecture only) ;
|
||||
;=----------------------------------------------------------------------------=;
|
||||
%define TRAM 0x0B8000 ; [T]ext[RAM]
|
||||
%define VRAM 0x0A0000 ; [V]ideo[RAM]
|
||||
|
||||
[BITS 16]
|
||||
[ORG 0x1000]
|
||||
|
||||
pop word [Bootdrv]
|
||||
jmp main
|
||||
|
||||
mov ax, cs
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
|
||||
mov [Bootdrv], dl
|
||||
jmp 0x0000:main
|
||||
|
||||
;; DATA
|
||||
%define TRAM 0x0B8000 ; [T]ext[RAM]
|
||||
%define VRAM 0x0A0000 ; [V]ideo[RAM]
|
||||
Bootdrv db 0x00
|
||||
|
||||
Bootdrv db 0
|
||||
VGA_HEIGHT dq 0
|
||||
VIDEO_MODE dw 0
|
||||
|
||||
;; GDT WITH DOC
|
||||
GDT64:
|
||||
NULL_SELECTOR: ;; null selector within 64 bits
|
||||
dw GDT_LENGTH ; limit of GDT
|
||||
dw GDT64 ; linear address of GDT
|
||||
dd 0x0
|
||||
CODE_SELECTOR: ;; 32-bit code selector (ring 0)
|
||||
dw 0x0FFFF ; Segment Limit 15:00
|
||||
db 0x0, 0x0, 0x0 ; Base Address 23:00
|
||||
db 10011010b ; |7|6|5|4|3|2|1|0|
|
||||
; | | | | | | | `----- 1 when segment used.
|
||||
; | | | | | | `------ 1 when writable.
|
||||
; | | | | | `------- 1 if "conformant". Don't know what is it... spectral ? xD
|
||||
; | | | | `-------- 1 always
|
||||
; | | | `--------- 1 for segment descriptor, 0 for system descriptor
|
||||
; | | `---------- DPL !!! 0 for ring 0
|
||||
; | `----------- DPL (2/2)
|
||||
; `------------ 1 if in physical memory, 0 if page fault
|
||||
db 11001111b ; |7|6|5|4|3|2|1|0|
|
||||
; | | | | | | | `----- Limit 16
|
||||
; | | | | | | `------ Limit 17
|
||||
; | | | | | `------- Limit 18
|
||||
; | | | | `-------- Limit 19
|
||||
; | | | `--------- available for use
|
||||
; | | `---------- 0 always
|
||||
; | `----------- size of data. 1 for 32bits
|
||||
; `------------ 0 if limit is in Bytes, 1 if it's in pages (4ko)
|
||||
db 0x0 ; Base Address 31:24
|
||||
|
||||
DATA_SELECTOR: ;; flat data selector (ring 0)
|
||||
dw 0x0FFFF ; Segment Limit 15:00
|
||||
db 0x0, 0x0, 0x0 ; Base Address 23:00
|
||||
db 10010010b ; |7|6|5|4|3|2|1|0|
|
||||
; | | | | | | | `----- 1 when segment used.
|
||||
; | | | | | | `------ 1 when writable.
|
||||
; | | | | | `------- expansion direction. 1 for a LIFO
|
||||
; | | | | `-------- 1 always
|
||||
; | | | `--------- 1 for segment descriptor, 0 for system descriptor
|
||||
; | | `---------- DPL !!! 0 for ring 0
|
||||
; | `----------- DPL (2/2)
|
||||
; `------------ 1 if in physical memory, 0 if page fault
|
||||
db 10001111b ; |7|6|5|4|3|2|1|0|
|
||||
; | | | | | | | `----- Limit 16
|
||||
; | | | | | | `------ Limit 17
|
||||
; | | | | | `------- Limit 18
|
||||
; | | | | `-------- Limit 19
|
||||
; | | | `--------- available for use
|
||||
; | | `---------- 0 always
|
||||
; | `----------- size of data. 1 for 32bits
|
||||
; `------------ 0 if limit is in Bytes, 1 if it's in pages (4ko)
|
||||
db 0x0 ; Base Address 31:24
|
||||
|
||||
LONG_SELECTOR: ;; 64-bit code selector (ring 0)
|
||||
dw 0x0FFFF ; Segment Limit 15:00
|
||||
db 0x0, 0x0, 0x0 ; Base Address 23:00
|
||||
db 10011010b ; |7|6|5|4|3|2|1|0|
|
||||
; | | | | | | | `----- 1 when segment used.
|
||||
; | | | | | | `------ 1 when writable.
|
||||
; | | | | | `------- 1 if "conformant". Don't know what is it... spectral ? xD
|
||||
; | | | | `-------- 1 always
|
||||
; | | | `--------- 1 for segment descriptor, 0 for system descriptor
|
||||
; | | `---------- DPL !!! 0 for ring 0
|
||||
; | `----------- DPL (2/2)
|
||||
; `------------ 1 if in physical memory, 0 if page fault
|
||||
db 10101111b ; |7|6|5|4|3|2|1|0|
|
||||
; | | | | | | | `----- Limit 16
|
||||
; | | | | | | `------ Limit 17
|
||||
; | | | | | `------- Limit 18
|
||||
; | | | | `-------- Limit 19
|
||||
; | | | `--------- available for use
|
||||
; | | `---------- 0 always
|
||||
; | `----------- size of data. 1 for 32bits
|
||||
; `------------ 0 if limit is in Bytes, 1 if it's in pages (4ko)
|
||||
db 0x0 ; Base Address 31:24
|
||||
GDT_LENGTH:
|
||||
GDT64:
|
||||
NULL_SELECTOR: ;; null selector within 64 bits
|
||||
dw GDT_LENGTH ; limit of GDT
|
||||
dw GDT64 ; linear address of GDT
|
||||
dd 0x0
|
||||
CODE_SELECTOR: ;; 32-bit code selector (ring 0)
|
||||
dw 0x0FFFF ; Segment Limit 15:00
|
||||
db 0x0, 0x0, 0x0 ; Base Address 23:00
|
||||
db 10011010b ; |7|6|5|4|3|2|1|0|
|
||||
; | | | | | | | `----- 1 when segment used.
|
||||
; | | | | | | `------ 1 when writable.
|
||||
; | | | | | `------- 1 if "conformant". Don't know what is it... spectral ? xD
|
||||
; | | | | `-------- 1 always
|
||||
; | | | `--------- 1 for segment descriptor, 0 for system descriptor
|
||||
; | | `---------- DPL !!! 0 for ring 0
|
||||
; | `----------- DPL (2/2)
|
||||
; `------------ 1 if in physical memory, 0 if page fault
|
||||
db 11001111b ; |7|6|5|4|3|2|1|0|
|
||||
; | | | | | | | `----- Limit 16
|
||||
; | | | | | | `------ Limit 17
|
||||
; | | | | | `------- Limit 18
|
||||
; | | | | `-------- Limit 19
|
||||
; | | | `--------- available for use
|
||||
; | | `---------- 0 always
|
||||
; | `----------- size of data. 1 for 32bits
|
||||
; `------------ 0 if limit is in Bytes, 1 if it's in pages (4ko)
|
||||
db 0x0 ; Base Address 31:24
|
||||
|
||||
DATA_SELECTOR: ;; flat data selector (ring 0)
|
||||
dw 0x0FFFF ; Segment Limit 15:00
|
||||
db 0x0, 0x0, 0x0 ; Base Address 23:00
|
||||
db 10010010b ; |7|6|5|4|3|2|1|0|
|
||||
; | | | | | | | `----- 1 when segment used.
|
||||
; | | | | | | `------ 1 when writable.
|
||||
; | | | | | `------- expansion direction. 1 for a LIFO
|
||||
; | | | | `-------- 1 always
|
||||
; | | | `--------- 1 for segment descriptor, 0 for system descriptor
|
||||
; | | `---------- DPL !!! 0 for ring 0
|
||||
; | `----------- DPL (2/2)
|
||||
; `------------ 1 if in physical memory, 0 if page fault
|
||||
db 10001111b ; |7|6|5|4|3|2|1|0|
|
||||
; | | | | | | | `----- Limit 16
|
||||
; | | | | | | `------ Limit 17
|
||||
; | | | | | `------- Limit 18
|
||||
; | | | | `-------- Limit 19
|
||||
; | | | `--------- available for use
|
||||
; | | `---------- 0 always
|
||||
; | `----------- size of data. 1 for 32bits
|
||||
; `------------ 0 if limit is in Bytes, 1 if it's in pages (4ko)
|
||||
db 0x0 ; Base Address 31:24
|
||||
|
||||
LONG_SELECTOR: ;; 64-bit code selector (ring 0)
|
||||
dw 0x0FFFF ; Segment Limit 15:00
|
||||
db 0x0, 0x0, 0x0 ; Base Address 23:00
|
||||
db 10011010b ; |7|6|5|4|3|2|1|0|
|
||||
; | | | | | | | `----- 1 when segment used.
|
||||
; | | | | | | `------ 1 when writable.
|
||||
; | | | | | `------- 1 if "conformant". Don't know what is it... spectral ? xD
|
||||
; | | | | `-------- 1 always
|
||||
; | | | `--------- 1 for segment descriptor, 0 for system descriptor
|
||||
; | | `---------- DPL !!! 0 for ring 0
|
||||
; | `----------- DPL (2/2)
|
||||
; `------------ 1 if in physical memory, 0 if page fault
|
||||
db 10101111b ; |7|6|5|4|3|2|1|0|
|
||||
; | | | | | | | `----- Limit 16
|
||||
; | | | | | | `------ Limit 17
|
||||
; | | | | | `------- Limit 18
|
||||
; | | | | `-------- Limit 19
|
||||
; | | | `--------- available for use
|
||||
; | | `---------- 0 always
|
||||
; | `----------- size of data. 1 for 32bits
|
||||
; `------------ 0 if limit is in Bytes, 1 if it's in pages (4ko)
|
||||
db 0x0 ; Base Address 31:24
|
||||
GDT_LENGTH:
|
||||
|
||||
[BITS 16]
|
||||
disable_cursor:
|
||||
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
|
||||
|
||||
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
|
||||
|
@ -125,7 +130,7 @@ get_dimensions:
|
|||
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 ;
|
||||
|
@ -160,11 +165,26 @@ Is64bits:
|
|||
stc
|
||||
ret
|
||||
|
||||
;; INCLUDES
|
||||
%include "boot/common.inc" ; for PrintB
|
||||
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:
|
||||
;; compatibility check
|
||||
main:
|
||||
;; compatibility check
|
||||
mov si, Init
|
||||
call PrintB
|
||||
pop si
|
||||
|
@ -174,7 +194,7 @@ main:
|
|||
mov si, Pass
|
||||
call PrintB
|
||||
|
||||
;; enabling A20
|
||||
;; Enabling A20
|
||||
mov si, EnA20
|
||||
call PrintB
|
||||
pop si
|
||||
|
@ -186,11 +206,11 @@ main:
|
|||
call PrintB
|
||||
|
||||
;; DISABLING CURSOR BLINKING AND GETTING INFOS
|
||||
call get_dimensions
|
||||
call disable_cursor
|
||||
|
||||
;;GO GDT64
|
||||
cli ; disable interrupts
|
||||
call get_dimensions
|
||||
call disable_cursor
|
||||
|
||||
;;GO GDT64
|
||||
cli ; disable interrupts
|
||||
lgdt [GDT64]
|
||||
;; ACTIVATE PROTECTED MODE
|
||||
mov eax, cr0
|
||||
|
@ -203,7 +223,7 @@ main:
|
|||
; |
|
||||
; `------ Paging bit
|
||||
mov cr0, eax
|
||||
|
||||
|
||||
push dword [VIDEO_MODE]
|
||||
push dword [VGA_HEIGHT]
|
||||
jmp (CODE_SELECTOR-GDT64):main32
|
||||
|
@ -244,11 +264,11 @@ main32:
|
|||
.make_page_entries:
|
||||
stosd
|
||||
add edi, 4
|
||||
add eax, 0x1000
|
||||
add eax, 0x1000
|
||||
loop .make_page_entries
|
||||
;; pointing pml4
|
||||
mov eax, 0x70000 ; Bass address of PML4
|
||||
mov cr3, eax ; load page-map level-4 base
|
||||
mov cr3, eax ; load page-map level-4 base
|
||||
|
||||
;; ACTIVATE LONG MODE
|
||||
mov ecx, 0xC0000080 ; address of MSR
|
||||
|
@ -257,7 +277,7 @@ main32:
|
|||
wrmsr ; write MSR
|
||||
|
||||
;; ACTIVATE PAGING
|
||||
mov eax, cr0
|
||||
mov eax, cr0
|
||||
or eax, 0x80000000 ; make bit 31 (PG = Paging) to 1 :
|
||||
; |1|000000000000000000000000000000
|
||||
; |
|
||||
|
@ -271,6 +291,23 @@ main32:
|
|||
|
||||
[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:
|
||||
;-----------------------------------------------------------------------;
|
||||
|
@ -297,8 +334,8 @@ write:
|
|||
jmp .pLoop
|
||||
.pEnd:
|
||||
pop rdi
|
||||
pop rsi
|
||||
ret
|
||||
pop rsi
|
||||
ret
|
||||
.lf:
|
||||
mov rax, [VGA_HEIGHT64]
|
||||
add [NextTRAM], rax ; Cursor moving
|
||||
|
@ -318,13 +355,15 @@ write:
|
|||
|
||||
jmp .pLoop
|
||||
|
||||
;; DATA
|
||||
;; DATA
|
||||
txt db 0x09, " Switching to Long Mode... OK", 0x0A, 0x0D, 0
|
||||
Init db 0x09, " Checking CPUID", 0
|
||||
EnA20 db 0x09, " Enabling A20 line", 0
|
||||
NoLongMode db 0x0A, 0x0D, "ERROR: Your computer is not designed for x64 OS", 0
|
||||
Init db "Booting OS/K !", 0x0D, 0x0A, 0x0D, 0x0A, 0x09, " Checking CPUID...",0
|
||||
Reinit db "Booting OS/K !", 0x0D, 0x0A, 0x0D, 0x0A, 0
|
||||
CPUIDD db 0x09, " Checking CPUID...", 0
|
||||
EnA20 db 0x09, " Enabling A20 line...", 0
|
||||
NoLongMode db 0x0A, 0x0D, "ERROR : Your computer is not designed for x64 OS", 0
|
||||
Pass db " OK", 0x0A, 0x0D, 0
|
||||
NextTRAM dq 0x0B8AA0 ; Last position of cursor
|
||||
NextTRAM dq 0x0B8000 ; Last position of cursor
|
||||
VIDEO_MODE64 dq 0
|
||||
VGA_HEIGHT64 dq 0
|
||||
VGA_X dq 0x0
|
||||
|
@ -335,30 +374,39 @@ main64:
|
|||
pop qword [VIDEO_MODE64]
|
||||
;; INITIALIZE STACK
|
||||
mov rsp, 0x9F000
|
||||
|
||||
call clear
|
||||
|
||||
;; NOTIFYING
|
||||
;; Printing
|
||||
mov bl, 0x0B
|
||||
mov esi, Reinit
|
||||
call write
|
||||
|
||||
mov bl, 0x0F
|
||||
mov esi, CPUIDD
|
||||
call write
|
||||
|
||||
mov bl, 0x0A
|
||||
mov esi, Pass
|
||||
call write
|
||||
|
||||
mov bl, 0x0F
|
||||
mov esi, EnA20
|
||||
call write
|
||||
|
||||
mov bl, 0x0A
|
||||
mov esi, Pass
|
||||
call write
|
||||
|
||||
mov bl, 0x0A
|
||||
mov esi, txt
|
||||
call write
|
||||
|
||||
mov bl, 0x0B
|
||||
mov esi, msg
|
||||
call write
|
||||
|
||||
mov bl, 0x0C
|
||||
mov esi, msg
|
||||
call write
|
||||
|
||||
mov bl, 0x0D
|
||||
mov esi, msg
|
||||
call write
|
||||
|
||||
mov bl, 0x0E
|
||||
mov esi, msg
|
||||
call write
|
||||
|
||||
;call KERNEL
|
||||
jmp $
|
||||
|
||||
jmp Die
|
||||
|
||||
[BITS 16]
|
||||
ErrorNo64:
|
||||
|
@ -368,6 +416,4 @@ Die:
|
|||
cli
|
||||
hlt ; die nooooow
|
||||
retf
|
||||
|
||||
times 1024-($-$$) db 144
|
||||
KERNEL:
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
;=----------------------------------------------------------------------------=;
|
||||
; GNU GPL OS/K ;
|
||||
; ;
|
||||
; Authors: spectral` ;
|
||||
; NeoX ;
|
||||
; ;
|
||||
; Desc: Functions for the OS/K mbr ;
|
||||
; (x86_64 architecture only) ;
|
||||
;=----------------------------------------------------------------------------=;
|
||||
|
||||
|
457
src/boot/mbr.s
457
src/boot/mbr.s
|
@ -4,185 +4,338 @@
|
|||
; Authors: spectral` ;
|
||||
; NeoX ;
|
||||
; ;
|
||||
; Desc: Master Boot Record for OS/K ;
|
||||
; Desc: Bootsector for OS/K ;
|
||||
; (x86_64 architecture only) ;
|
||||
;=----------------------------------------------------------------------------=;
|
||||
|
||||
%define SECOND_STAGE 0x100 ;about to change
|
||||
;; BOOT "SEGMENT"
|
||||
%define BOOT_SEG 0x07c0 ; (BOOT_SEG << 4) + BOOT_OFF = 0x007c00
|
||||
%define BOOT_OFF 0x0000
|
||||
|
||||
;; STACK "SEGMENT"
|
||||
%define STACK_SEG 0x0600 ; (STACK_SEG << 4) + STACK_OFF = 0x007000
|
||||
%define STACK_OFF 0x1000
|
||||
|
||||
[BITS 16] ; real mode
|
||||
[ORG 0x7C00] ; address where the BIOS/UEFI CSM is loading us
|
||||
;; DISK BUFFER "SEGMENT"
|
||||
%define BUFFER_SEG 0x2000 ; (BUFFER_SEG << 4) + BUFFER_OFF = 0x020000
|
||||
%define BUFFER_OFF 0x0000
|
||||
|
||||
jmp short Start
|
||||
;; SECOND STAGE LOADER "SEGMENT"
|
||||
%define LOAD_SEG 0x0000 ; (LOAD_SEG << 4) + LOAD_OFF = 0x030000
|
||||
%define LOAD_OFF 0x1000
|
||||
|
||||
;; File Allocation Table Disk Identifiers
|
||||
nop
|
||||
OEM_ID db "GPL OS/K"
|
||||
BytesPerSector dw 0x0200
|
||||
SectorsPerCluster db 0x08
|
||||
ReservedSectors dw 0x0020
|
||||
TotalFATs db 0x02
|
||||
MaxRootEntries dw 0x0000
|
||||
NumberOfSectors dw 0x0000
|
||||
MediaDescriptor db 0xF8
|
||||
SectorsPerFAT dw 0x0000
|
||||
SectorsPerTrack dw 0x003D
|
||||
SectorsPerHead dw 0x0002
|
||||
HiddenSectors dd 0x00000000
|
||||
TotalSectors dd 0x00FE3B1F
|
||||
BigSectorsPerFAT dd 0x00000778
|
||||
Flags dw 0x0000
|
||||
FSVersion dw 0x0000
|
||||
RootDirectoryStart dd 0x00000002
|
||||
FSInfoSector dw 0x0001
|
||||
BackupBootSector dw 0x0006
|
||||
[BITS 16] ; Ensure 16-bit code (because fuck UEFI)
|
||||
|
||||
TIMES 12 DB 0 ; going to the next offset
|
||||
;---------------------------------------------------
|
||||
; Disk description table
|
||||
;---------------------------------------------------
|
||||
Intro:
|
||||
|
||||
DriveNumber db 0x00
|
||||
ReservedByte db 0x00
|
||||
Signature db 0x29
|
||||
VolumeID dd 0xFFFFFFFF
|
||||
VolumeLabel db "OS/K BDISK "
|
||||
SystemID db "FAT32 "
|
||||
jmp short _start ; Jump over the BIOS PARAMETER BLOCK
|
||||
nop ; Required by BIOS to recognize the Disk
|
||||
BPB:
|
||||
%define OEMName bp+0x03 ; Disk label
|
||||
%define bytesPerSector bp+0x0b ; Bytes per sector
|
||||
%define sectorsPerCluster bp+0x0d ; Sectors per cluster
|
||||
%define reservedSectors bp+0x0e ; Reserved sectors
|
||||
%define fats bp+0x10 ; Number of fats
|
||||
%define rootDirEntries bp+0x11 ; Number of entries in root dir
|
||||
%define sectors bp+0x13 ; Logical sectors
|
||||
%define mediaType bp+0x15 ; Media descriptor byte
|
||||
%define fatSectors bp+0x16 ; Sectors per FAT
|
||||
%define sectorsPerTrack bp+0x18 ; Sectors per track
|
||||
%define heads bp+0x1a ; Number of sides/heads
|
||||
%define hiddenSectors bp+0x1c ; Hidden sectors
|
||||
%define hugeSectors bp+0x20 ; LBA sectors
|
||||
%define biosBootdrvNum bp+0x24 ; Bootdrv number
|
||||
%define reserved bp+0x25 ; This is not used
|
||||
%define bootSignature bp+0x26 ; Bootdrv signature
|
||||
%define volumeId bp+0x27 ; Volume ID
|
||||
%define volumeLabel bp+0x2b ; Volume Label
|
||||
%define fatTypeLabel bp+0x36 ; File system type
|
||||
times 0x3b db 0x00
|
||||
|
||||
Start:
|
||||
;; saving registers for future
|
||||
pushad
|
||||
pushfd
|
||||
pushf
|
||||
;; ENTRY POINT
|
||||
_start:
|
||||
jmp BOOT_SEG:$+5 ; Fix the cs:ip registers with a vaudou magical trip
|
||||
|
||||
;; dl contains the boot drive. Saving it.
|
||||
mov [Bootdrv], dl
|
||||
|
||||
;; hello world
|
||||
push si
|
||||
mov si, Starting
|
||||
call PrintB
|
||||
bootstrap:
|
||||
mov ax, BOOT_SEG ; Set segments to the location of the bootloader
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
|
||||
;; INIT STACK
|
||||
cli
|
||||
mov ax, STACK_SEG ; Init the staaaaaack
|
||||
mov ss, ax ; Continue init the staaaaaaaack
|
||||
mov sp, STACK_OFF ; Ok man, the stack is in 4K :O
|
||||
sti
|
||||
mov bp, (0x7c0-STACK_SEG) << 4 ; Correct bp for the disk description table !
|
||||
|
||||
;; SWITCHING TO LOADER
|
||||
mov si, Switch
|
||||
call PrintB
|
||||
pop si
|
||||
mov cx, word [SectorsPerCluster] ; size of a cluster in sectors is stored in cx
|
||||
|
||||
; computing location of the begining of the Data area and store in ax
|
||||
mov al, byte [TotalFATs] ; Total number of FATs
|
||||
mul word [BigSectorsPerFAT] ; Number of sectors for a FAT
|
||||
add ax, word [ReservedSectors] ; Find the start of the Data area
|
||||
mov word [Datasector], ax ; Store the begining of the Data area
|
||||
;; INITIALIZE BOOT DISK
|
||||
or dl, dl ; Verifying dl points actually to the boot drive
|
||||
jz loadRoot
|
||||
mov byte [Bootdrv], dl ; Another soul (the disk) saved !
|
||||
mov ah, 0x08
|
||||
int 0x13 ; int 0x13 : read drive parameters/geom
|
||||
jc loadRoot
|
||||
and cx, 0x003f ; Maximum sector number is the high bits 6-7 of cl
|
||||
mov word [sectorsPerTrack], cx ; And whose low 8 bits are in ch
|
||||
mov dl, dh ; Convert the maximum head number to a word with another vaudou magical trip
|
||||
xor dh, dh
|
||||
inc dx ; because head numbers start at zero
|
||||
mov word [heads], dx ; Another soul (the heads number) saved !
|
||||
|
||||
|
||||
;; LOAD THE ROOT DIRECTORY FROM DISK
|
||||
loadRoot:
|
||||
xor cx, cx
|
||||
mov ax, 32 ; Size of root dir = (rootDirEntries * 32) / bytesPerSector
|
||||
mul word [rootDirEntries] ; multiply by the total size of the root directory
|
||||
div word [bytesPerSector] ; divide by the number of bytes used per sector
|
||||
xchg cx, ax
|
||||
|
||||
mov al, byte [fats] ; Location of root dir = (fats * fatSectors) + reservedSectors
|
||||
mul word [fatSectors] ; multiply by the sectors used
|
||||
add ax, word [reservedSectors] ; increase ax by the reserved sectors
|
||||
mov word [userData], ax ; Start of user data = startOfRoot + numberOfRoot
|
||||
add word [userData], cx ; Add the size and location of the root directory
|
||||
|
||||
; reading 1st data cluster into memory (7C00:0200)
|
||||
mov ax, word [RootDirectoryStart]
|
||||
call ClusterLBA
|
||||
mov bx, 0x0200 ; copy 1st data cluter above bootcode
|
||||
call ReadSectors
|
||||
mov di, BUFFER_SEG ; Set the extra segment to the disk buffer
|
||||
mov es, di
|
||||
mov di, BUFFER_OFF ; Set es:di and load the root directory into the disk buffer
|
||||
call readSectors ; Read the sectoooooooors !
|
||||
|
||||
; Point Index register to 1st File Entry
|
||||
mov di, 0x0200 + 0x20
|
||||
;Point to the offset where the file location information contains
|
||||
mov dx, word [di + 0x001A]
|
||||
mov word [Cluster], dx
|
||||
;Set up the segments where the loader needs to be loaded ;)
|
||||
mov ax, 0100h ; set ES:BX = 0100:0000
|
||||
mov es, ax
|
||||
xor bx, bx
|
||||
|
||||
;Read the cluster which contains the loader
|
||||
mov cx, 0x0008
|
||||
mov ax, word [Cluster]
|
||||
call ClusterLBA
|
||||
call ReadSectors
|
||||
|
||||
;Jump to the location where the loader was loded
|
||||
popf
|
||||
popfd
|
||||
popad
|
||||
push word [Bootdrv]
|
||||
call dword SECOND_STAGE:0000
|
||||
;; FIND THE SECOND STAGE LOADER
|
||||
mov di, BUFFER_OFF ; Set es:di to the disk buffer
|
||||
mov cx, word [rootDirEntries] ; Search through all of the root dir entries
|
||||
xor ax, ax ; Clear ax for the file entry offset
|
||||
searchRoot:
|
||||
xchg cx, dx ; Save cx because it's a loop counter
|
||||
mov si, filename ; Load the filename
|
||||
mov cx, 11 ; Compare first 11 bytes
|
||||
rep cmpsb ; Compare si and di cx times
|
||||
je loadFat ; We found the LOADEEEEEEEER!!!
|
||||
add ax, 32 ; File entry offset
|
||||
mov di, BUFFER_OFF ; Point back to the start of the entry
|
||||
add di, ax ; Add the offset to point to the next entry
|
||||
xchg dx, cx
|
||||
loop searchRoot ; Continue to search for the file
|
||||
|
||||
; Exiting
|
||||
mov ah, 0x00
|
||||
int 0x19 ; warm boot computer
|
||||
;; ERROR...
|
||||
mov si, fileNotFound ; Could not find the file
|
||||
call print
|
||||
|
||||
;; 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
|
||||
|
||||
;;END OF MBR
|
||||
;; LOAD THE FAT FROM THE FILE
|
||||
loadFat:
|
||||
mov ax, word [es:di + 15] ; Get the file cluster at offset 26
|
||||
push ax ; Store the FAT cluster
|
||||
xor ax, ax ; Size of fat = (fats * fatSectors)
|
||||
mov al, byte [fats] ; Move number of fats into al
|
||||
mul word [fatSectors] ; Move fat sectors into bx
|
||||
mov cx, ax ; Store in cx
|
||||
mov ax, word [reservedSectors] ; Convert the first fat on the disk
|
||||
mov di, BUFFER_OFF ; Set es:di and load the fat sectors into the disk buffer
|
||||
call readSectors ; Read the sectooooooooooors !!!
|
||||
|
||||
;;----------------------------------------------------------------------------;;
|
||||
;; DATA
|
||||
Starting db 0x0A, 0x0D, 0x07, "GNU GPL OS/K", 0x0A, 0x0D, 0x0A, 0x0D, 0
|
||||
Switch db 0x09, " Loading Second Stage", 0
|
||||
AbsoluteSector db 0x00
|
||||
AbsoluteHead db 0x00
|
||||
AbsoluteTrack db 0x00
|
||||
Cluster dw 0x0000
|
||||
Datasector dw 0x0000
|
||||
;; LOAD THE CLUSTERS OF THE LOADER AND JUMP
|
||||
loadFile:
|
||||
mov di, LOAD_SEG
|
||||
mov es, di ; Set es:bx to where the file will load
|
||||
mov di, LOAD_OFF
|
||||
pop ax ; File cluster restored
|
||||
call readClusters ; Read clusters from the file
|
||||
mov dl, byte [Bootdrv] ; Pass the boot Bootdrv into dl
|
||||
jmp LOAD_SEG:LOAD_OFF ; Jump to the file loaded!
|
||||
|
||||
Bootdrv db 0x00
|
||||
hlt ; This should never be hit...
|
||||
; ...
|
||||
; ...
|
||||
; I hope....
|
||||
; ...
|
||||
|
||||
;; INCLUDES
|
||||
%include "boot/common.inc" ; for PrintB
|
||||
|
||||
;; INTERNAL FUNCTIONS
|
||||
;-------------------------------------------------------------------;
|
||||
; loading second stage loader (loader.s) ;
|
||||
;-------------------------------------------------------------------;
|
||||
ReadSectors:
|
||||
.main:
|
||||
mov di, 0x0005 ; five retries for error
|
||||
.sectorloop:
|
||||
|
||||
;---------------------------------------------------;
|
||||
; FUNCTIONS ;
|
||||
;---------------------------------------------------;
|
||||
|
||||
readClusters:
|
||||
;---------------------------------------------------;
|
||||
; 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 ;
|
||||
; ;
|
||||
;---------------------------------------------------;
|
||||
push ax
|
||||
push bx
|
||||
push cx
|
||||
call LbaToChs
|
||||
mov ah, 0x02 ; BIOS read sector
|
||||
mov al, 0x01 ; read one sector
|
||||
mov ch, BYTE [AbsoluteTrack] ; track
|
||||
mov cl, BYTE [AbsoluteSector] ; sector
|
||||
mov dh, BYTE [AbsoluteHead] ; head
|
||||
int 0x13 ; invoke BIOS
|
||||
jnc .success ; test for read error
|
||||
xor ax, ax ; BIOS reset disk
|
||||
int 0x13 ; invoke BIOS
|
||||
dec di ; decrement error counter
|
||||
push dx
|
||||
push di
|
||||
push es
|
||||
.clusterLoop:
|
||||
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 readSectors ; Read the sectors
|
||||
pop ax ; Current cluster number
|
||||
xor dx, dx
|
||||
.calculateNextSector16: ; Get the next sector for FAT16 (cluster * 2)
|
||||
mov bx, 2 ; Multiply the cluster by two (cluster is in ax)
|
||||
mul bx
|
||||
.loadNextSector:
|
||||
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
|
||||
.nextSectorCalculated:
|
||||
cmp ax, 0xfff8 ; Check if we are at the end of the file?
|
||||
jae .done
|
||||
add di, 512 ; Add to the pointer offset
|
||||
jnc .clusterLoop
|
||||
.fixBuffer: ; 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 .clusterLoop ; Load the next file cluster
|
||||
.done:
|
||||
pop es
|
||||
pop di
|
||||
pop dx
|
||||
pop cx
|
||||
pop bx
|
||||
pop ax
|
||||
jnz .sectorloop ; attempt to read again
|
||||
int 0x18
|
||||
.success:
|
||||
pop cx
|
||||
pop bx
|
||||
pop ax
|
||||
add bx, WORD [BytesPerSector] ; queue next buffer
|
||||
inc ax ; queue next sector
|
||||
loop .main ; read next sector
|
||||
ret
|
||||
|
||||
;-------------------------------------------------------------------;
|
||||
; Converts LBA Adresses to CHS ;
|
||||
;-------------------------------------------------------------------;
|
||||
LbaToChs:
|
||||
xor dx, dx ; prepare dx:ax for operation
|
||||
div WORD [SectorsPerTrack] ; calculate
|
||||
inc dl ; adjust for sector 0
|
||||
mov BYTE [AbsoluteSector], dl
|
||||
xor dx, dx ; prepare dx:ax for operation
|
||||
div WORD [SectorsPerHead] ; calculate
|
||||
mov BYTE [AbsoluteHead], dl
|
||||
mov BYTE [AbsoluteTrack], al
|
||||
|
||||
readSectors:
|
||||
;---------------------------------------------------;
|
||||
; 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 ;
|
||||
; ;
|
||||
;---------------------------------------------------;
|
||||
push ax
|
||||
push bx
|
||||
push cx
|
||||
push dx
|
||||
push di
|
||||
push es
|
||||
mov bx, di ; Convert es:di to es:bx for int 13h
|
||||
.sectorLoop:
|
||||
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
|
||||
.attemptRead:
|
||||
mov ax, 0x0201 ; Read Sectors func of int 13h, read one sector
|
||||
int 0x13 ; Call int 13h (BIOS disk I/O)
|
||||
jnc .readOk ; 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 .attemptRead ; Try to read the sector again
|
||||
mov si, diskError ; Error reading the disk :/
|
||||
call print
|
||||
jmp reboot
|
||||
.readOk:
|
||||
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 .nextSector
|
||||
.fixBuffer: ; 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
|
||||
.nextSector:
|
||||
loop .sectorLoop
|
||||
pop es
|
||||
pop di
|
||||
pop dx
|
||||
pop cx
|
||||
pop bx
|
||||
pop ax
|
||||
ret
|
||||
;-------------------------------------------------------------------;
|
||||
; Converts FAT Adresses to LBA ;
|
||||
;-------------------------------------------------------------------;
|
||||
ClusterLBA:
|
||||
sub ax, 0x0002 ; zero base cluster number
|
||||
xor cx, cx
|
||||
mov cl, BYTE [SectorsPerCluster] ; convert byte to word
|
||||
mul cx
|
||||
add ax, WORD [Datasector] ; base data sector
|
||||
|
||||
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:
|
||||
times 510-($-$$) db 144 ; NOP until 510
|
||||
dw 0xAA55 ; magic word
|
||||
|
||||
;; LOVELY DATA
|
||||
fileNotFound db "FStage ERR : NO LOADER", 0 ; File was not found
|
||||
diskError db "FStage ERR : DISK", 0 ; Error while reading from the disk
|
||||
userData dw 0 ; Start of the data sectors
|
||||
Bootdrv db 0 ; Boot Bootdrv number
|
||||
filename db "LOADER BIN" ; Filename
|
||||
|
||||
;; END
|
||||
times 510 - ($ - $$) db 0 ; Pad remainder of boot sector with zeros
|
||||
dw 0xaa55 ; Boot signature
|
||||
|
||||
|
|
Loading…
Reference in New Issue