/*
    Unix.h, Copyright 1999 (c) by George Fankhauser,
    Swiss Federal Institute of Technology,
    Computer Engineering and Networks Laboratory.
 
    TOPSY -- A Teachable Operating System.
             Implementation of a tiny and simple
             micro kernel for teaching purposes.
 
    For further information, please visit http://www.tik.ee.ethz.ch/~topsy
 
    This software is provided under the terms of the GNU General Public Licence.
 
    A full copy of the GNU GPL is provided in the file COPYING found in the 
    development root of Topsy.
*/
/*
	*** empty log message ***
	
	Revision 1.6  1999/05/19 15:15:00  gfa
	*** empty log message ***
 
	Revision 1.5  1999/05/19 14:30:48  gfa
	ome linux tweakin' done...
 
	Revision 1.4  1999/05/19 11:43:22  gfa
	new link script for linux
 
	Revision 1.3  1999/05/18 16:57:59  gfa
	*** empty log message ***
 
	Revision 1.2  1999/05/13 17:06:06  jeker
	Initial revision
 
*/
#ifndef _UNIX_H_
#define _UNIX_H_

#ifdef __sun__
#define __SOLARIS__
#endif

#ifdef __sun__
#define SOLARIS
#endif

/* this file contains all unix system specific includes and defines */

// used in IO/unix/IOHal.c and IO/Drivers/UnixConsole.c for read/write
#define STDIN_FILENO    0
#define STDOUT_FILENO   1
#define STDERR_FILENO   2

// the following address depends on the layout of a unix process and must
// be entered also into the user program link script when porting to
// another *ix

#ifdef linux
#define USERBRKAT 0x9000000
#endif

#ifdef SOLARIS
#define USERBRKAT 0x100000
#endif


#include <limits.h>     // replacement for Topsy/unix/limits.h
#ifdef linux
#include <asm/sigcontext.h> // for context switching
#define __USE_GNU
#include <ucontext.h>
#undef __USE_GNU
#endif
#include <ucontext.h>   // for context switching
#include <malloc.h>
#include <sys/types.h> // user file ops
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h> // mem mgmt: mprotect
#include <unistd.h>   // used for syscalls:
// ualarm in Threads/unix/TMClock.c
// kill   in Topsy/unix/SyscallMsg.c
// getpid in Topsy/unix/SyscallMsg.c
#include <signal.h>   // used in Threads/unix/TMHal.c and
// Topsy/unix/SyscallMsg.c
#include <setjmp.h>   // for contextswitches in Threads/unix/TMHal.c
#include <stdio.h>    // scanf of user symbol in startup...

#define NOFSIGNALS NSIG // used on most unices



#ifdef mips

#define SETSTACKPOINTER(ctxt, val)	(ctxt->uc.sc_sp = val)
#define SETRETURNVALUE(ctxt, val)	(ctxt->uc.sc_v0 = val)
#define SETPROGRAMCOUNTER(ctxt, val)	(ctxt->uc.sc_pc = val)
#define SETSTATUSREGISTER(ctxt, val)	(ctxt->uc.sc_sr = val)
#define SETFRAMEPOINTER(ctxt, val)	(ctxt->uc.sc_fp = val)
#define SETARGUMENT0(ctxt, val)		(ctxt->uc.sc_a0 = val)
#define SETARGUMENT1(ctxt, val)		(ctxt->uc.sc_a1 = val)
#define SETRETADDR(ctxt, val)		(ctxt->uc.sc_ra = val)
#define GETPROGRAMCOUNTER(ctxt)  	return ctxt->uc.sc_pc;
#define GETFAULTINGADDRESS(ctxt)	{ asm("mfc0 v0, $8;"); return; }

#elif sparc

#define SIGCONTEXT ucontext
#define mc uc_mcontext

#define SETSTATUSREGISTER(ctxt,val) (ctxt->uc.mc.gregs[REG_PSR] = val)
#define SETSTACKPOINTER(ctxt, val)  (ctxt->uc.mc.gregs[REG_SP] = val)
#define SETRETURNVALUE(ctxt, val)   (ctxt->uc.mc.gregs[REG_G7] = val)
#define SETPROGRAMCOUNTER(ctxt,val) ({ctxt->uc.mc.gregs[REG_PC]=val; \
				      ctxt->uc.mc.gregs[REG_nPC]=val+4;})
#define SETARGUMENT0(ctxt, val)  (ctxt->uc.mc.gregs[REG_O0] = val)
#define SETARGUMENT1(ctxt, val)  (ctxt->uc.mc.gregs[REG_O1] = val)
//#define SETFRAMEPOINTER(ctxt,val)(*(int*)(ctxt->uc.mc.gregs[REG_SP]+56)=val)
// o6 (sp) becomes i6 (fp) on save
#define SETFRAMEPOINTER(ctxt,val)({ *(int*)(ctxt->uc.mc.gregs[REG_SP]+56)=val;  })
//#define SETRETADDR(ctxt, val)    (*(int*)(ctxt->uc.mc.gregs[REG_SP]+60)=val)
// o7 becomes i7 (ra) on save; a ret is in fact a "retl %i7+8"
#define SETRETADDR(ctxt, val)    (ctxt->uc.mc.gregs[REG_O7] = val - 8)
#define GETPROGRAMCOUNTER(ctxt)  return ctxt->uc.mc.gregs[REG_PC];
#define GETFAULTINGADDRESS(ctxt)	return 0;

#elif i386

#ifdef linux
#define mc uc_mcontext
#endif
#define SETSTACKPOINTER(ctxt, val)	(ctxt->uc.mc.gregs[ESP] = val)
#define SETPROGRAMCOUNTER(ctxt, val)	(ctxt->uc.mc.gregs[EIP] = val)
#define SETSTATUSREGISTER(ctxt, val)	(ctxt->uc.mc.gregs[EFL] = val)
#define SETFRAMEPOINTER(ctxt, val)	(ctxt->uc.mc.gregs[EBP] = val)
#define SETRETURNVALUE(ctxt, val)	(ctxt->uc.mc.gregs[EAX] = val)
#define SETARGUMENT0(ctxt, val)  (*((char*)(ctxt->uc.mc.gregs[ESP] + 4))=val)
#define SETARGUMENT1(ctxt, val)	 (*((char*)(ctxt->uc.mc.gregs[ESP] + 8))=val)
#define SETRETADDR(ctxt, val)	 (*((char*)(ctxt->uc.mc.gregs[ESP])) = val)

#define GETPROGRAMCOUNTER(ctxt)         return ctxt->uc.mc.gregs[EIP];
#define GETFAULTINGADDRESS(ctxt)	return 0;

#endif // arch

#endif // _UNIX_H_
