170 lines
		
	
	
	
		
			2.6 KiB
		
	
	
	
		
			NASM
		
	
	
	
	
	
			
		
		
	
	
			170 lines
		
	
	
	
		
			2.6 KiB
		
	
	
	
		
			NASM
		
	
	
	
	
	
| ; SPDX-License-Identifier: MIT
 | |
| ; Copyright (c) 2021 Juhani 'nortti' Krekelä.
 | |
| 
 | |
| iosegment segment at 60h
 | |
| ioinit proc far
 | |
| ioinit endp
 | |
| iosegment ends
 | |
| 
 | |
| bootloader segment
 | |
| assume cs:bootloader, ds:bootloader, es:bootloader, ss:bootloader
 | |
| org 7c00h
 | |
| 
 | |
| jmp code
 | |
| 
 | |
| ; BPB
 | |
| 	db "Ordos   " ; OEM Identifier
 | |
| 	dw 512 ; Bytes per sector
 | |
| 	db 2 ; Sectors per cluster
 | |
| 	dw 1 ; Reserved sectors
 | |
| 	db 2 ; FATs
 | |
| 	dw 112 ; Root directory entries
 | |
| 	dw 2*320 ; Total sectors
 | |
| 	db 0ffh ; Media descriptor
 | |
| 	dw 1 ; Sectors per fat
 | |
| sectorspertrack dw 8
 | |
| heads dw 2
 | |
| 	dd 0 ; Hidden sectors
 | |
| 	dd 0 ; Total sectors (large)
 | |
| 
 | |
| code:
 | |
| 	cld
 | |
| 	mov ax, cs
 | |
| 	mov ds, ax
 | |
| 	mov es, ax
 | |
| 	cli
 | |
| 	mov ss, ax
 | |
| 	mov sp, 7c00h
 | |
| 	sti
 | |
| 
 | |
| 	mov drivenumber, dl
 | |
| 
 | |
| 	; TODO: Check we actually have the OS
 | |
| 	mov ax, 10
 | |
| 	mov bx, 600h
 | |
| 	mov cx, 17 ; This is what PC-DOS 1.10's full size ends up at
 | |
| 	call loadsectors
 | |
| 
 | |
| 	mov si, offset success_msg
 | |
| 	call printstr
 | |
| 
 | |
| 	jmp ioinit
 | |
| 
 | |
| ; IN:
 | |
| ;  ax = LBA of first sector
 | |
| ;  es:bx = destination buffer
 | |
| ;  cx = number of sectors to load
 | |
| loadsectors proc
 | |
| 	push ax
 | |
| 	push cx
 | |
| 	push dx
 | |
| 	push di
 | |
| 
 | |
| 	loading_loop:
 | |
| 		mov di, 3 + 1 ; Retry thrice, + 1 is since we dec first
 | |
| 
 | |
| 		retry:
 | |
| 
 | |
| 		push ax
 | |
| 		push cx
 | |
| 
 | |
| 		chs:
 | |
| 			xor dx, dx
 | |
| 			; cylinder (track) - head - sector
 | |
| 			; cylinder = LBA / sectorspertrack / heads
 | |
| 			; head = LBA / sectorspertrack % heads
 | |
| 			; sector = LBA % sectorspertrack + 1
 | |
| 			div sectorspertrack
 | |
| 			; ax = LBA / sectorspertrack
 | |
| 			; dx = LBA % sectorspertrack
 | |
| 
 | |
| 			; sector
 | |
| 			mov cl, dl
 | |
| 			inc cl
 | |
| 
 | |
| 			xor dx, dx
 | |
| 			div heads
 | |
| 			; ax = LBA / sectorspertrack / heads
 | |
| 			; dx = LBA / sectorspertrack % heads
 | |
| 
 | |
| 			; head
 | |
| 			mov dh, dl
 | |
| 
 | |
| 			; cylinder (track)
 | |
| 			mov ch, al
 | |
| 			shr ax, 1
 | |
| 			shr ax, 1
 | |
| 			and al, 0c0h
 | |
| 			or cl, al
 | |
| 
 | |
| 		mov ax, 0201h
 | |
| 		mov dl, drivenumber
 | |
| 		int 13h
 | |
| 
 | |
| 		jc disk_error
 | |
| 
 | |
| 		mov ax, 0e00h + '.'
 | |
| 		int 10h
 | |
| 
 | |
| 		pop cx
 | |
| 		pop ax
 | |
| 
 | |
| 		inc ax
 | |
| 		add bx, 512
 | |
| 
 | |
| 		loop loading_loop
 | |
| 
 | |
| 	pop di
 | |
| 	pop dx
 | |
| 	pop cx
 | |
| 	pop ax
 | |
| 	ret
 | |
| 
 | |
| 	disk_error:
 | |
| 		; Do we still have retries remaining?
 | |
| 		dec di
 | |
| 		jnz reset_disk
 | |
| 
 | |
| 		; No, die
 | |
| 		mov si, offset error_msg
 | |
| 		call printstr
 | |
| 
 | |
| 	hang:
 | |
| 		hlt
 | |
| 		jmp hang
 | |
| 
 | |
| 	reset_disk:
 | |
| 		; Yes, reset disk and retry
 | |
| 		xor ah, ah
 | |
| 		int 13h
 | |
| 
 | |
| 		pop cx
 | |
| 		pop ax
 | |
| 		jmp retry
 | |
| loadsectors endp
 | |
| 
 | |
| ; IN:
 | |
| ;  si = null-terminated string
 | |
| printstr proc
 | |
| 	lodsb
 | |
| 	test al, al
 | |
| 	jz ret_printstr
 | |
| 	mov ah, 0eh
 | |
| 	int 10h
 | |
| 	jmp printstr
 | |
| 
 | |
| 	ret_printstr:
 | |
| 		ret
 | |
| printstr endp
 | |
| 
 | |
| drivenumber db (?)
 | |
| 
 | |
| success_msg db 13, 10, "DOS Loaded", 13, 10, 0
 | |
| error_msg db 13, 10, "Disk error", 0
 | |
| 
 | |
| org 7c00h + 510
 | |
| 	dw 0aa55h
 | |
| 
 | |
| bootloader ends
 | |
| 
 | |
| end
 |