From 1d349f2f23908057618c01c04652ee094a756e47 Mon Sep 17 00:00:00 2001 From: Wes R Date: Mon, 21 Aug 2023 13:05:17 -0400 Subject: [PATCH] added some code to read from disk --- src/bootloader/boot.asm | 129 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 126 insertions(+), 3 deletions(-) diff --git a/src/bootloader/boot.asm b/src/bootloader/boot.asm index 7d13b2e..0622100 100644 --- a/src/bootloader/boot.asm +++ b/src/bootloader/boot.asm @@ -71,16 +71,139 @@ main: mov ss, ax mov sp, 0x7c00 ; stack will grow downwards in memory as it is filled + ;; read something from floppy disk + ;; BIOS should have placed drive number in dl + mov [ebr_drive_number], dl + mov ax, 1 ; LBA=1 start reading at first sector after bootloader + mov cl, 1 ; read 1 sector + mov bx, 0x7E00 ; data should be read into memory after the bootloader + call disk_read + ;; print message mov si, msg_hello call puts - hlt ; stop executing + cli + hlt + +floppy_error: + mov si, msg_read_failed + call puts + jmp wait_key_and_reboot + +wait_key_and_reboot: + mov ah, 0 + int 16h ; wait for keypress + jmp 0FFFFh:0 ; jump to begininng of BIOS .halt: - jmp .halt ; really make sure we're not executing random shit + cli + hlt + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Disk Routines +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Convert an LBA address to a CHS address +;; Parameters: +;; - ax: LBA Address +;; +;; Returns: +;; - cx[bits 0-5]: sector number +;; - cx[bits 6-15]: cylinder +;; - dh: head +;; +lba_to_chs: + push ax + push dx -msg_hello: db 'Hello Shitass!', ENDL, 0 ; named constant + ; Calculate Sector + ; div dvides whatever is in ax by the divisor supplied + ; ax contains our desired LBA at this point + xor dx, dx ; dx = 0 (dx receives the remainder after a div instruction) + div word [bdb_sectors_per_track] ; ax = LBA / sectors_per_track + ; dx = LBA % sectors_per_track + inc dx ; dx = dx + 1 (this is the sector value) + mov cx, dx ; put sector value into cx + + ; Calculate Cylinder/Head + ; ax still contains (LBA / sectors_per_track) at this point + xor dx, dx ; dx = 0 + div word [bdb_heads] ; ax = (LBA / sectors_per_track) / heads (this is the cylinder value) + ; dx = (LBA / sectors_per_track) % heads (this is the head value) + + ;; Move calculated values to target registers (cx already contains sector number by now) + mov dh, dl ; dl is the lower 8 bits of dx, this moves the calculated head value to dh + mov ch, al ; ch = cylinder (lower 8 bits) + shl ah, 6 + or cl, ah ; put upper 2 bits of cylinder in CL + + pop ax + mov dl, al ; restore whatever was in dl prior to this. dh needs to have the calculated head value + pop ax + ret + +;; Reads sectors from a disk into memory +;; Parameters: +;; - ax: LBA Address +;; - cl: number of sectors to read (128 max) +;; - dl: drive number +;; - es:bx: memory address where to store data +disk_read: + push ax + push bx + push cx + push dx + push di + + push cx ; save number of sectors to read to stack (lba_to_chs uses cx) + call lba_to_chs ; calculate CHS + pop ax ; restore number of sectors to read into ax, cx contains sector and cylinder, dh contains head + mov ah, 02h ; this is required by interrupt 13 + mov di, 3 ; retry count + +.retry: + pusha ; save all registers, BIOS does what BIOS wants + stc ; explicitly set carry flag to be safe + int 13h ; carry flag cleared = success + jnc .done ; jumo if carry not set + + ; read failed + popa + call disk_reset + + dec di + test di, di + jnz .retry + +.fail: + ; all retry attempts used + jmp floppy_error + +.done: + popa + + pop di + pop dx + pop cx + pop bx + pop ax + ret + +;; Resets disk controller +;; Parameters: +;; - dl: drive number +disk_reset: + pusha + mov ah, 0 + stc + int 13h + jc floppy_error + popa + ret + +msg_hello: db 'Hello Shitass!', ENDL, 0 ; named constant +msg_read_failed: db 'Read from disk failed!', ENDL, 0 times 510-($-$$) db 0 ; pad program with zeros up to byte 510 dw 0AA55h ; BIOS requires last two bytes of first sector to be AA55