Experimental bootloader update

This commit is contained in:
Adrien Bourmault 2018-12-21 23:57:41 +01:00
parent 960a949d9c
commit 21c3dd64e0
11 changed files with 492 additions and 329 deletions

BIN
bin/disk.img Normal file

Binary file not shown.

BIN
bin/loader.bin Normal file

Binary file not shown.

BIN
bin/mbr.bin Normal file

Binary file not shown.

BIN
obj/boot/loader.bin Normal file

Binary file not shown.

BIN
obj/boot/mbr.bin Normal file

Binary file not shown.

View File

@ -14,4 +14,6 @@
2018/12/06 - Actually started project, began MBR, decided directories organization, created this file and others 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 2018/12/08 - MBR actually supports Long Mode Compatibility Verification
- Added A20 line Enabling to MBR - 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

View File

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

View File

@ -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

View File

@ -7,114 +7,119 @@
; Desc: Kernel (second stage) Loader for OS/K ; ; Desc: Kernel (second stage) Loader for OS/K ;
; (x86_64 architecture only) ; ; (x86_64 architecture only) ;
;=----------------------------------------------------------------------------=; ;=----------------------------------------------------------------------------=;
%define TRAM 0x0B8000 ; [T]ext[RAM]
%define VRAM 0x0A0000 ; [V]ideo[RAM]
[BITS 16]
[ORG 0x1000] [ORG 0x1000]
pop word [Bootdrv] mov ax, cs
jmp main mov ds, ax
mov es, ax
mov [Bootdrv], dl
jmp 0x0000:main
;; DATA ;; DATA
%define TRAM 0x0B8000 ; [T]ext[RAM]
%define VRAM 0x0A0000 ; [V]ideo[RAM] Bootdrv db 0
Bootdrv db 0x00
VGA_HEIGHT dq 0 VGA_HEIGHT dq 0
VIDEO_MODE dw 0 VIDEO_MODE dw 0
;; GDT WITH DOC ;; GDT WITH DOC
GDT64: GDT64:
NULL_SELECTOR: ;; null selector within 64 bits NULL_SELECTOR: ;; null selector within 64 bits
dw GDT_LENGTH ; limit of GDT dw GDT_LENGTH ; limit of GDT
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 15:00
db 0x0, 0x0, 0x0 ; Base Address 23:00 db 0x0, 0x0, 0x0 ; Base Address 23:00
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.
; | | | | | `------- 1 if "conformant". Don't know what is it... spectral ? xD ; | | | | | `------- 1 if "conformant". Don't know what is it... spectral ? xD
; | | | | `-------- 1 always ; | | | | `-------- 1 always
; | | | `--------- 1 for segment descriptor, 0 for system descriptor ; | | | `--------- 1 for segment descriptor, 0 for system descriptor
; | | `---------- DPL !!! 0 for ring 0 ; | | `---------- DPL !!! 0 for ring 0
; | `----------- DPL (2/2) ; | `----------- DPL (2/2)
; `------------ 1 if in physical memory, 0 if page fault ; `------------ 1 if in physical memory, 0 if page fault
db 11001111b ; |7|6|5|4|3|2|1|0| db 11001111b ; |7|6|5|4|3|2|1|0|
; | | | | | | | `----- Limit 16 ; | | | | | | | `----- Limit 16
; | | | | | | `------ Limit 17 ; | | | | | | `------ Limit 17
; | | | | | `------- Limit 18 ; | | | | | `------- Limit 18
; | | | | `-------- Limit 19 ; | | | | `-------- Limit 19
; | | | `--------- available for use ; | | | `--------- available for use
; | | `---------- 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 31:24
DATA_SELECTOR: ;; flat data selector (ring 0) DATA_SELECTOR: ;; flat data selector (ring 0)
dw 0x0FFFF ; Segment Limit 15:00 dw 0x0FFFF ; Segment Limit 15:00
db 0x0, 0x0, 0x0 ; Base Address 23:00 db 0x0, 0x0, 0x0 ; Base Address 23:00
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.
; | | | | | `------- expansion direction. 1 for a LIFO ; | | | | | `------- expansion direction. 1 for a LIFO
; | | | | `-------- 1 always ; | | | | `-------- 1 always
; | | | `--------- 1 for segment descriptor, 0 for system descriptor ; | | | `--------- 1 for segment descriptor, 0 for system descriptor
; | | `---------- DPL !!! 0 for ring 0 ; | | `---------- DPL !!! 0 for ring 0
; | `----------- DPL (2/2) ; | `----------- DPL (2/2)
; `------------ 1 if in physical memory, 0 if page fault ; `------------ 1 if in physical memory, 0 if page fault
db 10001111b ; |7|6|5|4|3|2|1|0| db 10001111b ; |7|6|5|4|3|2|1|0|
; | | | | | | | `----- Limit 16 ; | | | | | | | `----- Limit 16
; | | | | | | `------ Limit 17 ; | | | | | | `------ Limit 17
; | | | | | `------- Limit 18 ; | | | | | `------- Limit 18
; | | | | `-------- Limit 19 ; | | | | `-------- Limit 19
; | | | `--------- available for use ; | | | `--------- available for use
; | | `---------- 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 31:24
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 15:00
db 0x0, 0x0, 0x0 ; Base Address 23:00 db 0x0, 0x0, 0x0 ; Base Address 23:00
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.
; | | | | | `------- 1 if "conformant". Don't know what is it... spectral ? xD ; | | | | | `------- 1 if "conformant". Don't know what is it... spectral ? xD
; | | | | `-------- 1 always ; | | | | `-------- 1 always
; | | | `--------- 1 for segment descriptor, 0 for system descriptor ; | | | `--------- 1 for segment descriptor, 0 for system descriptor
; | | `---------- DPL !!! 0 for ring 0 ; | | `---------- DPL !!! 0 for ring 0
; | `----------- DPL (2/2) ; | `----------- DPL (2/2)
; `------------ 1 if in physical memory, 0 if page fault ; `------------ 1 if in physical memory, 0 if page fault
db 10101111b ; |7|6|5|4|3|2|1|0| db 10101111b ; |7|6|5|4|3|2|1|0|
; | | | | | | | `----- Limit 16 ; | | | | | | | `----- Limit 16
; | | | | | | `------ Limit 17 ; | | | | | | `------ Limit 17
; | | | | | `------- Limit 18 ; | | | | | `------- Limit 18
; | | | | `-------- Limit 19 ; | | | | `-------- Limit 19
; | | | `--------- available for use ; | | | `--------- available for use
; | | `---------- 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 31:24
GDT_LENGTH: GDT_LENGTH:
[BITS 16]
disable_cursor: disable_cursor:
pushf pushf
push eax push eax
push edx push edx
mov dx, 0x3D4 mov dx, 0x3D4
mov al, 0xA ; low cursor shape register mov al, 0xA ; low cursor shape register
out dx, al out dx, al
inc dx inc dx
mov al, 0x20 ; bits 6-7 unused, bit 5 disables the cursor, bits 0-4 control the cursor shape mov al, 0x20 ; bits 6-7 unused, bit 5 disables the cursor, bits 0-4 control the cursor shape
out dx, al out dx, al
pop edx pop edx
pop eax pop eax
popf popf
ret ret
get_dimensions: get_dimensions:
push eax push eax
push ebx push ebx
@ -125,7 +130,7 @@ get_dimensions:
pop ebx pop ebx
pop eax pop eax
ret ret
;-----------------------------------------------------------------------; ;-----------------------------------------------------------------------;
; Checks if the CPU is compatible with 64-bits operating systems ; ; 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 ; ; If the 21th bit of the eax register is set, then CPUID is supported ;
@ -160,11 +165,26 @@ Is64bits:
stc stc
ret ret
;; INCLUDES PrintB:
%include "boot/common.inc" ; for 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
mov si, Init mov si, Init
call PrintB call PrintB
pop si pop si
@ -174,7 +194,7 @@ main:
mov si, Pass mov si, Pass
call PrintB call PrintB
;; enabling A20 ;; Enabling A20
mov si, EnA20 mov si, EnA20
call PrintB call PrintB
pop si pop si
@ -186,11 +206,11 @@ main:
call PrintB call PrintB
;; DISABLING CURSOR BLINKING AND GETTING INFOS ;; DISABLING CURSOR BLINKING AND GETTING INFOS
call get_dimensions call get_dimensions
call disable_cursor call disable_cursor
;;GO GDT64 ;;GO GDT64
cli ; disable interrupts cli ; disable interrupts
lgdt [GDT64] lgdt [GDT64]
;; ACTIVATE PROTECTED MODE ;; ACTIVATE PROTECTED MODE
mov eax, cr0 mov eax, cr0
@ -203,7 +223,7 @@ main:
; | ; |
; `------ Paging bit ; `------ Paging bit
mov cr0, eax mov cr0, eax
push dword [VIDEO_MODE] push dword [VIDEO_MODE]
push dword [VGA_HEIGHT] push dword [VGA_HEIGHT]
jmp (CODE_SELECTOR-GDT64):main32 jmp (CODE_SELECTOR-GDT64):main32
@ -244,11 +264,11 @@ main32:
.make_page_entries: .make_page_entries:
stosd stosd
add edi, 4 add edi, 4
add eax, 0x1000 add eax, 0x1000
loop .make_page_entries loop .make_page_entries
;; pointing pml4 ;; pointing pml4
mov eax, 0x70000 ; Bass address of 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 ;; ACTIVATE LONG MODE
mov ecx, 0xC0000080 ; address of MSR mov ecx, 0xC0000080 ; address of MSR
@ -257,7 +277,7 @@ main32:
wrmsr ; write MSR wrmsr ; write MSR
;; ACTIVATE PAGING ;; ACTIVATE PAGING
mov eax, cr0 mov eax, cr0
or eax, 0x80000000 ; make bit 31 (PG = Paging) to 1 : or eax, 0x80000000 ; make bit 31 (PG = Paging) to 1 :
; |1|000000000000000000000000000000 ; |1|000000000000000000000000000000
; | ; |
@ -271,6 +291,23 @@ main32:
[BITS 64] [BITS 64]
;; FUNCTIONS ;; 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: write:
;-----------------------------------------------------------------------; ;-----------------------------------------------------------------------;
@ -297,8 +334,8 @@ write:
jmp .pLoop jmp .pLoop
.pEnd: .pEnd:
pop rdi pop rdi
pop rsi pop rsi
ret ret
.lf: .lf:
mov rax, [VGA_HEIGHT64] mov rax, [VGA_HEIGHT64]
add [NextTRAM], rax ; Cursor moving add [NextTRAM], rax ; Cursor moving
@ -318,13 +355,15 @@ write:
jmp .pLoop jmp .pLoop
;; DATA ;; DATA
txt db 0x09, " Switching to Long Mode... OK", 0x0A, 0x0D, 0 txt db 0x09, " Switching to Long Mode... OK", 0x0A, 0x0D, 0
Init db 0x09, " Checking CPUID", 0 Init db "Booting OS/K !", 0x0D, 0x0A, 0x0D, 0x0A, 0x09, " Checking CPUID...",0
EnA20 db 0x09, " Enabling A20 line", 0 Reinit db "Booting OS/K !", 0x0D, 0x0A, 0x0D, 0x0A, 0
NoLongMode db 0x0A, 0x0D, "ERROR: Your computer is not designed for x64 OS", 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 Pass db " OK", 0x0A, 0x0D, 0
NextTRAM dq 0x0B8AA0 ; Last position of cursor NextTRAM dq 0x0B8000 ; Last position of cursor
VIDEO_MODE64 dq 0 VIDEO_MODE64 dq 0
VGA_HEIGHT64 dq 0 VGA_HEIGHT64 dq 0
VGA_X dq 0x0 VGA_X dq 0x0
@ -335,30 +374,39 @@ main64:
pop qword [VIDEO_MODE64] pop qword [VIDEO_MODE64]
;; INITIALIZE STACK ;; INITIALIZE STACK
mov rsp, 0x9F000 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 bl, 0x0A
mov esi, txt mov esi, txt
call write call write
mov bl, 0x0B
mov esi, msg
call write
mov bl, 0x0C
mov esi, msg
call write
mov bl, 0x0D mov bl, 0x0D
mov esi, msg mov esi, msg
call write call write
mov bl, 0x0E jmp Die
mov esi, msg
call write
;call KERNEL
jmp $
[BITS 16] [BITS 16]
ErrorNo64: ErrorNo64:
@ -368,6 +416,4 @@ Die:
cli cli
hlt ; die nooooow hlt ; die nooooow
retf retf
times 1024-($-$$) db 144
KERNEL: KERNEL:

View File

@ -1,11 +0,0 @@
;=----------------------------------------------------------------------------=;
; GNU GPL OS/K ;
; ;
; Authors: spectral` ;
; NeoX ;
; ;
; Desc: Functions for the OS/K mbr ;
; (x86_64 architecture only) ;
;=----------------------------------------------------------------------------=;

View File

@ -4,185 +4,338 @@
; Authors: spectral` ; ; Authors: spectral` ;
; NeoX ; ; NeoX ;
; ; ; ;
; Desc: Master Boot Record for OS/K ; ; Desc: Bootsector for OS/K ;
; (x86_64 architecture only) ; ; (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 ;; DISK BUFFER "SEGMENT"
[ORG 0x7C00] ; address where the BIOS/UEFI CSM is loading us %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 [BITS 16] ; Ensure 16-bit code (because fuck UEFI)
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
TIMES 12 DB 0 ; going to the next offset ;---------------------------------------------------
; Disk description table
;---------------------------------------------------
Intro:
DriveNumber db 0x00 jmp short _start ; Jump over the BIOS PARAMETER BLOCK
ReservedByte db 0x00 nop ; Required by BIOS to recognize the Disk
Signature db 0x29 BPB:
VolumeID dd 0xFFFFFFFF %define OEMName bp+0x03 ; Disk label
VolumeLabel db "OS/K BDISK " %define bytesPerSector bp+0x0b ; Bytes per sector
SystemID db "FAT32 " %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: ;; ENTRY POINT
;; saving registers for future _start:
pushad jmp BOOT_SEG:$+5 ; Fix the cs:ip registers with a vaudou magical trip
pushfd
pushf
;; dl contains the boot drive. Saving it. bootstrap:
mov [Bootdrv], dl mov ax, BOOT_SEG ; Set segments to the location of the bootloader
mov ds, ax
;; hello world mov es, ax
push si
mov si, Starting ;; INIT STACK
call PrintB 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 ;; INITIALIZE BOOT DISK
mov si, Switch or dl, dl ; Verifying dl points actually to the boot drive
call PrintB jz loadRoot
pop si mov byte [Bootdrv], dl ; Another soul (the disk) saved !
mov cx, word [SectorsPerCluster] ; size of a cluster in sectors is stored in cx mov ah, 0x08
int 0x13 ; int 0x13 : read drive parameters/geom
; computing location of the begining of the Data area and store in ax jc loadRoot
mov al, byte [TotalFATs] ; Total number of FATs and cx, 0x003f ; Maximum sector number is the high bits 6-7 of cl
mul word [BigSectorsPerFAT] ; Number of sectors for a FAT mov word [sectorsPerTrack], cx ; And whose low 8 bits are in ch
add ax, word [ReservedSectors] ; Find the start of the Data area mov dl, dh ; Convert the maximum head number to a word with another vaudou magical trip
mov word [Datasector], ax ; Store the begining of the Data area 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 di, BUFFER_SEG ; Set the extra segment to the disk buffer
mov ax, word [RootDirectoryStart] mov es, di
call ClusterLBA mov di, BUFFER_OFF ; Set es:di and load the root directory into the disk buffer
mov bx, 0x0200 ; copy 1st data cluter above bootcode call readSectors ; Read the sectoooooooors !
call ReadSectors
; Point Index register to 1st File Entry ;; FIND THE SECOND STAGE LOADER
mov di, 0x0200 + 0x20 mov di, BUFFER_OFF ; Set es:di to the disk buffer
;Point to the offset where the file location information contains mov cx, word [rootDirEntries] ; Search through all of the root dir entries
mov dx, word [di + 0x001A] xor ax, ax ; Clear ax for the file entry offset
mov word [Cluster], dx searchRoot:
;Set up the segments where the loader needs to be loaded ;) xchg cx, dx ; Save cx because it's a loop counter
mov ax, 0100h ; set ES:BX = 0100:0000 mov si, filename ; Load the filename
mov es, ax mov cx, 11 ; Compare first 11 bytes
xor bx, bx rep cmpsb ; Compare si and di cx times
je loadFat ; We found the LOADEEEEEEEER!!!
;Read the cluster which contains the loader add ax, 32 ; File entry offset
mov cx, 0x0008 mov di, BUFFER_OFF ; Point back to the start of the entry
mov ax, word [Cluster] add di, ax ; Add the offset to point to the next entry
call ClusterLBA xchg dx, cx
call ReadSectors loop searchRoot ; Continue to search for the file
;Jump to the location where the loader was loded
popf
popfd
popad
push word [Bootdrv]
call dword SECOND_STAGE:0000
; Exiting ;; ERROR...
mov ah, 0x00 mov si, fileNotFound ; Could not find the file
int 0x19 ; warm boot computer 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 !!!
;;----------------------------------------------------------------------------;; ;; LOAD THE CLUSTERS OF THE LOADER AND JUMP
;; DATA loadFile:
Starting db 0x0A, 0x0D, 0x07, "GNU GPL OS/K", 0x0A, 0x0D, 0x0A, 0x0D, 0 mov di, LOAD_SEG
Switch db 0x09, " Loading Second Stage", 0 mov es, di ; Set es:bx to where the file will load
AbsoluteSector db 0x00 mov di, LOAD_OFF
AbsoluteHead db 0x00 pop ax ; File cluster restored
AbsoluteTrack db 0x00 call readClusters ; Read clusters from the file
Cluster dw 0x0000 mov dl, byte [Bootdrv] ; Pass the boot Bootdrv into dl
Datasector dw 0x0000 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) ; ; FUNCTIONS ;
;-------------------------------------------------------------------; ;---------------------------------------------------;
ReadSectors:
.main: readClusters:
mov di, 0x0005 ; five retries for error ;---------------------------------------------------;
.sectorloop: ; 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 ax
push bx push bx
push cx push cx
call LbaToChs push dx
mov ah, 0x02 ; BIOS read sector push di
mov al, 0x01 ; read one sector push es
mov ch, BYTE [AbsoluteTrack] ; track .clusterLoop:
mov cl, BYTE [AbsoluteSector] ; sector xor bh, bh
mov dh, BYTE [AbsoluteHead] ; head xor dx, dx
int 0x13 ; invoke BIOS push ax ; Get the cluster start = (cluster - 2) * sectorsPerCluster + userData
jnc .success ; test for read error sub ax, 2 ; Subtract 2
xor ax, ax ; BIOS reset disk mov bl, byte [sectorsPerCluster] ; Sectors per cluster is a byte value
int 0x13 ; invoke BIOS mul bx ; multiply (cluster - 2) * sectorsPerCluster
dec di ; decrement error counter 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 cx
pop bx pop bx
pop ax 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 ret
;-------------------------------------------------------------------;
; Converts LBA Adresses to CHS ; readSectors:
;-------------------------------------------------------------------; ;---------------------------------------------------;
LbaToChs: ; Read sectors starting at a given sector by ;
xor dx, dx ; prepare dx:ax for operation ; the given times and load into a buffer. Please ;
div WORD [SectorsPerTrack] ; calculate ; note that this may allocate up to 128KB of ram. ;
inc dl ; adjust for sector 0 ; ;
mov BYTE [AbsoluteSector], dl ; Expects: AX = Starting sector ;
xor dx, dx ; prepare dx:ax for operation ; CX = Number of sectors to read ;
div WORD [SectorsPerHead] ; calculate ; ES:DI = Location to load sectors ;
mov BYTE [AbsoluteHead], dl ; ;
mov BYTE [AbsoluteTrack], al ; 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 ret
;-------------------------------------------------------------------;
; Converts FAT Adresses to LBA ; print:
;-------------------------------------------------------------------; ;---------------------------------------------------;
ClusterLBA: ; Print out a simple string. ;
sub ax, 0x0002 ; zero base cluster number ; ;
xor cx, cx ; Expects: DS:SI = String to print ;
mov cl, BYTE [SectorsPerCluster] ; convert byte to word ; ;
mul cx ; Returns: None ;
add ax, WORD [Datasector] ; base data sector ; ;
;---------------------------------------------------;
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 ret
End: ;; LOVELY DATA
times 510-($-$$) db 144 ; NOP until 510 fileNotFound db "FStage ERR : NO LOADER", 0 ; File was not found
dw 0xAA55 ; magic word 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