Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix disk/read write error handling and add int13h LBA BIOS extensions #7

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
108 changes: 101 additions & 7 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 @@ -64,6 +65,7 @@
#ifndef GRAPHICS_UPDATE_DELAY
#define GRAPHICS_UPDATE_DELAY 360000
#endif
#define APM_INST_DELAY 1000
#define KEYBOARD_TIMER_UPDATE_DELAY 20000
#define HALT_TIME_MICROSECONDS 100
#define KEYBOARD_TIMER_DELAY_FROM_HALT 1000
Expand Down Expand Up @@ -204,11 +206,14 @@ unsigned char mem[RAM_SIZE + 16], io_ports[IO_PORT_COUNT + 16],
hlt_this_time, setting_ss, prior_setting_ss, reset_ip_after_rep_trace,
shift_count;
unsigned short *regs16, reg_ip, seg_override, file_index, wave_counter, reg_ip_before_rep_trace;
unsigned int op_source, op_dest, rm_addr, op_to_addr, op_from_addr, i_data0, i_data1, i_data2, scratch_uint, scratch2_uint, keyboard_timer_inst_counter, graphics_inst_counter, set_flags_type, GRAPHICS_X, GRAPHICS_Y, pixel_colors[16], vmem_ctr;
int op_result, disk[3], scratch_int;
unsigned int op_source, op_dest, rm_addr, op_to_addr, op_from_addr, i_data0, i_data1, i_data2, scratch_uint, scratch2_uint, keyboard_timer_inst_counter, graphics_inst_counter, apm_inst_counter, set_flags_type, GRAPHICS_X, GRAPHICS_Y, pixel_colors[16], vmem_ctr;
int op_result, disk[3], scratch_int, device_status;
time_t clock_buf;
struct timeb ms_clock;

#define DEVICE_STATUS_GRAPHICS 1
#define DEVICE_STATUS_FASTCPU 2

#ifndef NO_GRAPHICS
SDL_AudioSpec sdl_audio = {44100, AUDIO_U8, 1, 0, 128};
SDL_Surface *sdl_screen;
Expand All @@ -219,6 +224,7 @@ unsigned short vid_addr_lookup[VIDEO_RAM_SIZE], cga_colors[4] = {0 /* Black */,
// Helper functions

void callxms();
void callapm();

// Set carry flag
char set_CF(int new_CF)
Expand Down Expand Up @@ -355,6 +361,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,11 +848,13 @@ 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();
OPCODE 5:
callapm();
}
if ((uint8_t)i_data0 == 11 // ud2
|| (uint8_t)i_data0 >= 32)
Expand Down Expand Up @@ -990,7 +1030,7 @@ int main(int argc, char **argv)
graphics_inst_counter = 0;
hlt_this_time = 0;
// Video card in graphics mode?
if (io_ports[0x3B8] & 2)
if (io_ports[0x3B8] & 2 && device_status & DEVICE_STATUS_GRAPHICS)
{
// If we don't already have an SDL window open, set it up and compute color and video memory translation tables
if (!sdl_screen)
Expand Down Expand Up @@ -1024,6 +1064,11 @@ int main(int argc, char **argv)
SDL_PumpEvents();
}
#endif
if (!setting_ss && !hlt_this_time && !(device_status & DEVICE_STATUS_FASTCPU) && ++apm_inst_counter >= APM_INST_DELAY) {
hlt_this_time = 1;
apm_inst_counter = 0;
}

if (hlt_this_time) {
struct timespec ts;
ts.tv_sec = 0;
Expand Down Expand Up @@ -1055,7 +1100,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 Expand Up @@ -1206,6 +1252,54 @@ uint32_t getfreexms() {
return lower;
}

void callapm() {
char buf[12];
int h, tmp;
switch (regs8[REG_AH]) {
OPCODE_CHAIN 0: // CPU slow
device_status &= ~DEVICE_STATUS_FASTCPU;
OPCODE 1: // CPU normal
device_status |= DEVICE_STATUS_FASTCPU;
OPCODE 2: // graphics card off
device_status &= ~DEVICE_STATUS_GRAPHICS;
OPCODE 3: // graphics card on
device_status |= DEVICE_STATUS_GRAPHICS;
OPCODE 4: // Get battery status
#ifdef _WIN32
regs8[REG_BL] = 0xff;
#else
h = open("/sys/class/power_supply/BAT0/status", O_RDONLY);
if (h >= 0 && (0 < read(h, buf, 12)))
regs8[REG_BL] = buf[0] == 'C' ? 3 /* charging */ : 2 /* critical */;
else
regs8[REG_BL] = 0xFF; // Unable
if (h >= 0) close(h);
h = open("/sys/class/power_supply/BAT0/capacity", O_RDONLY);
if (h >= 0 && ((tmp = read(h, buf, 10)) > 0))
buf[tmp] = 0, regs8[REG_CL] = atoi(buf);
else
regs8[REG_CL] = 0xFF; // Unable
if (h >= 0) close(h);
if (regs8[REG_CL] != 0xFF && regs8[REG_BL] == 2) {
if (regs8[REG_CL] >= 50) regs8[REG_BL] = 0; // High
else if (regs8[REG_CL] >= 10) regs8[REG_BL] = 1; // Low
// If we can't get battery charge and we're not charging it's critical
}
#endif
OPCODE 5: // Get AC status
#ifdef _WIN32
regs8[REG_BH] = 0xff;
#else
h = open("/sys/class/power_supply/AC/online", O_RDONLY);
if (h >= 0 && (0 < read(h, buf, 2)))
regs8[REG_BH] = buf[0] - 1; // 0 = offline, 1 = online
else
regs8[REG_BH] = 0xFF; // Unable
if (h >= 0) close(h);
#endif
}
}


void callxms() {
uint32_t ii, free;
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
Loading