/* Machine dependent definitions
   Copyright (C) 1991 Free Software Foundation

This file is part of the GNU Hurd.

The GNU Hurd is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.

The GNU Hurd is distributed in the hope that it will be useful, 
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with the GNU Hurd; see the file COPYING.  If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */

/* Written by Michael I. Bushnell.  */

#include <mach/i386/vm_param.h>
#include <mach/error.h>
#include <gnu/posix_errors.h>
#include <gnu/signal.h>

#define STATE_SIZE i386_THREAD_STATE_COUNT

/* Location of emulator's text segment */
#define EMUL_SIZE 0x0040000	/* XXX ??? */
#define EMUL_MINADDR (VM_MAX_ADDRESS - EMUL_SIZE)
#define EMUL_MAXADDR VM_MAX_ADDRESS

/* Which way does the stack grow?  */
#define STACK_DOWN

/* Size and alignment of stacks when running inside emulator */
#define STACK_SIZE (32 * 1024)
#define STACK_MASK (~(STACK_SIZE - 1)) /* Get to bottom of the stack */

#define INT_STACK_SIZE 1024
#define INT_STACK_MASK (~(STACK_SIZE - 1))

/* Struct at the base of each stack: */
struct stackbase
{
  volatile mach_port_t reply_port; /* MiG reply port */

  /* Definitions for interruption of RPCs */
  volatile int in_intr_call;	/* executing interruptible rpc */
  volatile int call_intred;	/* syscall return code after interrupt */
  volatile mach_port_t intr_port; /* NOT holding a reference */
  volatile int intr_type;
#define IO_INTR 1
#define WAIT_INTR 2  

  /* Definitions for copyin/copyout */
  volatile int in_ucopy;	/* set if we are in a copyin/out */
  volatile void *ucopy_ubase;	/* base address in user space */
  volatile int ucopy_len;	/* length of user space data */
  volatile int ucopy_pc;	/* where to go on error */
  volatile int ucopy_sp;	/* stack pointer */
};

/* Functions required by machine independent code */
void set_newuser_thread (task_t, thread_t, int *, int);
void set_newemul_thread (task_t, thread_t);
void fetch_state (thread_t, int *);
int thread_in_emulator (int *);
void abort_thread_rpc (thread_t, int *, int);
void zap_thread_sighandler (thread_t, int *, int, int, int, int,
			    struct sigstack *);
void set_sig_handler (int *, int, int, int, int, struct sigstack *);
void emulator_fault (int);
int write_corefile ();

/* Functions defined in i386/alix_vector.s */
void trampoline (void);
void endtrampoline (void);
void fork_init_point (void);
void emul_thd_init_point (void);
mach_port_t mig_get_reply_port (void);


/* Stubs for interruptible RPC's */
#define INTR_CALL_N(name, pt, type, arglist)				    \
({									    \
  int __sp;								    \
  struct stackbase *__base;						    \
  error_t __err;							    \
									    \
  asm ("movl %%esp,%0" : "=r" (__sp));					    \
  __base = (struct stackbase *)(__sp & STACK_MASK);			    \
  while (1)								    \
    {									    \
      __base->call_intred = NORMRETURN;					    \
      __base->intr_port = pt;						    \
      __base->intr_type = type;						    \
      __base->in_intr_call = 1;						    \
      if (__err = rpc_check_sigs ())					    \
	break;								    \
      __err = rpc_ ## name arglist;					    \
      if (__err == POSIX_EINTR || __err == MACH_RCV_INTERRUPTED		    \
          || __err == MACH_SEND_INTERRUPTED)				    \
        {								    \
	  /* If we get EINTR, but nobody's set call_intred, then the interrupt\
	     wasn't intended for us, and we can continue.  If we get a RECV \
	     intr, and it isn't accidental, then go back to the loop to pick \
	     up the return from the RPC (which should arrive "quickly").  */ \
          if ((__err == POSIX_EINTR && __base->call_intred == NORMRETURN)   \
	      || (__err == MACH_RCV_INTERRUPTED				    \
	          && __base->call_intred != NORMRETURN))		    \
	    continue;							    \
          __err = __base->call_intred;					    \
        }								    \
      break;								    \
    }									    \
  __base->in_intr_call = 0;						    \
  __err;								    \
})

#define io_write_inband(a,b,c,d,e,f,g,h) \
  INTR_CALL_N(io_write_inband, a, IO_INTR, (a,b,c,d,e,f,g,h))
#define io_write_outofband(a,b,c,d,e,f,g,h) \
  INTR_CALL_N(io_write_outofband, a, IO_INTR, (a,b,c,d,e,f,g,h))
#define	io_read_inband(a,b,c,d,e,f,g,h) \
  INTR_CALL_N(io_read_inband, a, IO_INTR, (a,b,c,d,e,f,g,h))
#define io_read_outofband(a,b,c,d,e,f,g,h) \
  INTR_CALL_N(io_read_outofband, a, IO_INTR, (a,b,c,d,e,f,g,h))
#define io_getcttyport rpc_io_getcttyport
#define io_ioctl_x(a,b,c,d,e) \
  INTR_CALL_N(io_ioctl_x, a, IO_INTR, (a,b,c,d,e))
#define io_ioctl_r(a,b,c,d,e,f,g) \
  INTR_CALL_N(io_ioctl_r, a, IO_INTR, (a,b,c,d,e,f,g))
#define io_ioctl_w(a,b,c,d,e,f,g) \
  INTR_CALL_N(io_ioctl_w, a, IO_INTR, (a,b,c,d,e,f,g))
#define io_ioctl_rw(a,b,c,d,e,f,g,h,i) \
  INTR_CALL_N(io_ioctl_rw, a, IO_INTR, (a,b,c,d,e,f,g,h,i))
#define io_set_flags rpc_io_set_flags
#define io_get_flags  rpc_io_get_flags  
#define io_select rpc_io_select
#define io_stat(a,b) INTR_CALL_N(io_stat, a, IO_INTR, (a,b))
#define io_reauthenticate rpc_io_reauthenticate
#define io_interrupt rpc_io_interrupt
#define io_server_version rpc_io_server_version
#define io_map rpc_io_map
#define io_map_cntl rpc_io_map_cntl
#define io_get_it(a,b) INTR_CALL_N(io_get_it, a, IO_INTR, (a,b))
#define io_release_it rpc_io_release_it
#define io_eofnotify rpc_io_eofnotify
#define io_prenotify rpc_io_prenotify
#define io_postnotify rpc_io_postnotify
#define io_readsleep(a,b) INTR_CALL_N(io_readsleep, a, IO_INTR, (a,b))
#define io_sigio rpc_io_sigio

#define file_exec(a, b, c, d, e, f, g, h, i, j, k, l) \
  INTR_CALL_N(file_exec, a, IO_INTR, (a,b,c,d,e,f,g,h,i,j,k,l))
#define file_chown(a,b,c) INTR_CALL_N(file_chown, a, IO_INTR, (a,b,c))
#define file_chauthor(a,b) INTR_CALL_N(file_chauthor, a, IO_INTR, (a,b))
#define file_chmod(a,b) INTR_CALL_N(file_chmod, a, IO_INTR, (a,b))
#define file_chflags(a,b) INTR_CALL_N(file_chflags, a, IO_INTR, (a,b))
#define file_utimes(a,b,c) INTR_CALL_N(file_utimes, a, IO_INTR, (a,b,c))
#define file_seek(a,b,c,d) INTR_CALL_N(file_seek, a, IO_INTR, (a,b,c,d))
#define file_truncate(a,b) INTR_CALL_N(file_truncate, a, IO_INTR, (a,b))
#define file_lock(a,b) INTR_CALL_N(file_lock, a, IO_INTR, (a,b))
#define file_getdev rpc_file_getdev
#define file_getcontrol rpc_file_getcontrol
#define file_statfs(a,b) INTR_CALL_N(file_statfs, a, IO_INTR, (a,b))
#define file_sync(a,b) INTR_CALL_N(file_sync, a, IO_INTR, (a,b))
#define file_syncfs(a,b,c) INTR_CALL_N(file_syncfs, a, IO_INTR, (a,b,c))
#define file_pathconf(a,b) INTR_CALL_N(file_pathconf, a, IO_INTR, (a,b))
#define file_getsockaddr rpc_file_getsockaddr
#define dir_pathtrans(a,b,c,d,e,f,g,h,i) \
  INTR_CALL_N(dir_pathtrans, a, IO_INTR, (a,b,c,d,e,f,g,h,i))
#define dir_setsys rpc_dir_setsys
#define dir_makesock(a,b,c,d) INTR_CALL_N(dir_makesock, a, IO_INTR, (a,b,c,d))
#define dir_lstat(a,b,c,d) INTR_CALL_N(dir_lstat, a, IO_INTR, (a,b,c,d))
#define dir_mkdir(a,b,c,d) INTR_CALL_N(dir_mkdir, a, IO_INTR, (a,b,c,d))
#define dir_rmdir(a,b,c) INTR_CALL_N(dir_rmdir, a, IO_INTR, (a,b,c))
#define dir_mknod(a,b,c,d,e) INTR_CALL_N(dir_mknod, a, IO_INTR, (a,b,c,d,e))
#define dir_unlink(a,b,c) INTR_CALL_N(dir_unlink, a, IO_INTR, (a,b,c))
#define dir_link(a,b,c,d) INTR_CALL_N(dir_link, a, IO_INTR, (a,b,c,d))
#define dir_symlink(a,b,c,d,e) \
  INTR_CALL_N(dir_symlink, a, IO_INTR, (a,b,c,d,e))
#define dir_readlink(a,b,c,d,e) \
  INTR_CALL_N(dir_readlink, a, IO_INTR, (a,b,c,d,e))
#define dir_rename(a,b,c,d,e,f) \
  INTR_CALL_N(dir_rename, a, IO_INTR, (a,b,c,d,e,f))
#define dir_set_translator(a,b,c,d,e,f,g,h) \
  INTR_CALL_N(dir_set_translator, a, IO_INTR, (a,b,c,d,e,f,g,h))
#define dir_get_translator(a,b,c,d) \
  INTR_CALL_N(dir_get_translator, a, IO_INTR, (a,b,c,d))
#define dir_statfs(a,b,c,d) INTR_CALL_N(dir_statfs, a, IO_INTR, (a,b,c,d))

#define socket_create rpc_socket_create
#define socket_listen rpc_socket_listen
#define socket_accept(a,b,c) INTR_CALL_N(socket_accept, a, IO_INTR, (a,b,c))
#define socket_connect(a,b) INTR_CALL_N(socket_connect, a, IO_INTR, (a,b))
#define socket_bind rpc_socket_bind
#define socket_name rpc_socket_name
#define socket_peername rpc_socket_peername
#define socket_connect2 rpc_socket_connect2
#define socket_create_address rpc_socket_create_address
#define socket_fabricate_address rpc_socket_fabricate_address
#define socket_whatis_address rpc_socket_whatis_address
#define socket_shutdown rpc_socket_shutdown
#define socket_getopt rpc_socket_getopt
#define socket_setopt rpc_socket_setopt
#define socket_send_inband(a,b,c,d,e,f,g,h,i,j) \
  INTR_CALL_N(socket_send_inband, a, IO_INTR, (a,b,c,d,e,f,g,h,i,j))
#define socket_send_outofband(a,b,c,d,e,f,g,h,i,j) \
  INTR_CALL_N(socket_send_outofband, a, IO_INTR, (a,b,c,d,e,f,g,h,i,j))
#define socket_recv_inband(a,b,c,d,e,f,g,h,i,j,k) \
  INTR_CALL_N(socket_recv_inband, a, IO_INTR, (a,b,c,d,e,f,g,h,i,j,k))
#define socket_recv_outofband(a,b,c,d,e,f,g,h,i,j,k) \
  INTR_CALL_N(socket_recv_outofband, a, IO_INTR, (a,b,c,d,e,f,g,h,i,j,k))

#define proc_sethostid rpc_proc_sethostid
#define proc_gethostid rpc_proc_gethostid
#define proc_sethostname rpc_proc_sethostname
#define proc_gethostname rpc_proc_gethostname
#define proc_getpids rpc_proc_getpids
#define proc_reauthenticate rpc_proc_reauthenticate
#define proc_register rpc_proc_register
#define proc_kill rpc_proc_kill
#define proc_ctty_kill rpc_proc_ctty_kill
#define proc_set_ctty rpc_proc_set_ctty
#define proc_wait(a,b,c,d,e,f) \
  INTR_CALL_N(proc_wait, a, WAIT_INTR,(a,b,c,d,e,f))
#define proc_waitintr rpc_proc_waitintr
#define proc_dostop rpc_proc_dostop
#define proc_markstop rpc_proc_markstop
#define proc_cont rpc_proc_cont
#define proc_exit rpc_proc_exit
#define proc_mark_exec rpc_proc_mark_exec
#define proc_mark_traced rpc_proc_mark_traced
#define proc_mark_nostopchild rpc_proc_mark_nostopchild
#define proc_setsid rpc_proc_setsid
#define proc_setpgrp rpc_proc_setpgrp
#define proc_getpgrp rpc_proc_getpgrp
#define proc_version rpc_proc_version
#define proc_getrusage rpc_proc_getrusage
#define proc_setpriority rpc_proc_setpriority
#define proc_getpriority rpc_proc_getpriority
#define proc_pid2task rpc_proc_pid2task
#define proc_task2pid rpc_proc_task2pid
#define proc_getallprocs rpc_proc_getallprocs
#define proc_getprocinfo rpc_proc_getprocinfo
#define proc_getprocargs rpc_proc_getprocargs
#define proc_setlogin rpc_proc_setlogin
#define proc_getlogin rpc_proc_getlogin
