pluto/src/bootloader/functions.asm
Edward Dean 7678019e03 Feature/bootloader (#2), closes #1
* Added bootloader files

* Changed to spaces from tabs
2019-03-27 21:33:59 +00:00

103 lines
5 KiB
NASM

; Print a null terminated string to the screen
; DS:SI is the location of the string
; Input:
; SI - pointer to the string to be printed in register SI
print_string_with_new_line:
pusha ; Push all registers onto the stack
mov ah, 0x0E ; Specify the teletype output function
xor bx, bx
.loop:
lodsb ; Load byte at address SI into AL and increment SI
cmp al, 0 ; If it the end of the null-terminated string
je .done ; Then exit
int 0x10 ; Else print the character in AL as an interrupt into the BIOS
jmp short .loop ; Repeat for next character
.done:
; Print the line feed and carriage return
mov al, 0x0A ; Teletype print sub function(0x0E), Line feed (0x0A)
int 0x10
mov al, 0x0D ; Carriage return
int 0x10
popa ; Pop the register of the stack
ret ; And return to caller
; Reboot the computer if there was an error
reboot:
m_write_line reboot_msg
xor ah, ah ; Sub function for reading a character
int 0x16 ; Wait for key press
int 0x19 ; Warm reboot
cli ; If failed to reboot, halt
hlt ; Halt
; Read a sector from the disk
; ES:BX is the location of the buffer that the data is read into
; As reads often fail, it will try 4 times to read from the disk. The counter is stored in CX.
; With the data buffer at ES:BX
; Input:
; AX - The logical block address (LBA)
; ES:BX - The buffer location which the sector will be read into
read_sector:
xor cx, cx ; Set the counter to 0
.read:
push ax ; Save the logical block address
push cx ; Save the counter
; Convert the logical block address into the head-cylinder/track-sector values
; The conversions are:
; (1) Sector = (LBA mod SectorsPerTrack) + 1
; (2) Cylinder = (LBA / SectorsPerTrack) / NumHeads
; (3) Head = (LBA / SectorsPerTrack) mod NumHeads
;
; Input:
; AX - the logical block address
; Output: These are used for the 0x13 BIOS interrupt to read from the disk along with ES:BX and ax
; CH - Lower 8 bits of cylinder
; CL - Upper 2 bits of cylinder and 6 bits for the sector
; DH - The head number
; DL - The drive number/ID
.lba_to_hcs:
push bx ; Save the buffer location
;mov bx, word [Sectors_per_track] ; Get the sectors per track
xor dx, dx ; Set DX to 0x0 (part of operand for DIV instruction and needs to be 0x00)
div word [Sectors_per_track] ; Divide (DX:AX / Sectors_per_track)
; Quotient (AX) - LBA / SectorsPerTrack
; Remainder (DX) - LBA mod SectorsPerTrack
inc dx ; (1) Sector = (LBA mod SectorsPerTrack) + 1
mov cl, dl ; Store sector in cl as defined for the output and for the 0x13 BIOS interrupt
;mov bx, word [Head_count] ; Get the number of heads
xor dx, dx
div word [Head_count] ; Quotient (AX) - Cylinder = (LBA / SectorsPerTrack) / NumHeads
; Remainder (DX) - Head = (LBA / SectorsPerTrack) mod NumHeads
mov ch, al ; Store cylinder in ch as defined for the output and for the 0x13 BIOS interrupt
mov dh, dl ; Store head in DH as defined for the output and for the 0x13 BIOS interrupt
mov dl, byte [Logical_drive_number] ; Store drive number in DL as defined for the output and for the 0x13 BIOS interrupt
pop bx ; Restore the buffer location
; Using the values above, read off the drive
mov ax, 0x0201 ; Sub function 2 to read from the disk, Read 1 (0x01) sector
int 0x13 ; Call BIOS interrupt 13h
jc short .read_fail ; If fails to read (carry bit set)
pop cx
pop ax ; Restore the logical block address
ret ; If read successful, then return to caller
.read_fail: ; If failed to read, try again, if tried 4 times, the reboot
pop cx ; Restore the counter
inc cx ; Increment the counter
cmp cx, 4 ; Compare if counter is equal to 4
je boot_error ; If equal, then error reading 4 times so reboot
xor ah, ah ; Reset the disk to try again
int 0x13
pop ax ; Restore the logical block address
jmp .read ; Try to read again