OpenCores
URL https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [gnu-src/] [gdb-6.8/] [sim/] [cris/] [traps.c] - Diff between revs 24 and 157

Only display areas with differences | Details | Blame | View Log

Rev 24 Rev 157
/* CRIS exception, interrupt, and trap (EIT) support
/* CRIS exception, interrupt, and trap (EIT) support
   Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
   Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
   Contributed by Axis Communications.
   Contributed by Axis Communications.
 
 
This file is part of the GNU simulators.
This file is part of the GNU simulators.
 
 
This program is free software; you can redistribute it and/or modify
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
(at your option) any later version.
 
 
This program is distributed in the hope that it will be useful,
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
GNU General Public License for more details.
 
 
You should have received a copy of the GNU General Public License
You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 
#include "sim-main.h"
#include "sim-main.h"
#include "sim-options.h"
#include "sim-options.h"
#include "bfd.h"
#include "bfd.h"
/* FIXME: get rid of targ-vals.h usage everywhere else.  */
/* FIXME: get rid of targ-vals.h usage everywhere else.  */
 
 
#include <stdarg.h>
#include <stdarg.h>
#ifdef HAVE_ERRNO_H
#ifdef HAVE_ERRNO_H
#include <errno.h>
#include <errno.h>
#endif
#endif
#ifdef HAVE_UNISTD_H
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#include <unistd.h>
#endif
#endif
#ifdef HAVE_FCNTL_H
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#include <fcntl.h>
#endif
#endif
#ifdef HAVE_SYS_PARAM_H
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#include <sys/param.h>
#endif
#endif
#ifdef HAVE_SYS_STAT_H
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#include <sys/stat.h>
#endif
#endif
/* For PATH_MAX, originally. */
/* For PATH_MAX, originally. */
#ifdef HAVE_LIMITS_H
#ifdef HAVE_LIMITS_H
#include <limits.h>
#include <limits.h>
#endif
#endif
 
 
/* From ld/sysdep.h.  */
/* From ld/sysdep.h.  */
#ifdef PATH_MAX
#ifdef PATH_MAX
# define SIM_PATHMAX PATH_MAX
# define SIM_PATHMAX PATH_MAX
#else
#else
# ifdef MAXPATHLEN
# ifdef MAXPATHLEN
#  define SIM_PATHMAX MAXPATHLEN
#  define SIM_PATHMAX MAXPATHLEN
# else
# else
#  define SIM_PATHMAX 1024
#  define SIM_PATHMAX 1024
# endif
# endif
#endif
#endif
 
 
/* The verbatim values are from asm-cris/unistd.h.  */
/* The verbatim values are from asm-cris/unistd.h.  */
 
 
#define TARGET_SYS_exit 1
#define TARGET_SYS_exit 1
#define TARGET_SYS_read 3
#define TARGET_SYS_read 3
#define TARGET_SYS_write 4
#define TARGET_SYS_write 4
#define TARGET_SYS_open 5
#define TARGET_SYS_open 5
#define TARGET_SYS_close 6
#define TARGET_SYS_close 6
#define TARGET_SYS_unlink 10
#define TARGET_SYS_unlink 10
#define TARGET_SYS_time 13
#define TARGET_SYS_time 13
#define TARGET_SYS_lseek 19
#define TARGET_SYS_lseek 19
#define TARGET_SYS_getpid 20
#define TARGET_SYS_getpid 20
#define TARGET_SYS_kill 37
#define TARGET_SYS_kill 37
#define TARGET_SYS_rename 38
#define TARGET_SYS_rename 38
#define TARGET_SYS_pipe 42
#define TARGET_SYS_pipe 42
#define TARGET_SYS_brk 45
#define TARGET_SYS_brk 45
#define TARGET_SYS_ioctl 54
#define TARGET_SYS_ioctl 54
#define TARGET_SYS_fcntl 55
#define TARGET_SYS_fcntl 55
#define TARGET_SYS_getppid 64
#define TARGET_SYS_getppid 64
#define TARGET_SYS_setrlimit 75
#define TARGET_SYS_setrlimit 75
#define TARGET_SYS_gettimeofday  78
#define TARGET_SYS_gettimeofday  78
#define TARGET_SYS_readlink 85
#define TARGET_SYS_readlink 85
#define TARGET_SYS_munmap 91
#define TARGET_SYS_munmap 91
#define TARGET_SYS_truncate 92
#define TARGET_SYS_truncate 92
#define TARGET_SYS_ftruncate 93
#define TARGET_SYS_ftruncate 93
#define TARGET_SYS_socketcall 102
#define TARGET_SYS_socketcall 102
#define TARGET_SYS_stat 106
#define TARGET_SYS_stat 106
#define TARGET_SYS_fstat 108
#define TARGET_SYS_fstat 108
#define TARGET_SYS_wait4 114
#define TARGET_SYS_wait4 114
#define TARGET_SYS_sigreturn 119
#define TARGET_SYS_sigreturn 119
#define TARGET_SYS_clone 120
#define TARGET_SYS_clone 120
#define TARGET_SYS_uname 122
#define TARGET_SYS_uname 122
#define TARGET_SYS_mprotect 125
#define TARGET_SYS_mprotect 125
#define TARGET_SYS_llseek 140
#define TARGET_SYS_llseek 140
#define TARGET_SYS__sysctl 149
#define TARGET_SYS__sysctl 149
#define TARGET_SYS_sched_setparam 154
#define TARGET_SYS_sched_setparam 154
#define TARGET_SYS_sched_getparam 155
#define TARGET_SYS_sched_getparam 155
#define TARGET_SYS_sched_setscheduler 156
#define TARGET_SYS_sched_setscheduler 156
#define TARGET_SYS_sched_getscheduler 157
#define TARGET_SYS_sched_getscheduler 157
#define TARGET_SYS_sched_yield 158
#define TARGET_SYS_sched_yield 158
#define TARGET_SYS_sched_get_priority_max 159
#define TARGET_SYS_sched_get_priority_max 159
#define TARGET_SYS_sched_get_priority_min 160
#define TARGET_SYS_sched_get_priority_min 160
#define TARGET_SYS_mremap 163
#define TARGET_SYS_mremap 163
#define TARGET_SYS_poll 168
#define TARGET_SYS_poll 168
#define TARGET_SYS_rt_sigaction 174
#define TARGET_SYS_rt_sigaction 174
#define TARGET_SYS_rt_sigprocmask 175
#define TARGET_SYS_rt_sigprocmask 175
#define TARGET_SYS_rt_sigsuspend 179
#define TARGET_SYS_rt_sigsuspend 179
#define TARGET_SYS_getcwd 183
#define TARGET_SYS_getcwd 183
#define TARGET_SYS_ugetrlimit 191
#define TARGET_SYS_ugetrlimit 191
#define TARGET_SYS_mmap2 192
#define TARGET_SYS_mmap2 192
#define TARGET_SYS_stat64 195
#define TARGET_SYS_stat64 195
#define TARGET_SYS_lstat64 196
#define TARGET_SYS_lstat64 196
#define TARGET_SYS_fstat64 197
#define TARGET_SYS_fstat64 197
#define TARGET_SYS_geteuid32 201
#define TARGET_SYS_geteuid32 201
#define TARGET_SYS_getuid32 199
#define TARGET_SYS_getuid32 199
#define TARGET_SYS_getegid32 202
#define TARGET_SYS_getegid32 202
#define TARGET_SYS_getgid32 200
#define TARGET_SYS_getgid32 200
#define TARGET_SYS_fcntl64 221
#define TARGET_SYS_fcntl64 221
 
 
#define TARGET_PROT_READ        0x1
#define TARGET_PROT_READ        0x1
#define TARGET_PROT_WRITE       0x2
#define TARGET_PROT_WRITE       0x2
#define TARGET_PROT_EXEC        0x4
#define TARGET_PROT_EXEC        0x4
#define TARGET_PROT_NONE        0x0
#define TARGET_PROT_NONE        0x0
 
 
#define TARGET_MAP_SHARED       0x01
#define TARGET_MAP_SHARED       0x01
#define TARGET_MAP_PRIVATE      0x02
#define TARGET_MAP_PRIVATE      0x02
#define TARGET_MAP_TYPE         0x0f
#define TARGET_MAP_TYPE         0x0f
#define TARGET_MAP_FIXED        0x10
#define TARGET_MAP_FIXED        0x10
#define TARGET_MAP_ANONYMOUS    0x20
#define TARGET_MAP_ANONYMOUS    0x20
 
 
#define TARGET_CTL_KERN         1
#define TARGET_CTL_KERN         1
#define TARGET_CTL_VM           2
#define TARGET_CTL_VM           2
#define TARGET_CTL_NET          3
#define TARGET_CTL_NET          3
#define TARGET_CTL_PROC         4
#define TARGET_CTL_PROC         4
#define TARGET_CTL_FS           5
#define TARGET_CTL_FS           5
#define TARGET_CTL_DEBUG        6
#define TARGET_CTL_DEBUG        6
#define TARGET_CTL_DEV          7
#define TARGET_CTL_DEV          7
#define TARGET_CTL_BUS          8
#define TARGET_CTL_BUS          8
#define TARGET_CTL_ABI          9
#define TARGET_CTL_ABI          9
 
 
#define TARGET_CTL_KERN_VERSION 4
#define TARGET_CTL_KERN_VERSION 4
 
 
/* linux/mman.h */
/* linux/mman.h */
#define TARGET_MREMAP_MAYMOVE  1
#define TARGET_MREMAP_MAYMOVE  1
#define TARGET_MREMAP_FIXED    2
#define TARGET_MREMAP_FIXED    2
 
 
#define TARGET_TCGETS 0x5401
#define TARGET_TCGETS 0x5401
 
 
#define TARGET_UTSNAME "#38 Sun Apr 1 00:00:00 MET 2001"
#define TARGET_UTSNAME "#38 Sun Apr 1 00:00:00 MET 2001"
 
 
/* Seconds since the above date + 10 minutes.  */
/* Seconds since the above date + 10 minutes.  */
#define TARGET_EPOCH 986080200
#define TARGET_EPOCH 986080200
 
 
/* Milliseconds since start of run.  We use the number of syscalls to
/* Milliseconds since start of run.  We use the number of syscalls to
   avoid introducing noise in the execution time.  */
   avoid introducing noise in the execution time.  */
#define TARGET_TIME_MS(cpu) ((cpu)->syscalls)
#define TARGET_TIME_MS(cpu) ((cpu)->syscalls)
 
 
/* Seconds as in time(2).  */
/* Seconds as in time(2).  */
#define TARGET_TIME(cpu) (TARGET_EPOCH + TARGET_TIME_MS (cpu) / 1000)
#define TARGET_TIME(cpu) (TARGET_EPOCH + TARGET_TIME_MS (cpu) / 1000)
 
 
#define TARGET_SCHED_OTHER 0
#define TARGET_SCHED_OTHER 0
 
 
#define TARGET_RLIMIT_STACK 3
#define TARGET_RLIMIT_STACK 3
#define TARGET_RLIMIT_NOFILE 7
#define TARGET_RLIMIT_NOFILE 7
 
 
#define SIM_TARGET_MAX_THREADS 64
#define SIM_TARGET_MAX_THREADS 64
#define SIM_MAX_ALLOC_CHUNK (512*1024*1024)
#define SIM_MAX_ALLOC_CHUNK (512*1024*1024)
 
 
/* From linux/sched.h.  */
/* From linux/sched.h.  */
#define TARGET_CSIGNAL 0x000000ff
#define TARGET_CSIGNAL 0x000000ff
#define TARGET_CLONE_VM 0x00000100
#define TARGET_CLONE_VM 0x00000100
#define TARGET_CLONE_FS 0x00000200
#define TARGET_CLONE_FS 0x00000200
#define TARGET_CLONE_FILES 0x00000400
#define TARGET_CLONE_FILES 0x00000400
#define TARGET_CLONE_SIGHAND 0x00000800
#define TARGET_CLONE_SIGHAND 0x00000800
#define TARGET_CLONE_PID 0x00001000
#define TARGET_CLONE_PID 0x00001000
#define TARGET_CLONE_PTRACE 0x00002000
#define TARGET_CLONE_PTRACE 0x00002000
#define TARGET_CLONE_VFORK 0x00004000
#define TARGET_CLONE_VFORK 0x00004000
#define TARGET_CLONE_PARENT 0x00008000
#define TARGET_CLONE_PARENT 0x00008000
#define TARGET_CLONE_THREAD 0x00010000
#define TARGET_CLONE_THREAD 0x00010000
#define TARGET_CLONE_SIGNAL (TARGET_CLONE_SIGHAND | TARGET_CLONE_THREAD)
#define TARGET_CLONE_SIGNAL (TARGET_CLONE_SIGHAND | TARGET_CLONE_THREAD)
 
 
/* From asm-cris/poll.h.  */
/* From asm-cris/poll.h.  */
#define TARGET_POLLIN 1
#define TARGET_POLLIN 1
 
 
/* From asm-cris/signal.h.  */
/* From asm-cris/signal.h.  */
#define TARGET_SIG_BLOCK 0
#define TARGET_SIG_BLOCK 0
#define TARGET_SIG_UNBLOCK 1
#define TARGET_SIG_UNBLOCK 1
#define TARGET_SIG_SETMASK 2
#define TARGET_SIG_SETMASK 2
 
 
#define TARGET_SIG_DFL 0
#define TARGET_SIG_DFL 0
#define TARGET_SIG_IGN 1
#define TARGET_SIG_IGN 1
#define TARGET_SIG_ERR ((USI)-1)
#define TARGET_SIG_ERR ((USI)-1)
 
 
#define TARGET_SIGHUP 1
#define TARGET_SIGHUP 1
#define TARGET_SIGINT 2
#define TARGET_SIGINT 2
#define TARGET_SIGQUIT 3
#define TARGET_SIGQUIT 3
#define TARGET_SIGILL 4
#define TARGET_SIGILL 4
#define TARGET_SIGTRAP 5
#define TARGET_SIGTRAP 5
#define TARGET_SIGABRT 6
#define TARGET_SIGABRT 6
#define TARGET_SIGIOT 6
#define TARGET_SIGIOT 6
#define TARGET_SIGBUS 7
#define TARGET_SIGBUS 7
#define TARGET_SIGFPE 8
#define TARGET_SIGFPE 8
#define TARGET_SIGKILL 9
#define TARGET_SIGKILL 9
#define TARGET_SIGUSR1 10
#define TARGET_SIGUSR1 10
#define TARGET_SIGSEGV 11
#define TARGET_SIGSEGV 11
#define TARGET_SIGUSR2 12
#define TARGET_SIGUSR2 12
#define TARGET_SIGPIPE 13
#define TARGET_SIGPIPE 13
#define TARGET_SIGALRM 14
#define TARGET_SIGALRM 14
#define TARGET_SIGTERM 15
#define TARGET_SIGTERM 15
#define TARGET_SIGSTKFLT 16
#define TARGET_SIGSTKFLT 16
#define TARGET_SIGCHLD 17
#define TARGET_SIGCHLD 17
#define TARGET_SIGCONT 18
#define TARGET_SIGCONT 18
#define TARGET_SIGSTOP 19
#define TARGET_SIGSTOP 19
#define TARGET_SIGTSTP 20
#define TARGET_SIGTSTP 20
#define TARGET_SIGTTIN 21
#define TARGET_SIGTTIN 21
#define TARGET_SIGTTOU 22
#define TARGET_SIGTTOU 22
#define TARGET_SIGURG 23
#define TARGET_SIGURG 23
#define TARGET_SIGXCPU 24
#define TARGET_SIGXCPU 24
#define TARGET_SIGXFSZ 25
#define TARGET_SIGXFSZ 25
#define TARGET_SIGVTALRM 26
#define TARGET_SIGVTALRM 26
#define TARGET_SIGPROF 27
#define TARGET_SIGPROF 27
#define TARGET_SIGWINCH 28
#define TARGET_SIGWINCH 28
#define TARGET_SIGIO 29
#define TARGET_SIGIO 29
#define TARGET_SIGPOLL SIGIO
#define TARGET_SIGPOLL SIGIO
/* Actually commented out in the kernel header.  */
/* Actually commented out in the kernel header.  */
#define TARGET_SIGLOST 29
#define TARGET_SIGLOST 29
#define TARGET_SIGPWR 30
#define TARGET_SIGPWR 30
#define TARGET_SIGSYS 31
#define TARGET_SIGSYS 31
 
 
/* From include/asm-cris/signal.h.  */
/* From include/asm-cris/signal.h.  */
#define TARGET_SA_NOCLDSTOP 0x00000001
#define TARGET_SA_NOCLDSTOP 0x00000001
#define TARGET_SA_NOCLDWAIT 0x00000002 /* not supported yet */
#define TARGET_SA_NOCLDWAIT 0x00000002 /* not supported yet */
#define TARGET_SA_SIGINFO 0x00000004
#define TARGET_SA_SIGINFO 0x00000004
#define TARGET_SA_ONSTACK 0x08000000
#define TARGET_SA_ONSTACK 0x08000000
#define TARGET_SA_RESTART 0x10000000
#define TARGET_SA_RESTART 0x10000000
#define TARGET_SA_NODEFER 0x40000000
#define TARGET_SA_NODEFER 0x40000000
#define TARGET_SA_RESETHAND 0x80000000
#define TARGET_SA_RESETHAND 0x80000000
#define TARGET_SA_INTERRUPT 0x20000000 /* dummy -- ignored */
#define TARGET_SA_INTERRUPT 0x20000000 /* dummy -- ignored */
#define TARGET_SA_RESTORER 0x04000000
#define TARGET_SA_RESTORER 0x04000000
 
 
/* From linux/wait.h.  */
/* From linux/wait.h.  */
#define TARGET_WNOHANG 1
#define TARGET_WNOHANG 1
#define TARGET_WUNTRACED 2
#define TARGET_WUNTRACED 2
#define TARGET___WNOTHREAD 0x20000000
#define TARGET___WNOTHREAD 0x20000000
#define TARGET___WALL 0x40000000
#define TARGET___WALL 0x40000000
#define TARGET___WCLONE 0x80000000
#define TARGET___WCLONE 0x80000000
 
 
/* From linux/limits.h. */
/* From linux/limits.h. */
#define TARGET_PIPE_BUF 4096
#define TARGET_PIPE_BUF 4096
 
 
static const char stat_map[] =
static const char stat_map[] =
"st_dev,2:space,10:space,4:st_mode,4:st_nlink,4:st_uid,4"
"st_dev,2:space,10:space,4:st_mode,4:st_nlink,4:st_uid,4"
":st_gid,4:st_rdev,2:space,10:st_size,8:st_blksize,4:st_blocks,4"
":st_gid,4:st_rdev,2:space,10:st_size,8:st_blksize,4:st_blocks,4"
":space,4:st_atime,4:space,4:st_mtime,4:space,4:st_ctime,4:space,4"
":space,4:st_atime,4:space,4:st_mtime,4:space,4:st_ctime,4:space,4"
":st_ino,8";
":st_ino,8";
 
 
static const CB_TARGET_DEFS_MAP syscall_map[] =
static const CB_TARGET_DEFS_MAP syscall_map[] =
{
{
  { CB_SYS_open, TARGET_SYS_open },
  { CB_SYS_open, TARGET_SYS_open },
  { CB_SYS_close, TARGET_SYS_close },
  { CB_SYS_close, TARGET_SYS_close },
  { CB_SYS_read, TARGET_SYS_read },
  { CB_SYS_read, TARGET_SYS_read },
  { CB_SYS_write, TARGET_SYS_write },
  { CB_SYS_write, TARGET_SYS_write },
  { CB_SYS_lseek, TARGET_SYS_lseek },
  { CB_SYS_lseek, TARGET_SYS_lseek },
  { CB_SYS_unlink, TARGET_SYS_unlink },
  { CB_SYS_unlink, TARGET_SYS_unlink },
  { CB_SYS_getpid, TARGET_SYS_getpid },
  { CB_SYS_getpid, TARGET_SYS_getpid },
  { CB_SYS_fstat, TARGET_SYS_fstat64 },
  { CB_SYS_fstat, TARGET_SYS_fstat64 },
  { CB_SYS_lstat, TARGET_SYS_lstat64 },
  { CB_SYS_lstat, TARGET_SYS_lstat64 },
  { CB_SYS_stat, TARGET_SYS_stat64 },
  { CB_SYS_stat, TARGET_SYS_stat64 },
  { CB_SYS_pipe, TARGET_SYS_pipe },
  { CB_SYS_pipe, TARGET_SYS_pipe },
  { CB_SYS_rename, TARGET_SYS_rename },
  { CB_SYS_rename, TARGET_SYS_rename },
  { CB_SYS_truncate, TARGET_SYS_truncate },
  { CB_SYS_truncate, TARGET_SYS_truncate },
  { CB_SYS_ftruncate, TARGET_SYS_ftruncate },
  { CB_SYS_ftruncate, TARGET_SYS_ftruncate },
  { 0, -1 }
  { 0, -1 }
};
};
 
 
/* An older, 32-bit-only stat mapping.  */
/* An older, 32-bit-only stat mapping.  */
static const char stat32_map[] =
static const char stat32_map[] =
"st_dev,2:space,2:st_ino,4:st_mode,2:st_nlink,2:st_uid,2"
"st_dev,2:space,2:st_ino,4:st_mode,2:st_nlink,2:st_uid,2"
":st_gid,2:st_rdev,2:space,2:st_size,4:st_blksize,4:st_blocks,4"
":st_gid,2:st_rdev,2:space,2:st_size,4:st_blksize,4:st_blocks,4"
":st_atime,4:space,4:st_mtime,4:space,4:st_ctime,4:space,12";
":st_atime,4:space,4:st_mtime,4:space,4:st_ctime,4:space,12";
 
 
/* Map for calls using the 32-bit struct stat.  Primarily used by the
/* Map for calls using the 32-bit struct stat.  Primarily used by the
   newlib Linux mapping.  */
   newlib Linux mapping.  */
static const CB_TARGET_DEFS_MAP syscall_stat32_map[] =
static const CB_TARGET_DEFS_MAP syscall_stat32_map[] =
{
{
  { CB_SYS_fstat, TARGET_SYS_fstat },
  { CB_SYS_fstat, TARGET_SYS_fstat },
  { CB_SYS_stat, TARGET_SYS_stat },
  { CB_SYS_stat, TARGET_SYS_stat },
  { 0, -1 }
  { 0, -1 }
};
};
 
 
/* Giving the true value for the running sim process will lead to
/* Giving the true value for the running sim process will lead to
   non-time-invariant behavior.  */
   non-time-invariant behavior.  */
#define TARGET_PID 42
#define TARGET_PID 42
 
 
/* Unfortunately, we don't get this from cris.cpu at the moment, and if
/* Unfortunately, we don't get this from cris.cpu at the moment, and if
   we did, we'd still don't get a register number with the "16" offset.  */
   we did, we'd still don't get a register number with the "16" offset.  */
#define TARGET_SRP_REGNUM (16+11)
#define TARGET_SRP_REGNUM (16+11)
 
 
/* Extracted by applying
/* Extracted by applying
   awk '/^#define/ { printf "#ifdef %s\n  { %s, %s },\n#endif\n", $2, $2, $3;}'
   awk '/^#define/ { printf "#ifdef %s\n  { %s, %s },\n#endif\n", $2, $2, $3;}'
   on .../include/asm/errno.h in a GNU/Linux/CRIS installation and
   on .../include/asm/errno.h in a GNU/Linux/CRIS installation and
   adjusting the synonyms.  */
   adjusting the synonyms.  */
 
 
static const CB_TARGET_DEFS_MAP errno_map[] =
static const CB_TARGET_DEFS_MAP errno_map[] =
{
{
#ifdef EPERM
#ifdef EPERM
  { EPERM, 1 },
  { EPERM, 1 },
#endif
#endif
#ifdef ENOENT
#ifdef ENOENT
  { ENOENT, 2 },
  { ENOENT, 2 },
#endif
#endif
#ifdef ESRCH
#ifdef ESRCH
  { ESRCH, 3 },
  { ESRCH, 3 },
#endif
#endif
#ifdef EINTR
#ifdef EINTR
  { EINTR, 4 },
  { EINTR, 4 },
#endif
#endif
#ifdef EIO
#ifdef EIO
  { EIO, 5 },
  { EIO, 5 },
#endif
#endif
#ifdef ENXIO
#ifdef ENXIO
  { ENXIO, 6 },
  { ENXIO, 6 },
#endif
#endif
#ifdef E2BIG
#ifdef E2BIG
  { E2BIG, 7 },
  { E2BIG, 7 },
#endif
#endif
#ifdef ENOEXEC
#ifdef ENOEXEC
  { ENOEXEC, 8 },
  { ENOEXEC, 8 },
#endif
#endif
#ifdef EBADF
#ifdef EBADF
  { EBADF, 9 },
  { EBADF, 9 },
#endif
#endif
#ifdef ECHILD
#ifdef ECHILD
  { ECHILD, 10 },
  { ECHILD, 10 },
#endif
#endif
#ifdef EAGAIN
#ifdef EAGAIN
  { EAGAIN, 11 },
  { EAGAIN, 11 },
#endif
#endif
#ifdef ENOMEM
#ifdef ENOMEM
  { ENOMEM, 12 },
  { ENOMEM, 12 },
#endif
#endif
#ifdef EACCES
#ifdef EACCES
  { EACCES, 13 },
  { EACCES, 13 },
#endif
#endif
#ifdef EFAULT
#ifdef EFAULT
  { EFAULT, 14 },
  { EFAULT, 14 },
#endif
#endif
#ifdef ENOTBLK
#ifdef ENOTBLK
  { ENOTBLK, 15 },
  { ENOTBLK, 15 },
#endif
#endif
#ifdef EBUSY
#ifdef EBUSY
  { EBUSY, 16 },
  { EBUSY, 16 },
#endif
#endif
#ifdef EEXIST
#ifdef EEXIST
  { EEXIST, 17 },
  { EEXIST, 17 },
#endif
#endif
#ifdef EXDEV
#ifdef EXDEV
  { EXDEV, 18 },
  { EXDEV, 18 },
#endif
#endif
#ifdef ENODEV
#ifdef ENODEV
  { ENODEV, 19 },
  { ENODEV, 19 },
#endif
#endif
#ifdef ENOTDIR
#ifdef ENOTDIR
  { ENOTDIR, 20 },
  { ENOTDIR, 20 },
#endif
#endif
#ifdef EISDIR
#ifdef EISDIR
  { EISDIR, 21 },
  { EISDIR, 21 },
#endif
#endif
#ifdef EINVAL
#ifdef EINVAL
  { EINVAL, 22 },
  { EINVAL, 22 },
#endif
#endif
#ifdef ENFILE
#ifdef ENFILE
  { ENFILE, 23 },
  { ENFILE, 23 },
#endif
#endif
#ifdef EMFILE
#ifdef EMFILE
  { EMFILE, 24 },
  { EMFILE, 24 },
#endif
#endif
#ifdef ENOTTY
#ifdef ENOTTY
  { ENOTTY, 25 },
  { ENOTTY, 25 },
#endif
#endif
#ifdef ETXTBSY
#ifdef ETXTBSY
  { ETXTBSY, 26 },
  { ETXTBSY, 26 },
#endif
#endif
#ifdef EFBIG
#ifdef EFBIG
  { EFBIG, 27 },
  { EFBIG, 27 },
#endif
#endif
#ifdef ENOSPC
#ifdef ENOSPC
  { ENOSPC, 28 },
  { ENOSPC, 28 },
#endif
#endif
#ifdef ESPIPE
#ifdef ESPIPE
  { ESPIPE, 29 },
  { ESPIPE, 29 },
#endif
#endif
#ifdef EROFS
#ifdef EROFS
  { EROFS, 30 },
  { EROFS, 30 },
#endif
#endif
#ifdef EMLINK
#ifdef EMLINK
  { EMLINK, 31 },
  { EMLINK, 31 },
#endif
#endif
#ifdef EPIPE
#ifdef EPIPE
  { EPIPE, 32 },
  { EPIPE, 32 },
#endif
#endif
#ifdef EDOM
#ifdef EDOM
  { EDOM, 33 },
  { EDOM, 33 },
#endif
#endif
#ifdef ERANGE
#ifdef ERANGE
  { ERANGE, 34 },
  { ERANGE, 34 },
#endif
#endif
#ifdef EDEADLK
#ifdef EDEADLK
  { EDEADLK, 35 },
  { EDEADLK, 35 },
#endif
#endif
#ifdef ENAMETOOLONG
#ifdef ENAMETOOLONG
  { ENAMETOOLONG, 36 },
  { ENAMETOOLONG, 36 },
#endif
#endif
#ifdef ENOLCK
#ifdef ENOLCK
  { ENOLCK, 37 },
  { ENOLCK, 37 },
#endif
#endif
#ifdef ENOSYS
#ifdef ENOSYS
  { ENOSYS, 38 },
  { ENOSYS, 38 },
#endif
#endif
#ifdef ENOTEMPTY
#ifdef ENOTEMPTY
  { ENOTEMPTY, 39 },
  { ENOTEMPTY, 39 },
#endif
#endif
#ifdef ELOOP
#ifdef ELOOP
  { ELOOP, 40 },
  { ELOOP, 40 },
#endif
#endif
#ifdef EWOULDBLOCK
#ifdef EWOULDBLOCK
  { EWOULDBLOCK, 11 },
  { EWOULDBLOCK, 11 },
#endif
#endif
#ifdef ENOMSG
#ifdef ENOMSG
  { ENOMSG, 42 },
  { ENOMSG, 42 },
#endif
#endif
#ifdef EIDRM
#ifdef EIDRM
  { EIDRM, 43 },
  { EIDRM, 43 },
#endif
#endif
#ifdef ECHRNG
#ifdef ECHRNG
  { ECHRNG, 44 },
  { ECHRNG, 44 },
#endif
#endif
#ifdef EL2NSYNC
#ifdef EL2NSYNC
  { EL2NSYNC, 45 },
  { EL2NSYNC, 45 },
#endif
#endif
#ifdef EL3HLT
#ifdef EL3HLT
  { EL3HLT, 46 },
  { EL3HLT, 46 },
#endif
#endif
#ifdef EL3RST
#ifdef EL3RST
  { EL3RST, 47 },
  { EL3RST, 47 },
#endif
#endif
#ifdef ELNRNG
#ifdef ELNRNG
  { ELNRNG, 48 },
  { ELNRNG, 48 },
#endif
#endif
#ifdef EUNATCH
#ifdef EUNATCH
  { EUNATCH, 49 },
  { EUNATCH, 49 },
#endif
#endif
#ifdef ENOCSI
#ifdef ENOCSI
  { ENOCSI, 50 },
  { ENOCSI, 50 },
#endif
#endif
#ifdef EL2HLT
#ifdef EL2HLT
  { EL2HLT, 51 },
  { EL2HLT, 51 },
#endif
#endif
#ifdef EBADE
#ifdef EBADE
  { EBADE, 52 },
  { EBADE, 52 },
#endif
#endif
#ifdef EBADR
#ifdef EBADR
  { EBADR, 53 },
  { EBADR, 53 },
#endif
#endif
#ifdef EXFULL
#ifdef EXFULL
  { EXFULL, 54 },
  { EXFULL, 54 },
#endif
#endif
#ifdef ENOANO
#ifdef ENOANO
  { ENOANO, 55 },
  { ENOANO, 55 },
#endif
#endif
#ifdef EBADRQC
#ifdef EBADRQC
  { EBADRQC, 56 },
  { EBADRQC, 56 },
#endif
#endif
#ifdef EBADSLT
#ifdef EBADSLT
  { EBADSLT, 57 },
  { EBADSLT, 57 },
#endif
#endif
#ifdef EDEADLOCK
#ifdef EDEADLOCK
  { EDEADLOCK, 35 },
  { EDEADLOCK, 35 },
#endif
#endif
#ifdef EBFONT
#ifdef EBFONT
  { EBFONT, 59 },
  { EBFONT, 59 },
#endif
#endif
#ifdef ENOSTR
#ifdef ENOSTR
  { ENOSTR, 60 },
  { ENOSTR, 60 },
#endif
#endif
#ifdef ENODATA
#ifdef ENODATA
  { ENODATA, 61 },
  { ENODATA, 61 },
#endif
#endif
#ifdef ETIME
#ifdef ETIME
  { ETIME, 62 },
  { ETIME, 62 },
#endif
#endif
#ifdef ENOSR
#ifdef ENOSR
  { ENOSR, 63 },
  { ENOSR, 63 },
#endif
#endif
#ifdef ENONET
#ifdef ENONET
  { ENONET, 64 },
  { ENONET, 64 },
#endif
#endif
#ifdef ENOPKG
#ifdef ENOPKG
  { ENOPKG, 65 },
  { ENOPKG, 65 },
#endif
#endif
#ifdef EREMOTE
#ifdef EREMOTE
  { EREMOTE, 66 },
  { EREMOTE, 66 },
#endif
#endif
#ifdef ENOLINK
#ifdef ENOLINK
  { ENOLINK, 67 },
  { ENOLINK, 67 },
#endif
#endif
#ifdef EADV
#ifdef EADV
  { EADV, 68 },
  { EADV, 68 },
#endif
#endif
#ifdef ESRMNT
#ifdef ESRMNT
  { ESRMNT, 69 },
  { ESRMNT, 69 },
#endif
#endif
#ifdef ECOMM
#ifdef ECOMM
  { ECOMM, 70 },
  { ECOMM, 70 },
#endif
#endif
#ifdef EPROTO
#ifdef EPROTO
  { EPROTO, 71 },
  { EPROTO, 71 },
#endif
#endif
#ifdef EMULTIHOP
#ifdef EMULTIHOP
  { EMULTIHOP, 72 },
  { EMULTIHOP, 72 },
#endif
#endif
#ifdef EDOTDOT
#ifdef EDOTDOT
  { EDOTDOT, 73 },
  { EDOTDOT, 73 },
#endif
#endif
#ifdef EBADMSG
#ifdef EBADMSG
  { EBADMSG, 74 },
  { EBADMSG, 74 },
#endif
#endif
#ifdef EOVERFLOW
#ifdef EOVERFLOW
  { EOVERFLOW, 75 },
  { EOVERFLOW, 75 },
#endif
#endif
#ifdef ENOTUNIQ
#ifdef ENOTUNIQ
  { ENOTUNIQ, 76 },
  { ENOTUNIQ, 76 },
#endif
#endif
#ifdef EBADFD
#ifdef EBADFD
  { EBADFD, 77 },
  { EBADFD, 77 },
#endif
#endif
#ifdef EREMCHG
#ifdef EREMCHG
  { EREMCHG, 78 },
  { EREMCHG, 78 },
#endif
#endif
#ifdef ELIBACC
#ifdef ELIBACC
  { ELIBACC, 79 },
  { ELIBACC, 79 },
#endif
#endif
#ifdef ELIBBAD
#ifdef ELIBBAD
  { ELIBBAD, 80 },
  { ELIBBAD, 80 },
#endif
#endif
#ifdef ELIBSCN
#ifdef ELIBSCN
  { ELIBSCN, 81 },
  { ELIBSCN, 81 },
#endif
#endif
#ifdef ELIBMAX
#ifdef ELIBMAX
  { ELIBMAX, 82 },
  { ELIBMAX, 82 },
#endif
#endif
#ifdef ELIBEXEC
#ifdef ELIBEXEC
  { ELIBEXEC, 83 },
  { ELIBEXEC, 83 },
#endif
#endif
#ifdef EILSEQ
#ifdef EILSEQ
  { EILSEQ, 84 },
  { EILSEQ, 84 },
#endif
#endif
#ifdef ERESTART
#ifdef ERESTART
  { ERESTART, 85 },
  { ERESTART, 85 },
#endif
#endif
#ifdef ESTRPIPE
#ifdef ESTRPIPE
  { ESTRPIPE, 86 },
  { ESTRPIPE, 86 },
#endif
#endif
#ifdef EUSERS
#ifdef EUSERS
  { EUSERS, 87 },
  { EUSERS, 87 },
#endif
#endif
#ifdef ENOTSOCK
#ifdef ENOTSOCK
  { ENOTSOCK, 88 },
  { ENOTSOCK, 88 },
#endif
#endif
#ifdef EDESTADDRREQ
#ifdef EDESTADDRREQ
  { EDESTADDRREQ, 89 },
  { EDESTADDRREQ, 89 },
#endif
#endif
#ifdef EMSGSIZE
#ifdef EMSGSIZE
  { EMSGSIZE, 90 },
  { EMSGSIZE, 90 },
#endif
#endif
#ifdef EPROTOTYPE
#ifdef EPROTOTYPE
  { EPROTOTYPE, 91 },
  { EPROTOTYPE, 91 },
#endif
#endif
#ifdef ENOPROTOOPT
#ifdef ENOPROTOOPT
  { ENOPROTOOPT, 92 },
  { ENOPROTOOPT, 92 },
#endif
#endif
#ifdef EPROTONOSUPPORT
#ifdef EPROTONOSUPPORT
  { EPROTONOSUPPORT, 93 },
  { EPROTONOSUPPORT, 93 },
#endif
#endif
#ifdef ESOCKTNOSUPPORT
#ifdef ESOCKTNOSUPPORT
  { ESOCKTNOSUPPORT, 94 },
  { ESOCKTNOSUPPORT, 94 },
#endif
#endif
#ifdef EOPNOTSUPP
#ifdef EOPNOTSUPP
  { EOPNOTSUPP, 95 },
  { EOPNOTSUPP, 95 },
#endif
#endif
#ifdef EPFNOSUPPORT
#ifdef EPFNOSUPPORT
  { EPFNOSUPPORT, 96 },
  { EPFNOSUPPORT, 96 },
#endif
#endif
#ifdef EAFNOSUPPORT
#ifdef EAFNOSUPPORT
  { EAFNOSUPPORT, 97 },
  { EAFNOSUPPORT, 97 },
#endif
#endif
#ifdef EADDRINUSE
#ifdef EADDRINUSE
  { EADDRINUSE, 98 },
  { EADDRINUSE, 98 },
#endif
#endif
#ifdef EADDRNOTAVAIL
#ifdef EADDRNOTAVAIL
  { EADDRNOTAVAIL, 99 },
  { EADDRNOTAVAIL, 99 },
#endif
#endif
#ifdef ENETDOWN
#ifdef ENETDOWN
  { ENETDOWN, 100 },
  { ENETDOWN, 100 },
#endif
#endif
#ifdef ENETUNREACH
#ifdef ENETUNREACH
  { ENETUNREACH, 101 },
  { ENETUNREACH, 101 },
#endif
#endif
#ifdef ENETRESET
#ifdef ENETRESET
  { ENETRESET, 102 },
  { ENETRESET, 102 },
#endif
#endif
#ifdef ECONNABORTED
#ifdef ECONNABORTED
  { ECONNABORTED, 103 },
  { ECONNABORTED, 103 },
#endif
#endif
#ifdef ECONNRESET
#ifdef ECONNRESET
  { ECONNRESET, 104 },
  { ECONNRESET, 104 },
#endif
#endif
#ifdef ENOBUFS
#ifdef ENOBUFS
  { ENOBUFS, 105 },
  { ENOBUFS, 105 },
#endif
#endif
#ifdef EISCONN
#ifdef EISCONN
  { EISCONN, 106 },
  { EISCONN, 106 },
#endif
#endif
#ifdef ENOTCONN
#ifdef ENOTCONN
  { ENOTCONN, 107 },
  { ENOTCONN, 107 },
#endif
#endif
#ifdef ESHUTDOWN
#ifdef ESHUTDOWN
  { ESHUTDOWN, 108 },
  { ESHUTDOWN, 108 },
#endif
#endif
#ifdef ETOOMANYREFS
#ifdef ETOOMANYREFS
  { ETOOMANYREFS, 109 },
  { ETOOMANYREFS, 109 },
#endif
#endif
#ifdef ETIMEDOUT
#ifdef ETIMEDOUT
  { ETIMEDOUT, 110 },
  { ETIMEDOUT, 110 },
#endif
#endif
#ifdef ECONNREFUSED
#ifdef ECONNREFUSED
  { ECONNREFUSED, 111 },
  { ECONNREFUSED, 111 },
#endif
#endif
#ifdef EHOSTDOWN
#ifdef EHOSTDOWN
  { EHOSTDOWN, 112 },
  { EHOSTDOWN, 112 },
#endif
#endif
#ifdef EHOSTUNREACH
#ifdef EHOSTUNREACH
  { EHOSTUNREACH, 113 },
  { EHOSTUNREACH, 113 },
#endif
#endif
#ifdef EALREADY
#ifdef EALREADY
  { EALREADY, 114 },
  { EALREADY, 114 },
#endif
#endif
#ifdef EINPROGRESS
#ifdef EINPROGRESS
  { EINPROGRESS, 115 },
  { EINPROGRESS, 115 },
#endif
#endif
#ifdef ESTALE
#ifdef ESTALE
  { ESTALE, 116 },
  { ESTALE, 116 },
#endif
#endif
#ifdef EUCLEAN
#ifdef EUCLEAN
  { EUCLEAN, 117 },
  { EUCLEAN, 117 },
#endif
#endif
#ifdef ENOTNAM
#ifdef ENOTNAM
  { ENOTNAM, 118 },
  { ENOTNAM, 118 },
#endif
#endif
#ifdef ENAVAIL
#ifdef ENAVAIL
  { ENAVAIL, 119 },
  { ENAVAIL, 119 },
#endif
#endif
#ifdef EISNAM
#ifdef EISNAM
  { EISNAM, 120 },
  { EISNAM, 120 },
#endif
#endif
#ifdef EREMOTEIO
#ifdef EREMOTEIO
  { EREMOTEIO, 121 },
  { EREMOTEIO, 121 },
#endif
#endif
#ifdef EDQUOT
#ifdef EDQUOT
  { EDQUOT, 122 },
  { EDQUOT, 122 },
#endif
#endif
#ifdef ENOMEDIUM
#ifdef ENOMEDIUM
  { ENOMEDIUM, 123 },
  { ENOMEDIUM, 123 },
#endif
#endif
#ifdef EMEDIUMTYPE
#ifdef EMEDIUMTYPE
  { EMEDIUMTYPE, 124 },
  { EMEDIUMTYPE, 124 },
#endif
#endif
  { 0, -1 }
  { 0, -1 }
};
};
 
 
/* Extracted by applying
/* Extracted by applying
   perl -ne 'if ($_ =~ /^#define/) { split;
   perl -ne 'if ($_ =~ /^#define/) { split;
     printf "#ifdef $_[1]\n  { %s, 0x%x },\n#endif\n",
     printf "#ifdef $_[1]\n  { %s, 0x%x },\n#endif\n",
             $_[1], $_[2] =~ /^0/ ? oct($_[2]) : $_[2];}'
             $_[1], $_[2] =~ /^0/ ? oct($_[2]) : $_[2];}'
   on pertinent parts of .../include/asm/fcntl.h in a GNU/Linux/CRIS
   on pertinent parts of .../include/asm/fcntl.h in a GNU/Linux/CRIS
   installation and removing synonyms and unnecessary items.  Don't
   installation and removing synonyms and unnecessary items.  Don't
   forget the end-marker.  */
   forget the end-marker.  */
 
 
/* These we treat specially, as they're used in the fcntl F_GETFL
/* These we treat specially, as they're used in the fcntl F_GETFL
   syscall.  For consistency, open_map is also manually edited to use
   syscall.  For consistency, open_map is also manually edited to use
   these macros.  */
   these macros.  */
#define TARGET_O_ACCMODE 0x3
#define TARGET_O_ACCMODE 0x3
#define TARGET_O_RDONLY 0x0
#define TARGET_O_RDONLY 0x0
#define TARGET_O_WRONLY 0x1
#define TARGET_O_WRONLY 0x1
 
 
static const CB_TARGET_DEFS_MAP open_map[] = {
static const CB_TARGET_DEFS_MAP open_map[] = {
#ifdef O_ACCMODE
#ifdef O_ACCMODE
  { O_ACCMODE, TARGET_O_ACCMODE },
  { O_ACCMODE, TARGET_O_ACCMODE },
#endif
#endif
#ifdef O_RDONLY
#ifdef O_RDONLY
  { O_RDONLY, TARGET_O_RDONLY },
  { O_RDONLY, TARGET_O_RDONLY },
#endif
#endif
#ifdef O_WRONLY
#ifdef O_WRONLY
  { O_WRONLY, TARGET_O_WRONLY },
  { O_WRONLY, TARGET_O_WRONLY },
#endif
#endif
#ifdef O_RDWR
#ifdef O_RDWR
  { O_RDWR, 0x2 },
  { O_RDWR, 0x2 },
#endif
#endif
#ifdef O_CREAT
#ifdef O_CREAT
  { O_CREAT, 0x40 },
  { O_CREAT, 0x40 },
#endif
#endif
#ifdef O_EXCL
#ifdef O_EXCL
  { O_EXCL, 0x80 },
  { O_EXCL, 0x80 },
#endif
#endif
#ifdef O_NOCTTY
#ifdef O_NOCTTY
  { O_NOCTTY, 0x100 },
  { O_NOCTTY, 0x100 },
#endif
#endif
#ifdef O_TRUNC
#ifdef O_TRUNC
  { O_TRUNC, 0x200 },
  { O_TRUNC, 0x200 },
#endif
#endif
#ifdef O_APPEND
#ifdef O_APPEND
  { O_APPEND, 0x400 },
  { O_APPEND, 0x400 },
#endif
#endif
#ifdef O_NONBLOCK
#ifdef O_NONBLOCK
  { O_NONBLOCK, 0x800 },
  { O_NONBLOCK, 0x800 },
#endif
#endif
#ifdef O_NDELAY
#ifdef O_NDELAY
  { O_NDELAY, 0x0 },
  { O_NDELAY, 0x0 },
#endif
#endif
#ifdef O_SYNC
#ifdef O_SYNC
  { O_SYNC, 0x1000 },
  { O_SYNC, 0x1000 },
#endif
#endif
#ifdef FASYNC
#ifdef FASYNC
  { FASYNC, 0x2000 },
  { FASYNC, 0x2000 },
#endif
#endif
#ifdef O_DIRECT
#ifdef O_DIRECT
  { O_DIRECT, 0x4000 },
  { O_DIRECT, 0x4000 },
#endif
#endif
#ifdef O_LARGEFILE
#ifdef O_LARGEFILE
  { O_LARGEFILE, 0x8000 },
  { O_LARGEFILE, 0x8000 },
#endif
#endif
#ifdef O_DIRECTORY
#ifdef O_DIRECTORY
  { O_DIRECTORY, 0x10000 },
  { O_DIRECTORY, 0x10000 },
#endif
#endif
#ifdef O_NOFOLLOW
#ifdef O_NOFOLLOW
  { O_NOFOLLOW, 0x20000 },
  { O_NOFOLLOW, 0x20000 },
#endif
#endif
  { -1, -1 }
  { -1, -1 }
};
};
 
 
/* Needed for the cris_pipe_nonempty and cris_pipe_empty syscalls.  */
/* Needed for the cris_pipe_nonempty and cris_pipe_empty syscalls.  */
static SIM_CPU *current_cpu_for_cb_callback;
static SIM_CPU *current_cpu_for_cb_callback;
 
 
static int syscall_read_mem (host_callback *, struct cb_syscall *,
static int syscall_read_mem (host_callback *, struct cb_syscall *,
                             unsigned long, char *, int);
                             unsigned long, char *, int);
static int syscall_write_mem (host_callback *, struct cb_syscall *,
static int syscall_write_mem (host_callback *, struct cb_syscall *,
                              unsigned long, const char *, int);
                              unsigned long, const char *, int);
static USI create_map (SIM_DESC, struct cris_sim_mmapped_page **,
static USI create_map (SIM_DESC, struct cris_sim_mmapped_page **,
                       USI addr, USI len);
                       USI addr, USI len);
static USI unmap_pages (SIM_DESC, struct cris_sim_mmapped_page **,
static USI unmap_pages (SIM_DESC, struct cris_sim_mmapped_page **,
                       USI addr, USI len);
                       USI addr, USI len);
static USI is_mapped (SIM_DESC, struct cris_sim_mmapped_page **,
static USI is_mapped (SIM_DESC, struct cris_sim_mmapped_page **,
                       USI addr, USI len);
                       USI addr, USI len);
static void dump_statistics (SIM_CPU *current_cpu);
static void dump_statistics (SIM_CPU *current_cpu);
static void make_first_thread (SIM_CPU *current_cpu);
static void make_first_thread (SIM_CPU *current_cpu);
 
 
/* Read/write functions for system call interface.  */
/* Read/write functions for system call interface.  */
 
 
static int
static int
syscall_read_mem (host_callback *cb ATTRIBUTE_UNUSED,
syscall_read_mem (host_callback *cb ATTRIBUTE_UNUSED,
                  struct cb_syscall *sc,
                  struct cb_syscall *sc,
                  unsigned long taddr, char *buf, int bytes)
                  unsigned long taddr, char *buf, int bytes)
{
{
  SIM_DESC sd = (SIM_DESC) sc->p1;
  SIM_DESC sd = (SIM_DESC) sc->p1;
  SIM_CPU *cpu = (SIM_CPU *) sc->p2;
  SIM_CPU *cpu = (SIM_CPU *) sc->p2;
 
 
  return sim_core_read_buffer (sd, cpu, read_map, buf, taddr, bytes);
  return sim_core_read_buffer (sd, cpu, read_map, buf, taddr, bytes);
}
}
 
 
static int
static int
syscall_write_mem (host_callback *cb ATTRIBUTE_UNUSED,
syscall_write_mem (host_callback *cb ATTRIBUTE_UNUSED,
                   struct cb_syscall *sc,
                   struct cb_syscall *sc,
                   unsigned long taddr, const char *buf, int bytes)
                   unsigned long taddr, const char *buf, int bytes)
{
{
  SIM_DESC sd = (SIM_DESC) sc->p1;
  SIM_DESC sd = (SIM_DESC) sc->p1;
  SIM_CPU *cpu = (SIM_CPU *) sc->p2;
  SIM_CPU *cpu = (SIM_CPU *) sc->p2;
 
 
  return sim_core_write_buffer (sd, cpu, write_map, buf, taddr, bytes);
  return sim_core_write_buffer (sd, cpu, write_map, buf, taddr, bytes);
}
}
 
 
/* When we risk running self-modified code (as in trampolines), this is
/* When we risk running self-modified code (as in trampolines), this is
   called from special-case insns.  The silicon CRIS CPU:s have enough
   called from special-case insns.  The silicon CRIS CPU:s have enough
   cache snooping implemented making this a simulator-only issue.  Tests:
   cache snooping implemented making this a simulator-only issue.  Tests:
   gcc.c-torture/execute/931002-1.c execution, -O3 -g
   gcc.c-torture/execute/931002-1.c execution, -O3 -g
   gcc.c-torture/execute/931002-1.c execution, -O3 -fomit-frame-pointer.  */
   gcc.c-torture/execute/931002-1.c execution, -O3 -fomit-frame-pointer.  */
 
 
void
void
cris_flush_simulator_decode_cache (SIM_CPU *current_cpu,
cris_flush_simulator_decode_cache (SIM_CPU *current_cpu,
                                   USI pc ATTRIBUTE_UNUSED)
                                   USI pc ATTRIBUTE_UNUSED)
{
{
  SIM_DESC sd = CPU_STATE (current_cpu);
  SIM_DESC sd = CPU_STATE (current_cpu);
 
 
#if WITH_SCACHE
#if WITH_SCACHE
  if (USING_SCACHE_P (sd))
  if (USING_SCACHE_P (sd))
    scache_flush_cpu (current_cpu);
    scache_flush_cpu (current_cpu);
#endif
#endif
}
}
 
 
/* Output statistics at the end of a run.  */
/* Output statistics at the end of a run.  */
static void
static void
dump_statistics (SIM_CPU *current_cpu)
dump_statistics (SIM_CPU *current_cpu)
{
{
  SIM_DESC sd = CPU_STATE (current_cpu);
  SIM_DESC sd = CPU_STATE (current_cpu);
  CRIS_MISC_PROFILE *profp
  CRIS_MISC_PROFILE *profp
    = CPU_CRIS_MISC_PROFILE (current_cpu);
    = CPU_CRIS_MISC_PROFILE (current_cpu);
  unsigned64 total = profp->basic_cycle_count;
  unsigned64 total = profp->basic_cycle_count;
  const char *textmsg = "Basic clock cycles, total @: %llu\n";
  const char *textmsg = "Basic clock cycles, total @: %llu\n";
 
 
  /* The --cris-stats={basic|unaligned|schedulable|all} counts affect
  /* The --cris-stats={basic|unaligned|schedulable|all} counts affect
     what's included in the "total" count only.  */
     what's included in the "total" count only.  */
  switch (CPU_CRIS_MISC_PROFILE (current_cpu)->flags
  switch (CPU_CRIS_MISC_PROFILE (current_cpu)->flags
          & FLAG_CRIS_MISC_PROFILE_ALL)
          & FLAG_CRIS_MISC_PROFILE_ALL)
    {
    {
    case FLAG_CRIS_MISC_PROFILE_SIMPLE:
    case FLAG_CRIS_MISC_PROFILE_SIMPLE:
      break;
      break;
 
 
    case (FLAG_CRIS_MISC_PROFILE_UNALIGNED | FLAG_CRIS_MISC_PROFILE_SIMPLE):
    case (FLAG_CRIS_MISC_PROFILE_UNALIGNED | FLAG_CRIS_MISC_PROFILE_SIMPLE):
      textmsg
      textmsg
        = "Clock cycles including stall cycles for unaligned accesses @: %llu\n";
        = "Clock cycles including stall cycles for unaligned accesses @: %llu\n";
      total += profp->unaligned_mem_dword_count;
      total += profp->unaligned_mem_dword_count;
      break;
      break;
 
 
    case (FLAG_CRIS_MISC_PROFILE_SCHEDULABLE | FLAG_CRIS_MISC_PROFILE_SIMPLE):
    case (FLAG_CRIS_MISC_PROFILE_SCHEDULABLE | FLAG_CRIS_MISC_PROFILE_SIMPLE):
      textmsg = "Schedulable clock cycles, total @: %llu\n";
      textmsg = "Schedulable clock cycles, total @: %llu\n";
      total
      total
        += (profp->memsrc_stall_count
        += (profp->memsrc_stall_count
            + profp->memraw_stall_count
            + profp->memraw_stall_count
            + profp->movemsrc_stall_count
            + profp->movemsrc_stall_count
            + profp->movemdst_stall_count
            + profp->movemdst_stall_count
            + profp->mulsrc_stall_count
            + profp->mulsrc_stall_count
            + profp->jumpsrc_stall_count
            + profp->jumpsrc_stall_count
            + profp->unaligned_mem_dword_count);
            + profp->unaligned_mem_dword_count);
      break;
      break;
 
 
    case FLAG_CRIS_MISC_PROFILE_ALL:
    case FLAG_CRIS_MISC_PROFILE_ALL:
      textmsg = "All accounted clock cycles, total @: %llu\n";
      textmsg = "All accounted clock cycles, total @: %llu\n";
      total
      total
        += (profp->memsrc_stall_count
        += (profp->memsrc_stall_count
            + profp->memraw_stall_count
            + profp->memraw_stall_count
            + profp->movemsrc_stall_count
            + profp->movemsrc_stall_count
            + profp->movemdst_stall_count
            + profp->movemdst_stall_count
            + profp->movemaddr_stall_count
            + profp->movemaddr_stall_count
            + profp->mulsrc_stall_count
            + profp->mulsrc_stall_count
            + profp->jumpsrc_stall_count
            + profp->jumpsrc_stall_count
            + profp->branch_stall_count
            + profp->branch_stall_count
            + profp->jumptarget_stall_count
            + profp->jumptarget_stall_count
            + profp->unaligned_mem_dword_count);
            + profp->unaligned_mem_dword_count);
      break;
      break;
 
 
    default:
    default:
      abort ();
      abort ();
 
 
      sim_io_eprintf (sd,
      sim_io_eprintf (sd,
                      "Internal inconsistency at %s:%d",
                      "Internal inconsistency at %s:%d",
                      __FILE__, __LINE__);
                      __FILE__, __LINE__);
      sim_engine_halt (sd, current_cpu, NULL, 0,
      sim_engine_halt (sd, current_cpu, NULL, 0,
                       sim_stopped, SIM_SIGILL);
                       sim_stopped, SIM_SIGILL);
    }
    }
 
 
  /* Historically, these messages have gone to stderr, so we'll keep it
  /* Historically, these messages have gone to stderr, so we'll keep it
     that way.  It's also easier to then tell it from normal program
     that way.  It's also easier to then tell it from normal program
     output.  FIXME: Add redirect option like "run -e file".  */
     output.  FIXME: Add redirect option like "run -e file".  */
  sim_io_eprintf (sd, textmsg, total);
  sim_io_eprintf (sd, textmsg, total);
 
 
  /* For v32, unaligned_mem_dword_count should always be 0.  For
  /* For v32, unaligned_mem_dword_count should always be 0.  For
     v10, memsrc_stall_count should always be 0.  */
     v10, memsrc_stall_count should always be 0.  */
  sim_io_eprintf (sd, "Memory source stall cycles: %llu\n",
  sim_io_eprintf (sd, "Memory source stall cycles: %llu\n",
                  (unsigned long long) (profp->memsrc_stall_count
                  (unsigned long long) (profp->memsrc_stall_count
                                        + profp->unaligned_mem_dword_count));
                                        + profp->unaligned_mem_dword_count));
  sim_io_eprintf (sd, "Memory read-after-write stall cycles: %llu\n",
  sim_io_eprintf (sd, "Memory read-after-write stall cycles: %llu\n",
                  (unsigned long long) profp->memraw_stall_count);
                  (unsigned long long) profp->memraw_stall_count);
  sim_io_eprintf (sd, "Movem source stall cycles: %llu\n",
  sim_io_eprintf (sd, "Movem source stall cycles: %llu\n",
                  (unsigned long long) profp->movemsrc_stall_count);
                  (unsigned long long) profp->movemsrc_stall_count);
  sim_io_eprintf (sd, "Movem destination stall cycles: %llu\n",
  sim_io_eprintf (sd, "Movem destination stall cycles: %llu\n",
                  (unsigned long long) profp->movemdst_stall_count);
                  (unsigned long long) profp->movemdst_stall_count);
  sim_io_eprintf (sd, "Movem address stall cycles: %llu\n",
  sim_io_eprintf (sd, "Movem address stall cycles: %llu\n",
                  (unsigned long long) profp->movemaddr_stall_count);
                  (unsigned long long) profp->movemaddr_stall_count);
  sim_io_eprintf (sd, "Multiplication source stall cycles: %llu\n",
  sim_io_eprintf (sd, "Multiplication source stall cycles: %llu\n",
                  (unsigned long long) profp->mulsrc_stall_count);
                  (unsigned long long) profp->mulsrc_stall_count);
  sim_io_eprintf (sd, "Jump source stall cycles: %llu\n",
  sim_io_eprintf (sd, "Jump source stall cycles: %llu\n",
                  (unsigned long long) profp->jumpsrc_stall_count);
                  (unsigned long long) profp->jumpsrc_stall_count);
  sim_io_eprintf (sd, "Branch misprediction stall cycles: %llu\n",
  sim_io_eprintf (sd, "Branch misprediction stall cycles: %llu\n",
                  (unsigned long long) profp->branch_stall_count);
                  (unsigned long long) profp->branch_stall_count);
  sim_io_eprintf (sd, "Jump target stall cycles: %llu\n",
  sim_io_eprintf (sd, "Jump target stall cycles: %llu\n",
                  (unsigned long long) profp->jumptarget_stall_count);
                  (unsigned long long) profp->jumptarget_stall_count);
}
}
 
 
/* Check whether any part of [addr .. addr + len - 1] is already mapped.
/* Check whether any part of [addr .. addr + len - 1] is already mapped.
   Return 1 if a overlap detected, 0 otherwise.  */
   Return 1 if a overlap detected, 0 otherwise.  */
 
 
static USI
static USI
is_mapped (SIM_DESC sd ATTRIBUTE_UNUSED,
is_mapped (SIM_DESC sd ATTRIBUTE_UNUSED,
           struct cris_sim_mmapped_page **rootp,
           struct cris_sim_mmapped_page **rootp,
           USI addr, USI len)
           USI addr, USI len)
{
{
  struct cris_sim_mmapped_page *mapp;
  struct cris_sim_mmapped_page *mapp;
 
 
  if (len == 0 || (len & 8191))
  if (len == 0 || (len & 8191))
    abort ();
    abort ();
 
 
  /* Iterate over the reverse-address sorted pages until we find a page in
  /* Iterate over the reverse-address sorted pages until we find a page in
     or lower than the checked area.  */
     or lower than the checked area.  */
  for (mapp = *rootp; mapp != NULL && mapp->addr >= addr; mapp = mapp->prev)
  for (mapp = *rootp; mapp != NULL && mapp->addr >= addr; mapp = mapp->prev)
    if (mapp->addr < addr + len && mapp->addr >= addr)
    if (mapp->addr < addr + len && mapp->addr >= addr)
      return 1;
      return 1;
 
 
  return 0;
  return 0;
}
}
 
 
/* Create mmapped memory.  */
/* Create mmapped memory.  */
 
 
static USI
static USI
create_map (SIM_DESC sd, struct cris_sim_mmapped_page **rootp, USI addr,
create_map (SIM_DESC sd, struct cris_sim_mmapped_page **rootp, USI addr,
            USI len)
            USI len)
{
{
  struct cris_sim_mmapped_page *mapp;
  struct cris_sim_mmapped_page *mapp;
  struct cris_sim_mmapped_page **higher_prevp = rootp;
  struct cris_sim_mmapped_page **higher_prevp = rootp;
  USI new_addr = 0x40000000;
  USI new_addr = 0x40000000;
 
 
  if (addr != 0)
  if (addr != 0)
    new_addr = addr;
    new_addr = addr;
  else if (*rootp)
  else if (*rootp)
    new_addr = rootp[0]->addr + 8192;
    new_addr = rootp[0]->addr + 8192;
 
 
  if (len != 8192)
  if (len != 8192)
    {
    {
      USI page_addr;
      USI page_addr;
 
 
      if (len & 8191)
      if (len & 8191)
        /* Which is better: return an error for this, or just round it up?  */
        /* Which is better: return an error for this, or just round it up?  */
        abort ();
        abort ();
 
 
      /* Do a recursive call for each page in the request.  */
      /* Do a recursive call for each page in the request.  */
      for (page_addr = new_addr; len != 0; page_addr += 8192, len -= 8192)
      for (page_addr = new_addr; len != 0; page_addr += 8192, len -= 8192)
        if (create_map (sd, rootp, page_addr, 8192) >= (USI) -8191)
        if (create_map (sd, rootp, page_addr, 8192) >= (USI) -8191)
          abort ();
          abort ();
 
 
      return new_addr;
      return new_addr;
    }
    }
 
 
  for (mapp = *rootp;
  for (mapp = *rootp;
       mapp != NULL && mapp->addr > new_addr;
       mapp != NULL && mapp->addr > new_addr;
       mapp = mapp->prev)
       mapp = mapp->prev)
    higher_prevp = &mapp->prev;
    higher_prevp = &mapp->prev;
 
 
  /* Allocate the new page, on the next higher page from the last one
  /* Allocate the new page, on the next higher page from the last one
     allocated, and link in the new descriptor before previous ones.  */
     allocated, and link in the new descriptor before previous ones.  */
  mapp = malloc (sizeof (*mapp));
  mapp = malloc (sizeof (*mapp));
 
 
  if (mapp == NULL)
  if (mapp == NULL)
    return (USI) -ENOMEM;
    return (USI) -ENOMEM;
 
 
  sim_core_attach (sd, NULL, 0, access_read_write_exec, 0,
  sim_core_attach (sd, NULL, 0, access_read_write_exec, 0,
                   new_addr, len,
                   new_addr, len,
                   0, NULL, NULL);
                   0, NULL, NULL);
 
 
  mapp->addr = new_addr;
  mapp->addr = new_addr;
  mapp->prev = *higher_prevp;
  mapp->prev = *higher_prevp;
  *higher_prevp = mapp;
  *higher_prevp = mapp;
 
 
  return new_addr;
  return new_addr;
}
}
 
 
/* Unmap one or more pages.  */
/* Unmap one or more pages.  */
 
 
static USI
static USI
unmap_pages (SIM_DESC sd, struct cris_sim_mmapped_page **rootp, USI addr,
unmap_pages (SIM_DESC sd, struct cris_sim_mmapped_page **rootp, USI addr,
            USI len)
            USI len)
{
{
  struct cris_sim_mmapped_page *mapp;
  struct cris_sim_mmapped_page *mapp;
  struct cris_sim_mmapped_page **higher_prevp = rootp;
  struct cris_sim_mmapped_page **higher_prevp = rootp;
 
 
  if (len != 8192)
  if (len != 8192)
    {
    {
      USI page_addr;
      USI page_addr;
 
 
      if (len & 8191)
      if (len & 8191)
        /* Which is better: return an error for this, or just round it up?  */
        /* Which is better: return an error for this, or just round it up?  */
        abort ();
        abort ();
 
 
      /* Loop backwards to make each call is O(1) over the number of pages
      /* Loop backwards to make each call is O(1) over the number of pages
         allocated, if we're unmapping from the high end of the pages.  */
         allocated, if we're unmapping from the high end of the pages.  */
      for (page_addr = addr + len - 8192;
      for (page_addr = addr + len - 8192;
           page_addr >= addr;
           page_addr >= addr;
           page_addr -= 8192)
           page_addr -= 8192)
        if (unmap_pages (sd, rootp, page_addr, 8192) != 0)
        if (unmap_pages (sd, rootp, page_addr, 8192) != 0)
          abort ();
          abort ();
 
 
      return 0;
      return 0;
    }
    }
 
 
  for (mapp = *rootp; mapp != NULL && mapp->addr > addr; mapp = mapp->prev)
  for (mapp = *rootp; mapp != NULL && mapp->addr > addr; mapp = mapp->prev)
    higher_prevp = &mapp->prev;
    higher_prevp = &mapp->prev;
 
 
  if (mapp == NULL || mapp->addr != addr)
  if (mapp == NULL || mapp->addr != addr)
    return EINVAL;
    return EINVAL;
 
 
  *higher_prevp = mapp->prev;
  *higher_prevp = mapp->prev;
  sim_core_detach (sd, NULL, 0, 0, addr);
  sim_core_detach (sd, NULL, 0, 0, addr);
  free (mapp);
  free (mapp);
  return 0;
  return 0;
}
}
 
 
/* The semantic code invokes this for illegal (unrecognized) instructions.  */
/* The semantic code invokes this for illegal (unrecognized) instructions.  */
 
 
SEM_PC
SEM_PC
sim_engine_invalid_insn (SIM_CPU *current_cpu, IADDR cia, SEM_PC vpc)
sim_engine_invalid_insn (SIM_CPU *current_cpu, IADDR cia, SEM_PC vpc)
{
{
  SIM_DESC sd = CPU_STATE (current_cpu);
  SIM_DESC sd = CPU_STATE (current_cpu);
 
 
  sim_engine_halt (sd, current_cpu, NULL, cia, sim_stopped, SIM_SIGILL);
  sim_engine_halt (sd, current_cpu, NULL, cia, sim_stopped, SIM_SIGILL);
  return vpc;
  return vpc;
}
}
 
 
/* Handlers from the CGEN description that should not be called.  */
/* Handlers from the CGEN description that should not be called.  */
 
 
USI
USI
cris_bmod_handler (SIM_CPU *current_cpu ATTRIBUTE_UNUSED,
cris_bmod_handler (SIM_CPU *current_cpu ATTRIBUTE_UNUSED,
                   UINT srcreg ATTRIBUTE_UNUSED,
                   UINT srcreg ATTRIBUTE_UNUSED,
                   USI dstreg ATTRIBUTE_UNUSED)
                   USI dstreg ATTRIBUTE_UNUSED)
{
{
  abort ();
  abort ();
}
}
 
 
void
void
h_supr_set_handler (SIM_CPU *current_cpu ATTRIBUTE_UNUSED,
h_supr_set_handler (SIM_CPU *current_cpu ATTRIBUTE_UNUSED,
                    UINT index ATTRIBUTE_UNUSED,
                    UINT index ATTRIBUTE_UNUSED,
                    USI page ATTRIBUTE_UNUSED,
                    USI page ATTRIBUTE_UNUSED,
                    USI newval ATTRIBUTE_UNUSED)
                    USI newval ATTRIBUTE_UNUSED)
{
{
  abort ();
  abort ();
}
}
 
 
USI
USI
h_supr_get_handler (SIM_CPU *current_cpu ATTRIBUTE_UNUSED,
h_supr_get_handler (SIM_CPU *current_cpu ATTRIBUTE_UNUSED,
                    UINT index ATTRIBUTE_UNUSED,
                    UINT index ATTRIBUTE_UNUSED,
                    USI page ATTRIBUTE_UNUSED)
                    USI page ATTRIBUTE_UNUSED)
{
{
  abort ();
  abort ();
}
}
 
 
/* Swap one context for another.  */
/* Swap one context for another.  */
 
 
static void
static void
schedule (SIM_CPU *current_cpu, int next)
schedule (SIM_CPU *current_cpu, int next)
{
{
  /* Need to mark context-switches in the trace output.  */
  /* Need to mark context-switches in the trace output.  */
  if ((CPU_CRIS_MISC_PROFILE (current_cpu)->flags
  if ((CPU_CRIS_MISC_PROFILE (current_cpu)->flags
       & FLAG_CRIS_MISC_PROFILE_XSIM_TRACE))
       & FLAG_CRIS_MISC_PROFILE_XSIM_TRACE))
    cris_trace_printf (CPU_STATE (current_cpu), current_cpu,
    cris_trace_printf (CPU_STATE (current_cpu), current_cpu,
                       "\t#:%d\n", next);
                       "\t#:%d\n", next);
 
 
  /* Copy the current context (if there is one) to its slot.  */
  /* Copy the current context (if there is one) to its slot.  */
  if (current_cpu->thread_data[current_cpu->threadno].cpu_context)
  if (current_cpu->thread_data[current_cpu->threadno].cpu_context)
    memcpy (current_cpu->thread_data[current_cpu->threadno].cpu_context,
    memcpy (current_cpu->thread_data[current_cpu->threadno].cpu_context,
            &current_cpu->cpu_data_placeholder,
            &current_cpu->cpu_data_placeholder,
            current_cpu->thread_cpu_data_size);
            current_cpu->thread_cpu_data_size);
 
 
  /* Copy the new context from its slot.  */
  /* Copy the new context from its slot.  */
  memcpy (&current_cpu->cpu_data_placeholder,
  memcpy (&current_cpu->cpu_data_placeholder,
          current_cpu->thread_data[next].cpu_context,
          current_cpu->thread_data[next].cpu_context,
          current_cpu->thread_cpu_data_size);
          current_cpu->thread_cpu_data_size);
 
 
  /* Update needed stuff to indicate the new context.  */
  /* Update needed stuff to indicate the new context.  */
  current_cpu->threadno = next;
  current_cpu->threadno = next;
 
 
  /* Handle pending signals.  */
  /* Handle pending signals.  */
  if (current_cpu->thread_data[next].sigpending
  if (current_cpu->thread_data[next].sigpending
      /* We don't run nested signal handlers.  This means that pause(2)
      /* We don't run nested signal handlers.  This means that pause(2)
         and sigsuspend(2) do not work in sighandlers, but that
         and sigsuspend(2) do not work in sighandlers, but that
         shouldn't be too hard a restriction.  It also greatly
         shouldn't be too hard a restriction.  It also greatly
         simplifies the code.  */
         simplifies the code.  */
      && current_cpu->thread_data[next].cpu_context_atsignal == NULL)
      && current_cpu->thread_data[next].cpu_context_atsignal == NULL)
  {
  {
    int sig;
    int sig;
 
 
    /* See if there's really a pending, non-blocked handler.  We don't
    /* See if there's really a pending, non-blocked handler.  We don't
       queue signals, so just use the first one in ascending order.  */
       queue signals, so just use the first one in ascending order.  */
    for (sig = 0; sig < 64; sig++)
    for (sig = 0; sig < 64; sig++)
      if (current_cpu->thread_data[next].sigdata[sig].pending
      if (current_cpu->thread_data[next].sigdata[sig].pending
          && !current_cpu->thread_data[next].sigdata[sig].blocked)
          && !current_cpu->thread_data[next].sigdata[sig].blocked)
      {
      {
        bfd_byte regbuf[4];
        bfd_byte regbuf[4];
        USI sp;
        USI sp;
        int i;
        int i;
        USI blocked;
        USI blocked;
        USI pc = sim_pc_get (current_cpu);
        USI pc = sim_pc_get (current_cpu);
 
 
        /* It's simpler to save the CPU context inside the simulator
        /* It's simpler to save the CPU context inside the simulator
           than on the stack.  */
           than on the stack.  */
        current_cpu->thread_data[next].cpu_context_atsignal
        current_cpu->thread_data[next].cpu_context_atsignal
          = (*current_cpu
          = (*current_cpu
             ->make_thread_cpu_data) (current_cpu,
             ->make_thread_cpu_data) (current_cpu,
                                      current_cpu->thread_data[next]
                                      current_cpu->thread_data[next]
                                      .cpu_context);
                                      .cpu_context);
 
 
        (*CPU_REG_FETCH (current_cpu)) (current_cpu, H_GR_SP, regbuf, 4);
        (*CPU_REG_FETCH (current_cpu)) (current_cpu, H_GR_SP, regbuf, 4);
        sp = bfd_getl32 (regbuf);
        sp = bfd_getl32 (regbuf);
 
 
        /* Make sure we have an aligned stack.  */
        /* Make sure we have an aligned stack.  */
        sp &= ~3;
        sp &= ~3;
 
 
        /* Make room for the signal frame, aligned.  FIXME: Check that
        /* Make room for the signal frame, aligned.  FIXME: Check that
           the memory exists, map it in if absent.  (BTW, should also
           the memory exists, map it in if absent.  (BTW, should also
           implement on-access automatic stack allocation).  */
           implement on-access automatic stack allocation).  */
        sp -= 20;
        sp -= 20;
 
 
        /* This isn't the same signal frame as the kernel uses, because
        /* This isn't the same signal frame as the kernel uses, because
           we don't want to bother getting all registers on and off the
           we don't want to bother getting all registers on and off the
           stack.  */
           stack.  */
 
 
        /* First, we store the currently blocked signals.  */
        /* First, we store the currently blocked signals.  */
        blocked = 0;
        blocked = 0;
        for (i = 0; i < 32; i++)
        for (i = 0; i < 32; i++)
          blocked
          blocked
            |= current_cpu->thread_data[next].sigdata[i + 1].blocked << i;
            |= current_cpu->thread_data[next].sigdata[i + 1].blocked << i;
        sim_core_write_aligned_4 (current_cpu, pc, 0, sp, blocked);
        sim_core_write_aligned_4 (current_cpu, pc, 0, sp, blocked);
        blocked = 0;
        blocked = 0;
        for (i = 0; i < 31; i++)
        for (i = 0; i < 31; i++)
          blocked
          blocked
            |= current_cpu->thread_data[next].sigdata[i + 33].blocked << i;
            |= current_cpu->thread_data[next].sigdata[i + 33].blocked << i;
        sim_core_write_aligned_4 (current_cpu, pc, 0, sp + 4, blocked);
        sim_core_write_aligned_4 (current_cpu, pc, 0, sp + 4, blocked);
 
 
        /* Then, the actual instructions.  This is CPU-specific, but we
        /* Then, the actual instructions.  This is CPU-specific, but we
           use instructions from the common subset for v10 and v32 which
           use instructions from the common subset for v10 and v32 which
           should be safe for the time being but could be parametrized
           should be safe for the time being but could be parametrized
           if need be.  */
           if need be.  */
        /* MOVU.W [PC+],R9.  */
        /* MOVU.W [PC+],R9.  */
        sim_core_write_aligned_2 (current_cpu, pc, 0, sp + 8, 0x9c5f);
        sim_core_write_aligned_2 (current_cpu, pc, 0, sp + 8, 0x9c5f);
        /* .WORD TARGET_SYS_sigreturn.  */
        /* .WORD TARGET_SYS_sigreturn.  */
        sim_core_write_aligned_2 (current_cpu, pc, 0, sp + 10,
        sim_core_write_aligned_2 (current_cpu, pc, 0, sp + 10,
                                  TARGET_SYS_sigreturn);
                                  TARGET_SYS_sigreturn);
        /* BREAK 13.  */
        /* BREAK 13.  */
        sim_core_write_aligned_2 (current_cpu, pc, 0, sp + 12, 0xe93d);
        sim_core_write_aligned_2 (current_cpu, pc, 0, sp + 12, 0xe93d);
 
 
        /* NOP (on v32; it's SETF on v10, but is the correct compatible
        /* NOP (on v32; it's SETF on v10, but is the correct compatible
           instruction.  Still, it doesn't matter because v10 has no
           instruction.  Still, it doesn't matter because v10 has no
           delay slot for BREAK so it will not be executed).  */
           delay slot for BREAK so it will not be executed).  */
        sim_core_write_aligned_2 (current_cpu, pc, 0, sp + 16, 0x05b0);
        sim_core_write_aligned_2 (current_cpu, pc, 0, sp + 16, 0x05b0);
 
 
        /* Modify registers to hold the right values for the sighandler
        /* Modify registers to hold the right values for the sighandler
           context: updated stackpointer and return address pointing to
           context: updated stackpointer and return address pointing to
           the sigreturn stub.  */
           the sigreturn stub.  */
        bfd_putl32 (sp, regbuf);
        bfd_putl32 (sp, regbuf);
        (*CPU_REG_STORE (current_cpu)) (current_cpu, H_GR_SP, regbuf, 4);
        (*CPU_REG_STORE (current_cpu)) (current_cpu, H_GR_SP, regbuf, 4);
        bfd_putl32 (sp + 8, regbuf);
        bfd_putl32 (sp + 8, regbuf);
        (*CPU_REG_STORE (current_cpu)) (current_cpu, TARGET_SRP_REGNUM,
        (*CPU_REG_STORE (current_cpu)) (current_cpu, TARGET_SRP_REGNUM,
                                        regbuf, 4);
                                        regbuf, 4);
 
 
        current_cpu->thread_data[next].sigdata[sig].pending = 0;
        current_cpu->thread_data[next].sigdata[sig].pending = 0;
 
 
        /* Block this signal (for the duration of the sighandler).  */
        /* Block this signal (for the duration of the sighandler).  */
        current_cpu->thread_data[next].sigdata[sig].blocked = 1;
        current_cpu->thread_data[next].sigdata[sig].blocked = 1;
 
 
        sim_pc_set (current_cpu, current_cpu->sighandler[sig]);
        sim_pc_set (current_cpu, current_cpu->sighandler[sig]);
        bfd_putl32 (sig, regbuf);
        bfd_putl32 (sig, regbuf);
        (*CPU_REG_STORE (current_cpu)) (current_cpu, H_GR_R10,
        (*CPU_REG_STORE (current_cpu)) (current_cpu, H_GR_R10,
                                        regbuf, 4);
                                        regbuf, 4);
 
 
        /* We ignore a SA_SIGINFO flag in the sigaction call; the code I
        /* We ignore a SA_SIGINFO flag in the sigaction call; the code I
           needed all this for, specifies a SA_SIGINFO call but treats it
           needed all this for, specifies a SA_SIGINFO call but treats it
           like an ordinary sighandler; only the signal number argument is
           like an ordinary sighandler; only the signal number argument is
           inspected.  To make future need to implement SA_SIGINFO
           inspected.  To make future need to implement SA_SIGINFO
           correctly possible, we set the siginfo argument register to a
           correctly possible, we set the siginfo argument register to a
           magic (hopefully non-address) number.  (NB: then, you should
           magic (hopefully non-address) number.  (NB: then, you should
           just need to pass the siginfo argument; it seems you probably
           just need to pass the siginfo argument; it seems you probably
           don't need to implement the specific rt_sigreturn.)  */
           don't need to implement the specific rt_sigreturn.)  */
        bfd_putl32 (0xbad5161f, regbuf);
        bfd_putl32 (0xbad5161f, regbuf);
        (*CPU_REG_STORE (current_cpu)) (current_cpu, H_GR_R11,
        (*CPU_REG_STORE (current_cpu)) (current_cpu, H_GR_R11,
                                        regbuf, 4);
                                        regbuf, 4);
 
 
        /* The third argument is unused and the kernel sets it to 0.  */
        /* The third argument is unused and the kernel sets it to 0.  */
        bfd_putl32 (0, regbuf);
        bfd_putl32 (0, regbuf);
        (*CPU_REG_STORE (current_cpu)) (current_cpu, H_GR_R12,
        (*CPU_REG_STORE (current_cpu)) (current_cpu, H_GR_R12,
                                        regbuf, 4);
                                        regbuf, 4);
        return;
        return;
      }
      }
 
 
    /* No, there actually was no pending signal for this thread.  Reset
    /* No, there actually was no pending signal for this thread.  Reset
       this flag.  */
       this flag.  */
    current_cpu->thread_data[next].sigpending = 0;
    current_cpu->thread_data[next].sigpending = 0;
  }
  }
}
}
 
 
/* Reschedule the simplest possible way until something else is absolutely
/* Reschedule the simplest possible way until something else is absolutely
   necessary:
   necessary:
   - A. Find the next process (round-robin) that doesn't have at_syscall
   - A. Find the next process (round-robin) that doesn't have at_syscall
        set, schedule it.
        set, schedule it.
   - B. If there is none, just run the next process, round-robin.
   - B. If there is none, just run the next process, round-robin.
   - Clear at_syscall for the current process.  */
   - Clear at_syscall for the current process.  */
 
 
static void
static void
reschedule (SIM_CPU *current_cpu)
reschedule (SIM_CPU *current_cpu)
{
{
  int i;
  int i;
 
 
  /* Iterate over all thread slots, because after a few thread creations
  /* Iterate over all thread slots, because after a few thread creations
     and exits, we don't know where the live ones are.  */
     and exits, we don't know where the live ones are.  */
  for (i = (current_cpu->threadno + 1) % SIM_TARGET_MAX_THREADS;
  for (i = (current_cpu->threadno + 1) % SIM_TARGET_MAX_THREADS;
       i != current_cpu->threadno;
       i != current_cpu->threadno;
       i = (i + 1) % SIM_TARGET_MAX_THREADS)
       i = (i + 1) % SIM_TARGET_MAX_THREADS)
    if (current_cpu->thread_data[i].cpu_context
    if (current_cpu->thread_data[i].cpu_context
        && current_cpu->thread_data[i].at_syscall == 0)
        && current_cpu->thread_data[i].at_syscall == 0)
      {
      {
        schedule (current_cpu, i);
        schedule (current_cpu, i);
        return;
        return;
      }
      }
 
 
  /* Pick any next live thread.  */
  /* Pick any next live thread.  */
  for (i = (current_cpu->threadno + 1) % SIM_TARGET_MAX_THREADS;
  for (i = (current_cpu->threadno + 1) % SIM_TARGET_MAX_THREADS;
       i != current_cpu->threadno;
       i != current_cpu->threadno;
       i = (i + 1) % SIM_TARGET_MAX_THREADS)
       i = (i + 1) % SIM_TARGET_MAX_THREADS)
    if (current_cpu->thread_data[i].cpu_context)
    if (current_cpu->thread_data[i].cpu_context)
      {
      {
        schedule (current_cpu, i);
        schedule (current_cpu, i);
        return;
        return;
      }
      }
 
 
  /* More than one live thread, but we couldn't find the next one?  */
  /* More than one live thread, but we couldn't find the next one?  */
  abort ();
  abort ();
}
}
 
 
/* Set up everything to receive (or IGN) an incoming signal to the
/* Set up everything to receive (or IGN) an incoming signal to the
   current context.  */
   current context.  */
 
 
static int
static int
deliver_signal (SIM_CPU *current_cpu, int sig, unsigned int pid)
deliver_signal (SIM_CPU *current_cpu, int sig, unsigned int pid)
{
{
  int i;
  int i;
  USI pc = sim_pc_get (current_cpu);
  USI pc = sim_pc_get (current_cpu);
 
 
  /* Find the thread index of the pid. */
  /* Find the thread index of the pid. */
  for (i = 0; i < SIM_TARGET_MAX_THREADS; i++)
  for (i = 0; i < SIM_TARGET_MAX_THREADS; i++)
    /* Apparently it's ok to send signals to zombies (so a check for
    /* Apparently it's ok to send signals to zombies (so a check for
       current_cpu->thread_data[i].cpu_context != NULL would be
       current_cpu->thread_data[i].cpu_context != NULL would be
       wrong). */
       wrong). */
    if (current_cpu->thread_data[i].threadid == pid - TARGET_PID)
    if (current_cpu->thread_data[i].threadid == pid - TARGET_PID)
      {
      {
        if (sig < 64)
        if (sig < 64)
          switch (current_cpu->sighandler[sig])
          switch (current_cpu->sighandler[sig])
            {
            {
            case TARGET_SIG_DFL:
            case TARGET_SIG_DFL:
              switch (sig)
              switch (sig)
                {
                {
                  /* The following according to the glibc
                  /* The following according to the glibc
                     documentation. (The kernel code has non-obvious
                     documentation. (The kernel code has non-obvious
                     execution paths.)  */
                     execution paths.)  */
                case TARGET_SIGFPE:
                case TARGET_SIGFPE:
                case TARGET_SIGILL:
                case TARGET_SIGILL:
                case TARGET_SIGSEGV:
                case TARGET_SIGSEGV:
                case TARGET_SIGBUS:
                case TARGET_SIGBUS:
                case TARGET_SIGABRT:
                case TARGET_SIGABRT:
                case TARGET_SIGTRAP:
                case TARGET_SIGTRAP:
                case TARGET_SIGSYS:
                case TARGET_SIGSYS:
 
 
                case TARGET_SIGTERM:
                case TARGET_SIGTERM:
                case TARGET_SIGINT:
                case TARGET_SIGINT:
                case TARGET_SIGQUIT:
                case TARGET_SIGQUIT:
                case TARGET_SIGKILL:
                case TARGET_SIGKILL:
                case TARGET_SIGHUP:
                case TARGET_SIGHUP:
 
 
                case TARGET_SIGALRM:
                case TARGET_SIGALRM:
                case TARGET_SIGVTALRM:
                case TARGET_SIGVTALRM:
                case TARGET_SIGPROF:
                case TARGET_SIGPROF:
                case TARGET_SIGSTOP:
                case TARGET_SIGSTOP:
 
 
                case TARGET_SIGPIPE:
                case TARGET_SIGPIPE:
                case TARGET_SIGLOST:
                case TARGET_SIGLOST:
                case TARGET_SIGXCPU:
                case TARGET_SIGXCPU:
                case TARGET_SIGXFSZ:
                case TARGET_SIGXFSZ:
                case TARGET_SIGUSR1:
                case TARGET_SIGUSR1:
                case TARGET_SIGUSR2:
                case TARGET_SIGUSR2:
                  sim_io_eprintf (CPU_STATE (current_cpu),
                  sim_io_eprintf (CPU_STATE (current_cpu),
                                  "Exiting pid %d due to signal %d\n",
                                  "Exiting pid %d due to signal %d\n",
                                  pid, sig);
                                  pid, sig);
                  sim_engine_halt (CPU_STATE (current_cpu), current_cpu,
                  sim_engine_halt (CPU_STATE (current_cpu), current_cpu,
                                   NULL, pc, sim_stopped,
                                   NULL, pc, sim_stopped,
                                   sig == TARGET_SIGABRT
                                   sig == TARGET_SIGABRT
                                   ? SIM_SIGABRT : SIM_SIGILL);
                                   ? SIM_SIGABRT : SIM_SIGILL);
                  return 0;
                  return 0;
 
 
                  /* The default for all other signals is to be ignored.  */
                  /* The default for all other signals is to be ignored.  */
                default:
                default:
                  return 0;
                  return 0;
                }
                }
 
 
            case TARGET_SIG_IGN:
            case TARGET_SIG_IGN:
              switch (sig)
              switch (sig)
                {
                {
                case TARGET_SIGKILL:
                case TARGET_SIGKILL:
                case TARGET_SIGSTOP:
                case TARGET_SIGSTOP:
                  /* Can't ignore these signals.  */
                  /* Can't ignore these signals.  */
                  sim_io_eprintf (CPU_STATE (current_cpu),
                  sim_io_eprintf (CPU_STATE (current_cpu),
                                  "Exiting pid %d due to signal %d\n",
                                  "Exiting pid %d due to signal %d\n",
                                  pid, sig);
                                  pid, sig);
                  sim_engine_halt (CPU_STATE (current_cpu), current_cpu,
                  sim_engine_halt (CPU_STATE (current_cpu), current_cpu,
                                   NULL, pc, sim_stopped, SIM_SIGILL);
                                   NULL, pc, sim_stopped, SIM_SIGILL);
                  return 0;
                  return 0;
 
 
                default:
                default:
                  return 0;
                  return 0;
                }
                }
              break;
              break;
 
 
            default:
            default:
              /* Mark the signal as pending, making schedule () check
              /* Mark the signal as pending, making schedule () check
                 closer.  The signal will be handled when the thread is
                 closer.  The signal will be handled when the thread is
                 scheduled and the signal is unblocked.  */
                 scheduled and the signal is unblocked.  */
              current_cpu->thread_data[i].sigdata[sig].pending = 1;
              current_cpu->thread_data[i].sigdata[sig].pending = 1;
              current_cpu->thread_data[i].sigpending = 1;
              current_cpu->thread_data[i].sigpending = 1;
              return 0;
              return 0;
            }
            }
        else
        else
          {
          {
            sim_io_eprintf (CPU_STATE (current_cpu),
            sim_io_eprintf (CPU_STATE (current_cpu),
                            "Unimplemented signal: %d\n", sig);
                            "Unimplemented signal: %d\n", sig);
            sim_engine_halt (CPU_STATE (current_cpu), current_cpu, NULL, pc,
            sim_engine_halt (CPU_STATE (current_cpu), current_cpu, NULL, pc,
                             sim_stopped, SIM_SIGILL);
                             sim_stopped, SIM_SIGILL);
          }
          }
      }
      }
 
 
  return
  return
    -cb_host_to_target_errno (STATE_CALLBACK (CPU_STATE (current_cpu)),
    -cb_host_to_target_errno (STATE_CALLBACK (CPU_STATE (current_cpu)),
                              ESRCH);
                              ESRCH);
}
}
 
 
/* Make the vector and the first item, the main thread.  */
/* Make the vector and the first item, the main thread.  */
 
 
static void
static void
make_first_thread (SIM_CPU *current_cpu)
make_first_thread (SIM_CPU *current_cpu)
{
{
  current_cpu->thread_data
  current_cpu->thread_data
    = xcalloc (1,
    = xcalloc (1,
               SIM_TARGET_MAX_THREADS
               SIM_TARGET_MAX_THREADS
               * sizeof (current_cpu->thread_data[0]));
               * sizeof (current_cpu->thread_data[0]));
  current_cpu->thread_data[0].cpu_context
  current_cpu->thread_data[0].cpu_context
    = (*current_cpu->make_thread_cpu_data) (current_cpu,
    = (*current_cpu->make_thread_cpu_data) (current_cpu,
                                            &current_cpu
                                            &current_cpu
                                            ->cpu_data_placeholder);
                                            ->cpu_data_placeholder);
  current_cpu->thread_data[0].parent_threadid = -1;
  current_cpu->thread_data[0].parent_threadid = -1;
 
 
  /* For good measure.  */
  /* For good measure.  */
  if (TARGET_SIG_DFL != 0)
  if (TARGET_SIG_DFL != 0)
    abort ();
    abort ();
}
}
 
 
/* Handle unknown system calls.  Returns (if it does) the syscall
/* Handle unknown system calls.  Returns (if it does) the syscall
   return value.  */
   return value.  */
 
 
static USI
static USI
cris_unknown_syscall (SIM_CPU *current_cpu, USI pc, char *s, ...)
cris_unknown_syscall (SIM_CPU *current_cpu, USI pc, char *s, ...)
{
{
  SIM_DESC sd = CPU_STATE (current_cpu);
  SIM_DESC sd = CPU_STATE (current_cpu);
  host_callback *cb = STATE_CALLBACK (sd);
  host_callback *cb = STATE_CALLBACK (sd);
 
 
  if (cris_unknown_syscall_action == CRIS_USYSC_MSG_STOP
  if (cris_unknown_syscall_action == CRIS_USYSC_MSG_STOP
      || cris_unknown_syscall_action == CRIS_USYSC_MSG_ENOSYS)
      || cris_unknown_syscall_action == CRIS_USYSC_MSG_ENOSYS)
    {
    {
      va_list ap;
      va_list ap;
 
 
      va_start (ap, s);
      va_start (ap, s);
      sim_io_evprintf (sd, s, ap);
      sim_io_evprintf (sd, s, ap);
      va_end (ap);
      va_end (ap);
 
 
      if (cris_unknown_syscall_action == CRIS_USYSC_MSG_STOP)
      if (cris_unknown_syscall_action == CRIS_USYSC_MSG_STOP)
        sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGILL);
        sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGILL);
    }
    }
 
 
  return -cb_host_to_target_errno (cb, ENOSYS);
  return -cb_host_to_target_errno (cb, ENOSYS);
}
}
 
 
/* Main function: the handler of the "break 13" syscall insn.  */
/* Main function: the handler of the "break 13" syscall insn.  */
 
 
USI
USI
cris_break_13_handler (SIM_CPU *current_cpu, USI callnum, USI arg1,
cris_break_13_handler (SIM_CPU *current_cpu, USI callnum, USI arg1,
                       USI arg2, USI arg3, USI arg4, USI arg5, USI arg6,
                       USI arg2, USI arg3, USI arg4, USI arg5, USI arg6,
                       USI pc)
                       USI pc)
{
{
  CB_SYSCALL s;
  CB_SYSCALL s;
  SIM_DESC sd = CPU_STATE (current_cpu);
  SIM_DESC sd = CPU_STATE (current_cpu);
  host_callback *cb = STATE_CALLBACK (sd);
  host_callback *cb = STATE_CALLBACK (sd);
  int retval;
  int retval;
  int threadno = current_cpu->threadno;
  int threadno = current_cpu->threadno;
 
 
  current_cpu->syscalls++;
  current_cpu->syscalls++;
 
 
  CB_SYSCALL_INIT (&s);
  CB_SYSCALL_INIT (&s);
  s.func = callnum;
  s.func = callnum;
  s.arg1 = arg1;
  s.arg1 = arg1;
  s.arg2 = arg2;
  s.arg2 = arg2;
  s.arg3 = arg3;
  s.arg3 = arg3;
 
 
  if (callnum == TARGET_SYS_exit && current_cpu->m1threads == 0)
  if (callnum == TARGET_SYS_exit && current_cpu->m1threads == 0)
    {
    {
      if (CPU_CRIS_MISC_PROFILE (current_cpu)->flags
      if (CPU_CRIS_MISC_PROFILE (current_cpu)->flags
          & FLAG_CRIS_MISC_PROFILE_ALL)
          & FLAG_CRIS_MISC_PROFILE_ALL)
        dump_statistics (current_cpu);
        dump_statistics (current_cpu);
      sim_engine_halt (sd, current_cpu, NULL, pc, sim_exited, arg1);
      sim_engine_halt (sd, current_cpu, NULL, pc, sim_exited, arg1);
    }
    }
 
 
  s.p1 = (PTR) sd;
  s.p1 = (PTR) sd;
  s.p2 = (PTR) current_cpu;
  s.p2 = (PTR) current_cpu;
  s.read_mem = syscall_read_mem;
  s.read_mem = syscall_read_mem;
  s.write_mem = syscall_write_mem;
  s.write_mem = syscall_write_mem;
 
 
  current_cpu_for_cb_callback = current_cpu;
  current_cpu_for_cb_callback = current_cpu;
 
 
  if (cb_syscall (cb, &s) != CB_RC_OK)
  if (cb_syscall (cb, &s) != CB_RC_OK)
    {
    {
      abort ();
      abort ();
      sim_io_eprintf (sd, "Break 13: invalid %d?  Returned %ld\n", callnum,
      sim_io_eprintf (sd, "Break 13: invalid %d?  Returned %ld\n", callnum,
                      s.result);
                      s.result);
      sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGILL);
      sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGILL);
    }
    }
 
 
  retval = s.result == -1 ? -s.errcode : s.result;
  retval = s.result == -1 ? -s.errcode : s.result;
 
 
  if (s.errcode != 0 && s.errcode == cb_host_to_target_errno (cb, ENOSYS))
  if (s.errcode != 0 && s.errcode == cb_host_to_target_errno (cb, ENOSYS))
    {
    {
      /* If the generic simulator call said ENOSYS, then let's try the
      /* If the generic simulator call said ENOSYS, then let's try the
         ones we know ourselves.
         ones we know ourselves.
 
 
         The convention is to provide *very limited* functionality on an
         The convention is to provide *very limited* functionality on an
         as-needed basis, only what's covered by the test-suite, tests
         as-needed basis, only what's covered by the test-suite, tests
         added when functionality changes and abort with a descriptive
         added when functionality changes and abort with a descriptive
         message for *everything* else.  Where there's no test-case, we
         message for *everything* else.  Where there's no test-case, we
         just abort.  */
         just abort.  */
      switch (callnum)
      switch (callnum)
        {
        {
        case 0:
        case 0:
          /* It's a pretty safe bet that the "old setup() system call"
          /* It's a pretty safe bet that the "old setup() system call"
             number will not be re-used; we can't say the same for higher
             number will not be re-used; we can't say the same for higher
             numbers.  We treat this simulator-generated call as "wait
             numbers.  We treat this simulator-generated call as "wait
             forever"; we re-run this insn.  The wait is ended by a
             forever"; we re-run this insn.  The wait is ended by a
             callback.  Sanity check that this is the reason we got
             callback.  Sanity check that this is the reason we got
             here. */
             here. */
          if (current_cpu->thread_data == NULL
          if (current_cpu->thread_data == NULL
              || (current_cpu->thread_data[threadno].pipe_write_fd == 0))
              || (current_cpu->thread_data[threadno].pipe_write_fd == 0))
            goto unimplemented_syscall;
            goto unimplemented_syscall;
 
 
          sim_pc_set (current_cpu, pc);
          sim_pc_set (current_cpu, pc);
          retval = arg1;
          retval = arg1;
          break;
          break;
 
 
        case TARGET_SYS_fcntl64:
        case TARGET_SYS_fcntl64:
        case TARGET_SYS_fcntl:
        case TARGET_SYS_fcntl:
          switch (arg2)
          switch (arg2)
            {
            {
            case 1:
            case 1:
              /* F_GETFD.
              /* F_GETFD.
                 Glibc checks stdin, stdout and stderr fd:s for
                 Glibc checks stdin, stdout and stderr fd:s for
                 close-on-exec security sanity.  We just need to provide a
                 close-on-exec security sanity.  We just need to provide a
                 OK return value.  If we really need to have a
                 OK return value.  If we really need to have a
                 close-on-exec flag true, we could just do a real fcntl
                 close-on-exec flag true, we could just do a real fcntl
                 here.  */
                 here.  */
              retval = 0;
              retval = 0;
              break;
              break;
 
 
            case 2:
            case 2:
              /* F_SETFD.  Just ignore attempts to set the close-on-exec
              /* F_SETFD.  Just ignore attempts to set the close-on-exec
                 flag.  */
                 flag.  */
              retval = 0;
              retval = 0;
              break;
              break;
 
 
            case 3:
            case 3:
              /* F_GETFL.  Check for the special case for open+fdopen.  */
              /* F_GETFL.  Check for the special case for open+fdopen.  */
              if (current_cpu->last_syscall == TARGET_SYS_open
              if (current_cpu->last_syscall == TARGET_SYS_open
                  && arg1 == current_cpu->last_open_fd)
                  && arg1 == current_cpu->last_open_fd)
                {
                {
                  retval = current_cpu->last_open_flags & TARGET_O_ACCMODE;
                  retval = current_cpu->last_open_flags & TARGET_O_ACCMODE;
                  break;
                  break;
                }
                }
              else if (arg1 == 0)
              else if (arg1 == 0)
                {
                {
                  /* Because we can't freopen fd:s 0, 1, 2 to mean
                  /* Because we can't freopen fd:s 0, 1, 2 to mean
                     something else than stdin, stdout and stderr
                     something else than stdin, stdout and stderr
                     (sim/common/syscall.c:cb_syscall special cases fd
                     (sim/common/syscall.c:cb_syscall special cases fd
                     0, 1 and 2), we know what flags that we can
                     0, 1 and 2), we know what flags that we can
                     sanely return for these fd:s.  */
                     sanely return for these fd:s.  */
                  retval = TARGET_O_RDONLY;
                  retval = TARGET_O_RDONLY;
                  break;
                  break;
                }
                }
              else if (arg1 == 1 || arg1 == 2)
              else if (arg1 == 1 || arg1 == 2)
                {
                {
                  retval = TARGET_O_WRONLY;
                  retval = TARGET_O_WRONLY;
                  break;
                  break;
                }
                }
              /* FALLTHROUGH */
              /* FALLTHROUGH */
            default:
            default:
              /* Nothing else is implemented.  */
              /* Nothing else is implemented.  */
              retval
              retval
                = cris_unknown_syscall (current_cpu, pc,
                = cris_unknown_syscall (current_cpu, pc,
                                        "Unimplemented %s syscall "
                                        "Unimplemented %s syscall "
                                        "(fd: 0x%lx: cmd: 0x%lx arg: "
                                        "(fd: 0x%lx: cmd: 0x%lx arg: "
                                        "0x%lx)\n",
                                        "0x%lx)\n",
                                        callnum == TARGET_SYS_fcntl
                                        callnum == TARGET_SYS_fcntl
                                        ? "fcntl" : "fcntl64",
                                        ? "fcntl" : "fcntl64",
                                        (unsigned long) (USI) arg1,
                                        (unsigned long) (USI) arg1,
                                        (unsigned long) (USI) arg2,
                                        (unsigned long) (USI) arg2,
                                        (unsigned long) (USI) arg3);
                                        (unsigned long) (USI) arg3);
              break;
              break;
            }
            }
          break;
          break;
 
 
        case TARGET_SYS_uname:
        case TARGET_SYS_uname:
          {
          {
            /* Fill in a few constants to appease glibc.  */
            /* Fill in a few constants to appease glibc.  */
            static const char sim_utsname[6][65] =
            static const char sim_utsname[6][65] =
            {
            {
              "Linux",
              "Linux",
              "sim-target",
              "sim-target",
              "2.4.5",
              "2.4.5",
              TARGET_UTSNAME,
              TARGET_UTSNAME,
              "cris",
              "cris",
              "localdomain"
              "localdomain"
            };
            };
 
 
            if ((s.write_mem) (cb, &s, arg1, (const char *) sim_utsname,
            if ((s.write_mem) (cb, &s, arg1, (const char *) sim_utsname,
                               sizeof (sim_utsname))
                               sizeof (sim_utsname))
                != sizeof (sim_utsname))
                != sizeof (sim_utsname))
              retval = -cb_host_to_target_errno (cb, EFAULT);
              retval = -cb_host_to_target_errno (cb, EFAULT);
            else
            else
              retval = 0;
              retval = 0;
            break;
            break;
          }
          }
 
 
        case TARGET_SYS_geteuid32:
        case TARGET_SYS_geteuid32:
          /* We tell the truth with these.  Maybe we shouldn't, but it
          /* We tell the truth with these.  Maybe we shouldn't, but it
             should match the "stat" information.  */
             should match the "stat" information.  */
          retval = geteuid ();
          retval = geteuid ();
          break;
          break;
 
 
        case TARGET_SYS_getuid32:
        case TARGET_SYS_getuid32:
          retval = getuid ();
          retval = getuid ();
          break;
          break;
 
 
        case TARGET_SYS_getegid32:
        case TARGET_SYS_getegid32:
          retval = getegid ();
          retval = getegid ();
          break;
          break;
 
 
        case TARGET_SYS_getgid32:
        case TARGET_SYS_getgid32:
          retval = getgid ();
          retval = getgid ();
          break;
          break;
 
 
        case TARGET_SYS_brk:
        case TARGET_SYS_brk:
          /* Most often, we just return the argument, like the Linux
          /* Most often, we just return the argument, like the Linux
             kernel.  */
             kernel.  */
          retval = arg1;
          retval = arg1;
 
 
          if (arg1 == 0)
          if (arg1 == 0)
            retval = current_cpu->endbrk;
            retval = current_cpu->endbrk;
          else if (arg1 <= current_cpu->endmem)
          else if (arg1 <= current_cpu->endmem)
            current_cpu->endbrk = arg1;
            current_cpu->endbrk = arg1;
          else
          else
            {
            {
              USI new_end = (arg1 + 8191) & ~8191;
              USI new_end = (arg1 + 8191) & ~8191;
 
 
              /* If the simulator wants to brk more than a certain very
              /* If the simulator wants to brk more than a certain very
                 large amount, something is wrong.  FIXME: Return an error
                 large amount, something is wrong.  FIXME: Return an error
                 or abort?  Have command-line selectable?  */
                 or abort?  Have command-line selectable?  */
              if (new_end - current_cpu->endmem > SIM_MAX_ALLOC_CHUNK)
              if (new_end - current_cpu->endmem > SIM_MAX_ALLOC_CHUNK)
                {
                {
                  current_cpu->endbrk = current_cpu->endmem;
                  current_cpu->endbrk = current_cpu->endmem;
                  retval = current_cpu->endmem;
                  retval = current_cpu->endmem;
                  break;
                  break;
                }
                }
 
 
              sim_core_attach (sd, NULL, 0, access_read_write_exec, 0,
              sim_core_attach (sd, NULL, 0, access_read_write_exec, 0,
                               current_cpu->endmem,
                               current_cpu->endmem,
                               new_end - current_cpu->endmem,
                               new_end - current_cpu->endmem,
                               0, NULL, NULL);
                               0, NULL, NULL);
              current_cpu->endbrk = arg1;
              current_cpu->endbrk = arg1;
              current_cpu->endmem = new_end;
              current_cpu->endmem = new_end;
            }
            }
          break;
          break;
 
 
        case TARGET_SYS_getpid:
        case TARGET_SYS_getpid:
          /* Correct until CLONE_THREAD is implemented.  */
          /* Correct until CLONE_THREAD is implemented.  */
          retval = current_cpu->thread_data == NULL
          retval = current_cpu->thread_data == NULL
            ? TARGET_PID
            ? TARGET_PID
            : TARGET_PID + current_cpu->thread_data[threadno].threadid;
            : TARGET_PID + current_cpu->thread_data[threadno].threadid;
          break;
          break;
 
 
        case TARGET_SYS_getppid:
        case TARGET_SYS_getppid:
          /* Correct until CLONE_THREAD is implemented.  */
          /* Correct until CLONE_THREAD is implemented.  */
          retval = current_cpu->thread_data == NULL
          retval = current_cpu->thread_data == NULL
            ? TARGET_PID - 1
            ? TARGET_PID - 1
            : (TARGET_PID
            : (TARGET_PID
               + current_cpu->thread_data[threadno].parent_threadid);
               + current_cpu->thread_data[threadno].parent_threadid);
          break;
          break;
 
 
        case TARGET_SYS_mmap2:
        case TARGET_SYS_mmap2:
          {
          {
            USI addr = arg1;
            USI addr = arg1;
            USI len = arg2;
            USI len = arg2;
            USI prot = arg3;
            USI prot = arg3;
            USI flags = arg4;
            USI flags = arg4;
            USI fd = arg5;
            USI fd = arg5;
            USI pgoff = arg6;
            USI pgoff = arg6;
 
 
            /* If the simulator wants to mmap more than the very large
            /* If the simulator wants to mmap more than the very large
               limit, something is wrong.  FIXME: Return an error or
               limit, something is wrong.  FIXME: Return an error or
               abort?  Have command-line selectable?  */
               abort?  Have command-line selectable?  */
            if (len > SIM_MAX_ALLOC_CHUNK)
            if (len > SIM_MAX_ALLOC_CHUNK)
              {
              {
                retval = -cb_host_to_target_errno (cb, ENOMEM);
                retval = -cb_host_to_target_errno (cb, ENOMEM);
                break;
                break;
              }
              }
 
 
            if ((prot != (TARGET_PROT_READ | TARGET_PROT_WRITE)
            if ((prot != (TARGET_PROT_READ | TARGET_PROT_WRITE)
                 && (prot
                 && (prot
                     != (TARGET_PROT_READ
                     != (TARGET_PROT_READ
                         | TARGET_PROT_WRITE
                         | TARGET_PROT_WRITE
                         | TARGET_PROT_EXEC))
                         | TARGET_PROT_EXEC))
                 && prot != TARGET_PROT_READ)
                 && prot != TARGET_PROT_READ)
                || (flags != (TARGET_MAP_ANONYMOUS | TARGET_MAP_PRIVATE)
                || (flags != (TARGET_MAP_ANONYMOUS | TARGET_MAP_PRIVATE)
                    && flags != TARGET_MAP_PRIVATE
                    && flags != TARGET_MAP_PRIVATE
                    && flags != TARGET_MAP_SHARED)
                    && flags != TARGET_MAP_SHARED)
                || (fd != (USI) -1 && prot != TARGET_PROT_READ)
                || (fd != (USI) -1 && prot != TARGET_PROT_READ)
                || pgoff != 0)
                || pgoff != 0)
              {
              {
                retval
                retval
                  = cris_unknown_syscall (current_cpu, pc,
                  = cris_unknown_syscall (current_cpu, pc,
                                                 "Unimplemented mmap2 call "
                                                 "Unimplemented mmap2 call "
                                                 "(0x%lx, 0x%lx, 0x%lx, "
                                                 "(0x%lx, 0x%lx, 0x%lx, "
                                                 "0x%lx, 0x%lx, 0x%lx)\n",
                                                 "0x%lx, 0x%lx, 0x%lx)\n",
                                                 (unsigned long) arg1,
                                                 (unsigned long) arg1,
                                                 (unsigned long) arg2,
                                                 (unsigned long) arg2,
                                                 (unsigned long) arg3,
                                                 (unsigned long) arg3,
                                                 (unsigned long) arg4,
                                                 (unsigned long) arg4,
                                                 (unsigned long) arg5,
                                                 (unsigned long) arg5,
                                                 (unsigned long) arg6);
                                                 (unsigned long) arg6);
                break;
                break;
              }
              }
            else if (fd != (USI) -1)
            else if (fd != (USI) -1)
              {
              {
                /* Map a file.  */
                /* Map a file.  */
 
 
                USI newaddr;
                USI newaddr;
                USI pos;
                USI pos;
 
 
                /* A non-aligned argument is allowed for files.  */
                /* A non-aligned argument is allowed for files.  */
                USI newlen = (len + 8191) & ~8191;
                USI newlen = (len + 8191) & ~8191;
 
 
                /* We only support read, which we should already have
                /* We only support read, which we should already have
                   checked.  Check again anyway.  */
                   checked.  Check again anyway.  */
                if (prot != TARGET_PROT_READ)
                if (prot != TARGET_PROT_READ)
                  abort ();
                  abort ();
 
 
                newaddr
                newaddr
                  = create_map (sd, &current_cpu->highest_mmapped_page, addr,
                  = create_map (sd, &current_cpu->highest_mmapped_page, addr,
                                newlen);
                                newlen);
 
 
                if (newaddr >= (USI) -8191)
                if (newaddr >= (USI) -8191)
                  {
                  {
                    abort ();
                    abort ();
                    retval = -cb_host_to_target_errno (cb, -(SI) newaddr);
                    retval = -cb_host_to_target_errno (cb, -(SI) newaddr);
                    break;
                    break;
                  }
                  }
 
 
                /* Find the current position in the file.  */
                /* Find the current position in the file.  */
                s.func = TARGET_SYS_lseek;
                s.func = TARGET_SYS_lseek;
                s.arg1 = fd;
                s.arg1 = fd;
                s.arg2 = 0;
                s.arg2 = 0;
                s.arg3 = SEEK_CUR;
                s.arg3 = SEEK_CUR;
                if (cb_syscall (cb, &s) != CB_RC_OK)
                if (cb_syscall (cb, &s) != CB_RC_OK)
                  abort ();
                  abort ();
                pos = s.result;
                pos = s.result;
 
 
                if (s.result < 0)
                if (s.result < 0)
                  abort ();
                  abort ();
 
 
                /* Use the standard read callback to read in "len"
                /* Use the standard read callback to read in "len"
                   bytes.  */
                   bytes.  */
                s.func = TARGET_SYS_read;
                s.func = TARGET_SYS_read;
                s.arg1 = fd;
                s.arg1 = fd;
                s.arg2 = newaddr;
                s.arg2 = newaddr;
                s.arg3 = len;
                s.arg3 = len;
                if (cb_syscall (cb, &s) != CB_RC_OK)
                if (cb_syscall (cb, &s) != CB_RC_OK)
                  abort ();
                  abort ();
 
 
                if ((USI) s.result != len)
                if ((USI) s.result != len)
                  abort ();
                  abort ();
 
 
                /* After reading, we need to go back to the previous
                /* After reading, we need to go back to the previous
                   position in the file.  */
                   position in the file.  */
                s.func = TARGET_SYS_lseek;
                s.func = TARGET_SYS_lseek;
                s.arg1 = fd;
                s.arg1 = fd;
                s.arg2 = pos;
                s.arg2 = pos;
                s.arg3 = SEEK_SET;
                s.arg3 = SEEK_SET;
                if (cb_syscall (cb, &s) != CB_RC_OK)
                if (cb_syscall (cb, &s) != CB_RC_OK)
                  abort ();
                  abort ();
                if (pos != (USI) s.result)
                if (pos != (USI) s.result)
                  abort ();
                  abort ();
 
 
                retval = newaddr;
                retval = newaddr;
              }
              }
            else
            else
              {
              {
                USI newaddr
                USI newaddr
                  = create_map (sd, &current_cpu->highest_mmapped_page, addr,
                  = create_map (sd, &current_cpu->highest_mmapped_page, addr,
                                (len + 8191) & ~8191);
                                (len + 8191) & ~8191);
 
 
                if (newaddr >= (USI) -8191)
                if (newaddr >= (USI) -8191)
                  retval = -cb_host_to_target_errno (cb, -(SI) newaddr);
                  retval = -cb_host_to_target_errno (cb, -(SI) newaddr);
                else
                else
                  retval = newaddr;
                  retval = newaddr;
              }
              }
            break;
            break;
          }
          }
 
 
        case TARGET_SYS_mprotect:
        case TARGET_SYS_mprotect:
          {
          {
            /* We only cover the case of linuxthreads mprotecting out its
            /* We only cover the case of linuxthreads mprotecting out its
               stack guard page.  */
               stack guard page.  */
            USI addr = arg1;
            USI addr = arg1;
            USI len = arg2;
            USI len = arg2;
            USI prot = arg3;
            USI prot = arg3;
 
 
            if ((addr & 8191) != 0
            if ((addr & 8191) != 0
                || len != 8192
                || len != 8192
                || prot != TARGET_PROT_NONE
                || prot != TARGET_PROT_NONE
                || !is_mapped (sd, &current_cpu->highest_mmapped_page, addr,
                || !is_mapped (sd, &current_cpu->highest_mmapped_page, addr,
                               len))
                               len))
              {
              {
                retval
                retval
                  = cris_unknown_syscall (current_cpu, pc,
                  = cris_unknown_syscall (current_cpu, pc,
                                          "Unimplemented mprotect call "
                                          "Unimplemented mprotect call "
                                          "(0x%lx, 0x%lx, 0x%lx)\n",
                                          "(0x%lx, 0x%lx, 0x%lx)\n",
                                          (unsigned long) arg1,
                                          (unsigned long) arg1,
                                          (unsigned long) arg2,
                                          (unsigned long) arg2,
                                          (unsigned long) arg3);
                                          (unsigned long) arg3);
                break;
                break;
              }
              }
 
 
            /* FIXME: We should account for pages like this that are
            /* FIXME: We should account for pages like this that are
               "mprotected out".  For now, we just tell the simulator
               "mprotected out".  For now, we just tell the simulator
               core to remove that page from its map.  */
               core to remove that page from its map.  */
            sim_core_detach (sd, NULL, 0, 0, addr);
            sim_core_detach (sd, NULL, 0, 0, addr);
            retval = 0;
            retval = 0;
            break;
            break;
          }
          }
 
 
        case TARGET_SYS_ioctl:
        case TARGET_SYS_ioctl:
          {
          {
            /* We support only a very limited functionality: checking
            /* We support only a very limited functionality: checking
               stdout with TCGETS to perform the isatty function.  The
               stdout with TCGETS to perform the isatty function.  The
               TCGETS ioctl isn't actually performed or the result used by
               TCGETS ioctl isn't actually performed or the result used by
               an isatty () caller in a "hello, world" program; only the
               an isatty () caller in a "hello, world" program; only the
               return value is then used.  Maybe we shouldn't care about
               return value is then used.  Maybe we shouldn't care about
               the environment of the simulator regarding isatty, but
               the environment of the simulator regarding isatty, but
               that's been working before, in the xsim simulator.  */
               that's been working before, in the xsim simulator.  */
            if (arg2 == TARGET_TCGETS && arg1 == 1)
            if (arg2 == TARGET_TCGETS && arg1 == 1)
              retval = isatty (1) ? 0 : cb_host_to_target_errno (cb, EINVAL);
              retval = isatty (1) ? 0 : cb_host_to_target_errno (cb, EINVAL);
            else
            else
              retval = -cb_host_to_target_errno (cb, EINVAL);
              retval = -cb_host_to_target_errno (cb, EINVAL);
            break;
            break;
          }
          }
 
 
        case TARGET_SYS_munmap:
        case TARGET_SYS_munmap:
          {
          {
            USI addr = arg1;
            USI addr = arg1;
            USI len = arg2;
            USI len = arg2;
            USI result
            USI result
              = unmap_pages (sd, &current_cpu->highest_mmapped_page, addr,
              = unmap_pages (sd, &current_cpu->highest_mmapped_page, addr,
                             len);
                             len);
            retval = result != 0 ? -cb_host_to_target_errno (cb, result) : 0;
            retval = result != 0 ? -cb_host_to_target_errno (cb, result) : 0;
            break;
            break;
          }
          }
 
 
        case TARGET_SYS_wait4:
        case TARGET_SYS_wait4:
          {
          {
            int i;
            int i;
            USI pid = arg1;
            USI pid = arg1;
            USI saddr = arg2;
            USI saddr = arg2;
            USI options = arg3;
            USI options = arg3;
            USI rusagep = arg4;
            USI rusagep = arg4;
 
 
            /* FIXME: We're not properly implementing __WCLONE, and we
            /* FIXME: We're not properly implementing __WCLONE, and we
               don't really need the special casing so we might as well
               don't really need the special casing so we might as well
               make this general.  */
               make this general.  */
            if ((!(pid == (USI) -1
            if ((!(pid == (USI) -1
                   && options == (TARGET___WCLONE | TARGET_WNOHANG)
                   && options == (TARGET___WCLONE | TARGET_WNOHANG)
                   && saddr != 0)
                   && saddr != 0)
                 && !(pid > 0
                 && !(pid > 0
                      && (options == TARGET___WCLONE
                      && (options == TARGET___WCLONE
                          || options == TARGET___WALL)))
                          || options == TARGET___WALL)))
                || rusagep != 0
                || rusagep != 0
                || current_cpu->thread_data == NULL)
                || current_cpu->thread_data == NULL)
              {
              {
                retval
                retval
                  = cris_unknown_syscall (current_cpu, pc,
                  = cris_unknown_syscall (current_cpu, pc,
                                          "Unimplemented wait4 call "
                                          "Unimplemented wait4 call "
                                          "(0x%lx, 0x%lx, 0x%lx, 0x%lx)\n",
                                          "(0x%lx, 0x%lx, 0x%lx, 0x%lx)\n",
                                          (unsigned long) arg1,
                                          (unsigned long) arg1,
                                          (unsigned long) arg2,
                                          (unsigned long) arg2,
                                          (unsigned long) arg3,
                                          (unsigned long) arg3,
                                          (unsigned long) arg4);
                                          (unsigned long) arg4);
                break;
                break;
              }
              }
 
 
            if (pid == (USI) -1)
            if (pid == (USI) -1)
              for (i = 1; i < SIM_TARGET_MAX_THREADS; i++)
              for (i = 1; i < SIM_TARGET_MAX_THREADS; i++)
                {
                {
                  if (current_cpu->thread_data[threadno].threadid
                  if (current_cpu->thread_data[threadno].threadid
                      == current_cpu->thread_data[i].parent_threadid
                      == current_cpu->thread_data[i].parent_threadid
                      && current_cpu->thread_data[i].threadid != 0
                      && current_cpu->thread_data[i].threadid != 0
                      && current_cpu->thread_data[i].cpu_context == NULL)
                      && current_cpu->thread_data[i].cpu_context == NULL)
                    {
                    {
                      /* A zombied child.  Get the exit value and clear the
                      /* A zombied child.  Get the exit value and clear the
                         zombied entry so it will be reused.  */
                         zombied entry so it will be reused.  */
                      sim_core_write_unaligned_4 (current_cpu, pc, 0, saddr,
                      sim_core_write_unaligned_4 (current_cpu, pc, 0, saddr,
                                                  current_cpu
                                                  current_cpu
                                                  ->thread_data[i].exitval);
                                                  ->thread_data[i].exitval);
                      retval
                      retval
                        = current_cpu->thread_data[i].threadid + TARGET_PID;
                        = current_cpu->thread_data[i].threadid + TARGET_PID;
                      memset (&current_cpu->thread_data[i], 0,
                      memset (&current_cpu->thread_data[i], 0,
                              sizeof (current_cpu->thread_data[i]));
                              sizeof (current_cpu->thread_data[i]));
                      goto outer_break;
                      goto outer_break;
                    }
                    }
                }
                }
            else
            else
              {
              {
                /* We're waiting for a specific PID.  If we don't find
                /* We're waiting for a specific PID.  If we don't find
                   it zombied on this run, rerun the syscall.  */
                   it zombied on this run, rerun the syscall.  */
                for (i = 1; i < SIM_TARGET_MAX_THREADS; i++)
                for (i = 1; i < SIM_TARGET_MAX_THREADS; i++)
                  if (pid == current_cpu->thread_data[i].threadid + TARGET_PID
                  if (pid == current_cpu->thread_data[i].threadid + TARGET_PID
                      && current_cpu->thread_data[i].cpu_context == NULL)
                      && current_cpu->thread_data[i].cpu_context == NULL)
                    {
                    {
                      if (saddr != 0)
                      if (saddr != 0)
                        /* Get the exit value if the caller wants it.  */
                        /* Get the exit value if the caller wants it.  */
                        sim_core_write_unaligned_4 (current_cpu, pc, 0,
                        sim_core_write_unaligned_4 (current_cpu, pc, 0,
                                                    saddr,
                                                    saddr,
                                                    current_cpu
                                                    current_cpu
                                                    ->thread_data[i]
                                                    ->thread_data[i]
                                                    .exitval);
                                                    .exitval);
 
 
                      retval
                      retval
                        = current_cpu->thread_data[i].threadid + TARGET_PID;
                        = current_cpu->thread_data[i].threadid + TARGET_PID;
                      memset (&current_cpu->thread_data[i], 0,
                      memset (&current_cpu->thread_data[i], 0,
                              sizeof (current_cpu->thread_data[i]));
                              sizeof (current_cpu->thread_data[i]));
 
 
                      goto outer_break;
                      goto outer_break;
                    }
                    }
 
 
                sim_pc_set (current_cpu, pc);
                sim_pc_set (current_cpu, pc);
              }
              }
 
 
            retval = -cb_host_to_target_errno (cb, ECHILD);
            retval = -cb_host_to_target_errno (cb, ECHILD);
          outer_break:
          outer_break:
            break;
            break;
          }
          }
 
 
        case TARGET_SYS_rt_sigaction:
        case TARGET_SYS_rt_sigaction:
          {
          {
            USI signum = arg1;
            USI signum = arg1;
            USI old_sa = arg3;
            USI old_sa = arg3;
            USI new_sa = arg2;
            USI new_sa = arg2;
 
 
            /* The kernel says:
            /* The kernel says:
               struct sigaction {
               struct sigaction {
                        __sighandler_t sa_handler;
                        __sighandler_t sa_handler;
                        unsigned long sa_flags;
                        unsigned long sa_flags;
                        void (*sa_restorer)(void);
                        void (*sa_restorer)(void);
                        sigset_t sa_mask;
                        sigset_t sa_mask;
               }; */
               }; */
 
 
            if (old_sa != 0)
            if (old_sa != 0)
              {
              {
                sim_core_write_unaligned_4 (current_cpu, pc, 0, old_sa + 0,
                sim_core_write_unaligned_4 (current_cpu, pc, 0, old_sa + 0,
                                            current_cpu->sighandler[signum]);
                                            current_cpu->sighandler[signum]);
                sim_core_write_unaligned_4 (current_cpu, pc, 0, arg3 + 4, 0);
                sim_core_write_unaligned_4 (current_cpu, pc, 0, arg3 + 4, 0);
                sim_core_write_unaligned_4 (current_cpu, pc, 0, arg3 + 8, 0);
                sim_core_write_unaligned_4 (current_cpu, pc, 0, arg3 + 8, 0);
 
 
                /* We'll assume _NSIG_WORDS is 2 for the kernel.  */
                /* We'll assume _NSIG_WORDS is 2 for the kernel.  */
                sim_core_write_unaligned_4 (current_cpu, pc, 0, arg3 + 12, 0);
                sim_core_write_unaligned_4 (current_cpu, pc, 0, arg3 + 12, 0);
                sim_core_write_unaligned_4 (current_cpu, pc, 0, arg3 + 16, 0);
                sim_core_write_unaligned_4 (current_cpu, pc, 0, arg3 + 16, 0);
              }
              }
            if (new_sa != 0)
            if (new_sa != 0)
              {
              {
                USI target_sa_handler
                USI target_sa_handler
                  = sim_core_read_unaligned_4 (current_cpu, pc, 0, new_sa);
                  = sim_core_read_unaligned_4 (current_cpu, pc, 0, new_sa);
                USI target_sa_flags
                USI target_sa_flags
                  = sim_core_read_unaligned_4 (current_cpu, pc, 0, new_sa + 4);
                  = sim_core_read_unaligned_4 (current_cpu, pc, 0, new_sa + 4);
                USI target_sa_restorer
                USI target_sa_restorer
                  = sim_core_read_unaligned_4 (current_cpu, pc, 0, new_sa + 8);
                  = sim_core_read_unaligned_4 (current_cpu, pc, 0, new_sa + 8);
                USI target_sa_mask_low
                USI target_sa_mask_low
                  = sim_core_read_unaligned_4 (current_cpu, pc, 0, new_sa + 12);
                  = sim_core_read_unaligned_4 (current_cpu, pc, 0, new_sa + 12);
                USI target_sa_mask_high
                USI target_sa_mask_high
                  = sim_core_read_unaligned_4 (current_cpu, pc, 0, new_sa + 16);
                  = sim_core_read_unaligned_4 (current_cpu, pc, 0, new_sa + 16);
 
 
                /* We won't interrupt a syscall so we won't restart it,
                /* We won't interrupt a syscall so we won't restart it,
                   but a signal(2) call ends up syscalling rt_sigaction
                   but a signal(2) call ends up syscalling rt_sigaction
                   with this flag, so we have to handle it.  The
                   with this flag, so we have to handle it.  The
                   sa_restorer field contains garbage when not
                   sa_restorer field contains garbage when not
                   TARGET_SA_RESTORER, so don't look at it.  For the
                   TARGET_SA_RESTORER, so don't look at it.  For the
                   time being, we don't nest sighandlers, so we
                   time being, we don't nest sighandlers, so we
                   ignore the sa_mask, which simplifies things.  */
                   ignore the sa_mask, which simplifies things.  */
                if ((target_sa_flags != 0
                if ((target_sa_flags != 0
                     && target_sa_flags != TARGET_SA_RESTART
                     && target_sa_flags != TARGET_SA_RESTART
                     && target_sa_flags != (TARGET_SA_RESTART|TARGET_SA_SIGINFO))
                     && target_sa_flags != (TARGET_SA_RESTART|TARGET_SA_SIGINFO))
                    || target_sa_handler == 0)
                    || target_sa_handler == 0)
                  {
                  {
                    retval
                    retval
                      = cris_unknown_syscall (current_cpu, pc,
                      = cris_unknown_syscall (current_cpu, pc,
                                              "Unimplemented rt_sigaction "
                                              "Unimplemented rt_sigaction "
                                              "syscall "
                                              "syscall "
                                              "(0x%lx, 0x%lx: "
                                              "(0x%lx, 0x%lx: "
                                              "[0x%x, 0x%x, 0x%x, "
                                              "[0x%x, 0x%x, 0x%x, "
                                              "{0x%x, 0x%x}], 0x%lx)\n",
                                              "{0x%x, 0x%x}], 0x%lx)\n",
                                              (unsigned long) arg1,
                                              (unsigned long) arg1,
                                              (unsigned long) arg2,
                                              (unsigned long) arg2,
                                              target_sa_handler,
                                              target_sa_handler,
                                              target_sa_flags,
                                              target_sa_flags,
                                              target_sa_restorer,
                                              target_sa_restorer,
                                              target_sa_mask_low,
                                              target_sa_mask_low,
                                              target_sa_mask_high,
                                              target_sa_mask_high,
                                              (unsigned long) arg3);
                                              (unsigned long) arg3);
                    break;
                    break;
                  }
                  }
 
 
                current_cpu->sighandler[signum] = target_sa_handler;
                current_cpu->sighandler[signum] = target_sa_handler;
 
 
                /* Because we may have unblocked signals, one may now be
                /* Because we may have unblocked signals, one may now be
                   pending, if there are threads, that is.  */
                   pending, if there are threads, that is.  */
                if (current_cpu->thread_data)
                if (current_cpu->thread_data)
                  current_cpu->thread_data[threadno].sigpending = 1;
                  current_cpu->thread_data[threadno].sigpending = 1;
              }
              }
            retval = 0;
            retval = 0;
            break;
            break;
          }
          }
 
 
        case TARGET_SYS_mremap:
        case TARGET_SYS_mremap:
          {
          {
            USI addr = arg1;
            USI addr = arg1;
            USI old_len = arg2;
            USI old_len = arg2;
            USI new_len = arg3;
            USI new_len = arg3;
            USI flags = arg4;
            USI flags = arg4;
            USI new_addr = arg5;
            USI new_addr = arg5;
            USI mapped_addr;
            USI mapped_addr;
 
 
            if (new_len == old_len)
            if (new_len == old_len)
              /* The program and/or library is possibly confused but
              /* The program and/or library is possibly confused but
                 this is a valid call.  Happens with ipps-1.40 on file
                 this is a valid call.  Happens with ipps-1.40 on file
                 svs_all.  */
                 svs_all.  */
              retval = addr;
              retval = addr;
            else if (new_len < old_len)
            else if (new_len < old_len)
              {
              {
                /* Shrinking is easy.  */
                /* Shrinking is easy.  */
                if (unmap_pages (sd, &current_cpu->highest_mmapped_page,
                if (unmap_pages (sd, &current_cpu->highest_mmapped_page,
                                 addr + new_len, old_len - new_len) != 0)
                                 addr + new_len, old_len - new_len) != 0)
                  retval = -cb_host_to_target_errno (cb, EINVAL);
                  retval = -cb_host_to_target_errno (cb, EINVAL);
                else
                else
                  retval = addr;
                  retval = addr;
              }
              }
            else if (! is_mapped (sd, &current_cpu->highest_mmapped_page,
            else if (! is_mapped (sd, &current_cpu->highest_mmapped_page,
                                  addr + old_len, new_len - old_len))
                                  addr + old_len, new_len - old_len))
              {
              {
                /* If the extension isn't mapped, we can just add it.  */
                /* If the extension isn't mapped, we can just add it.  */
                mapped_addr
                mapped_addr
                  = create_map (sd, &current_cpu->highest_mmapped_page,
                  = create_map (sd, &current_cpu->highest_mmapped_page,
                                addr + old_len, new_len - old_len);
                                addr + old_len, new_len - old_len);
 
 
                if (mapped_addr > (USI) -8192)
                if (mapped_addr > (USI) -8192)
                  retval = -cb_host_to_target_errno (cb, -(SI) mapped_addr);
                  retval = -cb_host_to_target_errno (cb, -(SI) mapped_addr);
                else
                else
                  retval = addr;
                  retval = addr;
              }
              }
            else if (flags & TARGET_MREMAP_MAYMOVE)
            else if (flags & TARGET_MREMAP_MAYMOVE)
              {
              {
                /* Create a whole new map and copy the contents
                /* Create a whole new map and copy the contents
                   block-by-block there.  We ignore the new_addr argument
                   block-by-block there.  We ignore the new_addr argument
                   for now.  */
                   for now.  */
                char buf[8192];
                char buf[8192];
                USI prev_addr = addr;
                USI prev_addr = addr;
                USI prev_len = old_len;
                USI prev_len = old_len;
 
 
                mapped_addr
                mapped_addr
                  = create_map (sd, &current_cpu->highest_mmapped_page,
                  = create_map (sd, &current_cpu->highest_mmapped_page,
                                0, new_len);
                                0, new_len);
 
 
                if (mapped_addr > (USI) -8192)
                if (mapped_addr > (USI) -8192)
                  {
                  {
                    retval = -cb_host_to_target_errno (cb, -(SI) new_addr);
                    retval = -cb_host_to_target_errno (cb, -(SI) new_addr);
                    break;
                    break;
                  }
                  }
 
 
                retval = mapped_addr;
                retval = mapped_addr;
 
 
                for (; old_len > 0;
                for (; old_len > 0;
                     old_len -= 8192, mapped_addr += 8192, addr += 8192)
                     old_len -= 8192, mapped_addr += 8192, addr += 8192)
                  {
                  {
                    if (sim_core_read_buffer (sd, current_cpu, read_map, buf,
                    if (sim_core_read_buffer (sd, current_cpu, read_map, buf,
                                              addr, 8192) != 8192
                                              addr, 8192) != 8192
                        || sim_core_write_buffer (sd, current_cpu, 0, buf,
                        || sim_core_write_buffer (sd, current_cpu, 0, buf,
                                                  mapped_addr, 8192) != 8192)
                                                  mapped_addr, 8192) != 8192)
                      abort ();
                      abort ();
                  }
                  }
 
 
                if (unmap_pages (sd, &current_cpu->highest_mmapped_page,
                if (unmap_pages (sd, &current_cpu->highest_mmapped_page,
                                 prev_addr, prev_len) != 0)
                                 prev_addr, prev_len) != 0)
                  abort ();
                  abort ();
              }
              }
            else
            else
              retval = -cb_host_to_target_errno (cb, -ENOMEM);
              retval = -cb_host_to_target_errno (cb, -ENOMEM);
            break;
            break;
          }
          }
 
 
        case TARGET_SYS_poll:
        case TARGET_SYS_poll:
          {
          {
            int npollfds = arg2;
            int npollfds = arg2;
            int timeout = arg3;
            int timeout = arg3;
            SI ufds = arg1;
            SI ufds = arg1;
            SI fd = -1;
            SI fd = -1;
            HI events = -1;
            HI events = -1;
            HI revents = 0;
            HI revents = 0;
            struct stat buf;
            struct stat buf;
            int i;
            int i;
 
 
            /* The kernel says:
            /* The kernel says:
                struct pollfd {
                struct pollfd {
                     int fd;
                     int fd;
                     short events;
                     short events;
                     short revents;
                     short revents;
                }; */
                }; */
 
 
            /* Check that this is the expected poll call from
            /* Check that this is the expected poll call from
               linuxthreads/manager.c; we don't support anything else.
               linuxthreads/manager.c; we don't support anything else.
               Remember, fd == 0 isn't supported.  */
               Remember, fd == 0 isn't supported.  */
            if (npollfds != 1
            if (npollfds != 1
                || ((fd = sim_core_read_unaligned_4 (current_cpu, pc,
                || ((fd = sim_core_read_unaligned_4 (current_cpu, pc,
                                                     0, ufds)) <= 0)
                                                     0, ufds)) <= 0)
                || ((events = sim_core_read_unaligned_2 (current_cpu, pc,
                || ((events = sim_core_read_unaligned_2 (current_cpu, pc,
                                                         0, ufds + 4))
                                                         0, ufds + 4))
                    != TARGET_POLLIN)
                    != TARGET_POLLIN)
                || ((cb->fstat) (cb, fd, &buf) != 0
                || ((cb->fstat) (cb, fd, &buf) != 0
                    || (buf.st_mode & S_IFIFO) == 0)
                    || (buf.st_mode & S_IFIFO) == 0)
                || current_cpu->thread_data == NULL)
                || current_cpu->thread_data == NULL)
              {
              {
                retval
                retval
                  = cris_unknown_syscall (current_cpu, pc,
                  = cris_unknown_syscall (current_cpu, pc,
                                          "Unimplemented poll syscall "
                                          "Unimplemented poll syscall "
                                          "(0x%lx: [0x%x, 0x%x, x], "
                                          "(0x%lx: [0x%x, 0x%x, x], "
                                          "0x%lx, 0x%lx)\n",
                                          "0x%lx, 0x%lx)\n",
                                          (unsigned long) arg1, fd, events,
                                          (unsigned long) arg1, fd, events,
                                          (unsigned long) arg2,
                                          (unsigned long) arg2,
                                          (unsigned long) arg3);
                                          (unsigned long) arg3);
                break;
                break;
              }
              }
 
 
            retval = 0;
            retval = 0;
 
 
            /* Iterate over threads; find a marker that a writer is
            /* Iterate over threads; find a marker that a writer is
               sleeping, waiting for a reader.  */
               sleeping, waiting for a reader.  */
            for (i = 0; i < SIM_TARGET_MAX_THREADS; i++)
            for (i = 0; i < SIM_TARGET_MAX_THREADS; i++)
              if (current_cpu->thread_data[i].cpu_context != NULL
              if (current_cpu->thread_data[i].cpu_context != NULL
                  && current_cpu->thread_data[i].pipe_read_fd == fd)
                  && current_cpu->thread_data[i].pipe_read_fd == fd)
                {
                {
                  revents = TARGET_POLLIN;
                  revents = TARGET_POLLIN;
                  retval = 1;
                  retval = 1;
                  break;
                  break;
                }
                }
 
 
            /* Timeout decreases with whatever time passed between the
            /* Timeout decreases with whatever time passed between the
               last syscall and this.  That's not exactly right for the
               last syscall and this.  That's not exactly right for the
               first call, but it's close enough that it isn't
               first call, but it's close enough that it isn't
               worthwhile to complicate matters by making that a special
               worthwhile to complicate matters by making that a special
               case.  */
               case.  */
            timeout
            timeout
              -= (TARGET_TIME_MS (current_cpu)
              -= (TARGET_TIME_MS (current_cpu)
                  - (current_cpu->thread_data[threadno].last_execution));
                  - (current_cpu->thread_data[threadno].last_execution));
 
 
            /* Arrange to repeat this syscall until timeout or event,
            /* Arrange to repeat this syscall until timeout or event,
               decreasing timeout at each iteration.  */
               decreasing timeout at each iteration.  */
            if (timeout > 0 && revents == 0)
            if (timeout > 0 && revents == 0)
              {
              {
                bfd_byte timeout_buf[4];
                bfd_byte timeout_buf[4];
 
 
                bfd_putl32 (timeout, timeout_buf);
                bfd_putl32 (timeout, timeout_buf);
                (*CPU_REG_STORE (current_cpu)) (current_cpu,
                (*CPU_REG_STORE (current_cpu)) (current_cpu,
                                                H_GR_R12, timeout_buf, 4);
                                                H_GR_R12, timeout_buf, 4);
                sim_pc_set (current_cpu, pc);
                sim_pc_set (current_cpu, pc);
                retval = arg1;
                retval = arg1;
                break;
                break;
              }
              }
 
 
            sim_core_write_unaligned_2 (current_cpu, pc, 0, ufds + 4 + 2,
            sim_core_write_unaligned_2 (current_cpu, pc, 0, ufds + 4 + 2,
                                        revents);
                                        revents);
            break;
            break;
          }
          }
 
 
        case TARGET_SYS_time:
        case TARGET_SYS_time:
          {
          {
            retval = (int) (*cb->time) (cb, 0L);
            retval = (int) (*cb->time) (cb, 0L);
 
 
            /* At time of this writing, CB_SYSCALL_time doesn't do the
            /* At time of this writing, CB_SYSCALL_time doesn't do the
               part of setting *arg1 to the return value.  */
               part of setting *arg1 to the return value.  */
            if (arg1)
            if (arg1)
              sim_core_write_unaligned_4 (current_cpu, pc, 0, arg1, retval);
              sim_core_write_unaligned_4 (current_cpu, pc, 0, arg1, retval);
            break;
            break;
          }
          }
 
 
        case TARGET_SYS_gettimeofday:
        case TARGET_SYS_gettimeofday:
          if (arg1 != 0)
          if (arg1 != 0)
            {
            {
              USI ts = TARGET_TIME (current_cpu);
              USI ts = TARGET_TIME (current_cpu);
              USI tms = TARGET_TIME_MS (current_cpu);
              USI tms = TARGET_TIME_MS (current_cpu);
 
 
              /* First dword is seconds since TARGET_EPOCH.  */
              /* First dword is seconds since TARGET_EPOCH.  */
              sim_core_write_unaligned_4 (current_cpu, pc, 0, arg1, ts);
              sim_core_write_unaligned_4 (current_cpu, pc, 0, arg1, ts);
 
 
              /* Second dword is microseconds.  */
              /* Second dword is microseconds.  */
              sim_core_write_unaligned_4 (current_cpu, pc, 0, arg1 + 4,
              sim_core_write_unaligned_4 (current_cpu, pc, 0, arg1 + 4,
                                          (tms % 1000) * 1000);
                                          (tms % 1000) * 1000);
            }
            }
          if (arg2 != 0)
          if (arg2 != 0)
            {
            {
              /* Time-zone info is always cleared.  */
              /* Time-zone info is always cleared.  */
              sim_core_write_unaligned_4 (current_cpu, pc, 0, arg2, 0);
              sim_core_write_unaligned_4 (current_cpu, pc, 0, arg2, 0);
              sim_core_write_unaligned_4 (current_cpu, pc, 0, arg2 + 4, 0);
              sim_core_write_unaligned_4 (current_cpu, pc, 0, arg2 + 4, 0);
            }
            }
          retval = 0;
          retval = 0;
          break;
          break;
 
 
        case TARGET_SYS_llseek:
        case TARGET_SYS_llseek:
          {
          {
            /* If it fits, tweak parameters to fit the "generic" 32-bit
            /* If it fits, tweak parameters to fit the "generic" 32-bit
               lseek and use that.  */
               lseek and use that.  */
            SI fd = arg1;
            SI fd = arg1;
            SI offs_hi = arg2;
            SI offs_hi = arg2;
            SI offs_lo = arg3;
            SI offs_lo = arg3;
            SI resultp = arg4;
            SI resultp = arg4;
            SI whence = arg5;
            SI whence = arg5;
            retval = 0;
            retval = 0;
 
 
            if (!((offs_hi == 0 && offs_lo >= 0)
            if (!((offs_hi == 0 && offs_lo >= 0)
                  || (offs_hi == -1 &&  offs_lo < 0)))
                  || (offs_hi == -1 &&  offs_lo < 0)))
              {
              {
                retval
                retval
                  = cris_unknown_syscall (current_cpu, pc,
                  = cris_unknown_syscall (current_cpu, pc,
                                          "Unimplemented llseek offset,"
                                          "Unimplemented llseek offset,"
                                          " fd %d: 0x%x:0x%x\n",
                                          " fd %d: 0x%x:0x%x\n",
                                          fd, (unsigned) arg2,
                                          fd, (unsigned) arg2,
                                          (unsigned) arg3);
                                          (unsigned) arg3);
                break;
                break;
              }
              }
 
 
            s.func = TARGET_SYS_lseek;
            s.func = TARGET_SYS_lseek;
            s.arg2 = offs_lo;
            s.arg2 = offs_lo;
            s.arg3 = whence;
            s.arg3 = whence;
            if (cb_syscall (cb, &s) != CB_RC_OK)
            if (cb_syscall (cb, &s) != CB_RC_OK)
              {
              {
                sim_io_eprintf (sd, "Break 13: invalid %d?  Returned %ld\n", callnum,
                sim_io_eprintf (sd, "Break 13: invalid %d?  Returned %ld\n", callnum,
                                s.result);
                                s.result);
                sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGILL);
                sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGILL);
              }
              }
            if (s.result < 0)
            if (s.result < 0)
              retval = -s.errcode;
              retval = -s.errcode;
            else
            else
              {
              {
                sim_core_write_unaligned_4 (current_cpu, pc, 0, resultp,
                sim_core_write_unaligned_4 (current_cpu, pc, 0, resultp,
                                            s.result);
                                            s.result);
                sim_core_write_unaligned_4 (current_cpu, pc, 0, resultp + 4,
                sim_core_write_unaligned_4 (current_cpu, pc, 0, resultp + 4,
                                            s.result < 0 ? -1 : 0);
                                            s.result < 0 ? -1 : 0);
              }
              }
            break;
            break;
          }
          }
 
 
        /* This one does have a generic callback function, but at the time
        /* This one does have a generic callback function, but at the time
           of this writing, cb_syscall does not have code for it, and we
           of this writing, cb_syscall does not have code for it, and we
           need target-specific code for the threads implementation
           need target-specific code for the threads implementation
           anyway.  */
           anyway.  */
        case TARGET_SYS_kill:
        case TARGET_SYS_kill:
          {
          {
            USI pid = arg1;
            USI pid = arg1;
            USI sig = arg2;
            USI sig = arg2;
 
 
            retval = 0;
            retval = 0;
 
 
            /* At kill(2), glibc sets signal masks such that the thread
            /* At kill(2), glibc sets signal masks such that the thread
               machinery is initialized.  Still, there is and was only
               machinery is initialized.  Still, there is and was only
               one thread.  */
               one thread.  */
            if (current_cpu->max_threadid == 0)
            if (current_cpu->max_threadid == 0)
              {
              {
                if (pid != TARGET_PID)
                if (pid != TARGET_PID)
                  {
                  {
                    retval = -cb_host_to_target_errno (cb, EPERM);
                    retval = -cb_host_to_target_errno (cb, EPERM);
                    break;
                    break;
                  }
                  }
 
 
                /* FIXME: Signal infrastructure (target-to-sim mapping).  */
                /* FIXME: Signal infrastructure (target-to-sim mapping).  */
                if (sig == TARGET_SIGABRT)
                if (sig == TARGET_SIGABRT)
                  /* A call "abort ()", i.e. "kill (getpid(), SIGABRT)" is
                  /* A call "abort ()", i.e. "kill (getpid(), SIGABRT)" is
                     the end-point for failing GCC test-cases.  */
                     the end-point for failing GCC test-cases.  */
                  sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped,
                  sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped,
                                   SIM_SIGABRT);
                                   SIM_SIGABRT);
                else
                else
                  {
                  {
                    sim_io_eprintf (sd, "Unimplemented signal: %d\n", sig);
                    sim_io_eprintf (sd, "Unimplemented signal: %d\n", sig);
                    sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped,
                    sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped,
                                     SIM_SIGILL);
                                     SIM_SIGILL);
                  }
                  }
 
 
                /* This will not be reached.  */
                /* This will not be reached.  */
                abort ();
                abort ();
              }
              }
            else
            else
              retval = deliver_signal (current_cpu, sig, pid);
              retval = deliver_signal (current_cpu, sig, pid);
            break;
            break;
          }
          }
 
 
        case TARGET_SYS_rt_sigprocmask:
        case TARGET_SYS_rt_sigprocmask:
          {
          {
            int i;
            int i;
            USI how = arg1;
            USI how = arg1;
            USI newsetp = arg2;
            USI newsetp = arg2;
            USI oldsetp = arg3;
            USI oldsetp = arg3;
 
 
            if (how != TARGET_SIG_BLOCK
            if (how != TARGET_SIG_BLOCK
                && how != TARGET_SIG_SETMASK
                && how != TARGET_SIG_SETMASK
                && how != TARGET_SIG_UNBLOCK)
                && how != TARGET_SIG_UNBLOCK)
              {
              {
                retval
                retval
                  = cris_unknown_syscall (current_cpu, pc,
                  = cris_unknown_syscall (current_cpu, pc,
                                          "Unimplemented rt_sigprocmask "
                                          "Unimplemented rt_sigprocmask "
                                          "syscall (0x%x, 0x%x, 0x%x)\n",
                                          "syscall (0x%x, 0x%x, 0x%x)\n",
                                          arg1, arg2, arg3);
                                          arg1, arg2, arg3);
                break;
                break;
              }
              }
 
 
            if (newsetp)
            if (newsetp)
              {
              {
                USI set_low
                USI set_low
                  = sim_core_read_unaligned_4 (current_cpu, pc, 0,
                  = sim_core_read_unaligned_4 (current_cpu, pc, 0,
                                               newsetp);
                                               newsetp);
                USI set_high
                USI set_high
                  = sim_core_read_unaligned_4 (current_cpu, pc, 0,
                  = sim_core_read_unaligned_4 (current_cpu, pc, 0,
                                               newsetp + 4);
                                               newsetp + 4);
 
 
                /* The sigmask is kept in the per-thread data, so we may
                /* The sigmask is kept in the per-thread data, so we may
                   need to create the first one.  */
                   need to create the first one.  */
                if (current_cpu->thread_data == NULL)
                if (current_cpu->thread_data == NULL)
                  make_first_thread (current_cpu);
                  make_first_thread (current_cpu);
 
 
                if (how == TARGET_SIG_SETMASK)
                if (how == TARGET_SIG_SETMASK)
                  for (i = 0; i < 64; i++)
                  for (i = 0; i < 64; i++)
                    current_cpu->thread_data[threadno].sigdata[i].blocked = 0;
                    current_cpu->thread_data[threadno].sigdata[i].blocked = 0;
 
 
                for (i = 0; i < 32; i++)
                for (i = 0; i < 32; i++)
                  if ((set_low & (1 << i)))
                  if ((set_low & (1 << i)))
                    current_cpu->thread_data[threadno].sigdata[i + 1].blocked
                    current_cpu->thread_data[threadno].sigdata[i + 1].blocked
                      = (how != TARGET_SIG_UNBLOCK);
                      = (how != TARGET_SIG_UNBLOCK);
 
 
                for (i = 0; i < 31; i++)
                for (i = 0; i < 31; i++)
                  if ((set_high & (1 << i)))
                  if ((set_high & (1 << i)))
                    current_cpu->thread_data[threadno].sigdata[i + 33].blocked
                    current_cpu->thread_data[threadno].sigdata[i + 33].blocked
                      = (how != TARGET_SIG_UNBLOCK);
                      = (how != TARGET_SIG_UNBLOCK);
 
 
                /* The mask changed, so a signal may be unblocked for
                /* The mask changed, so a signal may be unblocked for
                   execution.  */
                   execution.  */
                current_cpu->thread_data[threadno].sigpending = 1;
                current_cpu->thread_data[threadno].sigpending = 1;
              }
              }
 
 
            if (oldsetp != 0)
            if (oldsetp != 0)
              {
              {
                USI set_low = 0;
                USI set_low = 0;
                USI set_high = 0;
                USI set_high = 0;
 
 
                for (i = 0; i < 32; i++)
                for (i = 0; i < 32; i++)
                  if (current_cpu->thread_data[threadno]
                  if (current_cpu->thread_data[threadno]
                      .sigdata[i + 1].blocked)
                      .sigdata[i + 1].blocked)
                    set_low |= 1 << i;
                    set_low |= 1 << i;
                for (i = 0; i < 31; i++)
                for (i = 0; i < 31; i++)
                  if (current_cpu->thread_data[threadno]
                  if (current_cpu->thread_data[threadno]
                      .sigdata[i + 33].blocked)
                      .sigdata[i + 33].blocked)
                    set_high |= 1 << i;
                    set_high |= 1 << i;
 
 
                sim_core_write_unaligned_4 (current_cpu, pc, 0, oldsetp + 0, set_low);
                sim_core_write_unaligned_4 (current_cpu, pc, 0, oldsetp + 0, set_low);
                sim_core_write_unaligned_4 (current_cpu, pc, 0, oldsetp + 4, set_high);
                sim_core_write_unaligned_4 (current_cpu, pc, 0, oldsetp + 4, set_high);
              }
              }
 
 
            retval = 0;
            retval = 0;
            break;
            break;
          }
          }
 
 
        case TARGET_SYS_sigreturn:
        case TARGET_SYS_sigreturn:
          {
          {
            int i;
            int i;
            bfd_byte regbuf[4];
            bfd_byte regbuf[4];
            int was_sigsuspended;
            int was_sigsuspended;
 
 
            if (current_cpu->thread_data == NULL
            if (current_cpu->thread_data == NULL
                /* The CPU context is saved with the simulator data, not
                /* The CPU context is saved with the simulator data, not
                   on the stack as in the real world.  */
                   on the stack as in the real world.  */
                || (current_cpu->thread_data[threadno].cpu_context_atsignal
                || (current_cpu->thread_data[threadno].cpu_context_atsignal
                    == NULL))
                    == NULL))
              {
              {
                retval
                retval
                  = cris_unknown_syscall (current_cpu, pc,
                  = cris_unknown_syscall (current_cpu, pc,
                                          "Invalid sigreturn syscall: "
                                          "Invalid sigreturn syscall: "
                                          "no signal handler active "
                                          "no signal handler active "
                                          "(0x%lx, 0x%lx, 0x%lx, 0x%lx, "
                                          "(0x%lx, 0x%lx, 0x%lx, 0x%lx, "
                                          "0x%lx, 0x%lx)\n",
                                          "0x%lx, 0x%lx)\n",
                                          (unsigned long) arg1,
                                          (unsigned long) arg1,
                                          (unsigned long) arg2,
                                          (unsigned long) arg2,
                                          (unsigned long) arg3,
                                          (unsigned long) arg3,
                                          (unsigned long) arg4,
                                          (unsigned long) arg4,
                                          (unsigned long) arg5,
                                          (unsigned long) arg5,
                                          (unsigned long) arg6);
                                          (unsigned long) arg6);
                break;
                break;
              }
              }
 
 
            was_sigsuspended
            was_sigsuspended
              = current_cpu->thread_data[threadno].sigsuspended;
              = current_cpu->thread_data[threadno].sigsuspended;
 
 
            /* Restore the sigmask, either from the stack copy made when
            /* Restore the sigmask, either from the stack copy made when
               the sighandler was called, or from the saved state
               the sighandler was called, or from the saved state
               specifically for sigsuspend(2).  */
               specifically for sigsuspend(2).  */
            if (was_sigsuspended)
            if (was_sigsuspended)
              {
              {
                current_cpu->thread_data[threadno].sigsuspended = 0;
                current_cpu->thread_data[threadno].sigsuspended = 0;
                for (i = 0; i < 64; i++)
                for (i = 0; i < 64; i++)
                  current_cpu->thread_data[threadno].sigdata[i].blocked
                  current_cpu->thread_data[threadno].sigdata[i].blocked
                    = current_cpu->thread_data[threadno]
                    = current_cpu->thread_data[threadno]
                    .sigdata[i].blocked_suspendsave;
                    .sigdata[i].blocked_suspendsave;
              }
              }
            else
            else
              {
              {
                USI sp;
                USI sp;
                USI set_low;
                USI set_low;
                USI set_high;
                USI set_high;
 
 
                (*CPU_REG_FETCH (current_cpu)) (current_cpu,
                (*CPU_REG_FETCH (current_cpu)) (current_cpu,
                                            H_GR_SP, regbuf, 4);
                                            H_GR_SP, regbuf, 4);
                sp = bfd_getl32 (regbuf);
                sp = bfd_getl32 (regbuf);
                set_low
                set_low
                  = sim_core_read_unaligned_4 (current_cpu, pc, 0, sp);
                  = sim_core_read_unaligned_4 (current_cpu, pc, 0, sp);
                set_high
                set_high
                  = sim_core_read_unaligned_4 (current_cpu, pc, 0, sp + 4);
                  = sim_core_read_unaligned_4 (current_cpu, pc, 0, sp + 4);
 
 
                for (i = 0; i < 32; i++)
                for (i = 0; i < 32; i++)
                  current_cpu->thread_data[threadno].sigdata[i + 1].blocked
                  current_cpu->thread_data[threadno].sigdata[i + 1].blocked
                    = (set_low & (1 << i)) != 0;
                    = (set_low & (1 << i)) != 0;
                for (i = 0; i < 31; i++)
                for (i = 0; i < 31; i++)
                  current_cpu->thread_data[threadno].sigdata[i + 33].blocked
                  current_cpu->thread_data[threadno].sigdata[i + 33].blocked
                    = (set_high & (1 << i)) != 0;
                    = (set_high & (1 << i)) != 0;
              }
              }
 
 
            /* The mask changed, so a signal may be unblocked for
            /* The mask changed, so a signal may be unblocked for
               execution.  */
               execution.  */
            current_cpu->thread_data[threadno].sigpending = 1;
            current_cpu->thread_data[threadno].sigpending = 1;
 
 
            memcpy (&current_cpu->cpu_data_placeholder,
            memcpy (&current_cpu->cpu_data_placeholder,
                    current_cpu->thread_data[threadno].cpu_context_atsignal,
                    current_cpu->thread_data[threadno].cpu_context_atsignal,
                    current_cpu->thread_cpu_data_size);
                    current_cpu->thread_cpu_data_size);
            free (current_cpu->thread_data[threadno].cpu_context_atsignal);
            free (current_cpu->thread_data[threadno].cpu_context_atsignal);
            current_cpu->thread_data[threadno].cpu_context_atsignal = NULL;
            current_cpu->thread_data[threadno].cpu_context_atsignal = NULL;
 
 
            /* The return value must come from the saved R10.  */
            /* The return value must come from the saved R10.  */
            (*CPU_REG_FETCH (current_cpu)) (current_cpu, H_GR_R10, regbuf, 4);
            (*CPU_REG_FETCH (current_cpu)) (current_cpu, H_GR_R10, regbuf, 4);
            retval = bfd_getl32 (regbuf);
            retval = bfd_getl32 (regbuf);
 
 
            /* We must also break the "sigsuspension loop".  */
            /* We must also break the "sigsuspension loop".  */
            if (was_sigsuspended)
            if (was_sigsuspended)
              sim_pc_set (current_cpu, sim_pc_get (current_cpu) + 2);
              sim_pc_set (current_cpu, sim_pc_get (current_cpu) + 2);
            break;
            break;
          }
          }
 
 
        case TARGET_SYS_rt_sigsuspend:
        case TARGET_SYS_rt_sigsuspend:
          {
          {
            USI newsetp = arg1;
            USI newsetp = arg1;
            USI setsize = arg2;
            USI setsize = arg2;
 
 
            if (setsize != 8)
            if (setsize != 8)
              {
              {
                retval
                retval
                  = cris_unknown_syscall (current_cpu, pc,
                  = cris_unknown_syscall (current_cpu, pc,
                                          "Unimplemented rt_sigsuspend syscall"
                                          "Unimplemented rt_sigsuspend syscall"
                                          " arguments (0x%lx, 0x%lx)\n",
                                          " arguments (0x%lx, 0x%lx)\n",
                                          (unsigned long) arg1,
                                          (unsigned long) arg1,
                                          (unsigned long) arg2);
                                          (unsigned long) arg2);
                break;
                break;
              }
              }
 
 
            /* Don't change the signal mask if we're already in
            /* Don't change the signal mask if we're already in
               sigsuspend state (i.e. this syscall is a rerun).  */
               sigsuspend state (i.e. this syscall is a rerun).  */
            else if (!current_cpu->thread_data[threadno].sigsuspended)
            else if (!current_cpu->thread_data[threadno].sigsuspended)
              {
              {
                USI set_low
                USI set_low
                  = sim_core_read_unaligned_4 (current_cpu, pc, 0,
                  = sim_core_read_unaligned_4 (current_cpu, pc, 0,
                                               newsetp);
                                               newsetp);
                USI set_high
                USI set_high
                  = sim_core_read_unaligned_4 (current_cpu, pc, 0,
                  = sim_core_read_unaligned_4 (current_cpu, pc, 0,
                                               newsetp + 4);
                                               newsetp + 4);
                int i;
                int i;
 
 
                /* Save the current sigmask and insert the user-supplied
                /* Save the current sigmask and insert the user-supplied
                   one.  */
                   one.  */
                for (i = 0; i < 32; i++)
                for (i = 0; i < 32; i++)
                  {
                  {
                    current_cpu->thread_data[threadno]
                    current_cpu->thread_data[threadno]
                      .sigdata[i + 1].blocked_suspendsave
                      .sigdata[i + 1].blocked_suspendsave
                      = current_cpu->thread_data[threadno]
                      = current_cpu->thread_data[threadno]
                      .sigdata[i + 1].blocked;
                      .sigdata[i + 1].blocked;
 
 
                    current_cpu->thread_data[threadno]
                    current_cpu->thread_data[threadno]
                      .sigdata[i + 1].blocked = (set_low & (1 << i)) != 0;
                      .sigdata[i + 1].blocked = (set_low & (1 << i)) != 0;
                  }
                  }
                for (i = 0; i < 31; i++)
                for (i = 0; i < 31; i++)
                  {
                  {
                    current_cpu->thread_data[threadno]
                    current_cpu->thread_data[threadno]
                      .sigdata[i + 33].blocked_suspendsave
                      .sigdata[i + 33].blocked_suspendsave
                      = current_cpu->thread_data[threadno]
                      = current_cpu->thread_data[threadno]
                      .sigdata[i + 33].blocked;
                      .sigdata[i + 33].blocked;
                    current_cpu->thread_data[threadno]
                    current_cpu->thread_data[threadno]
                      .sigdata[i + 33].blocked = (set_high & (1 << i)) != 0;
                      .sigdata[i + 33].blocked = (set_high & (1 << i)) != 0;
                  }
                  }
 
 
                current_cpu->thread_data[threadno].sigsuspended = 1;
                current_cpu->thread_data[threadno].sigsuspended = 1;
 
 
                /* The mask changed, so a signal may be unblocked for
                /* The mask changed, so a signal may be unblocked for
                   execution. */
                   execution. */
                current_cpu->thread_data[threadno].sigpending = 1;
                current_cpu->thread_data[threadno].sigpending = 1;
              }
              }
 
 
            /* Because we don't use arg1 (newsetp) when this syscall is
            /* Because we don't use arg1 (newsetp) when this syscall is
               rerun, it doesn't matter that we overwrite it with the
               rerun, it doesn't matter that we overwrite it with the
               (constant) return value.  */
               (constant) return value.  */
            retval = -cb_host_to_target_errno (cb, EINTR);
            retval = -cb_host_to_target_errno (cb, EINTR);
            sim_pc_set (current_cpu, pc);
            sim_pc_set (current_cpu, pc);
            break;
            break;
          }
          }
 
 
          /* Add case labels here for other syscalls using the 32-bit
          /* Add case labels here for other syscalls using the 32-bit
             "struct stat", provided they have a corresponding simulator
             "struct stat", provided they have a corresponding simulator
             function of course.  */
             function of course.  */
        case TARGET_SYS_stat:
        case TARGET_SYS_stat:
        case TARGET_SYS_fstat:
        case TARGET_SYS_fstat:
          {
          {
            /* As long as the infrastructure doesn't cache anything
            /* As long as the infrastructure doesn't cache anything
               related to the stat mapping, this trick gets us a dual
               related to the stat mapping, this trick gets us a dual
               "struct stat"-type mapping in the least error-prone way.  */
               "struct stat"-type mapping in the least error-prone way.  */
            const char *saved_map = cb->stat_map;
            const char *saved_map = cb->stat_map;
            CB_TARGET_DEFS_MAP *saved_syscall_map = cb->syscall_map;
            CB_TARGET_DEFS_MAP *saved_syscall_map = cb->syscall_map;
 
 
            cb->syscall_map = (CB_TARGET_DEFS_MAP *) syscall_stat32_map;
            cb->syscall_map = (CB_TARGET_DEFS_MAP *) syscall_stat32_map;
            cb->stat_map = stat32_map;
            cb->stat_map = stat32_map;
 
 
            if (cb_syscall (cb, &s) != CB_RC_OK)
            if (cb_syscall (cb, &s) != CB_RC_OK)
              {
              {
                abort ();
                abort ();
                sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped,
                sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped,
                                 SIM_SIGILL);
                                 SIM_SIGILL);
              }
              }
            retval = s.result == -1 ? -s.errcode : s.result;
            retval = s.result == -1 ? -s.errcode : s.result;
 
 
            cb->stat_map = saved_map;
            cb->stat_map = saved_map;
            cb->syscall_map = saved_syscall_map;
            cb->syscall_map = saved_syscall_map;
            break;
            break;
          }
          }
 
 
        case TARGET_SYS_getcwd:
        case TARGET_SYS_getcwd:
          {
          {
            USI buf = arg1;
            USI buf = arg1;
            USI size = arg2;
            USI size = arg2;
 
 
            char *cwd = xmalloc (SIM_PATHMAX);
            char *cwd = xmalloc (SIM_PATHMAX);
            if (cwd != getcwd (cwd, SIM_PATHMAX))
            if (cwd != getcwd (cwd, SIM_PATHMAX))
              abort ();
              abort ();
 
 
            /* FIXME: When and if we support chdir, we need something
            /* FIXME: When and if we support chdir, we need something
               a bit more elaborate.  */
               a bit more elaborate.  */
            if (simulator_sysroot[0] != '\0')
            if (simulator_sysroot[0] != '\0')
              strcpy (cwd, "/");
              strcpy (cwd, "/");
 
 
            retval = -cb_host_to_target_errno (cb, ERANGE);
            retval = -cb_host_to_target_errno (cb, ERANGE);
            if (strlen (cwd) + 1 <= size)
            if (strlen (cwd) + 1 <= size)
              {
              {
                retval = strlen (cwd) + 1;
                retval = strlen (cwd) + 1;
                if (sim_core_write_buffer (sd, current_cpu, 0, cwd,
                if (sim_core_write_buffer (sd, current_cpu, 0, cwd,
                                           buf, retval)
                                           buf, retval)
                    != (unsigned int) retval)
                    != (unsigned int) retval)
                  retval = -cb_host_to_target_errno (cb, EFAULT);
                  retval = -cb_host_to_target_errno (cb, EFAULT);
              }
              }
            free (cwd);
            free (cwd);
            break;
            break;
          }
          }
 
 
        case TARGET_SYS_readlink:
        case TARGET_SYS_readlink:
          {
          {
            SI path = arg1;
            SI path = arg1;
            SI buf = arg2;
            SI buf = arg2;
            SI bufsiz = arg3;
            SI bufsiz = arg3;
            char *pbuf = xmalloc (SIM_PATHMAX);
            char *pbuf = xmalloc (SIM_PATHMAX);
            char *lbuf = xmalloc (SIM_PATHMAX);
            char *lbuf = xmalloc (SIM_PATHMAX);
            char *lbuf_alloc = lbuf;
            char *lbuf_alloc = lbuf;
            int nchars = -1;
            int nchars = -1;
            int i;
            int i;
            int o = 0;
            int o = 0;
 
 
            if (sim_core_read_unaligned_1 (current_cpu, pc, 0, path) == '/')
            if (sim_core_read_unaligned_1 (current_cpu, pc, 0, path) == '/')
              {
              {
                strcpy (pbuf, simulator_sysroot);
                strcpy (pbuf, simulator_sysroot);
                o += strlen (simulator_sysroot);
                o += strlen (simulator_sysroot);
              }
              }
 
 
            for (i = 0; i + o < SIM_PATHMAX; i++)
            for (i = 0; i + o < SIM_PATHMAX; i++)
              {
              {
                pbuf[i + o]
                pbuf[i + o]
                  = sim_core_read_unaligned_1 (current_cpu, pc, 0, path + i);
                  = sim_core_read_unaligned_1 (current_cpu, pc, 0, path + i);
                if (pbuf[i + o] == 0)
                if (pbuf[i + o] == 0)
                  break;
                  break;
              }
              }
 
 
            if (i + o == SIM_PATHMAX)
            if (i + o == SIM_PATHMAX)
              {
              {
                retval = -cb_host_to_target_errno (cb, ENAMETOOLONG);
                retval = -cb_host_to_target_errno (cb, ENAMETOOLONG);
                break;
                break;
              }
              }
 
 
            /* Intervene calls for certain files expected in the target
            /* Intervene calls for certain files expected in the target
               proc file system.  */
               proc file system.  */
            if (strcmp (pbuf + strlen (simulator_sysroot),
            if (strcmp (pbuf + strlen (simulator_sysroot),
                        "/proc/" XSTRING (TARGET_PID) "/exe") == 0)
                        "/proc/" XSTRING (TARGET_PID) "/exe") == 0)
              {
              {
                char *argv0
                char *argv0
                  = (STATE_PROG_ARGV (sd) != NULL
                  = (STATE_PROG_ARGV (sd) != NULL
                     ? *STATE_PROG_ARGV (sd) : NULL);
                     ? *STATE_PROG_ARGV (sd) : NULL);
 
 
                if (argv0 == NULL || *argv0 == '.')
                if (argv0 == NULL || *argv0 == '.')
                  {
                  {
                    retval
                    retval
                      = cris_unknown_syscall (current_cpu, pc,
                      = cris_unknown_syscall (current_cpu, pc,
                                              "Unimplemented readlink syscall "
                                              "Unimplemented readlink syscall "
                                              "(0x%lx: [\"%s\"], 0x%lx)\n",
                                              "(0x%lx: [\"%s\"], 0x%lx)\n",
                                              (unsigned long) arg1, pbuf,
                                              (unsigned long) arg1, pbuf,
                                              (unsigned long) arg2);
                                              (unsigned long) arg2);
                    break;
                    break;
                  }
                  }
                else if (*argv0 == '/')
                else if (*argv0 == '/')
                  {
                  {
                    if (strncmp (simulator_sysroot, argv0,
                    if (strncmp (simulator_sysroot, argv0,
                                 strlen (simulator_sysroot)) == 0)
                                 strlen (simulator_sysroot)) == 0)
                      argv0 += strlen (simulator_sysroot);
                      argv0 += strlen (simulator_sysroot);
 
 
                    strcpy (lbuf, argv0);
                    strcpy (lbuf, argv0);
                    nchars = strlen (argv0) + 1;
                    nchars = strlen (argv0) + 1;
                  }
                  }
                else
                else
                  {
                  {
                    if (getcwd (lbuf, SIM_PATHMAX) != NULL
                    if (getcwd (lbuf, SIM_PATHMAX) != NULL
                        && strlen (lbuf) + 2 + strlen (argv0) < SIM_PATHMAX)
                        && strlen (lbuf) + 2 + strlen (argv0) < SIM_PATHMAX)
                      {
                      {
                        if (strncmp (simulator_sysroot, lbuf,
                        if (strncmp (simulator_sysroot, lbuf,
                                     strlen (simulator_sysroot)) == 0)
                                     strlen (simulator_sysroot)) == 0)
                          lbuf += strlen (simulator_sysroot);
                          lbuf += strlen (simulator_sysroot);
 
 
                        strcat (lbuf, "/");
                        strcat (lbuf, "/");
                        strcat (lbuf, argv0);
                        strcat (lbuf, argv0);
                        nchars = strlen (lbuf) + 1;
                        nchars = strlen (lbuf) + 1;
                      }
                      }
                    else
                    else
                      abort ();
                      abort ();
                  }
                  }
              }
              }
            else
            else
              nchars = readlink (pbuf, lbuf, SIM_PATHMAX);
              nchars = readlink (pbuf, lbuf, SIM_PATHMAX);
 
 
            /* We trust that the readlink result returns a *relative*
            /* We trust that the readlink result returns a *relative*
               link, or one already adjusted for the file-path-prefix.
               link, or one already adjusted for the file-path-prefix.
               (We can't generally tell the difference, so we go with
               (We can't generally tell the difference, so we go with
               the easiest decision; no adjustment.)  */
               the easiest decision; no adjustment.)  */
 
 
            if (nchars == -1)
            if (nchars == -1)
              {
              {
                retval = -cb_host_to_target_errno (cb, errno);
                retval = -cb_host_to_target_errno (cb, errno);
                break;
                break;
              }
              }
 
 
            if (bufsiz < nchars)
            if (bufsiz < nchars)
              nchars = bufsiz;
              nchars = bufsiz;
 
 
            if (sim_core_write_buffer (sd, current_cpu, write_map, lbuf,
            if (sim_core_write_buffer (sd, current_cpu, write_map, lbuf,
                                       buf, nchars) != (unsigned int) nchars)
                                       buf, nchars) != (unsigned int) nchars)
              retval = -cb_host_to_target_errno (cb, EFAULT);
              retval = -cb_host_to_target_errno (cb, EFAULT);
            else
            else
              retval = nchars;
              retval = nchars;
 
 
            free (pbuf);
            free (pbuf);
            free (lbuf_alloc);
            free (lbuf_alloc);
            break;
            break;
          }
          }
 
 
        case TARGET_SYS_sched_getscheduler:
        case TARGET_SYS_sched_getscheduler:
          {
          {
            USI pid = arg1;
            USI pid = arg1;
 
 
            /* FIXME: Search (other) existing threads.  */
            /* FIXME: Search (other) existing threads.  */
            if (pid != 0 && pid != TARGET_PID)
            if (pid != 0 && pid != TARGET_PID)
              retval = -cb_host_to_target_errno (cb, ESRCH);
              retval = -cb_host_to_target_errno (cb, ESRCH);
            else
            else
              retval = TARGET_SCHED_OTHER;
              retval = TARGET_SCHED_OTHER;
            break;
            break;
          }
          }
 
 
        case TARGET_SYS_sched_getparam:
        case TARGET_SYS_sched_getparam:
          {
          {
            USI pid = arg1;
            USI pid = arg1;
            USI paramp = arg2;
            USI paramp = arg2;
 
 
            /* The kernel says:
            /* The kernel says:
               struct sched_param {
               struct sched_param {
                        int sched_priority;
                        int sched_priority;
               }; */
               }; */
 
 
            if (pid != 0 && pid != TARGET_PID)
            if (pid != 0 && pid != TARGET_PID)
              retval = -cb_host_to_target_errno (cb, ESRCH);
              retval = -cb_host_to_target_errno (cb, ESRCH);
            else
            else
              {
              {
                /* FIXME: Save scheduler setting before threads are
                /* FIXME: Save scheduler setting before threads are
                   created too.  */
                   created too.  */
                sim_core_write_unaligned_4 (current_cpu, pc, 0, paramp,
                sim_core_write_unaligned_4 (current_cpu, pc, 0, paramp,
                                            current_cpu->thread_data != NULL
                                            current_cpu->thread_data != NULL
                                            ? (current_cpu
                                            ? (current_cpu
                                               ->thread_data[threadno]
                                               ->thread_data[threadno]
                                               .priority)
                                               .priority)
                                            : 0);
                                            : 0);
                retval = 0;
                retval = 0;
              }
              }
            break;
            break;
          }
          }
 
 
        case TARGET_SYS_sched_setparam:
        case TARGET_SYS_sched_setparam:
          {
          {
            USI pid = arg1;
            USI pid = arg1;
            USI paramp = arg2;
            USI paramp = arg2;
 
 
            if ((pid != 0 && pid != TARGET_PID)
            if ((pid != 0 && pid != TARGET_PID)
                || sim_core_read_unaligned_4 (current_cpu, pc, 0,
                || sim_core_read_unaligned_4 (current_cpu, pc, 0,
                                              paramp) != 0)
                                              paramp) != 0)
              retval = -cb_host_to_target_errno (cb, EINVAL);
              retval = -cb_host_to_target_errno (cb, EINVAL);
            else
            else
              retval = 0;
              retval = 0;
            break;
            break;
          }
          }
 
 
        case TARGET_SYS_sched_setscheduler:
        case TARGET_SYS_sched_setscheduler:
          {
          {
            USI pid = arg1;
            USI pid = arg1;
            USI policy = arg2;
            USI policy = arg2;
            USI paramp = arg3;
            USI paramp = arg3;
 
 
            if ((pid != 0 && pid != TARGET_PID)
            if ((pid != 0 && pid != TARGET_PID)
                || policy != TARGET_SCHED_OTHER
                || policy != TARGET_SCHED_OTHER
                || sim_core_read_unaligned_4 (current_cpu, pc, 0,
                || sim_core_read_unaligned_4 (current_cpu, pc, 0,
                                              paramp) != 0)
                                              paramp) != 0)
              retval = -cb_host_to_target_errno (cb, EINVAL);
              retval = -cb_host_to_target_errno (cb, EINVAL);
            else
            else
              /* FIXME: Save scheduler setting to be read in later
              /* FIXME: Save scheduler setting to be read in later
                 sched_getparam calls.  */
                 sched_getparam calls.  */
              retval = 0;
              retval = 0;
            break;
            break;
          }
          }
 
 
        case TARGET_SYS_sched_yield:
        case TARGET_SYS_sched_yield:
          /* We reschedule to the next thread after a syscall anyway, so
          /* We reschedule to the next thread after a syscall anyway, so
             we don't have to do anything here than to set the return
             we don't have to do anything here than to set the return
             value.  */
             value.  */
          retval = 0;
          retval = 0;
          break;
          break;
 
 
        case TARGET_SYS_sched_get_priority_min:
        case TARGET_SYS_sched_get_priority_min:
        case TARGET_SYS_sched_get_priority_max:
        case TARGET_SYS_sched_get_priority_max:
          if (arg1 != 0)
          if (arg1 != 0)
            retval = -cb_host_to_target_errno (cb, EINVAL);
            retval = -cb_host_to_target_errno (cb, EINVAL);
          else
          else
            retval = 0;
            retval = 0;
          break;
          break;
 
 
        case TARGET_SYS_ugetrlimit:
        case TARGET_SYS_ugetrlimit:
          {
          {
            unsigned int curlim, maxlim;
            unsigned int curlim, maxlim;
            if (arg1 != TARGET_RLIMIT_STACK && arg1 != TARGET_RLIMIT_NOFILE)
            if (arg1 != TARGET_RLIMIT_STACK && arg1 != TARGET_RLIMIT_NOFILE)
              {
              {
                retval = -cb_host_to_target_errno (cb, EINVAL);
                retval = -cb_host_to_target_errno (cb, EINVAL);
                break;
                break;
              }
              }
 
 
            /* The kernel says:
            /* The kernel says:
               struct rlimit {
               struct rlimit {
                       unsigned long   rlim_cur;
                       unsigned long   rlim_cur;
                       unsigned long   rlim_max;
                       unsigned long   rlim_max;
               }; */
               }; */
            if (arg1 == TARGET_RLIMIT_NOFILE)
            if (arg1 == TARGET_RLIMIT_NOFILE)
              {
              {
                /* Sadly a very low limit.  Better not lie, though.  */
                /* Sadly a very low limit.  Better not lie, though.  */
                maxlim = curlim = MAX_CALLBACK_FDS;
                maxlim = curlim = MAX_CALLBACK_FDS;
              }
              }
            else /* arg1 == TARGET_RLIMIT_STACK */
            else /* arg1 == TARGET_RLIMIT_STACK */
              {
              {
                maxlim = 0xffffffff;
                maxlim = 0xffffffff;
                curlim = 0x800000;
                curlim = 0x800000;
              }
              }
            sim_core_write_unaligned_4 (current_cpu, pc, 0, arg2, curlim);
            sim_core_write_unaligned_4 (current_cpu, pc, 0, arg2, curlim);
            sim_core_write_unaligned_4 (current_cpu, pc, 0, arg2 + 4, maxlim);
            sim_core_write_unaligned_4 (current_cpu, pc, 0, arg2 + 4, maxlim);
            retval = 0;
            retval = 0;
            break;
            break;
          }
          }
 
 
        case TARGET_SYS_setrlimit:
        case TARGET_SYS_setrlimit:
          if (arg1 != TARGET_RLIMIT_STACK)
          if (arg1 != TARGET_RLIMIT_STACK)
            {
            {
              retval = -cb_host_to_target_errno (cb, EINVAL);
              retval = -cb_host_to_target_errno (cb, EINVAL);
              break;
              break;
            }
            }
          /* FIXME: Save values for future ugetrlimit calls.  */
          /* FIXME: Save values for future ugetrlimit calls.  */
          retval = 0;
          retval = 0;
          break;
          break;
 
 
        /* Provide a very limited subset of the sysctl functions, and
        /* Provide a very limited subset of the sysctl functions, and
           abort for the rest. */
           abort for the rest. */
        case TARGET_SYS__sysctl:
        case TARGET_SYS__sysctl:
          {
          {
            /* The kernel says:
            /* The kernel says:
               struct __sysctl_args {
               struct __sysctl_args {
                int *name;
                int *name;
                int nlen;
                int nlen;
                void *oldval;
                void *oldval;
                size_t *oldlenp;
                size_t *oldlenp;
                void *newval;
                void *newval;
                size_t newlen;
                size_t newlen;
                unsigned long __unused[4];
                unsigned long __unused[4];
               }; */
               }; */
            SI name = sim_core_read_unaligned_4 (current_cpu, pc, 0, arg1);
            SI name = sim_core_read_unaligned_4 (current_cpu, pc, 0, arg1);
            SI name0 = name == 0
            SI name0 = name == 0
              ? 0 : sim_core_read_unaligned_4 (current_cpu, pc, 0, name);
              ? 0 : sim_core_read_unaligned_4 (current_cpu, pc, 0, name);
            SI name1 = name == 0
            SI name1 = name == 0
              ? 0 : sim_core_read_unaligned_4 (current_cpu, pc, 0, name + 4);
              ? 0 : sim_core_read_unaligned_4 (current_cpu, pc, 0, name + 4);
            SI nlen
            SI nlen
              =  sim_core_read_unaligned_4 (current_cpu, pc, 0, arg1 + 4);
              =  sim_core_read_unaligned_4 (current_cpu, pc, 0, arg1 + 4);
            SI oldval
            SI oldval
              =  sim_core_read_unaligned_4 (current_cpu, pc, 0, arg1 + 8);
              =  sim_core_read_unaligned_4 (current_cpu, pc, 0, arg1 + 8);
            SI oldlenp
            SI oldlenp
              =  sim_core_read_unaligned_4 (current_cpu, pc, 0, arg1 + 12);
              =  sim_core_read_unaligned_4 (current_cpu, pc, 0, arg1 + 12);
            SI oldlen = oldlenp == 0
            SI oldlen = oldlenp == 0
              ? 0 : sim_core_read_unaligned_4 (current_cpu, pc, 0, oldlenp);
              ? 0 : sim_core_read_unaligned_4 (current_cpu, pc, 0, oldlenp);
            SI newval
            SI newval
              =  sim_core_read_unaligned_4 (current_cpu, pc, 0, arg1 + 16);
              =  sim_core_read_unaligned_4 (current_cpu, pc, 0, arg1 + 16);
            SI newlen
            SI newlen
              = sim_core_read_unaligned_4 (current_cpu, pc, 0, arg1 + 20);
              = sim_core_read_unaligned_4 (current_cpu, pc, 0, arg1 + 20);
 
 
            if (name0 == TARGET_CTL_KERN && name1 == TARGET_CTL_KERN_VERSION)
            if (name0 == TARGET_CTL_KERN && name1 == TARGET_CTL_KERN_VERSION)
              {
              {
                SI to_write = oldlen < (SI) sizeof (TARGET_UTSNAME)
                SI to_write = oldlen < (SI) sizeof (TARGET_UTSNAME)
                  ? oldlen : (SI) sizeof (TARGET_UTSNAME);
                  ? oldlen : (SI) sizeof (TARGET_UTSNAME);
 
 
                sim_core_write_unaligned_4 (current_cpu, pc, 0, oldlenp,
                sim_core_write_unaligned_4 (current_cpu, pc, 0, oldlenp,
                                            sizeof (TARGET_UTSNAME));
                                            sizeof (TARGET_UTSNAME));
 
 
                if (sim_core_write_buffer (sd, current_cpu, write_map,
                if (sim_core_write_buffer (sd, current_cpu, write_map,
                                           TARGET_UTSNAME, oldval,
                                           TARGET_UTSNAME, oldval,
                                           to_write)
                                           to_write)
                    != (unsigned int) to_write)
                    != (unsigned int) to_write)
                  retval = -cb_host_to_target_errno (cb, EFAULT);
                  retval = -cb_host_to_target_errno (cb, EFAULT);
                else
                else
                  retval = 0;
                  retval = 0;
                break;
                break;
              }
              }
 
 
            retval
            retval
              = cris_unknown_syscall (current_cpu, pc,
              = cris_unknown_syscall (current_cpu, pc,
                                      "Unimplemented _sysctl syscall "
                                      "Unimplemented _sysctl syscall "
                                      "(0x%lx: [0x%lx, 0x%lx],"
                                      "(0x%lx: [0x%lx, 0x%lx],"
                                      " 0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx)\n",
                                      " 0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx)\n",
                                      (unsigned long) name,
                                      (unsigned long) name,
                                      (unsigned long) name0,
                                      (unsigned long) name0,
                                      (unsigned long) name1,
                                      (unsigned long) name1,
                                      (unsigned long) nlen,
                                      (unsigned long) nlen,
                                      (unsigned long) oldval,
                                      (unsigned long) oldval,
                                      (unsigned long) oldlenp,
                                      (unsigned long) oldlenp,
                                      (unsigned long) newval,
                                      (unsigned long) newval,
                                      (unsigned long) newlen);
                                      (unsigned long) newlen);
            break;
            break;
          }
          }
 
 
        case TARGET_SYS_exit:
        case TARGET_SYS_exit:
          {
          {
            /* Here for all but the last thread.  */
            /* Here for all but the last thread.  */
            int i;
            int i;
            int pid
            int pid
              = current_cpu->thread_data[threadno].threadid + TARGET_PID;
              = current_cpu->thread_data[threadno].threadid + TARGET_PID;
            int ppid
            int ppid
              = (current_cpu->thread_data[threadno].parent_threadid
              = (current_cpu->thread_data[threadno].parent_threadid
                 + TARGET_PID);
                 + TARGET_PID);
            int exitsig = current_cpu->thread_data[threadno].exitsig;
            int exitsig = current_cpu->thread_data[threadno].exitsig;
 
 
            /* Any children are now all orphans.  */
            /* Any children are now all orphans.  */
            for (i = 0; i < SIM_TARGET_MAX_THREADS; i++)
            for (i = 0; i < SIM_TARGET_MAX_THREADS; i++)
              if (current_cpu->thread_data[i].parent_threadid
              if (current_cpu->thread_data[i].parent_threadid
                  == current_cpu->thread_data[threadno].threadid)
                  == current_cpu->thread_data[threadno].threadid)
                /* Make getppid(2) return 1 for them, poor little ones.  */
                /* Make getppid(2) return 1 for them, poor little ones.  */
                current_cpu->thread_data[i].parent_threadid = -TARGET_PID + 1;
                current_cpu->thread_data[i].parent_threadid = -TARGET_PID + 1;
 
 
            /* Free the cpu context data.  When the parent has received
            /* Free the cpu context data.  When the parent has received
               the exit status, we'll clear the entry too.  */
               the exit status, we'll clear the entry too.  */
            free (current_cpu->thread_data[threadno].cpu_context);
            free (current_cpu->thread_data[threadno].cpu_context);
            current_cpu->thread_data[threadno].cpu_context = NULL;
            current_cpu->thread_data[threadno].cpu_context = NULL;
            current_cpu->m1threads--;
            current_cpu->m1threads--;
            if (arg1 != 0)
            if (arg1 != 0)
              {
              {
                sim_io_eprintf (sd, "Thread %d exited with status %d\n",
                sim_io_eprintf (sd, "Thread %d exited with status %d\n",
                                pid, arg1);
                                pid, arg1);
                sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped,
                sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped,
                                 SIM_SIGILL);
                                 SIM_SIGILL);
              }
              }
 
 
            /* Still, we may want to support non-zero exit values.  */
            /* Still, we may want to support non-zero exit values.  */
            current_cpu->thread_data[threadno].exitval = arg1 << 8;
            current_cpu->thread_data[threadno].exitval = arg1 << 8;
 
 
            if (exitsig)
            if (exitsig)
              deliver_signal (current_cpu, exitsig, ppid);
              deliver_signal (current_cpu, exitsig, ppid);
            break;
            break;
          }
          }
 
 
        case TARGET_SYS_clone:
        case TARGET_SYS_clone:
          {
          {
            int nthreads = current_cpu->m1threads + 1;
            int nthreads = current_cpu->m1threads + 1;
            void *thread_cpu_data;
            void *thread_cpu_data;
            bfd_byte old_sp_buf[4];
            bfd_byte old_sp_buf[4];
            bfd_byte sp_buf[4];
            bfd_byte sp_buf[4];
            const bfd_byte zeros[4] = { 0, 0, 0, 0 };
            const bfd_byte zeros[4] = { 0, 0, 0, 0 };
            int i;
            int i;
 
 
            /* That's right, the syscall clone arguments are reversed
            /* That's right, the syscall clone arguments are reversed
               compared to sys_clone notes in clone(2) and compared to
               compared to sys_clone notes in clone(2) and compared to
               other Linux ports (i.e. it's the same order as in the
               other Linux ports (i.e. it's the same order as in the
               clone(2) libcall).  */
               clone(2) libcall).  */
            USI flags = arg2;
            USI flags = arg2;
            USI newsp = arg1;
            USI newsp = arg1;
 
 
            if (nthreads == SIM_TARGET_MAX_THREADS)
            if (nthreads == SIM_TARGET_MAX_THREADS)
              {
              {
                retval = -cb_host_to_target_errno (cb, EAGAIN);
                retval = -cb_host_to_target_errno (cb, EAGAIN);
                break;
                break;
              }
              }
 
 
            /* FIXME: Implement the low byte.  */
            /* FIXME: Implement the low byte.  */
            if ((flags & ~TARGET_CSIGNAL) !=
            if ((flags & ~TARGET_CSIGNAL) !=
                (TARGET_CLONE_VM
                (TARGET_CLONE_VM
                 | TARGET_CLONE_FS
                 | TARGET_CLONE_FS
                 | TARGET_CLONE_FILES
                 | TARGET_CLONE_FILES
                 | TARGET_CLONE_SIGHAND)
                 | TARGET_CLONE_SIGHAND)
                || newsp == 0)
                || newsp == 0)
              {
              {
                retval
                retval
                  = cris_unknown_syscall (current_cpu, pc,
                  = cris_unknown_syscall (current_cpu, pc,
                                          "Unimplemented clone syscall "
                                          "Unimplemented clone syscall "
                                          "(0x%lx, 0x%lx)\n",
                                          "(0x%lx, 0x%lx)\n",
                                          (unsigned long) arg1,
                                          (unsigned long) arg1,
                                          (unsigned long) arg2);
                                          (unsigned long) arg2);
                break;
                break;
              }
              }
 
 
            if (current_cpu->thread_data == NULL)
            if (current_cpu->thread_data == NULL)
              make_first_thread (current_cpu);
              make_first_thread (current_cpu);
 
 
            /* The created thread will get the new SP and a cleared R10.
            /* The created thread will get the new SP and a cleared R10.
               Since it's created out of a copy of the old thread and we
               Since it's created out of a copy of the old thread and we
               don't have a set-register-function that just take the
               don't have a set-register-function that just take the
               cpu_data as a parameter, we set the childs values first,
               cpu_data as a parameter, we set the childs values first,
               and write back or overwrite them in the parent after the
               and write back or overwrite them in the parent after the
               copy.  */
               copy.  */
            (*CPU_REG_FETCH (current_cpu)) (current_cpu,
            (*CPU_REG_FETCH (current_cpu)) (current_cpu,
                                            H_GR_SP, old_sp_buf, 4);
                                            H_GR_SP, old_sp_buf, 4);
            bfd_putl32 (newsp, sp_buf);
            bfd_putl32 (newsp, sp_buf);
            (*CPU_REG_STORE (current_cpu)) (current_cpu,
            (*CPU_REG_STORE (current_cpu)) (current_cpu,
                                            H_GR_SP, sp_buf, 4);
                                            H_GR_SP, sp_buf, 4);
            (*CPU_REG_STORE (current_cpu)) (current_cpu,
            (*CPU_REG_STORE (current_cpu)) (current_cpu,
                                            H_GR_R10, (bfd_byte *) zeros, 4);
                                            H_GR_R10, (bfd_byte *) zeros, 4);
            thread_cpu_data
            thread_cpu_data
              = (*current_cpu
              = (*current_cpu
                 ->make_thread_cpu_data) (current_cpu,
                 ->make_thread_cpu_data) (current_cpu,
                                          &current_cpu->cpu_data_placeholder);
                                          &current_cpu->cpu_data_placeholder);
            (*CPU_REG_STORE (current_cpu)) (current_cpu,
            (*CPU_REG_STORE (current_cpu)) (current_cpu,
                                            H_GR_SP, old_sp_buf, 4);
                                            H_GR_SP, old_sp_buf, 4);
 
 
            retval = ++current_cpu->max_threadid + TARGET_PID;
            retval = ++current_cpu->max_threadid + TARGET_PID;
 
 
            /* Find an unused slot.  After a few threads have been created
            /* Find an unused slot.  After a few threads have been created
               and exited, the array is expected to be a bit fragmented.
               and exited, the array is expected to be a bit fragmented.
               We don't reuse the first entry, though, that of the
               We don't reuse the first entry, though, that of the
               original thread.  */
               original thread.  */
            for (i = 1; i < SIM_TARGET_MAX_THREADS; i++)
            for (i = 1; i < SIM_TARGET_MAX_THREADS; i++)
              if (current_cpu->thread_data[i].cpu_context == NULL
              if (current_cpu->thread_data[i].cpu_context == NULL
                  /* Don't reuse a zombied entry.  */
                  /* Don't reuse a zombied entry.  */
                  && current_cpu->thread_data[i].threadid == 0)
                  && current_cpu->thread_data[i].threadid == 0)
                break;
                break;
 
 
            memcpy (&current_cpu->thread_data[i],
            memcpy (&current_cpu->thread_data[i],
                    &current_cpu->thread_data[threadno],
                    &current_cpu->thread_data[threadno],
                    sizeof (current_cpu->thread_data[i]));
                    sizeof (current_cpu->thread_data[i]));
            current_cpu->thread_data[i].cpu_context = thread_cpu_data;
            current_cpu->thread_data[i].cpu_context = thread_cpu_data;
            current_cpu->thread_data[i].cpu_context_atsignal = NULL;
            current_cpu->thread_data[i].cpu_context_atsignal = NULL;
            current_cpu->thread_data[i].threadid = current_cpu->max_threadid;
            current_cpu->thread_data[i].threadid = current_cpu->max_threadid;
            current_cpu->thread_data[i].parent_threadid
            current_cpu->thread_data[i].parent_threadid
              = current_cpu->thread_data[threadno].threadid;
              = current_cpu->thread_data[threadno].threadid;
            current_cpu->thread_data[i].pipe_read_fd = 0;
            current_cpu->thread_data[i].pipe_read_fd = 0;
            current_cpu->thread_data[i].pipe_write_fd = 0;
            current_cpu->thread_data[i].pipe_write_fd = 0;
            current_cpu->thread_data[i].at_syscall = 0;
            current_cpu->thread_data[i].at_syscall = 0;
            current_cpu->thread_data[i].sigpending = 0;
            current_cpu->thread_data[i].sigpending = 0;
            current_cpu->thread_data[i].sigsuspended = 0;
            current_cpu->thread_data[i].sigsuspended = 0;
            current_cpu->thread_data[i].exitsig = flags & TARGET_CSIGNAL;
            current_cpu->thread_data[i].exitsig = flags & TARGET_CSIGNAL;
            current_cpu->m1threads = nthreads;
            current_cpu->m1threads = nthreads;
            break;
            break;
          }
          }
 
 
        /* Better watch these in case they do something necessary.  */
        /* Better watch these in case they do something necessary.  */
        case TARGET_SYS_socketcall:
        case TARGET_SYS_socketcall:
          retval = -cb_host_to_target_errno (cb, ENOSYS);
          retval = -cb_host_to_target_errno (cb, ENOSYS);
          break;
          break;
 
 
        unimplemented_syscall:
        unimplemented_syscall:
        default:
        default:
          retval
          retval
            = cris_unknown_syscall (current_cpu, pc,
            = cris_unknown_syscall (current_cpu, pc,
                                    "Unimplemented syscall: %d "
                                    "Unimplemented syscall: %d "
                                    "(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n",
                                    "(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n",
                                    callnum, arg1, arg2, arg3, arg4, arg5,
                                    callnum, arg1, arg2, arg3, arg4, arg5,
                                    arg6);
                                    arg6);
        }
        }
    }
    }
 
 
  /* Minimal support for fcntl F_GETFL as used in open+fdopen.  */
  /* Minimal support for fcntl F_GETFL as used in open+fdopen.  */
  if (callnum == TARGET_SYS_open)
  if (callnum == TARGET_SYS_open)
    {
    {
      current_cpu->last_open_fd = retval;
      current_cpu->last_open_fd = retval;
      current_cpu->last_open_flags = arg2;
      current_cpu->last_open_flags = arg2;
    }
    }
 
 
  current_cpu->last_syscall = callnum;
  current_cpu->last_syscall = callnum;
 
 
  /* A system call is a rescheduling point.  For the time being, we don't
  /* A system call is a rescheduling point.  For the time being, we don't
     reschedule anywhere else.  */
     reschedule anywhere else.  */
  if (current_cpu->m1threads != 0
  if (current_cpu->m1threads != 0
      /* We need to schedule off from an exiting thread that is the
      /* We need to schedule off from an exiting thread that is the
         second-last one.  */
         second-last one.  */
      || (current_cpu->thread_data != NULL
      || (current_cpu->thread_data != NULL
          && current_cpu->thread_data[threadno].cpu_context == NULL))
          && current_cpu->thread_data[threadno].cpu_context == NULL))
    {
    {
      bfd_byte retval_buf[4];
      bfd_byte retval_buf[4];
 
 
      current_cpu->thread_data[threadno].last_execution
      current_cpu->thread_data[threadno].last_execution
        = TARGET_TIME_MS (current_cpu);
        = TARGET_TIME_MS (current_cpu);
      bfd_putl32 (retval, retval_buf);
      bfd_putl32 (retval, retval_buf);
      (*CPU_REG_STORE (current_cpu)) (current_cpu, H_GR_R10, retval_buf, 4);
      (*CPU_REG_STORE (current_cpu)) (current_cpu, H_GR_R10, retval_buf, 4);
 
 
      current_cpu->thread_data[threadno].at_syscall = 1;
      current_cpu->thread_data[threadno].at_syscall = 1;
      reschedule (current_cpu);
      reschedule (current_cpu);
 
 
      (*CPU_REG_FETCH (current_cpu)) (current_cpu, H_GR_R10, retval_buf, 4);
      (*CPU_REG_FETCH (current_cpu)) (current_cpu, H_GR_R10, retval_buf, 4);
      retval = bfd_getl32 (retval_buf);
      retval = bfd_getl32 (retval_buf);
    }
    }
 
 
  return retval;
  return retval;
}
}
 
 
/* Callback from simulator write saying that the pipe at (reader, writer)
/* Callback from simulator write saying that the pipe at (reader, writer)
   is now non-empty (so the writer should wait until the pipe is empty, at
   is now non-empty (so the writer should wait until the pipe is empty, at
   least not write to this or any other pipe).  Simplest is to just wait
   least not write to this or any other pipe).  Simplest is to just wait
   until the pipe is empty.  */
   until the pipe is empty.  */
 
 
static void
static void
cris_pipe_nonempty (host_callback *cb ATTRIBUTE_UNUSED,
cris_pipe_nonempty (host_callback *cb ATTRIBUTE_UNUSED,
                    int reader, int writer)
                    int reader, int writer)
{
{
  SIM_CPU *cpu = current_cpu_for_cb_callback;
  SIM_CPU *cpu = current_cpu_for_cb_callback;
  const bfd_byte zeros[4] = { 0, 0, 0, 0 };
  const bfd_byte zeros[4] = { 0, 0, 0, 0 };
 
 
  /* It's the current thread: we just have to re-run the current
  /* It's the current thread: we just have to re-run the current
     syscall instruction (presumably "break 13") and change the syscall
     syscall instruction (presumably "break 13") and change the syscall
     to the special simulator-wait code.  Oh, and set a marker that
     to the special simulator-wait code.  Oh, and set a marker that
     we're waiting, so we can disambiguate the special call from a
     we're waiting, so we can disambiguate the special call from a
     program error.
     program error.
 
 
     This function may be called multiple times between cris_pipe_empty,
     This function may be called multiple times between cris_pipe_empty,
     but we must avoid e.g. decreasing PC every time.  Check fd markers
     but we must avoid e.g. decreasing PC every time.  Check fd markers
     to tell.  */
     to tell.  */
  if (cpu->thread_data == NULL)
  if (cpu->thread_data == NULL)
    {
    {
      sim_io_eprintf (CPU_STATE (cpu),
      sim_io_eprintf (CPU_STATE (cpu),
                      "Terminating simulation due to writing pipe rd:wr %d:%d"
                      "Terminating simulation due to writing pipe rd:wr %d:%d"
                      " from one single thread\n", reader, writer);
                      " from one single thread\n", reader, writer);
      sim_engine_halt (CPU_STATE (cpu), cpu,
      sim_engine_halt (CPU_STATE (cpu), cpu,
                       NULL, sim_pc_get (cpu), sim_stopped, SIM_SIGILL);
                       NULL, sim_pc_get (cpu), sim_stopped, SIM_SIGILL);
    }
    }
  else if (cpu->thread_data[cpu->threadno].pipe_write_fd == 0)
  else if (cpu->thread_data[cpu->threadno].pipe_write_fd == 0)
    {
    {
      cpu->thread_data[cpu->threadno].pipe_write_fd = writer;
      cpu->thread_data[cpu->threadno].pipe_write_fd = writer;
      cpu->thread_data[cpu->threadno].pipe_read_fd = reader;
      cpu->thread_data[cpu->threadno].pipe_read_fd = reader;
      /* FIXME: We really shouldn't change registers other than R10 in
      /* FIXME: We really shouldn't change registers other than R10 in
         syscalls (like R9), here or elsewhere.  */
         syscalls (like R9), here or elsewhere.  */
      (*CPU_REG_STORE (cpu)) (cpu, H_GR_R9, (bfd_byte *) zeros, 4);
      (*CPU_REG_STORE (cpu)) (cpu, H_GR_R9, (bfd_byte *) zeros, 4);
      sim_pc_set (cpu, sim_pc_get (cpu) - 2);
      sim_pc_set (cpu, sim_pc_get (cpu) - 2);
    }
    }
}
}
 
 
/* Callback from simulator close or read call saying that the pipe at
/* Callback from simulator close or read call saying that the pipe at
   (reader, writer) is now empty (so the writer can write again, perhaps
   (reader, writer) is now empty (so the writer can write again, perhaps
   leave a waiting state).  If there are bytes remaining, they couldn't be
   leave a waiting state).  If there are bytes remaining, they couldn't be
   consumed (perhaps due to the pipe closing).  */
   consumed (perhaps due to the pipe closing).  */
 
 
static void
static void
cris_pipe_empty (host_callback *cb,
cris_pipe_empty (host_callback *cb,
                 int reader,
                 int reader,
                 int writer)
                 int writer)
{
{
  int i;
  int i;
  SIM_CPU *cpu = current_cpu_for_cb_callback;
  SIM_CPU *cpu = current_cpu_for_cb_callback;
  bfd_byte r10_buf[4];
  bfd_byte r10_buf[4];
  int remaining
  int remaining
    = cb->pipe_buffer[writer].size - cb->pipe_buffer[reader].size;
    = cb->pipe_buffer[writer].size - cb->pipe_buffer[reader].size;
 
 
  /* We need to find the thread that waits for this pipe.  */
  /* We need to find the thread that waits for this pipe.  */
  for (i = 0; i < SIM_TARGET_MAX_THREADS; i++)
  for (i = 0; i < SIM_TARGET_MAX_THREADS; i++)
    if (cpu->thread_data[i].cpu_context
    if (cpu->thread_data[i].cpu_context
        && cpu->thread_data[i].pipe_write_fd == writer)
        && cpu->thread_data[i].pipe_write_fd == writer)
      {
      {
        int retval;
        int retval;
 
 
        /* Temporarily switch to this cpu context, so we can change the
        /* Temporarily switch to this cpu context, so we can change the
           PC by ordinary calls.  */
           PC by ordinary calls.  */
 
 
        memcpy (cpu->thread_data[cpu->threadno].cpu_context,
        memcpy (cpu->thread_data[cpu->threadno].cpu_context,
                &cpu->cpu_data_placeholder,
                &cpu->cpu_data_placeholder,
                cpu->thread_cpu_data_size);
                cpu->thread_cpu_data_size);
        memcpy (&cpu->cpu_data_placeholder,
        memcpy (&cpu->cpu_data_placeholder,
                cpu->thread_data[i].cpu_context,
                cpu->thread_data[i].cpu_context,
                cpu->thread_cpu_data_size);
                cpu->thread_cpu_data_size);
 
 
        /* The return value is supposed to contain the number of
        /* The return value is supposed to contain the number of
           written bytes, which is the number of bytes requested and
           written bytes, which is the number of bytes requested and
           returned at the write call.  You might think the right
           returned at the write call.  You might think the right
           thing is to adjust the return-value to be only the
           thing is to adjust the return-value to be only the
           *consumed* number of bytes, but it isn't.  We're only
           *consumed* number of bytes, but it isn't.  We're only
           called if the pipe buffer is fully consumed or it is being
           called if the pipe buffer is fully consumed or it is being
           closed, possibly with remaining bytes.  For the latter
           closed, possibly with remaining bytes.  For the latter
           case, the writer is still supposed to see success for
           case, the writer is still supposed to see success for
           PIPE_BUF bytes (a constant which we happen to know and is
           PIPE_BUF bytes (a constant which we happen to know and is
           unlikely to change).  The return value may also be a
           unlikely to change).  The return value may also be a
           negative number; an error value.  This case is covered
           negative number; an error value.  This case is covered
           because "remaining" is always >= 0.  */
           because "remaining" is always >= 0.  */
        (*CPU_REG_FETCH (cpu)) (cpu, H_GR_R10, r10_buf, 4);
        (*CPU_REG_FETCH (cpu)) (cpu, H_GR_R10, r10_buf, 4);
        retval = (int) bfd_getl_signed_32 (r10_buf);
        retval = (int) bfd_getl_signed_32 (r10_buf);
        if (retval - remaining > TARGET_PIPE_BUF)
        if (retval - remaining > TARGET_PIPE_BUF)
          {
          {
            bfd_putl32 (retval - remaining, r10_buf);
            bfd_putl32 (retval - remaining, r10_buf);
            (*CPU_REG_STORE (cpu)) (cpu, H_GR_R10, r10_buf, 4);
            (*CPU_REG_STORE (cpu)) (cpu, H_GR_R10, r10_buf, 4);
          }
          }
        sim_pc_set (cpu, sim_pc_get (cpu) + 2);
        sim_pc_set (cpu, sim_pc_get (cpu) + 2);
        memcpy (cpu->thread_data[i].cpu_context,
        memcpy (cpu->thread_data[i].cpu_context,
                &cpu->cpu_data_placeholder,
                &cpu->cpu_data_placeholder,
                cpu->thread_cpu_data_size);
                cpu->thread_cpu_data_size);
        memcpy (&cpu->cpu_data_placeholder,
        memcpy (&cpu->cpu_data_placeholder,
                cpu->thread_data[cpu->threadno].cpu_context,
                cpu->thread_data[cpu->threadno].cpu_context,
                cpu->thread_cpu_data_size);
                cpu->thread_cpu_data_size);
        cpu->thread_data[i].pipe_read_fd = 0;
        cpu->thread_data[i].pipe_read_fd = 0;
        cpu->thread_data[i].pipe_write_fd = 0;
        cpu->thread_data[i].pipe_write_fd = 0;
        return;
        return;
      }
      }
 
 
  abort ();
  abort ();
}
}
 
 
/* We have a simulator-specific notion of time.  See TARGET_TIME.  */
/* We have a simulator-specific notion of time.  See TARGET_TIME.  */
 
 
static long
static long
cris_time (host_callback *cb ATTRIBUTE_UNUSED, long *t)
cris_time (host_callback *cb ATTRIBUTE_UNUSED, long *t)
{
{
  long retval = TARGET_TIME (current_cpu_for_cb_callback);
  long retval = TARGET_TIME (current_cpu_for_cb_callback);
  if (t)
  if (t)
    *t = retval;
    *t = retval;
  return retval;
  return retval;
}
}
 
 
/* Set target-specific callback data. */
/* Set target-specific callback data. */
 
 
void
void
cris_set_callbacks (host_callback *cb)
cris_set_callbacks (host_callback *cb)
{
{
  /* Yeargh, have to cast away constness to avoid warnings.  */
  /* Yeargh, have to cast away constness to avoid warnings.  */
  cb->syscall_map = (CB_TARGET_DEFS_MAP *) syscall_map;
  cb->syscall_map = (CB_TARGET_DEFS_MAP *) syscall_map;
  cb->errno_map = (CB_TARGET_DEFS_MAP *) errno_map;
  cb->errno_map = (CB_TARGET_DEFS_MAP *) errno_map;
 
 
  /* The kernel stat64 layout.  If we see a file > 2G, the "long"
  /* The kernel stat64 layout.  If we see a file > 2G, the "long"
     parameter to cb_store_target_endian will make st_size negative.
     parameter to cb_store_target_endian will make st_size negative.
     Similarly for st_ino.  FIXME: Find a 64-bit type, and use it
     Similarly for st_ino.  FIXME: Find a 64-bit type, and use it
     *unsigned*, and/or add syntax for signed-ness.  */
     *unsigned*, and/or add syntax for signed-ness.  */
  cb->stat_map = stat_map;
  cb->stat_map = stat_map;
  cb->open_map = (CB_TARGET_DEFS_MAP *) open_map;
  cb->open_map = (CB_TARGET_DEFS_MAP *) open_map;
  cb->pipe_nonempty = cris_pipe_nonempty;
  cb->pipe_nonempty = cris_pipe_nonempty;
  cb->pipe_empty = cris_pipe_empty;
  cb->pipe_empty = cris_pipe_empty;
  cb->time = cris_time;
  cb->time = cris_time;
}
}
 
 
/* Process an address exception.  */
/* Process an address exception.  */
 
 
void
void
cris_core_signal (SIM_DESC sd, SIM_CPU *current_cpu, sim_cia cia,
cris_core_signal (SIM_DESC sd, SIM_CPU *current_cpu, sim_cia cia,
                  unsigned int map, int nr_bytes, address_word addr,
                  unsigned int map, int nr_bytes, address_word addr,
                  transfer_type transfer, sim_core_signals sig)
                  transfer_type transfer, sim_core_signals sig)
{
{
  sim_core_signal (sd, current_cpu, cia, map, nr_bytes, addr,
  sim_core_signal (sd, current_cpu, cia, map, nr_bytes, addr,
                   transfer, sig);
                   transfer, sig);
}
}
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.