ftp.nice.ch/pub/next/developer/languages/c/djgpp-NS.s.tar.gz#/djgpp/go32/exphdlr.c

This is exphdlr.c in view mode; [Download] [Up]

/* This is file EXPHDLR.C */
/*
** Copyright (C) 1993 DJ Delorie, 24 Kirsten Ave, Rochester NH 03867-2954
**
** This file is distributed under the terms listed in the document
** "copying.dj", available from DJ Delorie at the address above.
** A copy of "copying.dj" should accompany this file; if not, a copy
** should be available from where this file was obtained.  This file
** may not be distributed without a verbatim copy of "copying.dj".
**
** This file is distributed WITHOUT ANY WARRANTY; without even the implied
** warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/

/* Modified for VCPI Implement by Y.Shibata Aug 5th 1991 */
/* Modified for DPMI Implement by H.Tsubakimoto */
/* Merged DPMI with V1.09+ C. Sandmann sandmann@clio.rice.edu */
/* History:66,55 */

#include <process.h>
#include <stdio.h>
#include <dos.h>
#include <sys/stat.h>
#include <time.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <dir.h>
#include <ctype.h>
#include <io.h>

#include "gotypes.h"
#include "gdt.h"
#include "idt.h"
#include "tss.h"
#include "utils.h"
#include "paging.h"
#include "npx.h"
#include "mono.h"
#include "vcpi.h"
#include "graphics.h"
#include "dpmi.h"
#include "extdebug.h"
#include "vcpi.h"
#include "ustat.h"
#include "dpmisim.h"
#include "dalloc.h"
#include "valloc.h"
#include "control.h"

extern void do_faulting_finish_message(int);
extern int old_video_mode;

void segfault(word32 v)
{
  if (!using_external_debugger || (tss_ptr == &ed_tss))
  {
    if (peekb(0x40, 0x49) != old_video_mode)
    {
      _AX = old_video_mode;
      geninterrupt(0x10);
    }
    fprintf(stderr, "Segmentation violation in pointer 0x%08lx at %x:%lx\n", v-ARENA, tss_ptr->tss_cs, tss_ptr->tss_eip);
    do_faulting_finish_message(0);
  }
  tss_ptr->tss_irqn = 14; /* make it a segfault */
  tss_ptr->tss_cr2 = v;
}

#define CHECK_SEGFAULT(p) { \
  if (!page_is_valid(p)) \
  { \
    segfault(p); \
    return 1; \
  } \
}

extern int debug_mode;

extern unsigned int cdecl _openfd[];
extern word32 far *graphics_pt;
extern int ctrl_break_hit;

extern int was_user_int;
extern word16 vcpi_installed;           /* VCPI Installed flag */
word16 new_pic;                         /* current IRQ0 Vector */
char transfer_buffer[4096];             /* must be near ptr for small model */
word32 transfer_linear;

int in_hardware_interrupt = 0;

word8 old_master_lo=0x08;
word8 hard_master_lo=0x08, hard_master_hi=0x0f;
word8 hard_slave_lo=0x70,  hard_slave_hi=0x77;

word32 user_dta;
static struct REGPACK r;
static int in_graphics_mode=0;
int ctrl_c_causes_break=1;

static int i_10(void), i_21(void), i_31(void), i_33(void), generic_handler(void), i_21_44(void);
static int turbo_assist(void);

static word32 flmerge(word32 rf, word32 tf)
{
  return (rf & 0xcff) | (tf & 0xfffff300L);
}

void static set_controller(int v)
{
/*  disable();  */
  int oldmask = inportb(0x21);
  outportb(0x20, 0x11);
  outportb(0x21, v);
  outportb(0x21, 4);
  outportb(0x21, 1);
  outportb(0x21, oldmask);
/*  enable();  */
}

static char cntrls_initted = 0;
extern char vector_78h, vector_79h;

int find_empty_pic(void)
{
  static word8 try[] = { 0x88, 0x90, 0x98, 0xa0, 0xa8, 0xb0, 0xb8, 0xf8, 0x68, 0x78 };
  int i, j;
  for (i=0; i<sizeof(try); i++)
  {
    char far * far * vec = (char far * far *)(0L+try[i]*4L);
    for (j=1; j<8; j++)
    {
      if (vec[j] != vec[0])
        goto not_empty;
    }
/*    printf("Empty = %d\n", try[i]); */
    return try[i];
    not_empty:;
  }
  return 0x78;
}

extern int  far _ev_kbinter;            /* keyboard interrupt flag */
extern void interrupt (* far _ev_oldkbint)(void);
extern void interrupt _ev_keybdint(void);
extern void interrupt (* far _ev_oldcriterr)(void);
extern void interrupt _ev_criterr(void);

word32 saved_interrupt_table[256];

void init_controllers(void)
{
  if(cntrls_initted) return;
  cntrls_initted = 1;

  movedata(0, 0, _DS, FP_OFF(saved_interrupt_table), 256*4);

  disable();

  if (vcpi_installed)
  {
    old_master_lo = vcpi_get_pic();
    hard_slave_lo = vcpi_get_secpic();
/*    printf("VCPI pics were m=%d s=%d\n", old_master_lo, hard_slave_lo); */
    hard_slave_hi = hard_slave_lo + 7;
  }
  else if(!use_DPMI)
  {
    old_master_lo = 0x08;
    hard_slave_lo = 0x70;
    hard_slave_hi = 0x77;
  }

  _ev_kbinter = 1;
  _ev_oldkbint = getvect(8+1);     /* this is *NOT* old_master_lo - required */
  setvect(8+1,_ev_keybdint);       /* so DV/X will work (it redirects) */
  _ev_oldcriterr = getvect(0x24);  /* critical error handler can't read kb */
  setvect(0x24,_ev_criterr);       /* so we force failure if events active */

  if(use_DPMI)
  {
    enable();
    return;
  }

  if (old_master_lo == 0x08)
  {
    hard_master_lo = find_empty_pic();
    if (vcpi_installed)
      vcpi_set_pics(hard_master_lo, hard_slave_lo);
    set_controller(hard_master_lo);
    movedata(0, 0x08*4, 0, hard_master_lo*4, 0x08*4);
  }
  else
  {
    hard_master_lo = old_master_lo;
  }
  hard_master_hi = hard_master_lo + 7;

  enable();
  vector_78h = hard_master_lo;
  vector_79h = hard_master_lo + 1;
}

void uninit_controllers(void)
{
  if(!cntrls_initted) return;
  cntrls_initted = 0;
  disable();

  movedata(_DS, FP_OFF(saved_interrupt_table), 0, 0, 256*4);

  if (old_master_lo == 0x08 && !use_DPMI)
  {
    if (vcpi_installed)
      vcpi_set_pics(0x08, hard_slave_lo);
    set_controller(0x08);
  }
  setvect(8+1,_ev_oldkbint);  /* not old_master_lo for XDV */
  enable();
}

static DPMIaddress exceptions[17];
static DPMIaddress interrupt10;
static DPMIaddress interrupt21;
static DPMIaddress interrupt33;
static DPMIaddress interrupt75;

void setDPMIvector(void)
{
  int i;
  for (i = 0; i < sizeof(exceptions) / sizeof(*exceptions); ++i) {
    DPMIehandler(i, &exceptions[i]);
    DPMIchangeException(i, &exceptions[i]);
  }
  DPMIhandler(0x10, &interrupt10);
  DPMIchangeInterrupt(0x10, &interrupt10);
  DPMIhandler(0x21, &interrupt21);
  DPMIchangeInterrupt(0x21, &interrupt21);
  DPMIhandler(0x33, &interrupt33);
  DPMIchangeInterrupt(0x33, &interrupt33);
  DPMIhandlerNPX(&interrupt75);
  DPMIchangeInterrupt(0x75, &interrupt75);
}

void restoreDPMIvector(void)
{
  int i;
  for (i = 0; i < sizeof(exceptions) / sizeof(*exceptions); ++i)
    DPMIchangeException(i, &exceptions[i]);
  DPMIchangeInterrupt(0x10, &interrupt10);
  DPMIchangeInterrupt(0x21, &interrupt21);
  DPMIchangeInterrupt(0x33, &interrupt33);
  DPMIchangeInterrupt(0x75, &interrupt75);
}

void tss2reg(struct REGPACK *r)
{
  r->r_ax = (word16)(tss_ptr->tss_eax);
  r->r_bx = (word16)(tss_ptr->tss_ebx);
  r->r_cx = (word16)(tss_ptr->tss_ecx);
  r->r_dx = (word16)(tss_ptr->tss_edx);
  r->r_si = (word16)(tss_ptr->tss_esi);
  r->r_di = (word16)(tss_ptr->tss_edi);
  r->r_flags = (word16)(tss_ptr->tss_eflags);
  r->r_ds = r->r_es = _DS;
}

void reg2tss(struct REGPACK *r)
{
  tss_ptr->tss_eax = r->r_ax;
  tss_ptr->tss_ebx = r->r_bx;
  tss_ptr->tss_ecx = r->r_cx;
  tss_ptr->tss_edx = r->r_dx;
  tss_ptr->tss_esi = r->r_si;
  tss_ptr->tss_edi = r->r_di;
  tss_ptr->tss_eflags = flmerge(r->r_flags, tss_ptr->tss_eflags);
}

/* The following routine should be used for _unsupported_ interrupt reflection
 * to real mode for go32. For any inrerrupts not directly handled by go32,
 * the return registers should _not_ be signed extended to fit the 32 bit
 * extended registers, but should ensure that the high order words are
 * preserved across the interrupt (this is how other extenders like DOS/4GW
 * and X32-VM do it). If you are calling the interrupt from int86() this is
 * not a problem, but if you do it from assembly code then it is ;-)
 */

void reg2tss_short(struct REGPACK *r)
{
  (short)tss_ptr->tss_eax = r->r_ax;
  (short)tss_ptr->tss_ebx = r->r_bx;
  (short)tss_ptr->tss_ecx = r->r_cx;
  (short)tss_ptr->tss_edx = r->r_dx;
  (short)tss_ptr->tss_esi = r->r_si;
  (short)tss_ptr->tss_edi = r->r_di;
  tss_ptr->tss_eflags = flmerge(r->r_flags, tss_ptr->tss_eflags);
}

extern int ctrl_c_flag;

int double_fault(void)
{
  fprintf(stderr, "double fault!\n");
  exit(1);
  return 1;
}

int check_nonpresent_387(void )
{
  if (!using_external_debugger)
  {
    fprintf(stderr, "Fatal!  Application attempted to use not-present 80387!\n");
    fprintf(stderr, "Floating point opcode at virtual address 0x%08lx\n", tss_ptr->tss_eip);
  }
  return 1;
}

int unsupported_int()
{
  if (!debug_mode)
    fprintf(stderr, "Unsupported INT 0x%02x\n", tss_ptr->tss_irqn);
  return 1;
}

#define U unsupported_int
typedef int (*FUNC)(void);
static FUNC exception_handler_list[] = {
  U, U, U, U, U, U, U,
  /* 07 */ check_nonpresent_387,
  /* 08 */ double_fault,
  U, U, U, U, U,
  /* 0e */ page_in,
  U,
  /* 10 */ i_10,		/* Video Interrupt */
  /* 11 */ generic_handler,	/* Equipment detection */
  /* 12 */ generic_handler,	/* Get memory size (outdated) */
  U,
  /* 14 */ generic_handler,	/* Serial communication */
  /* 15 */ generic_handler,	/* Lots of strange things */
  /* 16 */ generic_handler,	/* Keyboard */
  /* 17 */ generic_handler,	/* Parallel printer */
  U, U,
  /* 1a */ generic_handler,	/* Get/set system time */
  U, U, U, U, U, U,
  /* 21 */ i_21,		/* DOS Services */
  U, U, U, U, U, U, U, U, U, U, U, U, U, U, U,
  /* 31 */ i_31,		/* DPMIsim */
  U,
  /* 33 */ i_33			/* Mouse */
};
#undef U
#define NUM_EXCEPTIONS	(sizeof(exception_handler_list)/sizeof(exception_handler_list[0]))

exception_handler(void)
{
  int i;
  if (topline_info)
  {
    char buf[20];
    if (tss_ptr->tss_irqn == 14)
      sprintf(buf, "0x%08lx", tss_ptr->tss_cr2 - ARENA);
    else
      sprintf(buf, "0x%08lx", tss_ptr->tss_eip);
    for (i=0; buf[i]; i++)
      poke(screen_seg, i*2+80, buf[i] | 0x0600);
  }
  i = tss_ptr->tss_irqn;
/*  printf("i=%#02x\n", i); */
  if (((i >= hard_slave_lo)  && (i <= hard_slave_hi)
       && (i != hard_slave_lo + 5))
      || ((i >= hard_master_lo) && (i <= hard_master_hi)))
  {
    in_hardware_interrupt = 1;
    intr(i, &r);
    in_hardware_interrupt = 0;
    if (ctrl_break_hit)
      return 1;
    if (i == hard_master_lo + 1)
    {
      if (ctrl_c_causes_break)
      {
        r.r_ax = 0x0100;
        intr(0x16, &r);
        if (!(r.r_flags & 0x40) && (r.r_ax == 0x2e03))
        {
          _AH = 0;
          geninterrupt(0x16);
          ctrl_c_flag = 1;
        }
      }
    }
    if (ctrl_c_flag)
    {
      ctrl_c_flag = 0;
      if (ctrl_c_causes_break)
        return 1;
    }
    return 0;
  }
  if (i < NUM_EXCEPTIONS)
    return (exception_handler_list[i])();
  else
    return 1;
}

void retrieve_string(word32 v, char *transfer_buffer, char tchar)
{
  int i;
  if (!use_DPMI) {
#if 0
    for (i=0; i<4096; i++)
    {
      c = peek8(v);
      v++;
      transfer_buffer[i] = c;
      if (c == tchar)
        break;
    }
#else
    memscan32(v, transfer_buffer, tchar);
#endif
    return;
  } else {
    i = Pmemscan(tss_ptr->tss_ds, v, tchar, 4096);
    if (i == 0) i = 4096;
    Pmemget(tss_ptr->tss_ds, v, transfer_buffer, i);
    return;
  }
}

generic_handler(void)
{
  tss2reg(&r);
  intr(tss_ptr->tss_irqn, &r);
  reg2tss_short(&r);            /* KJB */
  return 0;
}

i_10(void)
{
  word32 v;
  word16 i, j;

/* CB changes */
/* OLD:
 * switch((word16)(tss_ptr->tss_eax) & 0xFF00) {
 *   case 0xFD00:
 *     graphics_pageflip();
 *     return 0;
 *   case 0xFE00:
 *     graphics_inquiry();
 *     return 0;
 *   case 0xFF00:
 *     graphics_mode((word16)(tss_ptr->tss_eax) & 0xff);
 *     in_graphics_mode = (peekb(0x40, 0x49) > 7);
 *     return 0;
 * }
 */
  if(((word16)tss_ptr->tss_eax & 0xff00) >= gr_assist_func_start) {
    graphics_assist();
    in_graphics_mode = (peekb(0x40, 0x49) > 7);
    return 0;
  }
/* end CB changes */

  tss2reg(&r);
  i = (word16)tss_ptr->tss_eax; /* int10 function 0x11 subfunctions 0 & 0x10 */
  if(i==0x1100 || i==0x1110) 
  { /* user-defined text characters */
    v = tss_ptr->tss_edx + ARENA; /* bh*cx bytes starting at (ds:dx) */
    CHECK_SEGFAULT(v);
    j = ((tss_ptr->tss_ebx >> 8) & 0xff) * ((word16)tss_ptr->tss_ecx);
    memget(v, transfer_buffer, j);
    r.r_dx = FP_OFF(transfer_buffer);
    r.r_ds = _DS;
    intr(0x10, &r);
    reg2tss(&r);
    tss_ptr->tss_ebp = r.r_es * 16L + r.r_bp + 0xe0000000L;
    return 0;
  }

  /* KJB - All unknown interrupts fall through to here (VESA VBE interrupts are
   * one set) and we use the reg2tss_short() routine to copy the registers
   * without sign extension so that we dont trash registers that the
   * application is not expecting to be changed. Note also that I moved the
   * code to change EBP into the above routine where it belongs.
   */

  intr(0x10, &r);
  reg2tss_short(&r);
  if (i == 0x1130)
    tss_ptr->tss_ebp = r.r_es * 16L + r.r_bp + 0xe0000000L;
  return 0;
}

#include "eventque.h"

#define  MSDRAW_STACK  128              /* stack size for mouse callback */

static word32  mousedraw_func32;        /* 32-bit mouse cursor drawing function */
static word32  mousedraw_contaddr;      /* jump to this address after mouse draw */
static char    mousedraw_active;        /* set while drawing mouse cursor */
EventQueue    *event_queue = NULL;      /* event queue */
typedef int far (*FFUNC)(void);
static FFUNC   mousedraw_callback = 0;	/* DPMI real mode callback to prot */

static void mousedraw_hook(void)
{
  disable();
  if(!mousedraw_active)
  {
    mousedraw_active = 1;
    if(use_DPMI)
    {
      mousedraw_callback();
      mousedraw_active = 0;
    }
    else
    {
      mousedraw_contaddr = a_tss.tss_eip;
      a_tss.tss_eip = mousedraw_func32;
    }
  }
  enable();
}

i_33(void)
{
  void (*msdrawfun)(void);
  int  queuesize;

  if(tss_ptr->tss_eax == 0x00ff) {
    if(event_queue != NULL) {
      EventQueueDeInit();
      event_queue = NULL;
    }
    if((queuesize = (int)tss_ptr->tss_ebx) > 0) {
      mousedraw_func32 = tss_ptr->tss_ecx;
      mousedraw_active = 0;
      msdrawfun = (mousedraw_func32 != 0L) ? mousedraw_hook : NULL;
      if(use_DPMI) {
        if(tss_ptr->tss_edx != 0x12345678L) return(0);	/* make sure V1.03 or more */
        mousedraw_callback = (FFUNC)mousedraw_func32;
      }
      event_queue = EventQueueInit(queuesize, MSDRAW_STACK, msdrawfun);
      if(event_queue != NULL) {
        tss_ptr->tss_ebx =
          (((word32)FP_SEG(event_queue)) << 4) +
          ((word32)FP_OFF(event_queue)) +
          0xe0000000L;
        tss_ptr->tss_ecx =
          (((word32)FP_SEG(&mousedraw_contaddr)) << 4) +
          ((word32)FP_OFF(&mousedraw_contaddr)) +
          0xe0000000L;
        tss_ptr->tss_edx =
          (((word32)FP_SEG(&mousedraw_active)) << 4) +
          ((word32)FP_OFF(&mousedraw_active)) +
          0xe0000000L;
      }
      else tss_ptr->tss_ebx = 0L;
    }
    tss_ptr->tss_eax = 0x0ff0;              /* acknowledge event handling */
    return(0);
  }
  if (*((unsigned far *)0x000000CEL) == 0)
    return 0;
  r.r_ax = (word16)(tss_ptr->tss_eax);
  r.r_bx = (word16)(tss_ptr->tss_ebx);
  r.r_cx = (word16)(tss_ptr->tss_ecx);
  r.r_dx = (word16)(tss_ptr->tss_edx);
  intr(0x33, &r);
  tss_ptr->tss_eax = r.r_ax;
  tss_ptr->tss_ebx = r.r_bx;
  tss_ptr->tss_ecx = r.r_cx;
  tss_ptr->tss_edx = r.r_dx;
  return 0;
}

/*1.07 TSS last_tss; */

i_21(void)
{
  word32 v, trans_total, countleft;
  int i, c, ah, tchar, trans_count;
  char *cp;
  tss2reg(&r);
  ah = ((word16)(tss_ptr->tss_eax) >> 8) & 0xff;

  if (ah & 0x80) switch (ah)
  {
    case 0xfe:
      return external_debugger_handler();
    case 0xff:
      return turbo_assist();
    default:
      return 1;
  }
  else switch (ah)
  {
    case 0x42: /* seek */
      _openfd[r.r_bx] &= 0xfdff; /* clear EOF */
      /* fall through */
    case 0x01: /* read with echo */
    case 0x02: /* con output */
    case 0x03: /* aux input */
    case 0x04: /* aux output */
    case 0x05: /* prn output */
    case 0x06: /* direct con i/o */
    case 0x07: /* direct con input */
    case 0x08: /* kbd read */
    case 0x0b: /* kbd status */
    case 0x0d: /* reset disk */
    case 0x0e: /* select disk */
    case 0x18: /* return al=0 */
    case 0x19: /* get disk */
    case 0x1d: /* return al=0 */
    case 0x1e: /* return al=0 */
    case 0x20: /* return al=0 */
    case 0x2a: /* get date */
    case 0x2b: /* set date */
    case 0x2c: /* get time */
    case 0x2d: /* set time */
    case 0x2e: /* (re)set verify flag */
    case 0x30: /* get version */
    case 0x36: /* get disk free space */
    case 0x37: /* get/set switch char */
    case 0x4d: /* get return code */
    case 0x54: /* get verify flag */
    case 0x57: /* get/set file time stamp */
    case 0x58: /* get/set UMB link state */
    case 0x5c: /* file locking */
    case 0x66: /* get/set global code page */
    case 0x67: /* set handle count */
    case 0x68: /* commit (flush and update directory) */
      intr(0x21, &r);
      reg2tss(&r);
      return 0;
    case 0x38: /* get country info */
      r.r_ds = _DS;
      r.r_dx = FP_OFF(transfer_buffer);
      intr(0x21, &r);
      if (r.r_flags & 1) 
      {
        tss_ptr->tss_eflags |= 1;
        tss_ptr->tss_eax = r.r_ax;
        return 0;
      }
      memput(tss_ptr->tss_edx + ARENA, transfer_buffer, 34);
      return 0;
    case 0x33: /* ^C checking and more */
      switch (r.r_ax & 0xff) 
      {
      case 0x01: /* set ^C */
      case 0x02: /* set extended ^C */
	ctrl_c_causes_break = r.r_dx & 0xff;
	/* fall through */
      case 0x00: /* get ^C */
      case 0x05: /* get boot drive */
      case 0x06: /* get true dos version */
	intr(0x21, &r);
	reg2tss(&r);
	return 0;
      default:
	return 1;
      }
    case 0x3e: /* close */
      if (using_external_debugger && r.r_bx < 2)
        return 0;
      if (r.r_bx == 1)
        redir_1_mono = 0;
      if (r.r_bx == 2)
        redir_2_mono = 0;
      intr(0x21, &r);
      reg2tss(&r);
      return 0;
    case 9: /* print string */
    case 0x39: /* mkdir */
    case 0x3a: /* rmdir */
    case 0x3b: /* chdir */
    case 0x41: /* unlink (delete) */
    case 0x43: /* chmod */
      if (ah == 9)
        tchar = '$';
      else
        tchar = 0;
      v = tss_ptr->tss_edx + ARENA;
      CHECK_SEGFAULT(v);
      retrieve_string(v, transfer_buffer, tchar);
      r.r_dx = FP_OFF(transfer_buffer);
      r.r_ds = _DS;
      intr(0x21, &r);
      reg2tss(&r);
      return 0;
    case 0x3c: /* creat (rewrite) */
      v = tss_ptr->tss_edx + ARENA;
      CHECK_SEGFAULT(v);
      retrieve_string(v, transfer_buffer, 0);
      i = _creat(transfer_buffer, (int)(tss_ptr->tss_ecx));
      if (i < 0)
      {
        tss_ptr->tss_eax = errno;
        tss_ptr->tss_eflags |= 1;
      }
      else
      {
        tss_ptr->tss_eax = i;
        tss_ptr->tss_eflags &= ~1;
      }
      return 0;
    case 0x3d: /* open */
      v = tss_ptr->tss_edx + ARENA;
      CHECK_SEGFAULT(v)
      retrieve_string(v, transfer_buffer, 0);
      i = (word16)(tss_ptr->tss_eax) & 0xf0;
      if (tss_ptr->tss_eax & O_WRONLY) i |= 1;
      if (tss_ptr->tss_eax & O_RDWR) i |= 2;
      i = _open(transfer_buffer, i);
      if (i < 0)
      {
        tss_ptr->tss_eax = errno;
        tss_ptr->tss_eflags |= 1;
      }
      else
      {
        tss_ptr->tss_eax = i;
        tss_ptr->tss_eflags &= ~1;
      }
      return 0;
    case 0x1a: /* set dta */
      user_dta = tss_ptr->tss_edx;
      setdta((char far *)transfer_buffer);
      return 0;
    case 0x2f: /* get dta */
      tss_ptr->tss_ebx = user_dta;
      return 0;
    case 0x56: /* rename/move */
      v = tss_ptr->tss_edx + ARENA;
      CHECK_SEGFAULT(v)
      retrieve_string(v, transfer_buffer, 0);
      i = strlen(transfer_buffer) + 1;
      r.r_dx = FP_OFF(transfer_buffer);
      r.r_ds = _DS;
      v = tss_ptr->tss_edi + ARENA;
      retrieve_string(v, transfer_buffer+i, 0);
      r.r_di = FP_OFF(transfer_buffer)+i;
      r.r_es = _DS;
      intr(0x21, &r);
      tss_ptr->tss_eax = r.r_ax;
      tss_ptr->tss_eflags = flmerge(r.r_flags, tss_ptr->tss_eflags);
      return 0;
    case 0x3f: /* read */
      if (!tss_ptr->tss_edx) {
        fprintf(stderr, "This image has a buggy read.s module.  Run DPMIFIX on it and try again.\n");
        return 1;
      }
      if (tss_ptr->tss_edx == transfer_linear)
      {
        i = read(r.r_bx, transfer_buffer, r.r_cx);
        if (i<0)
        {
          tss_ptr->tss_eflags |= 1; /* carry */
          tss_ptr->tss_eax = _doserrno;
        }
        else
        {
          tss_ptr->tss_eflags &= ~1;
          tss_ptr->tss_eax = i;
        }
        return 0;
      }
      trans_total = 0;
      countleft = tss_ptr->tss_ecx;
      v = tss_ptr->tss_edx;
      CHECK_SEGFAULT(v+ARENA)
      while (countleft > 0)
      {
        trans_count = (word16)((countleft <= 4096) ? countleft : 4096);
        i = read(r.r_bx, transfer_buffer, trans_count);
        if (i < 0)
        {
          tss_ptr->tss_eflags |= 1; /* carry */
          tss_ptr->tss_eax = _doserrno;
          return 0;
        }
        memput(v+ARENA, transfer_buffer, i);
        trans_total += i;
        v += i;
        countleft -= i;
        if (isatty(r.r_bx) && (i<trans_count))
          break; /* they're line buffered */
        if (i == 0)
          break;
      }
      tss_ptr->tss_eax = trans_total;
      tss_ptr->tss_eflags &= ~1;
      return 0;
    case 0x40: /* write */
      if (tss_ptr->tss_edx == transfer_linear)
      {
        if ((r.r_bx == 1) && redir_1_mono)
          i = mono_write(transfer_buffer, r.r_cx);
        else if ((r.r_bx == 2) && redir_2_mono)
          i = mono_write(transfer_buffer, r.r_cx);
        else
        {
          int fd = r.r_bx;
          if (r.r_cx == 0) /* for ftruncate */
            i = _write(fd, transfer_buffer, r.r_cx);
          else
            i = write(fd, transfer_buffer, r.r_cx);
        }
        if (i<0)
        {
          tss_ptr->tss_eflags |= 1; /* carry */
          tss_ptr->tss_eax = _doserrno;
        }
        else
        {
          tss_ptr->tss_eflags &= ~1;
          tss_ptr->tss_eax = i;
        }
        return 0;
      }
      trans_total = 0;
      countleft = tss_ptr->tss_ecx;
      if (countleft == 0)
      {
        r.r_ax = 0x4000;
        r.r_cx = 0;
        intr(0x21,&r);
        tss_ptr->tss_eax = 0;
        tss_ptr->tss_eflags &= ~1;
        return 0;
      }
      v = tss_ptr->tss_edx;
      CHECK_SEGFAULT(v+ARENA);
      r.r_dx = (int)transfer_buffer;
      while (countleft > 0)
      {
        trans_count = (word16)((countleft <= 4096) ? countleft : 4096);
        memget(v+ARENA, transfer_buffer, trans_count);
        if ((r.r_bx == 1) && redir_1_mono)
          i = mono_write(transfer_buffer, trans_count);
        else if ((r.r_bx == 2) && redir_2_mono)
          i = mono_write(transfer_buffer, trans_count);
        else
        {
          int fd = r.r_bx;
          i = write(fd, transfer_buffer, trans_count);
          if (in_graphics_mode && (fd < 3))
          {
            word32 far *p = graphics_pt;
            for (c = 0; c < 256; c++)
              *p++ &= ~PT_P;
          }
        }
        if (i<0) /* carry */
        {
          tss_ptr->tss_eflags |= 1; /* carry */
          tss_ptr->tss_eax = _doserrno;
          return 0;
        }
        trans_total += i;
        v += i;
        countleft -= i;
        if (i < trans_count)
          break;
      }
      tss_ptr->tss_eax = trans_total;
      tss_ptr->tss_eflags &= ~1;
      return 0;
    case 0x44: /* ioctl */
      return i_21_44();
    case 0x45: /* dup */
      i = _openfd[r.r_bx];
      intr(0x21, &r);
      if (!(r.r_flags & 1))
        _openfd[r.r_ax] = i;
      reg2tss(&r);
      return 0;
    case 0x46: /* dup2 */
      i = _openfd[r.r_bx];
      c = r.r_cx;
      intr(0x21, &r);
      if (!(r.r_flags & 1))
        _openfd[c] = i;
      reg2tss(&r);
      return 0;
    case 0x4e: /* find first */
      CHECK_SEGFAULT(user_dta+ARENA);
      v = tss_ptr->tss_edx + ARENA;
      CHECK_SEGFAULT(v);
      retrieve_string(v, transfer_buffer+43, 0);
      r.r_dx = FP_OFF(transfer_buffer+43);
      r.r_ds = _DS;
      intr(0x21, &r);
      reg2tss(&r);
      for (i=20; i>=0; i--)
        transfer_buffer[i+28] = transfer_buffer[i+26];
      transfer_buffer[32+13] = 0; /* asciiz termination */
      memput(user_dta+ARENA, transfer_buffer, 48);
      return 0;
    case 0x4f: /* find next */
      CHECK_SEGFAULT(user_dta+ARENA);
      memget(user_dta+ARENA, transfer_buffer, 48);
      for (i=0; i<=20; i++)
        transfer_buffer[i+26] = transfer_buffer[i+28];
      intr(0x21, &r);
      reg2tss(&r);
      for (i=20; i>=0; i--)
        transfer_buffer[i+28] = transfer_buffer[i+26];
      transfer_buffer[32+13] = 0; /* asciiz termination */
      memput(user_dta+ARENA, transfer_buffer, 48);
      return 0;
    case 0x47: /* getwd */
      getcurdir((int)(tss_ptr->tss_edx & 0xff), transfer_buffer);
      for (cp=transfer_buffer; *cp; cp++)
      {
        if (*cp == '\\') *cp = '/';
        *cp = tolower(*cp);
      }
      memput(tss_ptr->tss_esi+ARENA, transfer_buffer, strlen(transfer_buffer)+1);
      tss_ptr->tss_eax = (unsigned)r.r_ax;
      tss_ptr->tss_eflags &= ~1;
      return 0;
    case 0x4a: /* sbrk/brk -- NOT ORGINAL MEANING */
      if (tss_ptr->tss_eax & 0xff)
        tss_ptr->tss_eax = paging_sbrk(tss_ptr->tss_ebx);
      else
        tss_ptr->tss_eax = paging_brk(tss_ptr->tss_ebx);
      return 0;
    case 0x4c: /* exit */
      if (using_external_debugger && (tss_ptr == &a_tss))
        return 1;
      else
        exit((word8)(tss_ptr->tss_eax));
    default:
      return 1;
  }
}

static int reg2gate(word32 r)
{
  int g = (int)(r & 0xff);
  if (g >= 0x08 && g <= 0x0f)
    g = g - 0x08 + hard_master_lo;
  else if (g >= 0x70 && g <= 0x77)
    g = g - 0x70 + hard_slave_lo;
  return g;
}

static int dpmisim_is_exec = 0;

int i_31(void)
{
  int gate, i;
  word16 far *fptr;
  word16 dpmisim_spare_stack[128];
  union REGS r;
  struct SREGS s;
  switch ((word16)(tss_ptr->tss_eax))
  {
    case 0x0100:
      r.h.ah = 0x48;
      r.x.bx = (word16)tss_ptr->tss_ebx;
      int86(0x21, &r, &r);
      if ((r.x.flags & 1) && ((word16)tss_ptr->tss_ebx != 0xffff))
      {
        valloc_shrink_rmem(((word16)tss_ptr->tss_ebx)/256 + 1);
        r.h.ah = 0x48;
        r.x.bx = (word16)tss_ptr->tss_ebx;
        int86(0x21, &r, &r);
/*        if (r.x.flags & 1)
          printf("biggest after shrinking is %04x\n", r.x.bx); */
      }
      tss_ptr->tss_eflags &= ~1;
      tss_ptr->tss_eflags |= r.x.flags & 1;
      tss_ptr->tss_edx =
      tss_ptr->tss_eax = r.x.ax;
      tss_ptr->tss_ebx = r.x.bx;
/*      printf("allocated %x, %d %x\n", r.x.ax, r.x.flags & 1, r.x.bx); */
      return 0;

    case 0x0101:
      r.h.ah = 0x49;
      s.es = (word16)tss_ptr->tss_edx;
      int86x(0x21, &r, &r, &s);
/*      printf("released %x, %d %x\n", (word16)tss_ptr->tss_edx, r.x.flags & 1, r.x.ax); */
      return 0;

    case 0x0102:
      r.h.ah = 0x4a;
      r.x.bx = (word16)tss_ptr->tss_ebx;
      s.es = (word16)tss_ptr->tss_edx;
      int86x(0x21, &r, &r, &s);
      tss_ptr->tss_eflags &= ~1;
      tss_ptr->tss_eflags |= r.x.flags & 1;
      tss_ptr->tss_eax = r.x.ax;
      tss_ptr->tss_ebx = r.x.bx;
      return 0;

    case 0x0200:
/*      gate = (word8)tss_ptr->tss_ebx; */
      gate = reg2gate(tss_ptr->tss_ebx);
      tss_ptr->tss_ecx = peek(0, gate*4+2);
      tss_ptr->tss_edx = peek(0, gate*4);
      tss_ptr->tss_eflags &= ~1;
      return 0;

    case 0x0201:
/*      gate = (word8)tss_ptr->tss_ebx; */
      gate = reg2gate(tss_ptr->tss_ebx);
      disable();
      poke(0, gate*4+2, tss_ptr->tss_ecx);
      poke(0, gate*4, tss_ptr->tss_edx);
      enable();
      tss_ptr->tss_eflags &= ~1;
      return 0;

    case 0x0204:
      gate = reg2gate(tss_ptr->tss_ebx);
      tss_ptr->tss_ecx = idt[gate].selector;
      tss_ptr->tss_edx = idt[gate].offset0 | (idt[gate].offset1 << 16);
      tss_ptr->tss_eflags &= ~1;
      return 0;

    case 0x0205:
      gate = reg2gate(tss_ptr->tss_ebx);
      idt[gate].selector = (word16)(tss_ptr->tss_ecx);
      idt[gate].offset0 = (word16)(tss_ptr->tss_edx);
      idt[gate].offset1 = (word16)(tss_ptr->tss_edx >> 16);
      idt[gate].stype = 0x8e00;
      tss_ptr->tss_eflags &= ~1;
      return 0;

    case 0x0300:
    case 0x0301:
    case 0x0302:
      CHECK_SEGFAULT(tss_ptr->tss_edi + ARENA);
      if ((word16)tss_ptr->tss_ecx)
      {
        tss_ptr->tss_eax = 0x8021;
        tss_ptr->tss_eflags |= 1;
        return 0;
      }
      memget(tss_ptr->tss_edi + ARENA, dpmisim_regs, 50);

      if (dpmisim_regs[24] == 0)
      {
        dpmisim_regs[24] = _SS;
        dpmisim_regs[23] = (word16)(dpmisim_spare_stack) + sizeof(dpmisim_spare_stack);
      }
      if ((word16)tss_ptr->tss_eax != 0x0301)
      {
        dpmisim_regs[23] -= 2;	/* fake pushing flags on stack */
        fptr = MK_FP(dpmisim_regs[24], dpmisim_regs[23]);
        *fptr = dpmisim_regs[16];
      }

      if ((word16)tss_ptr->tss_eax == 0x0300)
      {
        dpmisim_regs[21] = peek(0, (word8)tss_ptr->tss_ebx * 4);
        dpmisim_regs[22] = peek(0, (word8)tss_ptr->tss_ebx * 4 + 2);
      }

      if (dpmisim_is_exec)
      {
        word32 our_interrupt_table[256];
        page_out_everything();
        movedata(0, 0, FP_SEG(our_interrupt_table), FP_OFF(our_interrupt_table), 256*4);
        uninit_controllers();
        dpmisim();
        init_controllers();
        ctrl_break_hit = 0;
        disable();
        movedata(FP_SEG(our_interrupt_table), FP_OFF(our_interrupt_table), 0, 0, 256*4);
        enable();
       page_in_everything();
      }
      else
        dpmisim();

      memput(tss_ptr->tss_edi + ARENA, dpmisim_regs, 50);
      tss_ptr->tss_eflags &= ~1;
      return 0;

    case 0x0303:
      CHECK_SEGFAULT(tss_ptr->tss_edi + ARENA);
      for (i=0; i<16; i++)
        if (dpmisim_rmcb[i].cb_address == 0)
          break;
      if (i == 16)
      {
        tss_ptr->tss_eflags |= 1;
        tss_ptr->tss_eax = 0x8015;
        return 0;
      }
      dpmisim_rmcb[i].cb_address = tss_ptr->tss_esi;
      dpmisim_rmcb[i].reg_ptr = tss_ptr->tss_edi;
      tss_ptr->tss_eflags &= ~1;
      tss_ptr->tss_ecx = _CS;
      tss_ptr->tss_edx = (word16)dpmisim_rmcb0 + i * ((word16)dpmisim_rmcb1 - (word16)dpmisim_rmcb0);
      return 0;

    case 0x0304:
      if ((word16)tss_ptr->tss_ecx == _CS)
        for (i=0; i<16; i++)
          if ((word16)tss_ptr->tss_edx == (word16)dpmisim_rmcb0 + i * ((word16)dpmisim_rmcb1 - (word16)dpmisim_rmcb0))
          {
            dpmisim_rmcb[i].cb_address = 0;
            tss_ptr->tss_eflags &= ~1;
            return 0;
          }
      tss_ptr->tss_eflags |= 1;
      tss_ptr->tss_eax = 0x8024;
      return 0;
      
    case 0x0500:
      CHECK_SEGFAULT(tss_ptr->tss_edi + ARENA);
      memset(transfer_buffer, 0xff, 48);
      ((word32 *)transfer_buffer)[8] = dalloc_max_size();
      ((word32 *)transfer_buffer)[4] =
      ((word32 *)transfer_buffer)[6] = valloc_max_size();
      ((word32 *)transfer_buffer)[2] =
      ((word32 *)transfer_buffer)[5] = valloc_max_size() - valloc_used();
      ((word32 *)transfer_buffer)[1] = 
        ((word32 *)transfer_buffer)[5] + ((word32 *)transfer_buffer)[8] - dalloc_used();
      ((word32 *)transfer_buffer)[0] = ((word32 *)transfer_buffer)[1] * 4096L;
      memput(tss_ptr->tss_edi + ARENA, transfer_buffer, 48);
      tss_ptr->tss_eflags &= ~1;
      return 0;

    case 0x0600: /* These all deal with locking memory.  We ignore them for now, */
    case 0x0601: /* but allow them to succeed to that in real DPMI mode you can */
    case 0x0602: /* use them. */
    case 0x0603:
    case 0x0702:
    case 0x0703:
      tss_ptr->tss_eflags &= ~1;
      return 0;

    case 0x0604:
      tss_ptr->tss_ebx = 0;
      tss_ptr->tss_ecx = 4096;
      tss_ptr->tss_eflags &= ~1;
      return 0;

    default: /* mark as unsupported */
      tss_ptr->tss_eflags |= 1;
      tss_ptr->tss_eax = 0x8001;
      return 0;
  }
}

struct time32 {
  word32 secs;
  word32 usecs;
};

struct tz32 {
  word32 offset;
  word32 dst;
};

struct  stat32 {
        short st_dev;
        short st_ino;
        short st_mode;
        short st_nlink;
        short st_uid;
        short st_gid;
        short st_rdev;
        short st_align_for_word32;
        long  st_size;
        long  st_atime;
        long  st_mtime;
        long  st_ctime;
        long  st_blksize;
};

turbo_assist(void)
{
  word32 p1, p2, r;
  struct time32 time32;
  struct tz32 tz32;
  struct stat32 statbuf32;
  struct stat statbuf;
  int i;
  char buf[128], *bp;
  word32 our_interrupt_table[256];

  p1 = tss_ptr->tss_ebx;
  p2 = tss_ptr->tss_ecx;
  switch ((word8)(tss_ptr->tss_eax))
  {
    case 1: /* creat */
      retrieve_string(p1+ARENA, buf, 0);
      r = creat(buf, S_IREAD | S_IWRITE);
      break;

    case 2: /* open */
      retrieve_string(p1+ARENA, buf, 0);
      r = open(buf, (int)p2, S_IREAD | S_IWRITE);
      break;

    case 3: /* fstat */
      memset(&statbuf, 0, sizeof(statbuf));
      r = fstat((int)p1, &statbuf);
      statbuf32.st_dev = statbuf.st_dev;
      statbuf32.st_ino = statbuf.st_ino;
      statbuf32.st_mode = statbuf.st_mode;
      statbuf32.st_nlink = statbuf.st_nlink;
      statbuf32.st_uid = 42;
      statbuf32.st_gid = 42;
      statbuf32.st_rdev = statbuf.st_rdev;
      statbuf32.st_size = statbuf.st_size;
      statbuf32.st_atime = statbuf.st_atime;
      statbuf32.st_mtime = statbuf.st_mtime;
      statbuf32.st_ctime = statbuf.st_ctime;
      statbuf32.st_blksize = 4096;
      memput(p2+ARENA, &statbuf32, sizeof(statbuf32));
      break;

    case 4: /* gettimeofday */
      if (p2)
      {
        CHECK_SEGFAULT(p2+ARENA);
        tz32.offset = timezone;
        tz32.dst = daylight;
        memput(p2+ARENA, &tz32, sizeof(tz32));
      }
      if (p1)
      {
        int dh;
        CHECK_SEGFAULT(p1+ARENA);
        time((long *)&(time32.secs));
        _AH = 0x2c;
        geninterrupt(0x21);
        dh = _DH;
        time32.usecs = _DL * 10000L;
        if (time32.secs % 60 != dh)
          time32.secs++;
        memput(p1+ARENA, &time32, sizeof(time32));
      }
      r = 0;
      break;

    case 5: /* settimeofday */
      if (p2)
      {
        CHECK_SEGFAULT(p2+ARENA);
        memget(p2+ARENA, &tz32, sizeof(tz32));
        timezone = tz32.offset;
        daylight = (int)tz32.dst;
      }
      if (p1)
      {
        CHECK_SEGFAULT(p1+ARENA);
        memget(p1+ARENA, &time32, sizeof(time32));
        stime((long *)&(time32.secs));
      }
      r = 0;
      break;

    case 6: /* stat */
      memset(&statbuf, 0, sizeof(statbuf));
      retrieve_string(p1+ARENA, transfer_buffer, 0);
      r = unixlike_stat(transfer_buffer, &statbuf);
      statbuf32.st_dev = statbuf.st_dev;
      statbuf32.st_ino = statbuf.st_ino;
      statbuf32.st_mode = statbuf.st_mode;
      statbuf32.st_nlink = statbuf.st_nlink;
      statbuf32.st_uid = statbuf.st_uid;
      statbuf32.st_gid = statbuf.st_gid;
      statbuf32.st_rdev = statbuf.st_rdev;
      statbuf32.st_size = statbuf.st_size;
      statbuf32.st_atime = statbuf.st_atime;
      statbuf32.st_mtime = statbuf.st_mtime;
      statbuf32.st_ctime = statbuf.st_ctime;
      statbuf32.st_blksize = 4096;
      memput(p2+ARENA, &statbuf32, sizeof(statbuf32));
      break;

    case 7: /* system */
      retrieve_string(p1+ARENA, transfer_buffer, 0);
      page_out_everything();
      movedata(0, 0, FP_SEG(our_interrupt_table), FP_OFF(our_interrupt_table), 256*4);
      uninit_controllers();
      sscanf(transfer_buffer, "%s%n", buf, &i);
      if (strpbrk(transfer_buffer, "<>|") == NULL)
        r = spawnlp(P_WAIT, buf, buf, transfer_buffer+i, 0);
      else
        r = -1;
      bp = buf+strlen(buf)-4;
      if (stricmp(bp, ".exe") && stricmp(bp, ".com") && (r & 0x80000000L))
        r = system(transfer_buffer);
      init_controllers();
      ctrl_break_hit = 0;
      disable();
      movedata(FP_SEG(our_interrupt_table), FP_OFF(our_interrupt_table), 0, 0, 256*4);
      enable();
      page_in_everything();
      break;

    case 8: /* _setmode() */
      _BX=(int)p1;
      _AX=0x4400;
      geninterrupt(0x21);
      i = _DX;
      if (p2 & O_BINARY)
        i |= 0x20;
      else
        i &= ~0x20;
      _BX=(int)p1;
      _DX = i;
      _AX=0x4401;
      geninterrupt(0x21);
      r = setmode((int)p1, (int)p2);
      break;

    case 9: /* chmod */
      retrieve_string(p1+ARENA, buf, 0);
      r = chmod(buf, (int)p2);
      break;

    case 10: /* DPMI exec */
      dpmisim_is_exec = 1;
      tss_ptr->tss_eax = 0x0300;
      i_31();
      dpmisim_is_exec = 0;
      return 0;

    default:
      return 1;
  }
  tss_ptr->tss_eflags &= ~1;
  if (r == -1)
  {
    tss_ptr->tss_eflags |= 1;
    tss_ptr->tss_eax = (errno == 35) ? 36 : errno;
    return 0;
  }
  tss_ptr->tss_eax = r;
  return 0;
}

i_21_44(void)
{
  switch ((word8)(tss_ptr->tss_eax))
  {
    case 0x00:
    case 0x01:
    case 0x06:
    case 0x07:
    case 0x08:
    case 0x09:
    case 0x0a:
    case 0x0b:
    case 0x0e:
    case 0x0f:
      intr(0x21, &r);
      tss_ptr->tss_edx = r.r_dx;
      tss_ptr->tss_eax = r.r_ax;
      tss_ptr->tss_eflags = flmerge(r.r_flags, tss_ptr->tss_eflags);
      return 0;
    default:
      return 1;
  }
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.