I call int 0x19 only if something fails. When I do, I print a message and wait for a keypress to reboot, so from what I see when I run bochs, it isn't calling int 0x19. I do call int 0x18 in the read sector code. When I take that out, the program freezes, but doesn't give the boot device error that I was getting. Of course, by removing that code I probably just introduced a new error, so the response is probably completely unrelated. Here's the code with working parts omitted:
Code: Select all
[BITS 16] ;16 bit code generation
[ORG 0x500]
start:
;Adjust data segment
cli
xor ax, ax
mov ds, ax
;Print status message
mov si, msgLoading
call WriteMessage
;Check for compatible processor
call detect_cpu
;Enable A20 Line
call enableA20
;Reset the disk
mov ah, 0 ;0050:000b 0x50b
mov dl, BYTE [DriveNumber]
int 0x13
;Load the kernel
call loadkernel
;Enter protected mode
cli ; Disable interrupts, we want to be alone
xor ax, ax
mov ds, ax ; Set DS-register to 0 - used by lgdt
lgdt [gdt_desc] ; Load the GDT descriptor
mov eax, cr0 ; Copy the contents of CR0 into EAX
or eax, 1 ; Set bit 0
mov cr0, eax ; Copy the contents of EAX into CR0
;Far jump to 32 bit code
jmp 08h:clear_pipe
;*********************Load kernel with FAT*****************************
loadkernel:
;****************Begin using FAT file system to find OS Boot Program***********
;compute size of root directory and store in cx
xor cx, cx
xor dx, dx
mov ax, 0x0020 ;32 byte directory entry
mul WORD [MaxRootEntries] ;total size of directory
div WORD [BytesPerSector] ;sectors used by directory
xchg ax, cx
;compute location of root directory and store in ax
mov al, BYTE [TotalFATs]
mul WORD [SectorsPerFAT]
add ax, WORD [ReservedSectors]
mov WORD [datasector], ax
add WORD [datasector], cx
;read root directory into memory (7C00:0200) above boot code
mov bx, 0x1000
call ReadSectors ;0x54e
;browse root directory for binary image
mov cx, WORD [MaxRootEntries]
mov di, 0x1000
.LOOP
push cx
mov cx, 0x000B
mov si, ImageName ;Image name to find
push di
rep cmpsb ;Test entry for match
pop di
je LOAD_FAT
pop cx
add di, 0x0020
loop .LOOP
jmp FAILURE
LOAD_FAT:
; save starting cluster of boot image
mov dx, WORD [di + 0x001A]
mov WORD [cluster], dx ; file's first cluster
; compute size of FAT and store in "cx"
xor ax, ax
mov al, BYTE [TotalFATs] ; number of FATs
mul WORD [SectorsPerFAT] ; sectors used by FATs
mov cx, ax
; compute location of FAT and store in "ax"
mov ax, WORD [ReservedSectors] ; adjust for bootsector
; read FAT into memory (7C00:0200)
mov bx, 0x1000 ; copy FAT above bootcode
call ReadSectors
; read image file into memory (0090:0000)
mov si, msgCRLF
call WriteMessage
mov ax, 0x0090
mov es, ax ; destination for image
mov bx, 0x0000 ; destination for image
push bx
LOAD_IMAGE:
mov ax, WORD [cluster] ; cluster to read
pop bx ; buffer to read into
call ClusterLBA ; convert cluster to LBA
xor cx, cx
mov cl, BYTE [SectorsPerCluster] ; sectors to read
call ReadSectors
push bx
; compute next cluster
mov ax, WORD [cluster] ; identify current cluster
mov cx, ax ; copy current cluster
mov dx, ax ; copy current cluster
shr dx, 0x0001 ; divide by two
add cx, dx ; sum for (3/2)
mov bx, 0x1000 ; location of FAT in memory
add bx, cx ; index into FAT
mov dx, WORD [bx] ; read two bytes from FAT
test ax, 0x0001
jnz .ODD_CLUSTER
.EVEN_CLUSTER:
and dx, 0000111111111111b ; take low twelve bits
jmp .DONE
.ODD_CLUSTER:
shr dx, 0x0004 ; take high twelve bits
.DONE:
mov WORD [cluster], dx ; store new cluster
cmp dx, 0x0FF0 ; test for end of file
jb LOAD_IMAGE
DONE:
mov si, msgSuccess
call WriteMessage
ret
FAILURE:
mov si, msgFailure
call WriteMessage
mov ah, 0x00
int 0x16 ; await keypress
int 0x19 ; warm boot computer
;*****OMITTED CODE********
;*************************************************************************
; PROCEDURE ReadSectors
; reads "cx" sectors from disk starting at "ax" into memory location "es:bx"
;*************************************************************************
ReadSectors:
.MAIN
mov di, 0x0005 ; five retries for error
.SECTORLOOP
push ax
push bx
push cx
call LBACHS
mov ah, 0x02 ; BIOS read sector
mov al, 0x01 ; read one sector
mov ch, BYTE [absoluteTrack] ; track
mov cl, BYTE [absoluteSector] ; sector
mov dh, BYTE [absoluteHead] ; head
mov dl, BYTE [DriveNumber] ; drive
int 0x13 ; invoke BIOS
jnc .SUCCESS ; test for read error
xor ax, ax ; BIOS reset disk
int 0x13 ; invoke BIOS
dec di ; decrement error counter
pop cx
pop bx
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
;*************************************************************************
; PROCEDURE ClusterLBA
; convert FAT cluster into LBA addressing scheme
; LBA = (cluster - 2) * sectors per cluster
;*************************************************************************
ClusterLBA:
sub ax, 0x0002 ; zero base cluster number
xor cx, cx
mov cl, BYTE [SectorsPerCluster] ; convert byte to word
mul cx
add ax, WORD [datasector] ; base data sector
ret
;*************************************************************************
; PROCEDURE LBACHS
; convert "ax2; LBA addressing scheme to CHS addressing scheme
; absolute sector = (logical sector / sectors per track) + 1
; absolute head = (logical sector / sectors per track) MOD number of heads
; absolute track = logical sector / (sectors per track * number of heads)
;*************************************************************************
LBACHS:
xor dx, dx ; prepare dx:ax for operation
div WORD [SectorsPerTrack] ; calculate
inc dl ; adjust for sector 0
mov BYTE [absoluteSector], dl
xor dx, dx ; prepare dx:ax for operation
div WORD [NumHeads] ; calculate
mov BYTE [absoluteHead], dl
mov BYTE [absoluteTrack], al
ret
;*************************Protected Mode Code************************
[BITS 32] ; We now need 32-bit instructions
clear_pipe:
mov ax, 10h ; Save data segment identifyer
mov ds, ax ; Move a valid data segment into the data segment register
mov ss, ax ; Move a valid data segment into the stack segment register
mov esp, 090000h ; Move the stack pointer to 090000h
mov byte [ds:0B8000h], 'P' ; Move the ASCII-code of 'P' into first video memory
mov byte [ds:0B8001h], 1Bh ; Assign a color code
hang:
jmp hang ; Loop, self-jump
;**********************Global Descriptor Table***********************
gdt: ; Address for the GDT
gdt_null: ; Null Segment
dd 0
dd 0
gdt_code: ; Code segment, read/execute, nonconforming
dw 0FFFFh
dw 0
db 0
db 10011010b
db 11001111b
db 0
gdt_data: ; Data segment, read/write, expand down
dw 0FFFFh
dw 0
db 0
db 10010010b
db 11001111b
db 0
gdt_end: ; Used to calculate the size of the GDT
gdt_desc: ; The GDT descriptor
dw gdt_end - gdt - 1 ; Limit (size)
dd gdt ; Address of the GDT
;**********************Our "data section"*****************************
msgLoading db 13, 10, "Running boot code", 13, 10, 0
msgProcessor db "Checking for compatible CPU", 13, 10, 0
msgProcGood db "Compatible processor found", 13, 10, 0
msgProcBad db "ERROR: No compatible processor. Press any key to reboot", 13, 10, 0
msgA20Warn db "WARNING: Non-standard method used to enable A20", 13, 10, 0
msgA20Succeed db "A20 Line successfully enabled", 13, 10, 0
msgA20Fail db "ERROR: Could not enable A20 line", 13, 10, 0
msgFailure db "ERROR: Failed to load the kernel", 13, 10, 0
msgSuccess db "Loaded kernel", 13, 10, 0
msgTest db "TEST!!!", 13, 10, 0
absoluteSector db 0x00
absoluteHead db 0x00
absoluteTrack db 0x00
datasector dw 0x0000
cluster dw 0x0000
msgCRLF db 13, 10, 0
ImageName db "KERNEL BIN"
;***********************FAT12 data*****************************
OEM_ID db "StOSBOOT"
BytesPerSector dw 0x0200
SectorsPerCluster db 0x01
ReservedSectors dw 0x0001
TotalFATs db 0x02
MaxRootEntries dw 0x00E0
TotalSectorsSmall dw 0x0B40
MediaDescriptor db 0xF0
SectorsPerFAT dw 0x0009
SectorsPerTrack dw 0x0012
NumHeads dw 0x0002
HiddenSectors dd 0x00000000
TotalSectorsLarge dd 0x00000000
DriveNumber db 0x00
Flags db 0x00
Signature db 0x29
VolumeID dd 0xFFFFFFFF
VolumeLabel db "StOS BOOT"
SystemID db "FAT12 "