os-k/src/boot/mbr.s

342 lines
16 KiB
ArmAsm
Raw Normal View History

;=----------------------------------------------------------------------------=;
; GNU GPL OS/K ;
; ;
; Authors: spectral` ;
; NeoX ;
; ;
2018-12-21 23:57:41 +01:00
; Desc: Bootsector for OS/K ;
; (x86_64 architecture only) ;
;=----------------------------------------------------------------------------=;
2018-12-21 23:57:41 +01:00
;; 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
;; DISK BUFFER "SEGMENT"
%define BUFFER_SEG 0x2000 ; (BUFFER_SEG << 4) + BUFFER_OFF = 0x020000
%define BUFFER_OFF 0x0000
;; SECOND STAGE LOADER "SEGMENT"
%define LOAD_SEG 0x0000 ; (LOAD_SEG << 4) + LOAD_OFF = 0x030000
%define LOAD_OFF 0x1000
[BITS 16] ; Ensure 16-bit code (because fuck UEFI)
;---------------------------------------------------
; Disk description table
;---------------------------------------------------
Intro:
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
;; ENTRY POINT
_start:
jmp BOOT_SEG:$+5 ; Fix the cs:ip registers with a vaudou magical trip
2018-12-21 23:57:41 +01:00
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 !
2018-12-21 23:57:41 +01:00
;; 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
2018-12-21 23:57:41 +01:00
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 !
;; 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
2018-12-21 23:57:41 +01:00
;; 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
2018-12-21 23:57:41 +01:00
;; 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
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!
hlt ; This should never be hit...
; ...
; ...
; I hope....
; ...
;---------------------------------------------------;
; 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
2018-12-21 23:57:41 +01:00
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
2018-12-21 23:57:41 +01:00
ret
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
2018-12-21 23:57:41 +01:00
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
2018-12-21 23:57:41 +01:00
;; 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