/***************************************************************************** * FILE: cdosx32.c * * * * DESC: * * - int 0x21 dos call handler * * * * Copyright (C) 1993,1994 * * Rainer Schnitker, Heeper Str. 283, 33607 Bielefeld * * email: rainer@mathematik.uni-bielefeld.de * * * *****************************************************************************/ #include "DPMI.H" #include "PRINTF.H" #include "RMLIB.H" #include "PROCESS.H" #include "FS.H" #include "SIGNALS.H" #include "START32.H" #include "CDOSX32.H" #include "COPY32.H" #include "TERMIO.H" #include "DOSERRNO.H" #include "DJIO.H" #include "RSX.H" /* define segment offset usage */ #ifdef __EMX__ #define SET_SEG_OFF(pointer, seg, off) \ { seg = (((unsigned) (pointer) & ~0xFFF) >> 4) + ds16real; \ off = (unsigned) (pointer) & 0xFFF; } #else /* 16 bit compiler */ #define SET_SEG_OFF(pointer, seg, off) \ { seg = ds16real; off = (WORD) (pointer) ;} #endif #ifdef __EMX__ #define SET_SEG_OFF_64(pointer, seg, off) \ { seg = (((unsigned) (pointer) & ~0xFFFF) >> 4) + ds16real; \ off = (unsigned) (pointer) & 0xFFFF; } #else /* 16 bit compiler */ #define SET_SEG_OFF_64(pointer, seg, off) \ { seg = ds16real; off = (WORD) (pointer) ;} #endif extern WORD _psp; /* PSP after protected mode switch */ static char iobuffer[IOBUF_SIZE + 3]; char *iobuf = iobuffer; /* I/O buffer for real-mode operations */ DWORD iobuf_addr; DWORD iobuf_linear; /* linear address I/O for djgpp */ void align_iobuf(void) { iobuf = (char *) ((unsigned) (iobuf + 3) & ~3); iobuf_addr = ((DWORD) ds16real << 4) + (DWORD) (UINT) iobuf; iobuf_linear = iobuf_addr + 4096L; /* if we use this buffer */ if (opt_printall) printf("lin address of iobuf %lX\n", iobuf_linear); } #define CONVERT_BX_DOSHANDLE { \ int h = get_dos_handle(BX); \ if (h < 0) { \ EAX = EMX_EBADF; \ return CARRY_ON; \ } \ else BX = h; } static void put_regs(TRANSLATION *tr) { tr->eax = EAX; tr->ebx = EBX; tr->ecx = ECX; tr->edx = EDX; } static void get_regs(TRANSLATION *tr) { EAX = tr->eax; EBX = tr->ebx; ECX = tr->ecx; EDX = tr->edx; FLAGS = tr->flags; } static char rm_stack[512]; unsigned real_mode_stack = (unsigned) (rm_stack + 510); /* call Real-Mode INT0x21 */ static int realdos(TRANSLATION *tr) { SET_SEG_OFF_64(real_mode_stack, tr->ss, tr->sp); tr->flags = 0x3200; tr->eax &= 0xFFFF; tr->cs = cs16real; tr->es = tr->ds; /* DPMI-Call to Real-Mode DOS */ SimulateRMint(0x21, 0, 0, tr); /* return Carry-bit */ return (tr->flags & 1); } static int illegal_syscall() { puts("Illegal Parameter in syscall"); send_signal(npz, SIGSEGV); EAX = EMX_EINTR; return CARRY_ON; } #define TEST_ILLEGAL( OFFSET, LENGHT ) \ if (verify_illegal(npz, OFFSET, LENGHT)) return illegal_syscall(); #define TEST_ILLEGAL_WRITE( OFFSET, LENGHT ) \ if (verify_illegal_write(npz, OFFSET, LENGHT)) return illegal_syscall(); /* ** INT 0x21 handler returns: ** ** CARRY_ON : error, set carry-bit, errno in eax ** CARRY_OFF: no error, clear carry-bit ** CARRY_NON: carry-bit set by realdos -> dos error code in ax, ** translate ax to errno */ int int21normal(void) { static DWORD user_dta; /* prot-mode DTA address */ TRANSLATION tr; /* registers set for mode-switching */ int err, new_handle; unsigned char rAH, rAL; rAH = (BYTE) (AX >> 8); rAL = (BYTE) EAX; switch (rAH) { /* ** register based functions ** no changes needed - only ax,dx,flags (bx,cx) used */ case 0x01: /* read char */ case 0x02: /* write char */ case 0x03: /* read char stdaux */ case 0x04: /* write char stdaux */ case 0x05: /* read char prn */ case 0x06: /* con output&input */ case 0x07: /* char input & echo */ case 0x08: /* char output & echo */ case 0x0b: /* get stdin stat */ case 0x0c: /* flush buffer & read std input */ case 0x0d: /* disk reset */ case 0x0e: /* select drive */ case 0x19: /* get drive */ case 0x2a: /* get system date (cx) */ case 0x2b: /* set system date (cx) */ case 0x2c: /* get time (cx) */ case 0x2d: /* set time (cx) */ case 0x2e: /* set verify */ case 0x30: /* get DOS version (bx,cx) */ case 0x33: /* extended break check */ case 0x36: /* get free disk space (bx,cx) */ case 0x37: /* get&set switch char */ case 0x54: /* get verify flag */ case 0x58: /* get/set UMB link state */ case 0x5c: /* un-&lock file */ case 0x66: /* code page */ put_regs(&tr); realdos(&tr); get_regs(&tr); return CARRY_NON; case 0x44: /* IOCTL */ switch (rAL) { case 0x00: /* get device info */ case 0x01: /* set device info */ case 0x06: /* get input status */ case 0x07: /* get output status */ case 0x0a: /* check handle remote */ CONVERT_BX_DOSHANDLE; /* fall through */ case 0x08: /* check block device remove */ case 0x09: /* check block device remote */ case 0x0b: /* set sharing */ case 0x0e: /* get log drive map */ case 0x0f: /* set log drive map */ case 0x10: /* query ioctl handle */ case 0x11: /* query ioctl drive */ put_regs(&tr); realdos(&tr); get_regs(&tr); return CARRY_NON; default: EAX = EMX_EIO; return CARRY_ON; } /* ** simple file handle functions ** convert handle */ case 0x57: /* get file state (bx,cx) */ case 0x68: /* fflush file (bx) */ CONVERT_BX_DOSHANDLE; put_regs(&tr); realdos(&tr); get_regs(&tr); return CARRY_NON; case 0x3e: /* close file (bx) */ err = sys_close(BX); if (err < 0) { EAX = emx_errno; return CARRY_ON; } else { EAX = 0; return CARRY_OFF; } case 0x42: /* lseek file */ { long pos; if (npz->p_flags & PF_EMX_FILE) pos = EDX; else pos = (ECX << 16) | (EDX & 0xFFFF); if ((EAX = sys_lseek(BX, pos, rAL))== -1L) { EAX = emx_errno; return CARRY_ON; } if (npz->p_flags & PF_DJGPP_FILE) { EDX = EAX >> 16; } return CARRY_OFF; } case 0x45: /* dup file (bx) */ if ((new_handle = sys_dup(BX)) < 0) { EAX = (long) -new_handle; return CARRY_ON; } EAX = (long) new_handle; return CARRY_OFF; case 0x46: /* dup2 file (bx,cx) */ if ((new_handle = sys_dup2(BX, CX)) < 0) { EAX = (long) -new_handle; return CARRY_ON; } EAX = (long) new_handle; return CARRY_OFF; /* ** ASCiiZero functions ** ** copy name -> real_buffer , call realdos */ case 0x09: /* string to output */ TEST_ILLEGAL(EDX, 2); getstr32_16(DS, EDX, iobuf, '$'); tr.eax = EAX; SET_SEG_OFF(iobuf, tr.ds, tr.edx); realdos(&tr); return CARRY_NON; case 0x39: /* MKDIR name */ case 0x3a: /* RMDIR name */ case 0x3b: /* CHDIR name */ case 0x41: /* UNLINK name */ case 0x43: /* ATTRIB name */ TEST_ILLEGAL(EDX, 2); if (rAH == 0x3c) /* fix umask bug */ ECX &= ~1L; put_regs(&tr); strcpy32_16(DS, EDX, iobuf); SET_SEG_OFF(iobuf, tr.ds, tr.edx); realdos(&tr); get_regs(&tr); return CARRY_NON; case 0x3c: /* CREATE name */ case 0x3d: /* OPEN name */ case 0x5b: /* CREATE New file */ /* ** only DOS handles !! ** others with EMX: 0x7F ; DJGPP 0xFF */ if (rAH == 0x3c) /* fix umask bug */ ECX &= ~1L; TEST_ILLEGAL(EDX, 2); strcpy32_16(DS, EDX, iobuf); put_regs(&tr); SET_SEG_OFF(iobuf, tr.ds, tr.edx); if (!realdos(&tr)) { new_handle = get_empty_proc_filp(); npz->filp[new_handle]->f_mode = FMODE_READ | FMODE_WRITE; npz->filp[new_handle]->f_doshandle = (BYTE) tr.eax; npz->filp[new_handle]->f_op = & msdos_fop; tr.eax = (long) new_handle; } get_regs(&tr); return CARRY_NON; case 0x56: /* RENAME oldname name (strlen < 1024) */ TEST_ILLEGAL(EDX, 2); TEST_ILLEGAL(EDI, 2); strcpy32_16(DS, EDX, iobuf); strcpy32_16(DS, EDI, iobuf + 1024); put_regs(&tr); SET_SEG_OFF(iobuf, tr.ds, tr.edx); tr.es = tr.ds; tr.edi = tr.edx + 1024; realdos(&tr); get_regs(&tr); return CARRY_NON; case 0x5a: /* CREATE TEMP name */ TEST_ILLEGAL_WRITE(EDX, 2); put_regs(&tr); strcpy32_16(DS, EDX, iobuf); SET_SEG_OFF(iobuf, tr.ds, tr.edx); if (!realdos(&tr)) { strcpy16_32(DS, EDX, iobuf); new_handle = get_empty_proc_filp(); npz->filp[new_handle]->f_mode = FMODE_READ | FMODE_WRITE; npz->filp[new_handle]->f_doshandle = (BYTE) tr.eax; npz->filp[new_handle]->f_op = & msdos_fop; tr.eax = (long) new_handle; } get_regs(&tr); return CARRY_NON; case 0x6c: /* EXTENDED OPEN/CREATE file */ TEST_ILLEGAL(ESI, 2); strcpy32_16(DS, ESI, iobuf); put_regs(&tr); SET_SEG_OFF(iobuf, tr.ds, tr.esi); if (!realdos(&tr)) { new_handle = get_empty_proc_filp(); npz->filp[new_handle]->f_mode = FMODE_READ | FMODE_WRITE; npz->filp[new_handle]->f_doshandle = (BYTE) tr.eax; npz->filp[new_handle]->f_op = & msdos_fop; tr.eax = (long) new_handle; } get_regs(&tr); return CARRY_NON; /* ** buffer functions ** ** copy data before or after realdos */ case 0x0a: /* BUFFERED INPUT */ { BYTE no_chars; TEST_ILLEGAL_WRITE(EDX, 4); put_regs(&tr); no_chars = (BYTE) read32(DS, EDX); iobuf[0] = no_chars;/* no of chars */ SET_SEG_OFF(iobuf, tr.ds, tr.edx); realdos(&tr); cpy16_32(DS, EDX, iobuf, (DWORD) no_chars + 2); /* copy of chars */ return CARRY_OFF; } case 0x3f: /* READ from file */ if (EDX != iobuf_linear) { TEST_ILLEGAL(EDX, ECX); } if (ECX == 0) { EAX = 0; return CARRY_OFF; } if ((npz->p_flags & PF_DJGPP_FILE) && EDX == 0) { printf("read.o not ok ; run DPMIFIX from DJGPP 1.10\n"); EAX = EMX_EIO; return CARRY_ON; } EAX = sys_read(BX, EDX, ECX); if ((long) EAX < 0) { EAX = - (long)EAX; return CARRY_ON; } else return CARRY_OFF; case 0x40: /* WRITE to file */ if (EDX != iobuf_linear) { TEST_ILLEGAL_WRITE(EDX, ECX); } EAX = sys_write(BX, EDX, ECX); if ((long)EAX < 0) { EAX = - (long)EAX; return CARRY_ON; } else return CARRY_OFF; case 0x38: /* GET COUNTRY INFO */ if (DX != 0xFFFF) { TEST_ILLEGAL_WRITE(EDX, 34); put_regs(&tr); SET_SEG_OFF(iobuf, tr.ds, tr.edx); if (!realdos(&tr)) cpy16_32(DS, EDX, iobuf, 34L); get_regs(&tr); } else { put_regs(&tr); realdos(&tr); get_regs(&tr); } return CARRY_NON; case 0x47: /* GET CURR DIRECTORY */ TEST_ILLEGAL_WRITE(ESI, 64); put_regs(&tr); SET_SEG_OFF(iobuf, tr.ds, tr.esi); if (!realdos(&tr)) cpy16_32(DS, ESI, iobuf, 64L); get_regs(&tr); return CARRY_NON; case 0x4e: /* FINDFIRST */ /* DTA: iobuf byte 0-42 , wild _string: iobuf + 64 */ if (npz->p_flags & PF_EMX_FILE) { /* set dta address to iobuf */ user_dta = ESI; SET_SEG_OFF(iobuf, tr.ds, tr.edx); tr.eax = 0x1a00; realdos(&tr); } TEST_ILLEGAL(EDX, 2); TEST_ILLEGAL_WRITE(user_dta, 43); strcpy32_16(DS, EDX, iobuf + 64); tr.eax = EAX; tr.ecx = ECX; SET_SEG_OFF((iobuf+64), tr.ds, tr.edx); if (realdos(&tr)) EAX = tr.eax; else cpy16_32(DS, user_dta, iobuf, 43); FLAGS = tr.flags; return CARRY_NON; case 0x4f: /* FINDNEXT */ /* DTA: iobuf byte 0-42 */ if (npz->p_flags & PF_EMX_FILE) { user_dta = ESI; SET_SEG_OFF(iobuf, tr.ds, tr.edx); tr.eax = 0x1a00; /* set dta address */ realdos(&tr); } TEST_ILLEGAL_WRITE(user_dta, 43); /* put user dta in iobuf */ cpy32_16(DS, user_dta, iobuf, 43); tr.eax = EAX; if (realdos(&tr)) EAX = tr.eax; else cpy16_32(DS, user_dta, iobuf, 43); FLAGS = tr.flags; return CARRY_NON; /* ** some special handling */ case 0x1a: /* SET DTA */ TEST_ILLEGAL(EDX, 2); user_dta = EDX; tr.eax = 0x1a00; SET_SEG_OFF(iobuf, tr.ds, tr.edx); realdos(&tr); return CARRY_OFF; case 0x2f: /* GET DTA */ EBX = user_dta; return CARRY_OFF; case 0x62: /* GET PSP */ EBX = (DWORD) _psp; return CARRY_OFF; /* ** functions complete changed ** need to call DPMI-functions */ case 0x48: /* ALLOC MEM */ case 0x49: /* FREE MEM */ EAX = EMX_EIO; return CARRY_ON; case 0x4a: /* RESIZE MEM */ if (npz->p_flags & PF_EMX_FILE) { EAX = EMX_EIO; return CARRY_ON; } else { if (EAX & 0xff) EAX = getmem(EBX, npz); else EAX = npz->brk_value; if (EAX == -1) EAX = 0; return CARRY_OFF; /* sbrk.s didn't check carry */ } case 0x4c: return do_exit4c(0); case 0x4d: { unsigned status = 0; /* sys_wait(&status); */ AX = status >> 8; /* al = return code */ return CARRY_OFF; } default: printf("Warning: Not implemented DOS function ah=%02X\n", rAH); EAX = EMX_EIO; return CARRY_ON; } /* switch R_AH */ } #include "DJIO.H" /* ** read for dos handles */ ARGUSER cdosx_read(int handle, ARGUSER buf, ARGUSER count) { long org_bytes; int iob_bytes; int ret_bytes; /* termio check */ if ((npz->p_flags & PF_TERMIO) && rm_isatty(handle)) { if ((ret_bytes = termio_read(DS, buf, (int)count)) < 0) { emx_errno = -ret_bytes; return -1; } else return ret_bytes; } if ((npz->p_flags & PF_DJGPP_FILE) && buf == (ARGUSER)iobuf_linear) return dj_read(handle, iobuf+4096, (unsigned)count); org_bytes = count; while (count > 0) { iob_bytes = (count <= IOBUF_SIZE) ? (int) count : IOBUF_SIZE; if (npz->p_flags & PF_DJGPP_FILE) { if ((ret_bytes = dj_read(handle, iobuf, iob_bytes)) == -1) return -(long)errno_djgpp(emx_errno); } else { if ((ret_bytes = rm_read(handle, iobuf, iob_bytes)) == -1) return -(long)emx_errno; } cpy16_32(DS, buf, iobuf, (long) ret_bytes); count -= (long) ret_bytes; if (ret_bytes < iob_bytes) /* EOF */ break; buf += ret_bytes; } return (org_bytes - count); } /* ** write for dos handles */ ARGUSER cdosx_write(int handle, ARGUSER buf, ARGUSER count) { long org_bytes; int iob_bytes; int ret_bytes; if (!count) return (ARGUSER) rm_write(handle, &iobuf, 0); if ((npz->p_flags & PF_DJGPP_FILE) && buf == (ARGUSER) iobuf_linear) return dj_write(handle, iobuf+4096, (unsigned)count); org_bytes = count; while (count > 0) { iob_bytes = (count <= IOBUF_SIZE) ? (int) count : IOBUF_SIZE; cpy32_16(DS, buf, iobuf, (long)iob_bytes); if (npz->p_flags & PF_DJGPP_FILE) { if ((ret_bytes = dj_write(handle, iobuf, iob_bytes)) == -1) return -(long)errno_djgpp(emx_errno); } else { if ((ret_bytes = rm_write(handle, iobuf, iob_bytes)) == -1) return -(long)emx_errno; } count -= (long) ret_bytes; if (ret_bytes < iob_bytes) /* disk full */ break; buf += ret_bytes; } return (org_bytes - count); } typedef union { unsigned long flat; struct FarPtr { unsigned short off16; unsigned short seg16; } farptr; } PTR; #pragma pack(1) typedef struct { char signatur[4]; char version[2]; PTR oem_name; char capabilities[4]; PTR modes; char blocks[2]; } VESAINFO; #pragma pack() static unsigned real_mode_vio10(TRANSLATION *pTrans) { pTrans->sp = pTrans->ss = 0; pTrans->flags = 0x3200; return SimulateRMint(0x10, 0, 0, pTrans); } static unsigned real_mode_mou33(TRANSLATION *pTrans) { pTrans->sp = pTrans->ss = 0; pTrans->flags = 0x3200; return SimulateRMint(0x33, 0, 0, pTrans); } /* ** support for vesa modes ah = 0x4F, al = 00 - 08 */ static void vio10(void) { unsigned char rAH, rAL; TRANSLATION tr; VESAINFO *pInfo; DWORD offset; rAH = (BYTE) (AX >> 8); rAL = (BYTE) EAX; if (rAH != 0x4F) return; switch (rAL) { case 0x00: SET_SEG_OFF(iobuf, tr.es, tr.edi); put_regs(&tr); real_mode_vio10(&tr); if ((tr.eax & 0xFF) != 0x4f) break; else EAX = tr.eax; /* success */ pInfo = (VESAINFO *) iobuf; offset = ((DWORD) pInfo->oem_name.farptr.seg16 << 4) + (DWORD) pInfo->oem_name.farptr.off16; pInfo->oem_name.flat = (dpmi10) ? offset + DPMI_PRG_DATA : offset - npz->memaddress; offset = ((DWORD) pInfo->modes.farptr.seg16 << 4) + (DWORD) pInfo->modes.farptr.off16; pInfo->modes.flat = (dpmi10) ? offset + DPMI_PRG_DATA : offset - npz->memaddress; cpy16_32(ES, EDI, iobuf, 256); break; case 0x01: SET_SEG_OFF(iobuf, tr.es, tr.edi); put_regs(&tr); real_mode_vio10(&tr); if ((tr.eax & 0xFF) != 0x4f) break; else EAX = tr.eax; * (DWORD *) (iobuf + 0x0C) = 0; /* zero far function */ cpy16_32(ES, EDI, iobuf, 256); break; case 0x02: /* set SVGA mode */ case 0x03: /* get SVGA mode */ case 0x05: /* return ax */ case 0x06: /* return ax,bx,cx,dx */ case 0x07: /* return ax */ case 0x08: /* return ax,bx */ put_regs(&tr); real_mode_vio10(&tr); get_regs(&tr); break; case 0x04: /* unsupported */ default: printf("Not supported Vesa call %X", AX); return; } } /* ** support for mouse calls */ static void mou33(void) { TRANSLATION tr; unsigned char rAH = (BYTE) EAX; if (rAH > 0x35) /* not supported */ return; switch (rAH) { case 0x0C: /* Define IRQ routine */ case 0x14: /* Exchange IRQ routines */ case 0x16: /* Save state */ case 0x17: /* Restore state */ case 0x18: /* Set event handler */ case 0x19: /* Return event handler */ case 0x29: /* Enumerate video modes */ case 0x2B: /* Load acceleration prof. */ case 0x2C: /* Get acceleration prof. */ case 0x2D: /* Select acc. profile */ case 0x2E: /* Set acc. profile names */ case 0x33: /* Switch settings etc. */ case 0x34: /* Get initialization file */ break; /* not supported */ case 0x09: /* define graphic cursor es:dx */ put_regs(&tr); cpy32_16(ES, EDX, iobuf, 32); SET_SEG_OFF(iobuf, tr.es, tr.edx); real_mode_mou33(&tr); EAX = tr.eax; break; case 0x12: /* graphic cursor block es:dx ; bh*ch*4 bytes */ put_regs(&tr); cpy32_16(ES, EDX, iobuf, BH * CH * 4); SET_SEG_OFF(iobuf, tr.es, tr.edx); real_mode_mou33(&tr); get_regs(&tr); break; default: put_regs(&tr); real_mode_mou33(&tr); get_regs(&tr); break; } } void prot_mode_interrupt(void) { int int_no = (int) npz->regs.faultno; if (int_no == 0x10) return vio10(); else if (int_no == 0x33) return mou33(); }