Skip to content

Commit

Permalink
Fix disk/read write error handling and add int13h LBA BIOS extensions
Browse files Browse the repository at this point in the history
  • Loading branch information
joshudson committed Dec 10, 2023
1 parent a010490 commit 1dcc99d
Show file tree
Hide file tree
Showing 6 changed files with 248 additions and 33 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,7 @@ bios.bin
bios.lst
tinyxms.sys
tinyxms.lst
quitemu.com
quitemu.lst
8086tiny
hd.img
42 changes: 38 additions & 4 deletions 8086tiny.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <memory.h>
#include <stdint.h>
#include <stdlib.h>
#include <errno.h>

#define AMOUNT_XMS_HANDLES 32
#define XMS_REPORTED_FREE (16 * 1024 * 1024)
Expand Down Expand Up @@ -355,6 +356,38 @@ code_to_utf8(unsigned char *const buffer,
return 3;
}

// read/write routine -- Joshua Hudson <joshudson@gmail.com> 2023
unsigned char readwrite(int handle, unsigned char *buffer, unsigned char nsectors, char mopcode)
{
if (nsectors == 0) return 0xFF; // not sure if right, DosBOX does this
ssize_t r;
size_t len = (size_t)nsectors << 9;
ssize_t(*rw)(int,unsigned char*,size_t) = (mopcode != 3) ? (ssize_t(*)(int,unsigned char*,size_t))read:(ssize_t(*)(int,unsigned char*,size_t))write;
while (((r = rw(handle, buffer, len)) > 0 || r < 0 && errno == EINTR)) {
if (r < 0) continue; // EINTR
buffer += (size_t)r;
if (!(len -= (size_t)r)) {
// All data transferred
if (mopcode == 3) {
#ifndef _WIN32
if (fdatasync(handle)) break; // r will not be 0; switches on errno
//#else I'd have to rewrite a whole lot to implement the call on Windows.
#endif
}
return 0;
}
// Network FS had to chunk write down
}
// Error pathway
if (r == 0) return 0x04; // Sector not found
switch (errno) {
case ENODEV: case ENXIO: return 0xAA; // Drive not ready
case EBADF: case EROFS: return mopcode == 3 ? 0x03 /* write protected */ : 0x0A;
case ENOSPC: case EDQUOT: return 0x04; // sparce file and out of disk: best fit is no such sector
default: return 0x0A; // bad sector: it's EIO and there aren't many likely cases
}
}

// Emulator entry point
int main(int argc, char **argv)
{
Expand Down Expand Up @@ -810,9 +843,9 @@ int main(int argc, char **argv)
CAST(short)mem[SEGREG(REG_ES, REG_BX, 36+)] = ms_clock.millitm;
OPCODE 2: // DISK_READ
OPCODE_CHAIN 3: // DISK_WRITE
regs8[REG_AL] = ~lseek(disk[regs8[REG_DL]], CAST(unsigned)regs16[REG_BP] << 9, 0)
? ((char)i_data0 == 3 ? (int(*)())write : (int(*)())read)(disk[regs8[REG_DL]], mem + SEGREG(REG_ES, REG_BX,), regs16[REG_AX])
: 0;
regs8[REG_AH] = ~lseek(disk[regs8[REG_DL]], CAST(unsigned)regs16[REG_BP] << 9, 0)
? readwrite(disk[regs8[REG_DL]], mem + SEGREG(REG_ES, REG_BX,), regs8[REG_AL], (char)i_data0)
: (errno == EINVAL) ? 0x04 /* out of range on disk device */ : 0xAA /* no disk */;
OPCODE 4: // XMS
callxms();
}
Expand Down Expand Up @@ -1055,7 +1088,8 @@ int main(int argc, char **argv)
#ifndef NO_GRAPHICS
SDL_Quit();
#endif
return 0;
// I really want to be able to pass an exit code out, but the pre-existing QUITEMU passes garbage. -JH
return (regs16[REG_BX] == 0x1234) ? regs8[REG_AL] : 0;
}


Expand Down
9 changes: 6 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,14 @@ bios.bin: bios.asm
tinyxms.sys: tinyxms.asm
nasm -f bin -I ../lmacros/ -I lmacros/ -l tinyxms.lst -o tinyxms.sys tinyxms.asm

8086tiny: 8086tiny.c bios.bin tinyxms.sys
quitemu.com: quitemu.asm
nasm -f bin -o quitemu.com quitemu.asm

8086tiny: 8086tiny.c bios.bin tinyxms.sys quitemu.com
${CC} 8086tiny.c ${OPTS_SDL} ${OPTS_ALL} -o 8086tiny
strip 8086tiny

8086tiny_slowcpu: 8086tiny.c bios.bin tinyxms.sys
8086tiny_slowcpu: 8086tiny.c bios.bin tinyxms.sys quitemu.com
${CC} 8086tiny.c ${OPTS_SDL} ${OPTS_ALL} ${OPTS_SLOWCPU} -o 8086tiny
strip 8086tiny

Expand All @@ -31,4 +34,4 @@ no_graphics: 8086tiny.c bios.bin tinyxms.sys
strip 8086tiny

clean:
rm -f 8086tiny bios.bin bios.lst tinyxms.sys tinyxms.lst
rm -f 8086tiny bios.bin bios.lst tinyxms.sys tinyxms.lst quitemu.com
186 changes: 160 additions & 26 deletions bios.asm
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ main:
dw flags_mult ; Table 19: FLAGS multipliers


biosstr db '8086tiny BIOS Revision 1.62!', 0, 0
biosstr db '8086tiny BIOS Revision 1.70!', 0, 0


bios_entry:
Expand Down Expand Up @@ -2141,6 +2141,14 @@ int13:
je int13_getdisktype
cmp ah, 0x16 ; Detect disk change
je int13_diskchange
cmp ah, 0x41
je int13_echeck
cmp ah, 0x42
je int13_eread_disk
cmp ah, 0x43
je int13_ewrite_disk
cmp ah, 0x48
je int13_eparam

mov ah, 1 ; Invalid function
jmp reach_stack_stc
Expand Down Expand Up @@ -2204,18 +2212,12 @@ int13:

call chs_to_abs

; Now, SI:BP contains the absolute sector offset of the block. We then multiply by 512 to get the offset into the disk image
; Now, SI:BP contains the absolute sector offset of the block.

mov ah, 0
cpu 186
shl ax, 9
extended_read_disk
shr ax, 9
cpu 8086
mov ah, 0x02 ; Put read code back

cmp al, 0
je rd_error
cmp ah, 0
jne rd_error

; Read was successful. Now, check if we have read the boot sector. If so, we want to update
; our internal table of sectors/track to match the disk format
Expand Down Expand Up @@ -2247,14 +2249,11 @@ int13:

rd_noerror:

clc
mov ah, 0 ; No error
jmp rd_finish
db 0A8h ; test al, imm8 (NC, skip stc)

rd_error:

stc
mov ah, 4 ; Sector not found

rd_finish:

Expand Down Expand Up @@ -2323,24 +2322,16 @@ int13:
wr_fine:

mov ah, 0
cpu 186
shl ax, 9
extended_write_disk
shr ax, 9
cpu 8086
mov ah, 0x03 ; Put write code back

cmp al, 0
je wr_error
cmp ah, 0
jne wr_error

clc
mov ah, 0 ; No error
jmp wr_finish
db 0A8h ; test al, imm8 (NC, skip stc)

wr_error:

stc
mov ah, 4 ; Sector not found

wr_finish:

Expand Down Expand Up @@ -2451,6 +2442,148 @@ wr_fine:
mov ah, 0 ; Disk not changed
jmp reach_stack_clc

;******************************************************************
; INT 13h LBA Extensions - Joshua Hudson <joshudson@gmail.com> 2023

int13_echeck:

cmp dl, 0x80
jne int13_enofloppy
mov ah, 0x20
mov bx, 0xAA55
mov cx, 1
jmp reach_stack_clc

int13_enofloppy: ; Special version for int13_echeck: don't set disk status
mov ah, 1
jmp reach_stack_stc

int13_eread_disk:

cmp dl, 0x80
jne no_int13e
jmp int13_ereadwrite_disk

int13_ewrite_disk:

cmp dl, 0x80
jne no_int13e
;; Phoenix BIOS had to disable and move write/verify because of messed-up callers
;; Don't look at low bit of AL to decide write verify or not. We can't implement anyway.
jmp int13_ereadwrite_disk

int13_eparam:

cmp dl, 0x80
jne no_int13e
cmp [si], word 0x1E
jne no_int13e
push ax
xor ax, ax
mov [si + 2], ax
mov [si + 0x06], ax
mov [si + 0x0A], ax
mov [si + 0x0E], ax
mov [si + 0x14], ax
mov [si + 0x16], ax
mov [si + 0x1A], ax
mov [si + 0x1E], ax
mov ax, [cs:hd_max_track] ; Not bothering to detranslate -- there's no ATA device to talk to
mov [si + 0x04], ax
mov ax, [cs:hd_max_head]
mov [si + 0x08], ax
mov ax, [cs:hd_max_sector]
mov [si + 0x0C], ax
mov ax, [cs:hd_secs_lo]
mov [si + 0x10], ax
mov ax, [cs:hd_secs_hi]
mov [si + 0x12], ax
mov [si + 0x18], word 512
pop ax
mov ah, 0
jmp int13_eresult

no_int13e: ; Invalid function argument
mov ah, 1
int13_eresult:
mov [cs:disk_laststatus], ah
cmp ah, 0
jne int13_efail
jmp reach_stack_clc
int13_efail:
jmp reach_stack_stc

int13_ereadwrite_disk:

cmp [si], byte 0x10
jne no_int13e
cmp [si + 3], byte 0
je int13_erangeok
mov ah, 0x0D
jmp int13_eresult

int13_erangefail:

mov ah, 0x04
jmp int13_eresult

int13_erangeok:

cmp [si + 12], word 0
jne int13_erangefail
cmp [si + 14], word 0
jne int13_erangefail

push dx
push si
push ax
push bp
push es
push bx

mov al, [si + 2]
mov es, [si + 6]
mov bx, [si + 4]
mov bp, [si + 8]
mov si, [si + 10]
mov dl, 0 ; Hard disk handle offset

cmp si, [cs:hd_secs_hi]
jb int13_erangeok2
ja int13_erangefail2
cmp bp, [cs:hd_secs_lo]
jae int13_erangefail2

int13_erangeok2:
cmp ah, 0x43
je int13_ewritecall

extended_read_disk
jmp int13_edecode

int13_ewritecall:

extended_write_disk
;jmp int13_edecode

int13_edecode:

mov dh, ah
pop bx
pop es
pop bp
pop ax
mov ah, dh
pop si
pop dx

jmp int13_eresult

int13_erangefail2:

mov ah, 0x04
jmp int13_edecode

; ************************* INT 14h - serial port functions

int14:
Expand Down Expand Up @@ -3880,6 +4013,7 @@ int_table dw int0
dw int1d
dw 0xf000
dw int1e
dw 0xf000

itbl_size equ $-int_table

Expand Down Expand Up @@ -4087,4 +4221,4 @@ tm_msec equ $+36

mem_top:
jmp 0F000h:100h
db '03/08/14', 0, 0xfe, 0
db '11/26/23', 0, 0xfe, 0
40 changes: 40 additions & 0 deletions quitemu.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
CPU 8086

BITS 16

ORG 0x100

mov si, 0x80
lodsb
mov bl, al
mov bh, 0
add bx, si
mov cl, 10
xor dx, dx
lop:
cmp si, bx
je go
lodsb
cmp al, ' '
je lop
cmp al, 9
je lop
sub al, '0'
jb help
cmp al, 9
ja help
xchg ax, dx
mul cl
add al, dl
xchg ax, dx
jmp lop
help:
mov dx, msg
mov ah, 9
int 21h
ret
go:
xchg ax, dx
mov bx, 0x1234 ; Tell emulator to use AL as exit code
jmp 0:0 ; Actual enstruction that exits emulator
msg db 'Quits 8086tiny emulator', 13, 10, 'Usage: QUITEMU [exit code]', 13, 10, '$'
Loading

0 comments on commit 1dcc99d

Please sign in to comment.