/*-=-=-=-=-=-=-=-=-=-=-=- RCCL/RCI Notice of Copyright -=-=-=-=-=-=-=-=-=-=-*
 *									    *
 *	Copyright (C) 1987, 1991 by Mike Parker.			    *
 *									    *
 *	Information on copyright permissions, as well as a complete	    *
 *	disclaimer of warranty, is given in the file COPYRIGHT.		    *
 *									    *
 *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/

#include <errno.h>

#include <vax/mtpr.h>
#include <vax/frame.h>

#include <sys/types.h> /* grrr */
#include <sys/stat.h>

#include "../sys/rciext/kamsgs.h"
#include "../sys/rciext/kacrash.h"

#include "regs.h"
#include "getmapplace.h"
#include "sirr.h"
#include "clock.h"

extern int errno;

#define SYSCALL(name) \
int sys_/**/name(code,na,ap,regs,pcloc,pslloc)\
int code;\
int na;\
int *ap;\
int regs[];\
int *pcloc;\
int *pslloc;

#define ERROR(errno) return((regs[R0]=(errno)),1)
#define RETURN(val) return((regs[R0]=(val)),0)

SYSCALL(nosys)
{
 printf("Invalid syscall number %d, %d args\n",code,na);
 ERROR(EINVAL);
}

SYSCALL(exit)
{
 extern CRASHINFO crashinfo;

 crashinfo.type = CI_EXIT;
 crashinfo.pc = *pcloc;
 crashinfo.psl = *pslloc;
 crashinfo.u.subtype = ap[0];
 usercrash(regs);
 RETURN(0); /* will die before reaching user mode */
}

SYSCALL(fstat)
{
 struct stat *buf;

 if (2 < (unsigned int)ap[0])
  { ERROR(EBADF);
  }
 buf = (struct stat *) ap[1];
 if (probew((int)buf,sizeof(struct stat)))
  { ERROR(EFAULT);
  }
 buf->st_dev = makedev(9,0); /* /dev/ra0a */
 buf->st_ino = 50; /* random inumber */
 buf->st_mode = 020622; /* char special, rw--w--w- */
 buf->st_nlink = 1;
 buf->st_uid = 0;
 buf->st_gid = 0;
 buf->st_rdev = makedev(0,0); /* /dev/console */
 buf->st_size = 0;
 buf->st_atime = 0; /* hope nobody uses these */
 buf->st_mtime = 0;
 buf->st_ctime = 0;
 buf->st_blksize = 8192;
 buf->st_blocks = 0;
 RETURN(0);
}

SYSCALL(read)
{
 char *buf;
 int len;

 if (ap[0] != 0)
  { ERROR(EBADF);
  }
 buf = (char *) ap[1];
 len = ap[2];
 if (len <= 0)
  { RETURN(0);
  }
 if (probew((int)buf,len))
  { ERROR(EFAULT);
  }
 buf[0] = consgetchar();
 RETURN(1);
}

SYSCALL(write)
{
 char *buf;
 int len;
 int i;

 if ((ap[0] != 1) && (ap[0] != 2))
  { ERROR(EBADF);
  }
 buf = (char *) ap[1];
 len = ap[2];
 if (len <= 0)
  { RETURN(0);
  }
 if (prober((int)buf,len))
  { ERROR(EFAULT);
  }
 for (i=0;i<len;i++)
  { consputchar(buf[i]);
  }
 RETURN(len);
}

SYSCALL(close)
{
 RETURN(0);
}

SYSCALL(brk)
{
 if (setbreak(ap[0]))
  { ERROR(ENOMEM);
  }
 else
  { RETURN(0);
  }
}

SYSCALL(ioctl)
{
 RETURN(0);
}

SYSCALL(getpagesize)
{
 RETURN(512);
}

SYSCALL(cmkrnl)
{
 RETURN((*(int (*)())ap[0])(ap[1]));
}

SYSCALL(gettime100)
{
 extern int time100;

 RETURN(time100);
}

SYSCALL(getmapplace)
{
 extern int toy;
 extern int Qbus;
 extern int IOpage;
 extern int Qbusmapregs;
 extern int uapage;
 extern int bboards[4];

 switch (ap[0])
  { case MAP_TOY:
       RETURN(toy);
       break;
    case MAP_QBUS:
       RETURN(Qbus);
       break;
    case MAP_IOPAGE:
       RETURN(IOpage);
       break;
    case MAP_QBUSMAPREGS:
       RETURN(Qbusmapregs);
       break;
    case MAP_UAPAGE:
       RETURN(uapage);
       break;
    case MAP_BBOARD(0):
       RETURN(bboards[0]);
       break;
    case MAP_BBOARD(1):
       RETURN(bboards[1]);
       break;
    case MAP_BBOARD(2):
       RETURN(bboards[2]);
       break;
    case MAP_BBOARD(3):
       RETURN(bboards[3]);
       break;
    default:
       ERROR(EINVAL);
       break;
  }
}

SYSCALL(gettimesch)
{
 extern int timesch;

 RETURN(timesch);
}

SYSCALL(schslippage)
{
 extern int sch_missedticks;

 RETURN(sch_missedticks);
}

SYSCALL(sendsignal)
{
 int s;

 s = splhigh();
 switch (ap[0])
  { case 0:
       beginmsg(9);
       putmsgbyte(MSG_SIGNAL);
       putmsgint(9);
       putmsgint(ap[1]);
       endmsg();
       ringdoorbell(0);
       break;
    default:
       sendsig(ap[1]);
       break;
  }
 splx(s);
 RETURN(0);
}

SYSCALL(ast100)
{
 extern int asttime100;
 extern int (*astfxn100)();
 extern int astarg100;
 int s;

 s = splhigh();
 asttime100 = ap[0];
 astfxn100 = (int (*)())ap[1];
 astarg100 = ap[2];
 splx(s);
 RETURN(0);
}

SYSCALL(astsch)
{
 extern int asttimesch;
 extern int (*astfxnsch)();
 extern int astargsch;
 int s;

 s = splhigh();
 asttimesch = ap[0];
 astfxnsch = (int (*)())ap[1];
 astargsch = ap[2];
 splx(s);
 RETURN(0);
}

SYSCALL(getmem)
{
 int mem;

 mem = sbrk(ap[0],0);
 if (mem == -1)
  { ERROR(ENOMEM);
  }
 else
  { RETURN(mem);
  }
}

SYSCALL(clearast)
{
 extern int astactive;
 int s;

 s = splhigh();
 astactive = 0;
 mtpr(SIRR,SIR_AST);
 splx(s);
 RETURN(0);
}

SYSCALL(blockast)
{
 extern int astactive;
 int s;

 s = splhigh();
 astactive = 1;
 splx(s);
 RETURN(0);
}

SYSCALL(handlesig)
{
 set_sig_handler(ap[0],(int (*)())ap[1]);
}

SYSCALL(badaddr)
{
 if ((ap[1] == 1) || (ap[1] == 2) || (ap[1] == 4))
  { if (badaddr(ap[0],ap[1]))
     { ERROR(EFAULT);
     }
    else
     { RETURN(0);
     }
  }
 else
  { ERROR(EINVAL);
  }
}

SYSCALL(debugger)
{
 extern int trapregs[];

 bcopy(&regs[R0],trapregs,14*4);
 debugger();
}

SYSCALL(halt)
{
 halt();
}

SYSCALL(exportclock)
{
 extern char export_clocks[4];
 extern int slavenum;

 if (ap[0] == slavenum)
  { ERROR(EINVAL);
  }
 export_clocks[ap[0]] = ap[1];
}

SYSCALL(schedast)
{
#define clockno (ap[0])
#define when (ap[1])
#define handler ((int (*)())ap[2])
#define argument (ap[3])
 int s;
 register TIMER *t;
 extern TIMER clock_asts[4];
 extern int slavenum;

 if ((clockno < 0) || (clockno > 3)) ERROR(EINVAL);
 s = splhigh();
 t = &clock_asts[clockno];
 if (when <= *t->time)
  { t->fxn = 0;
    if (handler)
     { ast(handler,argument);
     }
  }
 else
  { t->timeout = when;
    t->fxn = handler;
    t->arg = argument;
  }
 splx(s);
 RETURN(0);
#undef clockno
#undef when
#undef handler
#undef argument
}

SYSCALL(physmem)
{
 RETURN(phys_mem_left());
}
