Metropoli BBS
VIEWER: exphdlr.c MODE: TEXT (ASCII)
/* This is file EXPHDLR.C */
/*
** Copyright (C) 1991 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.
*/

/* 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 "build.h"
#include "types.h"
#include "gdt.h"
#include "idt.h"
#include "tss.h"
#include "utils.h"
#include "paging.h"
#include "npx.h"
#include "mono.h"

#define SEGFAULT(p) { \
  printf("Segmentation violation in pointer 0x%08lx\n", (p)); \
  return 1; \
  }

extern int was_user_int;
char transfer_buffer[4096];	/* must be near ptr for small model */

word32 user_dta;
static struct REGPACK r;

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

static set_controller(v)
{
  disable();
  outportb(0x20, 0x11);
  outportb(0x21, v);
  outportb(0x21, 4);
  outportb(0x21, 1);
  enable();
}

init_controllers()
{
  movedata(0, 0x08*4, 0, 0x78*4, 0x08*4);
  set_controller(0x78);
}

uninit_controllers()
{
  set_controller(0x08);
}

extern int ctrl_c_flag;

exception_handler()
{
  int i;
#if TOPLINEINFO
  char buf[20];
  sprintf(buf, "0x%08lx", tss_ptr->tss_eip);
  for (i=0; buf[i]; i++)
    poke(screen_seg, i*2+80, buf[i] | 0x0600);
#endif
  i = tss_ptr->tss_irqn;
/*  printf("i=%#02x, a0=%02x\n", i, inportb(0xa0)); */
  if ((i>=0x70) && (i<0x7f) && (i != 0x75))
  {
    if (i<0x78)
      intr(i, &r);
    else
      intr(i-0x70, &r);
    if (i == 0x79)
    {
      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;
      return 1;
    }
    return 0;
  }
  switch (i)
  {
    case 8:
      printf("double fault!\n");
      exit(1);
    case 0:
    case 1:
    case 2:
    case 3:
    case 4:
    case 5:
    case 6:
    case 9:
    case 10:
    case 11:
    case 12:
    case 13:
    case 15:
      return 1;
    case 0x75:
      return 1;
    case 7:
      printf("Fatal!  Application attempted to use not-present 80387!\n");
      printf("Floating point opcode at virtual address 0x%08lx\n", tss_ptr->tss_eip);
      return 1;
    case 14:
      return page_in();

    case 0x10:
      return i_10();
    case 0x11:
    case 0x12:
    case 0x14:
    case 0x16:
    case 0x17:
    case 0x1a:
      return generic_handler();
    case 0x21:
      return i_21();
    case 0x33:
      return i_33();
    default:
      return 1;
  }
}

#if DEBUGGER
static char flset[] = "VMRF  NT    OFDNIETFMIZR  AC  PE  CY";
static char floff[] = "              UPID  PLNZ      PO  NC";
static char fluse[] = {1,1,0,1,0,0,1,1,1,1,1,1,0,1,0,1,0,1};

tssprint(TSS *t)
{
  int i;
  printf("eax=%08lx  ebx=%08lx  ecx=%08lx  edx=%08lx\n",
    t->tss_eax, t->tss_ebx, t->tss_ecx, t->tss_edx);
  printf("esi=%08lx  edi=%08lx  ebp=%08lx ",
    t->tss_esi, t->tss_edi, t->tss_ebp);
  for (i=0; i<18; i++)
    if (fluse[i])
      if (t->tss_eflags & (1<<(17-i)))
        printf(" %2.2s", flset+i*2);
      else
        printf(" %2.2s", floff+i*2);
  printf("\nds=%04x es=%04x fs=%04x gs=%04x ss:esp=%04x:%08lx cs=%04x\n",
    t->tss_ds, t->tss_es, t->tss_fs, t->tss_gs, t->tss_ss, t->tss_esp, t->tss_cs);
}
#endif /* DEBUGGER */

int retrieve_string(word32 v, char *transfer_buffer, char tchar)
{
  int i;
  char c;
  for (i=0; i<4096; i++)
  {
    c = peek8(v);
    v++;
    transfer_buffer[i] = c;
    if (c == tchar)
      break;
  }
  return i+1; /* number of characters placed in buffer */
}

static int old_text_mode = -1;

generic_handler()
{
  tss2reg(&r);
  intr(tss_ptr->tss_irqn, &r);
  reg2tss(&r);
  return 0;
}

i_10()
{
  if ((tss_ptr->tss_eax & 0xFF00) == 0xFF00)
  {
    graphics_mode(tss_ptr->tss_eax & 0xff);
    return 0;
  }
  tss2reg(&r);
  intr(0x10, &r);
  reg2tss(&r);
  tss_ptr->tss_ebp = r.r_es * 16L + r.r_bp + 0xe0000000L;
  return 0;
}

i_33()
{
  if (*((unsigned far *)0x000000CEL) == 0)
    return 0;
  r.r_ax = tss_ptr->tss_eax;
  r.r_bx = tss_ptr->tss_ebx;
  r.r_cx = tss_ptr->tss_ecx;
  r.r_dx = 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;
}

TSS last_tss;

i_21()
{
  word32 v, trans_total, countleft;
  int i, c, ah, tchar, trans_count;
  char *cp;
  memcpy(&last_tss, tss_ptr, sizeof(TSS));
  tss2reg(&r);
  ah = (tss_ptr->tss_eax >> 8) & 0xff;
#if 0
  printf("int 21h ax=0x%04x bx=0x%04x cx=0x%04x dx=0x%04x\n",
    (int)(tss_ptr->tss_eax),
    (int)(tss_ptr->tss_ebx),
    (int)(tss_ptr->tss_ecx),
    (int)(tss_ptr->tss_edx)
    );
#endif
  switch (ah)
  {
    case 1:
    case 2:
    case 3:
    case 4:
    case 5:
    case 6:
    case 7:
    case 8:
    case 0x0b:
    case 0x2a:
    case 0x2b:
    case 0x2c:
    case 0x2d:
    case 0x33:
    case 0x42:
    case 0x45:
    case 0x46:
    case 0x57:
    case 0x68:
      intr(0x21, &r);
      reg2tss(&r);
      return 0;
    case 0x3e:
#if DEBUGGER
      if (r.r_bx <= 2)
        return 0;
#endif
      intr(0x21, &r);
      reg2tss(&r);
      return 0;
    case 9:
    case 0x39:
    case 0x3a:
    case 0x3b:
    case 0x41:
    case 0x43:
      if (ah == 9)
        tchar = '$';
      else
        tchar = 0;
      v = tss_ptr->tss_edx + ARENA;
      if (!page_is_valid(v))
      {
        printf("Segmentation violation in pointer 0x%08lx\n", tss_ptr->tss_edx);
        return 1;
      }
      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:
      v = tss_ptr->tss_edx + ARENA;
      if (!page_is_valid(v))
      {
        printf("Segmentation violation in pointer 0x%08lx\n", tss_ptr->tss_edx);
        return 1;
      }
      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:
      v = tss_ptr->tss_edx + ARENA;
      if (!page_is_valid(v))
      {
        printf("Segmentation violation in pointer 0x%08lx\n", tss_ptr->tss_edx);
        return 1;
      }
      retrieve_string(v, transfer_buffer, 0);
      i = 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:
      user_dta = tss_ptr->tss_edx;
      setdta((char far *)transfer_buffer);
      return 0;
    case 0x2f:
      tss_ptr->tss_ebx = user_dta;
      return 0;
    case 0x30:
      intr(0x21, &r);
      reg2tss(&r);
      return 0;
    case 0x56:
      v = tss_ptr->tss_edx + ARENA;
      if (!page_is_valid(v))
      {
        printf("Segmentation violation in pointer 0x%08lx\n", tss_ptr->tss_edx);
        return 1;
      }
      i = retrieve_string(v, transfer_buffer, 0);
      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:
      trans_total = 0;
      countleft = tss_ptr->tss_ecx;
      v = tss_ptr->tss_edx;
      if (!page_is_valid(v+ARENA))
      {
        printf("Segmentation violation in pointer 0x%08lx\n", tss_ptr->tss_edx);
        return 1;
      }
      while (countleft > 0)
      {
        trans_count = (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:
      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;
      if (!page_is_valid(v+ARENA))
        SEGFAULT(v);
      r.r_dx = (int)transfer_buffer;
      while (countleft > 0)
      {
        trans_count = (countleft <= 4096) ? countleft : 4096;
        memget(v+ARENA, transfer_buffer, trans_count);
        i = write(r.r_bx, transfer_buffer, trans_count);
        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:
      return i_21_44();
    case 0x4e:
      if (!page_is_valid(user_dta+ARENA))
        SEGFAULT(user_dta);
      v = tss_ptr->tss_edx + ARENA;
      if (!page_is_valid(v))
        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:
      if (!page_is_valid(user_dta+ARENA))
        SEGFAULT(user_dta);
      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:
      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));
      tss_ptr->tss_eax = (unsigned)r.r_ax;
      tss_ptr->tss_eflags &= ~1;
      return 0;
    case 0x4a:
      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:
#if DEBUGGER
      printf("Program exited normally, return code %d (0x%x)\n",
             (int)(tss_ptr->tss_eax & 0xff), (int)(tss_ptr->tss_eax & 0xff));
      return 1;
#else
      exit(tss_ptr->tss_eax & 0xff);
#endif
    case 0xff:
      return turbo_assist();
    default:
      return 1;
  }
}

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;
};

static int dev_count=1;

turbo_assist()
{
  word32 p1, p2, p3, r;
  struct time32 time32;
  struct tz32 tz32;
  struct stat32 statbuf32;
  struct stat statbuf;
  int i;

  char buf[128];
  p1 = tss_ptr->tss_ebx;
  p2 = tss_ptr->tss_ecx;
  p3 = tss_ptr->tss_edx;
  switch (tss_ptr->tss_eax & 0xff)
  {
    case 1:
      retrieve_string(p1+ARENA, buf, 0);
      r = creat(buf, S_IREAD | S_IWRITE);
      break;
    case 2:
      retrieve_string(p1+ARENA, buf, 0);
      r = open(buf, (int)p2, S_IREAD | S_IWRITE);
      break;
    case 3:
      memset(&statbuf, 0, sizeof(statbuf));
      r = fstat((int)p1, &statbuf);
      statbuf32.st_dev = dev_count++;
      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 = 512;
      memput(p2+ARENA, &statbuf32, sizeof(statbuf32));
      break;
    case 4:
      if (p2)
      {
        if (!page_is_valid(p2+ARENA))
          SEGFAULT(p2);
        tz32.offset = timezone;
        tz32.dst = daylight;
        memput(p2+ARENA, &tz32, sizeof(tz32));
      }
      if (p1)
      {
        if (!page_is_valid(p1+ARENA))
          SEGFAULT(p1);
        time(&(time32.secs));
        _AH = 0x2c;
        geninterrupt(0x21);
        time32.usecs = _DL * 10000L;
        memput(p1+ARENA, &time32, sizeof(time32));
      }
      r = 0;
      break;
    case 5:
      if (p2)
      {
        if (!page_is_valid(p2+ARENA))
          SEGFAULT(p2);
        memget(p2+ARENA, &tz32, sizeof(tz32));
        timezone = tz32.offset;
        daylight = tz32.dst;
      }
      if (p1)
      {
        if (!page_is_valid(p1+ARENA))
          SEGFAULT(p1);
        memget(p1+ARENA, &time32, sizeof(time32));
        stime(&(time32.secs));
      }
      r = 0;
      break;
    case 6:
      memset(&statbuf, 0, sizeof(statbuf));
      retrieve_string(p1+ARENA, transfer_buffer, 0);
      r = stat(transfer_buffer, &statbuf);
      statbuf32.st_dev = dev_count++;
      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 = 512;
      memput(p2+ARENA, &statbuf32, sizeof(statbuf32));
      break;
    case 7:
      retrieve_string(p1+ARENA, transfer_buffer, 0);
      page_out_everything();
      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;
      if (r & 0x80000000L)
        r = system(transfer_buffer);
      init_controllers();
      page_in_everything();
      break;
    case 8:
      r = setmode((int)p1, (int)p2);
      break;
    default:
      return 1;
  }
  tss_ptr->tss_eflags &= ~1;
  if (r == -1)
  {
    tss_ptr->tss_eflags |= 1;
    tss_ptr->tss_eax = errno;
    return 0;
  }
  tss_ptr->tss_eax = r;
  return 0;
}

i_21_44()
{
  switch (tss_ptr->tss_eax & 0xff)
  {
    case 0x00:
    case 0x01:
    case 0x06:
    case 0x07:
      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;
  }
}

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

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);
}
[ RETURN TO DIRECTORY ]