166e63ce3Schristos /* CRIS exception, interrupt, and trap (EIT) support
2*1424dfb3Schristos Copyright (C) 2004-2020 Free Software Foundation, Inc.
366e63ce3Schristos Contributed by Axis Communications.
466e63ce3Schristos
566e63ce3Schristos This file is part of the GNU simulators.
666e63ce3Schristos
766e63ce3Schristos This program is free software; you can redistribute it and/or modify
866e63ce3Schristos it under the terms of the GNU General Public License as published by
966e63ce3Schristos the Free Software Foundation; either version 3 of the License, or
1066e63ce3Schristos (at your option) any later version.
1166e63ce3Schristos
1266e63ce3Schristos This program is distributed in the hope that it will be useful,
1366e63ce3Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of
1466e63ce3Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1566e63ce3Schristos GNU General Public License for more details.
1666e63ce3Schristos
1766e63ce3Schristos You should have received a copy of the GNU General Public License
1866e63ce3Schristos along with this program. If not, see <http://www.gnu.org/licenses/>. */
1966e63ce3Schristos
2066e63ce3Schristos #include "sim-main.h"
21ed6a76a9Schristos #include "sim-syscall.h"
2266e63ce3Schristos #include "sim-options.h"
2366e63ce3Schristos #include "bfd.h"
2466e63ce3Schristos /* FIXME: get rid of targ-vals.h usage everywhere else. */
2566e63ce3Schristos
2666e63ce3Schristos #include <stdarg.h>
2766e63ce3Schristos #ifdef HAVE_ERRNO_H
2866e63ce3Schristos #include <errno.h>
2966e63ce3Schristos #endif
3066e63ce3Schristos #ifdef HAVE_UNISTD_H
3166e63ce3Schristos #include <unistd.h>
3266e63ce3Schristos #endif
3366e63ce3Schristos #ifdef HAVE_FCNTL_H
3466e63ce3Schristos #include <fcntl.h>
3566e63ce3Schristos #endif
3666e63ce3Schristos #ifdef HAVE_SYS_PARAM_H
3766e63ce3Schristos #include <sys/param.h>
3866e63ce3Schristos #endif
3966e63ce3Schristos #ifdef HAVE_SYS_STAT_H
4066e63ce3Schristos #include <sys/stat.h>
4166e63ce3Schristos #endif
4266e63ce3Schristos /* For PATH_MAX, originally. */
4366e63ce3Schristos #ifdef HAVE_LIMITS_H
4466e63ce3Schristos #include <limits.h>
4566e63ce3Schristos #endif
4666e63ce3Schristos
4766e63ce3Schristos /* From ld/sysdep.h. */
4866e63ce3Schristos #ifdef PATH_MAX
4966e63ce3Schristos # define SIM_PATHMAX PATH_MAX
5066e63ce3Schristos #else
5166e63ce3Schristos # ifdef MAXPATHLEN
5266e63ce3Schristos # define SIM_PATHMAX MAXPATHLEN
5366e63ce3Schristos # else
5466e63ce3Schristos # define SIM_PATHMAX 1024
5566e63ce3Schristos # endif
5666e63ce3Schristos #endif
5766e63ce3Schristos
5866e63ce3Schristos /* The verbatim values are from asm-cris/unistd.h. */
5966e63ce3Schristos
6066e63ce3Schristos #define TARGET_SYS_exit 1
6166e63ce3Schristos #define TARGET_SYS_read 3
6266e63ce3Schristos #define TARGET_SYS_write 4
6366e63ce3Schristos #define TARGET_SYS_open 5
6466e63ce3Schristos #define TARGET_SYS_close 6
6566e63ce3Schristos #define TARGET_SYS_unlink 10
6666e63ce3Schristos #define TARGET_SYS_time 13
6766e63ce3Schristos #define TARGET_SYS_lseek 19
6866e63ce3Schristos #define TARGET_SYS_getpid 20
6966e63ce3Schristos #define TARGET_SYS_access 33
7066e63ce3Schristos #define TARGET_SYS_kill 37
7166e63ce3Schristos #define TARGET_SYS_rename 38
7266e63ce3Schristos #define TARGET_SYS_pipe 42
7366e63ce3Schristos #define TARGET_SYS_brk 45
7466e63ce3Schristos #define TARGET_SYS_ioctl 54
7566e63ce3Schristos #define TARGET_SYS_fcntl 55
7666e63ce3Schristos #define TARGET_SYS_getppid 64
7766e63ce3Schristos #define TARGET_SYS_setrlimit 75
7866e63ce3Schristos #define TARGET_SYS_gettimeofday 78
7966e63ce3Schristos #define TARGET_SYS_readlink 85
8066e63ce3Schristos #define TARGET_SYS_munmap 91
8166e63ce3Schristos #define TARGET_SYS_truncate 92
8266e63ce3Schristos #define TARGET_SYS_ftruncate 93
8366e63ce3Schristos #define TARGET_SYS_socketcall 102
8466e63ce3Schristos #define TARGET_SYS_stat 106
8566e63ce3Schristos #define TARGET_SYS_fstat 108
8666e63ce3Schristos #define TARGET_SYS_wait4 114
8766e63ce3Schristos #define TARGET_SYS_sigreturn 119
8866e63ce3Schristos #define TARGET_SYS_clone 120
8966e63ce3Schristos #define TARGET_SYS_uname 122
9066e63ce3Schristos #define TARGET_SYS_mprotect 125
9166e63ce3Schristos #define TARGET_SYS_llseek 140
9266e63ce3Schristos #define TARGET_SYS_writev 146
9366e63ce3Schristos #define TARGET_SYS__sysctl 149
9466e63ce3Schristos #define TARGET_SYS_sched_setparam 154
9566e63ce3Schristos #define TARGET_SYS_sched_getparam 155
9666e63ce3Schristos #define TARGET_SYS_sched_setscheduler 156
9766e63ce3Schristos #define TARGET_SYS_sched_getscheduler 157
9866e63ce3Schristos #define TARGET_SYS_sched_yield 158
9966e63ce3Schristos #define TARGET_SYS_sched_get_priority_max 159
10066e63ce3Schristos #define TARGET_SYS_sched_get_priority_min 160
10166e63ce3Schristos #define TARGET_SYS_mremap 163
10266e63ce3Schristos #define TARGET_SYS_poll 168
10366e63ce3Schristos #define TARGET_SYS_rt_sigaction 174
10466e63ce3Schristos #define TARGET_SYS_rt_sigprocmask 175
10566e63ce3Schristos #define TARGET_SYS_rt_sigsuspend 179
10666e63ce3Schristos #define TARGET_SYS_getcwd 183
10766e63ce3Schristos #define TARGET_SYS_ugetrlimit 191
10866e63ce3Schristos #define TARGET_SYS_mmap2 192
10966e63ce3Schristos #define TARGET_SYS_stat64 195
11066e63ce3Schristos #define TARGET_SYS_lstat64 196
11166e63ce3Schristos #define TARGET_SYS_fstat64 197
11266e63ce3Schristos #define TARGET_SYS_geteuid32 201
11366e63ce3Schristos #define TARGET_SYS_getuid32 199
11466e63ce3Schristos #define TARGET_SYS_getegid32 202
11566e63ce3Schristos #define TARGET_SYS_getgid32 200
11666e63ce3Schristos #define TARGET_SYS_fcntl64 221
11766e63ce3Schristos #define TARGET_SYS_set_thread_area 243
11866e63ce3Schristos #define TARGET_SYS_exit_group 252
11966e63ce3Schristos
12066e63ce3Schristos #define TARGET_PROT_READ 0x1
12166e63ce3Schristos #define TARGET_PROT_WRITE 0x2
12266e63ce3Schristos #define TARGET_PROT_EXEC 0x4
12366e63ce3Schristos #define TARGET_PROT_NONE 0x0
12466e63ce3Schristos
12566e63ce3Schristos #define TARGET_MAP_SHARED 0x01
12666e63ce3Schristos #define TARGET_MAP_PRIVATE 0x02
12766e63ce3Schristos #define TARGET_MAP_TYPE 0x0f
12866e63ce3Schristos #define TARGET_MAP_FIXED 0x10
12966e63ce3Schristos #define TARGET_MAP_ANONYMOUS 0x20
13066e63ce3Schristos #define TARGET_MAP_DENYWRITE 0x800
13166e63ce3Schristos
13266e63ce3Schristos #define TARGET_CTL_KERN 1
13366e63ce3Schristos #define TARGET_CTL_VM 2
13466e63ce3Schristos #define TARGET_CTL_NET 3
13566e63ce3Schristos #define TARGET_CTL_PROC 4
13666e63ce3Schristos #define TARGET_CTL_FS 5
13766e63ce3Schristos #define TARGET_CTL_DEBUG 6
13866e63ce3Schristos #define TARGET_CTL_DEV 7
13966e63ce3Schristos #define TARGET_CTL_BUS 8
14066e63ce3Schristos #define TARGET_CTL_ABI 9
14166e63ce3Schristos
14266e63ce3Schristos #define TARGET_CTL_KERN_VERSION 4
14366e63ce3Schristos
14466e63ce3Schristos /* linux/mman.h */
14566e63ce3Schristos #define TARGET_MREMAP_MAYMOVE 1
14666e63ce3Schristos #define TARGET_MREMAP_FIXED 2
14766e63ce3Schristos
14866e63ce3Schristos #define TARGET_TCGETS 0x5401
14966e63ce3Schristos
15066e63ce3Schristos #define TARGET_UTSNAME "#7 Thu Jan 1 00:00:00 MET 2009"
15166e63ce3Schristos
15266e63ce3Schristos /* Seconds since 1970-01-01 to the above date + 10 minutes;
15366e63ce3Schristos 'date -d "Thu Jan 1 00:00:10 MET 2009" +%s'. */
15466e63ce3Schristos #define TARGET_EPOCH 1230764410
15566e63ce3Schristos
15666e63ce3Schristos /* Milliseconds since start of run. We use the number of syscalls to
15766e63ce3Schristos avoid introducing noise in the execution time. */
15866e63ce3Schristos #define TARGET_TIME_MS(cpu) ((cpu)->syscalls)
15966e63ce3Schristos
16066e63ce3Schristos /* Seconds as in time(2). */
16166e63ce3Schristos #define TARGET_TIME(cpu) (TARGET_EPOCH + TARGET_TIME_MS (cpu) / 1000)
16266e63ce3Schristos
16366e63ce3Schristos #define TARGET_SCHED_OTHER 0
16466e63ce3Schristos
16566e63ce3Schristos #define TARGET_RLIMIT_STACK 3
16666e63ce3Schristos #define TARGET_RLIMIT_NOFILE 7
16766e63ce3Schristos
16866e63ce3Schristos #define SIM_TARGET_MAX_THREADS 64
16966e63ce3Schristos #define SIM_MAX_ALLOC_CHUNK (512*1024*1024)
17066e63ce3Schristos
17166e63ce3Schristos /* From linux/sched.h. */
17266e63ce3Schristos #define TARGET_CSIGNAL 0x000000ff
17366e63ce3Schristos #define TARGET_CLONE_VM 0x00000100
17466e63ce3Schristos #define TARGET_CLONE_FS 0x00000200
17566e63ce3Schristos #define TARGET_CLONE_FILES 0x00000400
17666e63ce3Schristos #define TARGET_CLONE_SIGHAND 0x00000800
17766e63ce3Schristos #define TARGET_CLONE_PID 0x00001000
17866e63ce3Schristos #define TARGET_CLONE_PTRACE 0x00002000
17966e63ce3Schristos #define TARGET_CLONE_VFORK 0x00004000
18066e63ce3Schristos #define TARGET_CLONE_PARENT 0x00008000
18166e63ce3Schristos #define TARGET_CLONE_THREAD 0x00010000
18266e63ce3Schristos #define TARGET_CLONE_SIGNAL (TARGET_CLONE_SIGHAND | TARGET_CLONE_THREAD)
18366e63ce3Schristos
18466e63ce3Schristos /* From asm-cris/poll.h. */
18566e63ce3Schristos #define TARGET_POLLIN 1
18666e63ce3Schristos
18766e63ce3Schristos /* From asm-cris/signal.h. */
18866e63ce3Schristos #define TARGET_SIG_BLOCK 0
18966e63ce3Schristos #define TARGET_SIG_UNBLOCK 1
19066e63ce3Schristos #define TARGET_SIG_SETMASK 2
19166e63ce3Schristos
19266e63ce3Schristos #define TARGET_SIG_DFL 0
19366e63ce3Schristos #define TARGET_SIG_IGN 1
19466e63ce3Schristos #define TARGET_SIG_ERR ((USI)-1)
19566e63ce3Schristos
19666e63ce3Schristos #define TARGET_SIGHUP 1
19766e63ce3Schristos #define TARGET_SIGINT 2
19866e63ce3Schristos #define TARGET_SIGQUIT 3
19966e63ce3Schristos #define TARGET_SIGILL 4
20066e63ce3Schristos #define TARGET_SIGTRAP 5
20166e63ce3Schristos #define TARGET_SIGABRT 6
20266e63ce3Schristos #define TARGET_SIGIOT 6
20366e63ce3Schristos #define TARGET_SIGBUS 7
20466e63ce3Schristos #define TARGET_SIGFPE 8
20566e63ce3Schristos #define TARGET_SIGKILL 9
20666e63ce3Schristos #define TARGET_SIGUSR1 10
20766e63ce3Schristos #define TARGET_SIGSEGV 11
20866e63ce3Schristos #define TARGET_SIGUSR2 12
20966e63ce3Schristos #define TARGET_SIGPIPE 13
21066e63ce3Schristos #define TARGET_SIGALRM 14
21166e63ce3Schristos #define TARGET_SIGTERM 15
21266e63ce3Schristos #define TARGET_SIGSTKFLT 16
21366e63ce3Schristos #define TARGET_SIGCHLD 17
21466e63ce3Schristos #define TARGET_SIGCONT 18
21566e63ce3Schristos #define TARGET_SIGSTOP 19
21666e63ce3Schristos #define TARGET_SIGTSTP 20
21766e63ce3Schristos #define TARGET_SIGTTIN 21
21866e63ce3Schristos #define TARGET_SIGTTOU 22
21966e63ce3Schristos #define TARGET_SIGURG 23
22066e63ce3Schristos #define TARGET_SIGXCPU 24
22166e63ce3Schristos #define TARGET_SIGXFSZ 25
22266e63ce3Schristos #define TARGET_SIGVTALRM 26
22366e63ce3Schristos #define TARGET_SIGPROF 27
22466e63ce3Schristos #define TARGET_SIGWINCH 28
22566e63ce3Schristos #define TARGET_SIGIO 29
22666e63ce3Schristos #define TARGET_SIGPOLL SIGIO
22766e63ce3Schristos /* Actually commented out in the kernel header. */
22866e63ce3Schristos #define TARGET_SIGLOST 29
22966e63ce3Schristos #define TARGET_SIGPWR 30
23066e63ce3Schristos #define TARGET_SIGSYS 31
23166e63ce3Schristos
23266e63ce3Schristos /* From include/asm-cris/signal.h. */
23366e63ce3Schristos #define TARGET_SA_NOCLDSTOP 0x00000001
23466e63ce3Schristos #define TARGET_SA_NOCLDWAIT 0x00000002 /* not supported yet */
23566e63ce3Schristos #define TARGET_SA_SIGINFO 0x00000004
23666e63ce3Schristos #define TARGET_SA_ONSTACK 0x08000000
23766e63ce3Schristos #define TARGET_SA_RESTART 0x10000000
23866e63ce3Schristos #define TARGET_SA_NODEFER 0x40000000
23966e63ce3Schristos #define TARGET_SA_RESETHAND 0x80000000
24066e63ce3Schristos #define TARGET_SA_INTERRUPT 0x20000000 /* dummy -- ignored */
24166e63ce3Schristos #define TARGET_SA_RESTORER 0x04000000
24266e63ce3Schristos
24366e63ce3Schristos /* From linux/wait.h. */
24466e63ce3Schristos #define TARGET_WNOHANG 1
24566e63ce3Schristos #define TARGET_WUNTRACED 2
24666e63ce3Schristos #define TARGET___WNOTHREAD 0x20000000
24766e63ce3Schristos #define TARGET___WALL 0x40000000
24866e63ce3Schristos #define TARGET___WCLONE 0x80000000
24966e63ce3Schristos
25066e63ce3Schristos /* From linux/limits.h. */
25166e63ce3Schristos #define TARGET_PIPE_BUF 4096
25266e63ce3Schristos
25366e63ce3Schristos /* From unistd.h. */
25466e63ce3Schristos #define TARGET_R_OK 4
25566e63ce3Schristos #define TARGET_W_OK 2
25666e63ce3Schristos #define TARGET_X_OK 1
25766e63ce3Schristos #define TARGET_F_OK 0
25866e63ce3Schristos
25966e63ce3Schristos static const char stat_map[] =
26066e63ce3Schristos "st_dev,2:space,10:space,4:st_mode,4:st_nlink,4:st_uid,4"
26166e63ce3Schristos ":st_gid,4:st_rdev,2:space,10:st_size,8:st_blksize,4:st_blocks,4"
26266e63ce3Schristos ":space,4:st_atime,4:space,4:st_mtime,4:space,4:st_ctime,4:space,4"
26366e63ce3Schristos ":st_ino,8";
26466e63ce3Schristos
26566e63ce3Schristos static const CB_TARGET_DEFS_MAP syscall_map[] =
26666e63ce3Schristos {
267ed6a76a9Schristos { "open", CB_SYS_open, TARGET_SYS_open },
268ed6a76a9Schristos { "close", CB_SYS_close, TARGET_SYS_close },
269ed6a76a9Schristos { "read", CB_SYS_read, TARGET_SYS_read },
270ed6a76a9Schristos { "write", CB_SYS_write, TARGET_SYS_write },
271ed6a76a9Schristos { "lseek", CB_SYS_lseek, TARGET_SYS_lseek },
272ed6a76a9Schristos { "unlink", CB_SYS_unlink, TARGET_SYS_unlink },
273ed6a76a9Schristos { "getpid", CB_SYS_getpid, TARGET_SYS_getpid },
274ed6a76a9Schristos { "fstat", CB_SYS_fstat, TARGET_SYS_fstat64 },
275ed6a76a9Schristos { "lstat", CB_SYS_lstat, TARGET_SYS_lstat64 },
276ed6a76a9Schristos { "stat", CB_SYS_stat, TARGET_SYS_stat64 },
277ed6a76a9Schristos { "pipe", CB_SYS_pipe, TARGET_SYS_pipe },
278ed6a76a9Schristos { "rename", CB_SYS_rename, TARGET_SYS_rename },
279ed6a76a9Schristos { "truncate", CB_SYS_truncate, TARGET_SYS_truncate },
280ed6a76a9Schristos { "ftruncate", CB_SYS_ftruncate, TARGET_SYS_ftruncate },
281ed6a76a9Schristos { 0, -1, -1 }
28266e63ce3Schristos };
28366e63ce3Schristos
28466e63ce3Schristos /* An older, 32-bit-only stat mapping. */
28566e63ce3Schristos static const char stat32_map[] =
28666e63ce3Schristos "st_dev,2:space,2:st_ino,4:st_mode,2:st_nlink,2:st_uid,2"
28766e63ce3Schristos ":st_gid,2:st_rdev,2:space,2:st_size,4:st_blksize,4:st_blocks,4"
28866e63ce3Schristos ":st_atime,4:space,4:st_mtime,4:space,4:st_ctime,4:space,12";
28966e63ce3Schristos
29066e63ce3Schristos /* Map for calls using the 32-bit struct stat. Primarily used by the
29166e63ce3Schristos newlib Linux mapping. */
29266e63ce3Schristos static const CB_TARGET_DEFS_MAP syscall_stat32_map[] =
29366e63ce3Schristos {
294ed6a76a9Schristos { "fstat", CB_SYS_fstat, TARGET_SYS_fstat },
295ed6a76a9Schristos { "stat", CB_SYS_stat, TARGET_SYS_stat },
296ed6a76a9Schristos { 0, -1, -1 }
29766e63ce3Schristos };
29866e63ce3Schristos
29966e63ce3Schristos /* Giving the true value for the running sim process will lead to
30066e63ce3Schristos non-time-invariant behavior. */
30166e63ce3Schristos #define TARGET_PID 42
30266e63ce3Schristos
30366e63ce3Schristos /* Unfortunately, we don't get this from cris.cpu at the moment, and if
30466e63ce3Schristos we did, we'd still don't get a register number with the "16" offset. */
30566e63ce3Schristos #define TARGET_SRP_REGNUM (16+11)
30666e63ce3Schristos
30766e63ce3Schristos /* Extracted by applying
30866e63ce3Schristos awk '/^#define/ { printf "#ifdef %s\n { %s, %s },\n#endif\n", $2, $2, $3;}'
30966e63ce3Schristos on .../include/asm/errno.h in a GNU/Linux/CRIS installation and
31066e63ce3Schristos adjusting the synonyms. */
31166e63ce3Schristos
31266e63ce3Schristos static const CB_TARGET_DEFS_MAP errno_map[] =
31366e63ce3Schristos {
31466e63ce3Schristos #ifdef EPERM
315ed6a76a9Schristos { "EPERM", EPERM, 1 },
31666e63ce3Schristos #endif
31766e63ce3Schristos #ifdef ENOENT
318ed6a76a9Schristos { "ENOENT", ENOENT, 2 },
31966e63ce3Schristos #endif
32066e63ce3Schristos #ifdef ESRCH
321ed6a76a9Schristos { "ESRCH", ESRCH, 3 },
32266e63ce3Schristos #endif
32366e63ce3Schristos #ifdef EINTR
324ed6a76a9Schristos { "EINTR", EINTR, 4 },
32566e63ce3Schristos #endif
32666e63ce3Schristos #ifdef EIO
327ed6a76a9Schristos { "EIO", EIO, 5 },
32866e63ce3Schristos #endif
32966e63ce3Schristos #ifdef ENXIO
330ed6a76a9Schristos { "ENXIO", ENXIO, 6 },
33166e63ce3Schristos #endif
33266e63ce3Schristos #ifdef E2BIG
333ed6a76a9Schristos { "E2BIG", E2BIG, 7 },
33466e63ce3Schristos #endif
33566e63ce3Schristos #ifdef ENOEXEC
336ed6a76a9Schristos { "ENOEXEC", ENOEXEC, 8 },
33766e63ce3Schristos #endif
33866e63ce3Schristos #ifdef EBADF
339ed6a76a9Schristos { "EBADF", EBADF, 9 },
34066e63ce3Schristos #endif
34166e63ce3Schristos #ifdef ECHILD
342ed6a76a9Schristos { "ECHILD", ECHILD, 10 },
34366e63ce3Schristos #endif
34466e63ce3Schristos #ifdef EAGAIN
345ed6a76a9Schristos { "EAGAIN", EAGAIN, 11 },
34666e63ce3Schristos #endif
34766e63ce3Schristos #ifdef ENOMEM
348ed6a76a9Schristos { "ENOMEM", ENOMEM, 12 },
34966e63ce3Schristos #endif
35066e63ce3Schristos #ifdef EACCES
351ed6a76a9Schristos { "EACCES", EACCES, 13 },
35266e63ce3Schristos #endif
35366e63ce3Schristos #ifdef EFAULT
354ed6a76a9Schristos { "EFAULT", EFAULT, 14 },
35566e63ce3Schristos #endif
35666e63ce3Schristos #ifdef ENOTBLK
357ed6a76a9Schristos { "ENOTBLK", ENOTBLK, 15 },
35866e63ce3Schristos #endif
35966e63ce3Schristos #ifdef EBUSY
360ed6a76a9Schristos { "EBUSY", EBUSY, 16 },
36166e63ce3Schristos #endif
36266e63ce3Schristos #ifdef EEXIST
363ed6a76a9Schristos { "EEXIST", EEXIST, 17 },
36466e63ce3Schristos #endif
36566e63ce3Schristos #ifdef EXDEV
366ed6a76a9Schristos { "EXDEV", EXDEV, 18 },
36766e63ce3Schristos #endif
36866e63ce3Schristos #ifdef ENODEV
369ed6a76a9Schristos { "ENODEV", ENODEV, 19 },
37066e63ce3Schristos #endif
37166e63ce3Schristos #ifdef ENOTDIR
372ed6a76a9Schristos { "ENOTDIR", ENOTDIR, 20 },
37366e63ce3Schristos #endif
37466e63ce3Schristos #ifdef EISDIR
375ed6a76a9Schristos { "EISDIR", EISDIR, 21 },
37666e63ce3Schristos #endif
37766e63ce3Schristos #ifdef EINVAL
378ed6a76a9Schristos { "EINVAL", EINVAL, 22 },
37966e63ce3Schristos #endif
38066e63ce3Schristos #ifdef ENFILE
381ed6a76a9Schristos { "ENFILE", ENFILE, 23 },
38266e63ce3Schristos #endif
38366e63ce3Schristos #ifdef EMFILE
384ed6a76a9Schristos { "EMFILE", EMFILE, 24 },
38566e63ce3Schristos #endif
38666e63ce3Schristos #ifdef ENOTTY
387ed6a76a9Schristos { "ENOTTY", ENOTTY, 25 },
38866e63ce3Schristos #endif
38966e63ce3Schristos #ifdef ETXTBSY
390ed6a76a9Schristos { "ETXTBSY", ETXTBSY, 26 },
39166e63ce3Schristos #endif
39266e63ce3Schristos #ifdef EFBIG
393ed6a76a9Schristos { "EFBIG", EFBIG, 27 },
39466e63ce3Schristos #endif
39566e63ce3Schristos #ifdef ENOSPC
396ed6a76a9Schristos { "ENOSPC", ENOSPC, 28 },
39766e63ce3Schristos #endif
39866e63ce3Schristos #ifdef ESPIPE
399ed6a76a9Schristos { "ESPIPE", ESPIPE, 29 },
40066e63ce3Schristos #endif
40166e63ce3Schristos #ifdef EROFS
402ed6a76a9Schristos { "EROFS", EROFS, 30 },
40366e63ce3Schristos #endif
40466e63ce3Schristos #ifdef EMLINK
405ed6a76a9Schristos { "EMLINK", EMLINK, 31 },
40666e63ce3Schristos #endif
40766e63ce3Schristos #ifdef EPIPE
408ed6a76a9Schristos { "EPIPE", EPIPE, 32 },
40966e63ce3Schristos #endif
41066e63ce3Schristos #ifdef EDOM
411ed6a76a9Schristos { "EDOM", EDOM, 33 },
41266e63ce3Schristos #endif
41366e63ce3Schristos #ifdef ERANGE
414ed6a76a9Schristos { "ERANGE", ERANGE, 34 },
41566e63ce3Schristos #endif
41666e63ce3Schristos #ifdef EDEADLK
417ed6a76a9Schristos { "EDEADLK", EDEADLK, 35 },
41866e63ce3Schristos #endif
41966e63ce3Schristos #ifdef ENAMETOOLONG
420ed6a76a9Schristos { "ENAMETOOLONG", ENAMETOOLONG, 36 },
42166e63ce3Schristos #endif
42266e63ce3Schristos #ifdef ENOLCK
423ed6a76a9Schristos { "ENOLCK", ENOLCK, 37 },
42466e63ce3Schristos #endif
42566e63ce3Schristos #ifdef ENOSYS
426ed6a76a9Schristos { "ENOSYS", ENOSYS, 38 },
42766e63ce3Schristos #endif
42866e63ce3Schristos #ifdef ENOTEMPTY
429ed6a76a9Schristos { "ENOTEMPTY", ENOTEMPTY, 39 },
43066e63ce3Schristos #endif
43166e63ce3Schristos #ifdef ELOOP
432ed6a76a9Schristos { "ELOOP", ELOOP, 40 },
43366e63ce3Schristos #endif
43466e63ce3Schristos #ifdef EWOULDBLOCK
435ed6a76a9Schristos { "EWOULDBLOCK", EWOULDBLOCK, 11 },
43666e63ce3Schristos #endif
43766e63ce3Schristos #ifdef ENOMSG
438ed6a76a9Schristos { "ENOMSG", ENOMSG, 42 },
43966e63ce3Schristos #endif
44066e63ce3Schristos #ifdef EIDRM
441ed6a76a9Schristos { "EIDRM", EIDRM, 43 },
44266e63ce3Schristos #endif
44366e63ce3Schristos #ifdef ECHRNG
444ed6a76a9Schristos { "ECHRNG", ECHRNG, 44 },
44566e63ce3Schristos #endif
44666e63ce3Schristos #ifdef EL2NSYNC
447ed6a76a9Schristos { "EL2NSYNC", EL2NSYNC, 45 },
44866e63ce3Schristos #endif
44966e63ce3Schristos #ifdef EL3HLT
450ed6a76a9Schristos { "EL3HLT", EL3HLT, 46 },
45166e63ce3Schristos #endif
45266e63ce3Schristos #ifdef EL3RST
453ed6a76a9Schristos { "EL3RST", EL3RST, 47 },
45466e63ce3Schristos #endif
45566e63ce3Schristos #ifdef ELNRNG
456ed6a76a9Schristos { "ELNRNG", ELNRNG, 48 },
45766e63ce3Schristos #endif
45866e63ce3Schristos #ifdef EUNATCH
459ed6a76a9Schristos { "EUNATCH", EUNATCH, 49 },
46066e63ce3Schristos #endif
46166e63ce3Schristos #ifdef ENOCSI
462ed6a76a9Schristos { "ENOCSI", ENOCSI, 50 },
46366e63ce3Schristos #endif
46466e63ce3Schristos #ifdef EL2HLT
465ed6a76a9Schristos { "EL2HLT", EL2HLT, 51 },
46666e63ce3Schristos #endif
46766e63ce3Schristos #ifdef EBADE
468ed6a76a9Schristos { "EBADE", EBADE, 52 },
46966e63ce3Schristos #endif
47066e63ce3Schristos #ifdef EBADR
471ed6a76a9Schristos { "EBADR", EBADR, 53 },
47266e63ce3Schristos #endif
47366e63ce3Schristos #ifdef EXFULL
474ed6a76a9Schristos { "EXFULL", EXFULL, 54 },
47566e63ce3Schristos #endif
47666e63ce3Schristos #ifdef ENOANO
477ed6a76a9Schristos { "ENOANO", ENOANO, 55 },
47866e63ce3Schristos #endif
47966e63ce3Schristos #ifdef EBADRQC
480ed6a76a9Schristos { "EBADRQC", EBADRQC, 56 },
48166e63ce3Schristos #endif
48266e63ce3Schristos #ifdef EBADSLT
483ed6a76a9Schristos { "EBADSLT", EBADSLT, 57 },
48466e63ce3Schristos #endif
48566e63ce3Schristos #ifdef EDEADLOCK
486ed6a76a9Schristos { "EDEADLOCK", EDEADLOCK, 35 },
48766e63ce3Schristos #endif
48866e63ce3Schristos #ifdef EBFONT
489ed6a76a9Schristos { "EBFONT", EBFONT, 59 },
49066e63ce3Schristos #endif
49166e63ce3Schristos #ifdef ENOSTR
492ed6a76a9Schristos { "ENOSTR", ENOSTR, 60 },
49366e63ce3Schristos #endif
49466e63ce3Schristos #ifdef ENODATA
495ed6a76a9Schristos { "ENODATA", ENODATA, 61 },
49666e63ce3Schristos #endif
49766e63ce3Schristos #ifdef ETIME
498ed6a76a9Schristos { "ETIME", ETIME, 62 },
49966e63ce3Schristos #endif
50066e63ce3Schristos #ifdef ENOSR
501ed6a76a9Schristos { "ENOSR", ENOSR, 63 },
50266e63ce3Schristos #endif
50366e63ce3Schristos #ifdef ENONET
504ed6a76a9Schristos { "ENONET", ENONET, 64 },
50566e63ce3Schristos #endif
50666e63ce3Schristos #ifdef ENOPKG
507ed6a76a9Schristos { "ENOPKG", ENOPKG, 65 },
50866e63ce3Schristos #endif
50966e63ce3Schristos #ifdef EREMOTE
510ed6a76a9Schristos { "EREMOTE", EREMOTE, 66 },
51166e63ce3Schristos #endif
51266e63ce3Schristos #ifdef ENOLINK
513ed6a76a9Schristos { "ENOLINK", ENOLINK, 67 },
51466e63ce3Schristos #endif
51566e63ce3Schristos #ifdef EADV
516ed6a76a9Schristos { "EADV", EADV, 68 },
51766e63ce3Schristos #endif
51866e63ce3Schristos #ifdef ESRMNT
519ed6a76a9Schristos { "ESRMNT", ESRMNT, 69 },
52066e63ce3Schristos #endif
52166e63ce3Schristos #ifdef ECOMM
522ed6a76a9Schristos { "ECOMM", ECOMM, 70 },
52366e63ce3Schristos #endif
52466e63ce3Schristos #ifdef EPROTO
525ed6a76a9Schristos { "EPROTO", EPROTO, 71 },
52666e63ce3Schristos #endif
52766e63ce3Schristos #ifdef EMULTIHOP
528ed6a76a9Schristos { "EMULTIHOP", EMULTIHOP, 72 },
52966e63ce3Schristos #endif
53066e63ce3Schristos #ifdef EDOTDOT
531ed6a76a9Schristos { "EDOTDOT", EDOTDOT, 73 },
53266e63ce3Schristos #endif
53366e63ce3Schristos #ifdef EBADMSG
534ed6a76a9Schristos { "EBADMSG", EBADMSG, 74 },
53566e63ce3Schristos #endif
53666e63ce3Schristos #ifdef EOVERFLOW
537ed6a76a9Schristos { "EOVERFLOW", EOVERFLOW, 75 },
53866e63ce3Schristos #endif
53966e63ce3Schristos #ifdef ENOTUNIQ
540ed6a76a9Schristos { "ENOTUNIQ", ENOTUNIQ, 76 },
54166e63ce3Schristos #endif
54266e63ce3Schristos #ifdef EBADFD
543ed6a76a9Schristos { "EBADFD", EBADFD, 77 },
54466e63ce3Schristos #endif
54566e63ce3Schristos #ifdef EREMCHG
546ed6a76a9Schristos { "EREMCHG", EREMCHG, 78 },
54766e63ce3Schristos #endif
54866e63ce3Schristos #ifdef ELIBACC
549ed6a76a9Schristos { "ELIBACC", ELIBACC, 79 },
55066e63ce3Schristos #endif
55166e63ce3Schristos #ifdef ELIBBAD
552ed6a76a9Schristos { "ELIBBAD", ELIBBAD, 80 },
55366e63ce3Schristos #endif
55466e63ce3Schristos #ifdef ELIBSCN
555ed6a76a9Schristos { "ELIBSCN", ELIBSCN, 81 },
55666e63ce3Schristos #endif
55766e63ce3Schristos #ifdef ELIBMAX
558ed6a76a9Schristos { "ELIBMAX", ELIBMAX, 82 },
55966e63ce3Schristos #endif
56066e63ce3Schristos #ifdef ELIBEXEC
561ed6a76a9Schristos { "ELIBEXEC", ELIBEXEC, 83 },
56266e63ce3Schristos #endif
56366e63ce3Schristos #ifdef EILSEQ
564ed6a76a9Schristos { "EILSEQ", EILSEQ, 84 },
56566e63ce3Schristos #endif
56666e63ce3Schristos #ifdef ERESTART
567ed6a76a9Schristos { "ERESTART", ERESTART, 85 },
56866e63ce3Schristos #endif
56966e63ce3Schristos #ifdef ESTRPIPE
570ed6a76a9Schristos { "ESTRPIPE", ESTRPIPE, 86 },
57166e63ce3Schristos #endif
57266e63ce3Schristos #ifdef EUSERS
573ed6a76a9Schristos { "EUSERS", EUSERS, 87 },
57466e63ce3Schristos #endif
57566e63ce3Schristos #ifdef ENOTSOCK
576ed6a76a9Schristos { "ENOTSOCK", ENOTSOCK, 88 },
57766e63ce3Schristos #endif
57866e63ce3Schristos #ifdef EDESTADDRREQ
579ed6a76a9Schristos { "EDESTADDRREQ", EDESTADDRREQ, 89 },
58066e63ce3Schristos #endif
58166e63ce3Schristos #ifdef EMSGSIZE
582ed6a76a9Schristos { "EMSGSIZE", EMSGSIZE, 90 },
58366e63ce3Schristos #endif
58466e63ce3Schristos #ifdef EPROTOTYPE
585ed6a76a9Schristos { "EPROTOTYPE", EPROTOTYPE, 91 },
58666e63ce3Schristos #endif
58766e63ce3Schristos #ifdef ENOPROTOOPT
588ed6a76a9Schristos { "ENOPROTOOPT", ENOPROTOOPT, 92 },
58966e63ce3Schristos #endif
59066e63ce3Schristos #ifdef EPROTONOSUPPORT
591ed6a76a9Schristos { "EPROTONOSUPPORT", EPROTONOSUPPORT, 93 },
59266e63ce3Schristos #endif
59366e63ce3Schristos #ifdef ESOCKTNOSUPPORT
594ed6a76a9Schristos { "ESOCKTNOSUPPORT", ESOCKTNOSUPPORT, 94 },
59566e63ce3Schristos #endif
59666e63ce3Schristos #ifdef EOPNOTSUPP
597ed6a76a9Schristos { "EOPNOTSUPP", EOPNOTSUPP, 95 },
59866e63ce3Schristos #endif
59966e63ce3Schristos #ifdef EPFNOSUPPORT
600ed6a76a9Schristos { "EPFNOSUPPORT", EPFNOSUPPORT, 96 },
60166e63ce3Schristos #endif
60266e63ce3Schristos #ifdef EAFNOSUPPORT
603ed6a76a9Schristos { "EAFNOSUPPORT", EAFNOSUPPORT, 97 },
60466e63ce3Schristos #endif
60566e63ce3Schristos #ifdef EADDRINUSE
606ed6a76a9Schristos { "EADDRINUSE", EADDRINUSE, 98 },
60766e63ce3Schristos #endif
60866e63ce3Schristos #ifdef EADDRNOTAVAIL
609ed6a76a9Schristos { "EADDRNOTAVAIL", EADDRNOTAVAIL, 99 },
61066e63ce3Schristos #endif
61166e63ce3Schristos #ifdef ENETDOWN
612ed6a76a9Schristos { "ENETDOWN", ENETDOWN, 100 },
61366e63ce3Schristos #endif
61466e63ce3Schristos #ifdef ENETUNREACH
615ed6a76a9Schristos { "ENETUNREACH", ENETUNREACH, 101 },
61666e63ce3Schristos #endif
61766e63ce3Schristos #ifdef ENETRESET
618ed6a76a9Schristos { "ENETRESET", ENETRESET, 102 },
61966e63ce3Schristos #endif
62066e63ce3Schristos #ifdef ECONNABORTED
621ed6a76a9Schristos { "ECONNABORTED", ECONNABORTED, 103 },
62266e63ce3Schristos #endif
62366e63ce3Schristos #ifdef ECONNRESET
624ed6a76a9Schristos { "ECONNRESET", ECONNRESET, 104 },
62566e63ce3Schristos #endif
62666e63ce3Schristos #ifdef ENOBUFS
627ed6a76a9Schristos { "ENOBUFS", ENOBUFS, 105 },
62866e63ce3Schristos #endif
62966e63ce3Schristos #ifdef EISCONN
630ed6a76a9Schristos { "EISCONN", EISCONN, 106 },
63166e63ce3Schristos #endif
63266e63ce3Schristos #ifdef ENOTCONN
633ed6a76a9Schristos { "ENOTCONN", ENOTCONN, 107 },
63466e63ce3Schristos #endif
63566e63ce3Schristos #ifdef ESHUTDOWN
636ed6a76a9Schristos { "ESHUTDOWN", ESHUTDOWN, 108 },
63766e63ce3Schristos #endif
63866e63ce3Schristos #ifdef ETOOMANYREFS
639ed6a76a9Schristos { "ETOOMANYREFS", ETOOMANYREFS, 109 },
64066e63ce3Schristos #endif
64166e63ce3Schristos #ifdef ETIMEDOUT
642ed6a76a9Schristos { "ETIMEDOUT", ETIMEDOUT, 110 },
64366e63ce3Schristos #endif
64466e63ce3Schristos #ifdef ECONNREFUSED
645ed6a76a9Schristos { "ECONNREFUSED", ECONNREFUSED, 111 },
64666e63ce3Schristos #endif
64766e63ce3Schristos #ifdef EHOSTDOWN
648ed6a76a9Schristos { "EHOSTDOWN", EHOSTDOWN, 112 },
64966e63ce3Schristos #endif
65066e63ce3Schristos #ifdef EHOSTUNREACH
651ed6a76a9Schristos { "EHOSTUNREACH", EHOSTUNREACH, 113 },
65266e63ce3Schristos #endif
65366e63ce3Schristos #ifdef EALREADY
654ed6a76a9Schristos { "EALREADY", EALREADY, 114 },
65566e63ce3Schristos #endif
65666e63ce3Schristos #ifdef EINPROGRESS
657ed6a76a9Schristos { "EINPROGRESS", EINPROGRESS, 115 },
65866e63ce3Schristos #endif
65966e63ce3Schristos #ifdef ESTALE
660ed6a76a9Schristos { "ESTALE", ESTALE, 116 },
66166e63ce3Schristos #endif
66266e63ce3Schristos #ifdef EUCLEAN
663ed6a76a9Schristos { "EUCLEAN", EUCLEAN, 117 },
66466e63ce3Schristos #endif
66566e63ce3Schristos #ifdef ENOTNAM
666ed6a76a9Schristos { "ENOTNAM", ENOTNAM, 118 },
66766e63ce3Schristos #endif
66866e63ce3Schristos #ifdef ENAVAIL
669ed6a76a9Schristos { "ENAVAIL", ENAVAIL, 119 },
67066e63ce3Schristos #endif
67166e63ce3Schristos #ifdef EISNAM
672ed6a76a9Schristos { "EISNAM", EISNAM, 120 },
67366e63ce3Schristos #endif
67466e63ce3Schristos #ifdef EREMOTEIO
675ed6a76a9Schristos { "EREMOTEIO", EREMOTEIO, 121 },
67666e63ce3Schristos #endif
67766e63ce3Schristos #ifdef EDQUOT
678ed6a76a9Schristos { "EDQUOT", EDQUOT, 122 },
67966e63ce3Schristos #endif
68066e63ce3Schristos #ifdef ENOMEDIUM
681ed6a76a9Schristos { "ENOMEDIUM", ENOMEDIUM, 123 },
68266e63ce3Schristos #endif
68366e63ce3Schristos #ifdef EMEDIUMTYPE
684ed6a76a9Schristos { "EMEDIUMTYPE", EMEDIUMTYPE, 124 },
68566e63ce3Schristos #endif
686ed6a76a9Schristos { 0, 0, 0 }
68766e63ce3Schristos };
68866e63ce3Schristos
68966e63ce3Schristos /* Extracted by applying
69066e63ce3Schristos perl -ne 'if ($_ =~ /^#define/) { split;
69166e63ce3Schristos printf "#ifdef $_[1]\n { %s, 0x%x },\n#endif\n",
69266e63ce3Schristos $_[1], $_[2] =~ /^0/ ? oct($_[2]) : $_[2];}'
69366e63ce3Schristos on pertinent parts of .../include/asm/fcntl.h in a GNU/Linux/CRIS
69466e63ce3Schristos installation and removing synonyms and unnecessary items. Don't
69566e63ce3Schristos forget the end-marker. */
69666e63ce3Schristos
69766e63ce3Schristos /* These we treat specially, as they're used in the fcntl F_GETFL
69866e63ce3Schristos syscall. For consistency, open_map is also manually edited to use
69966e63ce3Schristos these macros. */
70066e63ce3Schristos #define TARGET_O_ACCMODE 0x3
70166e63ce3Schristos #define TARGET_O_RDONLY 0x0
70266e63ce3Schristos #define TARGET_O_WRONLY 0x1
70366e63ce3Schristos
70466e63ce3Schristos static const CB_TARGET_DEFS_MAP open_map[] = {
70566e63ce3Schristos #ifdef O_ACCMODE
706ed6a76a9Schristos { "O_ACCMODE", O_ACCMODE, TARGET_O_ACCMODE },
70766e63ce3Schristos #endif
70866e63ce3Schristos #ifdef O_RDONLY
709ed6a76a9Schristos { "O_RDONLY", O_RDONLY, TARGET_O_RDONLY },
71066e63ce3Schristos #endif
71166e63ce3Schristos #ifdef O_WRONLY
712ed6a76a9Schristos { "O_WRONLY", O_WRONLY, TARGET_O_WRONLY },
71366e63ce3Schristos #endif
71466e63ce3Schristos #ifdef O_RDWR
715ed6a76a9Schristos { "O_RDWR", O_RDWR, 0x2 },
71666e63ce3Schristos #endif
71766e63ce3Schristos #ifdef O_CREAT
718ed6a76a9Schristos { "O_CREAT", O_CREAT, 0x40 },
71966e63ce3Schristos #endif
72066e63ce3Schristos #ifdef O_EXCL
721ed6a76a9Schristos { "O_EXCL", O_EXCL, 0x80 },
72266e63ce3Schristos #endif
72366e63ce3Schristos #ifdef O_NOCTTY
724ed6a76a9Schristos { "O_NOCTTY", O_NOCTTY, 0x100 },
72566e63ce3Schristos #endif
72666e63ce3Schristos #ifdef O_TRUNC
727ed6a76a9Schristos { "O_TRUNC", O_TRUNC, 0x200 },
72866e63ce3Schristos #endif
72966e63ce3Schristos #ifdef O_APPEND
730ed6a76a9Schristos { "O_APPEND", O_APPEND, 0x400 },
73166e63ce3Schristos #endif
73266e63ce3Schristos #ifdef O_NONBLOCK
733ed6a76a9Schristos { "O_NONBLOCK", O_NONBLOCK, 0x800 },
73466e63ce3Schristos #endif
73566e63ce3Schristos #ifdef O_NDELAY
736ed6a76a9Schristos { "O_NDELAY", O_NDELAY, 0x0 },
73766e63ce3Schristos #endif
73866e63ce3Schristos #ifdef O_SYNC
739ed6a76a9Schristos { "O_SYNC", O_SYNC, 0x1000 },
74066e63ce3Schristos #endif
74166e63ce3Schristos #ifdef FASYNC
742ed6a76a9Schristos { "FASYNC", FASYNC, 0x2000 },
74366e63ce3Schristos #endif
74466e63ce3Schristos #ifdef O_DIRECT
745ed6a76a9Schristos { "O_DIRECT", O_DIRECT, 0x4000 },
74666e63ce3Schristos #endif
74766e63ce3Schristos #ifdef O_LARGEFILE
748ed6a76a9Schristos { "O_LARGEFILE", O_LARGEFILE, 0x8000 },
74966e63ce3Schristos #endif
75066e63ce3Schristos #ifdef O_DIRECTORY
751ed6a76a9Schristos { "O_DIRECTORY", O_DIRECTORY, 0x10000 },
75266e63ce3Schristos #endif
75366e63ce3Schristos #ifdef O_NOFOLLOW
754ed6a76a9Schristos { "O_NOFOLLOW", O_NOFOLLOW, 0x20000 },
75566e63ce3Schristos #endif
756ed6a76a9Schristos { 0, -1, -1 }
75766e63ce3Schristos };
75866e63ce3Schristos
75966e63ce3Schristos /* Let's be less drastic and more traceable. FIXME: mark as noreturn. */
76066e63ce3Schristos #define abort() \
76166e63ce3Schristos sim_io_error (sd, "simulator unhandled condition at %s:%d", \
76266e63ce3Schristos __FUNCTION__, __LINE__)
76366e63ce3Schristos
76466e63ce3Schristos /* Needed for the cris_pipe_nonempty and cris_pipe_empty syscalls. */
76566e63ce3Schristos static SIM_CPU *current_cpu_for_cb_callback;
76666e63ce3Schristos
76766e63ce3Schristos static USI create_map (SIM_DESC, struct cris_sim_mmapped_page **,
76866e63ce3Schristos USI addr, USI len);
76966e63ce3Schristos static USI unmap_pages (SIM_DESC, struct cris_sim_mmapped_page **,
77066e63ce3Schristos USI addr, USI len);
77166e63ce3Schristos static USI is_mapped (SIM_DESC, struct cris_sim_mmapped_page **,
77266e63ce3Schristos USI addr, USI len);
77366e63ce3Schristos static void dump_statistics (SIM_CPU *current_cpu);
77466e63ce3Schristos static void make_first_thread (SIM_CPU *current_cpu);
77566e63ce3Schristos
77666e63ce3Schristos /* When we risk running self-modified code (as in trampolines), this is
77766e63ce3Schristos called from special-case insns. The silicon CRIS CPU:s have enough
77866e63ce3Schristos cache snooping implemented making this a simulator-only issue. Tests:
77966e63ce3Schristos gcc.c-torture/execute/931002-1.c execution, -O3 -g
78066e63ce3Schristos gcc.c-torture/execute/931002-1.c execution, -O3 -fomit-frame-pointer. */
78166e63ce3Schristos
78266e63ce3Schristos void
cris_flush_simulator_decode_cache(SIM_CPU * current_cpu,USI pc ATTRIBUTE_UNUSED)78366e63ce3Schristos cris_flush_simulator_decode_cache (SIM_CPU *current_cpu,
78466e63ce3Schristos USI pc ATTRIBUTE_UNUSED)
78566e63ce3Schristos {
78666e63ce3Schristos SIM_DESC sd = CPU_STATE (current_cpu);
78766e63ce3Schristos
78866e63ce3Schristos #if WITH_SCACHE
78966e63ce3Schristos if (USING_SCACHE_P (sd))
79066e63ce3Schristos scache_flush_cpu (current_cpu);
79166e63ce3Schristos #endif
79266e63ce3Schristos }
79366e63ce3Schristos
79466e63ce3Schristos /* Output statistics at the end of a run. */
79566e63ce3Schristos static void
dump_statistics(SIM_CPU * current_cpu)79666e63ce3Schristos dump_statistics (SIM_CPU *current_cpu)
79766e63ce3Schristos {
79866e63ce3Schristos SIM_DESC sd = CPU_STATE (current_cpu);
79966e63ce3Schristos CRIS_MISC_PROFILE *profp
80066e63ce3Schristos = CPU_CRIS_MISC_PROFILE (current_cpu);
80166e63ce3Schristos unsigned64 total = profp->basic_cycle_count;
80266e63ce3Schristos const char *textmsg = "Basic clock cycles, total @: %llu\n";
80366e63ce3Schristos
80466e63ce3Schristos /* The --cris-stats={basic|unaligned|schedulable|all} counts affect
80566e63ce3Schristos what's included in the "total" count only. */
80666e63ce3Schristos switch (CPU_CRIS_MISC_PROFILE (current_cpu)->flags
80766e63ce3Schristos & FLAG_CRIS_MISC_PROFILE_ALL)
80866e63ce3Schristos {
80966e63ce3Schristos case FLAG_CRIS_MISC_PROFILE_SIMPLE:
81066e63ce3Schristos break;
81166e63ce3Schristos
81266e63ce3Schristos case (FLAG_CRIS_MISC_PROFILE_UNALIGNED | FLAG_CRIS_MISC_PROFILE_SIMPLE):
81366e63ce3Schristos textmsg
81466e63ce3Schristos = "Clock cycles including stall cycles for unaligned accesses @: %llu\n";
81566e63ce3Schristos total += profp->unaligned_mem_dword_count;
81666e63ce3Schristos break;
81766e63ce3Schristos
81866e63ce3Schristos case (FLAG_CRIS_MISC_PROFILE_SCHEDULABLE | FLAG_CRIS_MISC_PROFILE_SIMPLE):
81966e63ce3Schristos textmsg = "Schedulable clock cycles, total @: %llu\n";
82066e63ce3Schristos total
82166e63ce3Schristos += (profp->memsrc_stall_count
82266e63ce3Schristos + profp->memraw_stall_count
82366e63ce3Schristos + profp->movemsrc_stall_count
82466e63ce3Schristos + profp->movemdst_stall_count
82566e63ce3Schristos + profp->mulsrc_stall_count
82666e63ce3Schristos + profp->jumpsrc_stall_count
82766e63ce3Schristos + profp->unaligned_mem_dword_count);
82866e63ce3Schristos break;
82966e63ce3Schristos
83066e63ce3Schristos case FLAG_CRIS_MISC_PROFILE_ALL:
83166e63ce3Schristos textmsg = "All accounted clock cycles, total @: %llu\n";
83266e63ce3Schristos total
83366e63ce3Schristos += (profp->memsrc_stall_count
83466e63ce3Schristos + profp->memraw_stall_count
83566e63ce3Schristos + profp->movemsrc_stall_count
83666e63ce3Schristos + profp->movemdst_stall_count
83766e63ce3Schristos + profp->movemaddr_stall_count
83866e63ce3Schristos + profp->mulsrc_stall_count
83966e63ce3Schristos + profp->jumpsrc_stall_count
84066e63ce3Schristos + profp->branch_stall_count
84166e63ce3Schristos + profp->jumptarget_stall_count
84266e63ce3Schristos + profp->unaligned_mem_dword_count);
84366e63ce3Schristos break;
84466e63ce3Schristos
84566e63ce3Schristos default:
84666e63ce3Schristos abort ();
84766e63ce3Schristos
84866e63ce3Schristos sim_io_eprintf (sd,
84966e63ce3Schristos "Internal inconsistency at %s:%d",
85066e63ce3Schristos __FILE__, __LINE__);
85166e63ce3Schristos sim_engine_halt (sd, current_cpu, NULL, 0,
85266e63ce3Schristos sim_stopped, SIM_SIGILL);
85366e63ce3Schristos }
85466e63ce3Schristos
85566e63ce3Schristos /* Historically, these messages have gone to stderr, so we'll keep it
85666e63ce3Schristos that way. It's also easier to then tell it from normal program
85766e63ce3Schristos output. FIXME: Add redirect option like "run -e file". */
85866e63ce3Schristos sim_io_eprintf (sd, textmsg, total);
85966e63ce3Schristos
86066e63ce3Schristos /* For v32, unaligned_mem_dword_count should always be 0. For
86166e63ce3Schristos v10, memsrc_stall_count should always be 0. */
86266e63ce3Schristos sim_io_eprintf (sd, "Memory source stall cycles: %llu\n",
86366e63ce3Schristos (unsigned long long) (profp->memsrc_stall_count
86466e63ce3Schristos + profp->unaligned_mem_dword_count));
86566e63ce3Schristos sim_io_eprintf (sd, "Memory read-after-write stall cycles: %llu\n",
86666e63ce3Schristos (unsigned long long) profp->memraw_stall_count);
86766e63ce3Schristos sim_io_eprintf (sd, "Movem source stall cycles: %llu\n",
86866e63ce3Schristos (unsigned long long) profp->movemsrc_stall_count);
86966e63ce3Schristos sim_io_eprintf (sd, "Movem destination stall cycles: %llu\n",
87066e63ce3Schristos (unsigned long long) profp->movemdst_stall_count);
87166e63ce3Schristos sim_io_eprintf (sd, "Movem address stall cycles: %llu\n",
87266e63ce3Schristos (unsigned long long) profp->movemaddr_stall_count);
87366e63ce3Schristos sim_io_eprintf (sd, "Multiplication source stall cycles: %llu\n",
87466e63ce3Schristos (unsigned long long) profp->mulsrc_stall_count);
87566e63ce3Schristos sim_io_eprintf (sd, "Jump source stall cycles: %llu\n",
87666e63ce3Schristos (unsigned long long) profp->jumpsrc_stall_count);
87766e63ce3Schristos sim_io_eprintf (sd, "Branch misprediction stall cycles: %llu\n",
87866e63ce3Schristos (unsigned long long) profp->branch_stall_count);
87966e63ce3Schristos sim_io_eprintf (sd, "Jump target stall cycles: %llu\n",
88066e63ce3Schristos (unsigned long long) profp->jumptarget_stall_count);
88166e63ce3Schristos }
88266e63ce3Schristos
88366e63ce3Schristos /* Check whether any part of [addr .. addr + len - 1] is already mapped.
88466e63ce3Schristos Return 1 if a overlap detected, 0 otherwise. */
88566e63ce3Schristos
88666e63ce3Schristos static USI
is_mapped(SIM_DESC sd ATTRIBUTE_UNUSED,struct cris_sim_mmapped_page ** rootp,USI addr,USI len)88766e63ce3Schristos is_mapped (SIM_DESC sd ATTRIBUTE_UNUSED,
88866e63ce3Schristos struct cris_sim_mmapped_page **rootp,
88966e63ce3Schristos USI addr, USI len)
89066e63ce3Schristos {
89166e63ce3Schristos struct cris_sim_mmapped_page *mapp;
89266e63ce3Schristos
89366e63ce3Schristos if (len == 0 || (len & 8191))
89466e63ce3Schristos abort ();
89566e63ce3Schristos
89666e63ce3Schristos /* Iterate over the reverse-address sorted pages until we find a page in
89766e63ce3Schristos or lower than the checked area. */
89866e63ce3Schristos for (mapp = *rootp; mapp != NULL && mapp->addr >= addr; mapp = mapp->prev)
89966e63ce3Schristos if (mapp->addr < addr + len && mapp->addr >= addr)
90066e63ce3Schristos return 1;
90166e63ce3Schristos
90266e63ce3Schristos return 0;
90366e63ce3Schristos }
90466e63ce3Schristos
90566e63ce3Schristos /* Check whether any part of [addr .. addr + len - 1] is *un*mapped.
90666e63ce3Schristos Return 1 if the whole area is mapped, 0 otherwise. */
90766e63ce3Schristos
90866e63ce3Schristos static USI
is_mapped_only(SIM_DESC sd ATTRIBUTE_UNUSED,struct cris_sim_mmapped_page ** rootp,USI addr,USI len)90966e63ce3Schristos is_mapped_only (SIM_DESC sd ATTRIBUTE_UNUSED,
91066e63ce3Schristos struct cris_sim_mmapped_page **rootp,
91166e63ce3Schristos USI addr, USI len)
91266e63ce3Schristos {
91366e63ce3Schristos struct cris_sim_mmapped_page *mapp;
91466e63ce3Schristos
91566e63ce3Schristos if (len == 0 || (len & 8191))
91666e63ce3Schristos abort ();
91766e63ce3Schristos
91866e63ce3Schristos /* Iterate over the reverse-address sorted pages until we find a page
91966e63ce3Schristos lower than the checked area. */
92066e63ce3Schristos for (mapp = *rootp; mapp != NULL && mapp->addr >= addr; mapp = mapp->prev)
92166e63ce3Schristos if (addr == mapp->addr && len == 8192)
92266e63ce3Schristos return 1;
92366e63ce3Schristos else if (addr + len > mapp->addr)
92466e63ce3Schristos len -= 8192;
92566e63ce3Schristos
92666e63ce3Schristos return 0;
92766e63ce3Schristos }
92866e63ce3Schristos
92966e63ce3Schristos /* Debug helper; to be run from gdb. */
93066e63ce3Schristos
93166e63ce3Schristos void
cris_dump_map(SIM_CPU * current_cpu)93266e63ce3Schristos cris_dump_map (SIM_CPU *current_cpu)
93366e63ce3Schristos {
93466e63ce3Schristos struct cris_sim_mmapped_page *mapp;
93566e63ce3Schristos USI start, end;
93666e63ce3Schristos
93766e63ce3Schristos for (mapp = current_cpu->highest_mmapped_page,
93866e63ce3Schristos start = mapp == NULL ? 0 : mapp->addr + 8192,
93966e63ce3Schristos end = mapp == NULL ? 0 : mapp->addr + 8191;
94066e63ce3Schristos mapp != NULL;
94166e63ce3Schristos mapp = mapp->prev)
94266e63ce3Schristos {
94366e63ce3Schristos if (mapp->addr != start - 8192)
94466e63ce3Schristos {
94566e63ce3Schristos sim_io_eprintf (CPU_STATE (current_cpu), "0x%x..0x%x\n", start, end);
94666e63ce3Schristos end = mapp->addr + 8191;
94766e63ce3Schristos }
94866e63ce3Schristos
94966e63ce3Schristos start = mapp->addr;
95066e63ce3Schristos }
95166e63ce3Schristos
95266e63ce3Schristos if (current_cpu->highest_mmapped_page != NULL)
95366e63ce3Schristos sim_io_eprintf (CPU_STATE (current_cpu), "0x%x..0x%x\n", start, end);
95466e63ce3Schristos }
95566e63ce3Schristos
95666e63ce3Schristos /* Create mmapped memory. ADDR is -1 if any address will do. Caller
95766e63ce3Schristos must make sure that the address isn't already mapped. */
95866e63ce3Schristos
95966e63ce3Schristos static USI
create_map(SIM_DESC sd,struct cris_sim_mmapped_page ** rootp,USI addr,USI len)96066e63ce3Schristos create_map (SIM_DESC sd, struct cris_sim_mmapped_page **rootp, USI addr,
96166e63ce3Schristos USI len)
96266e63ce3Schristos {
96366e63ce3Schristos struct cris_sim_mmapped_page *mapp;
96466e63ce3Schristos struct cris_sim_mmapped_page **higher_prevp = rootp;
96566e63ce3Schristos USI new_addr = 0x40000000;
96666e63ce3Schristos
96766e63ce3Schristos if (addr != (USI) -1)
96866e63ce3Schristos new_addr = addr;
96966e63ce3Schristos else if (*rootp && rootp[0]->addr >= new_addr)
97066e63ce3Schristos new_addr = rootp[0]->addr + 8192;
97166e63ce3Schristos
97266e63ce3Schristos if (len != 8192)
97366e63ce3Schristos {
97466e63ce3Schristos USI page_addr;
97566e63ce3Schristos
97666e63ce3Schristos if (len & 8191)
97766e63ce3Schristos /* Which is better: return an error for this, or just round it up? */
97866e63ce3Schristos abort ();
97966e63ce3Schristos
98066e63ce3Schristos /* Do a recursive call for each page in the request. */
98166e63ce3Schristos for (page_addr = new_addr; len != 0; page_addr += 8192, len -= 8192)
98266e63ce3Schristos if (create_map (sd, rootp, page_addr, 8192) >= (USI) -8191)
98366e63ce3Schristos abort ();
98466e63ce3Schristos
98566e63ce3Schristos return new_addr;
98666e63ce3Schristos }
98766e63ce3Schristos
98866e63ce3Schristos for (mapp = *rootp;
98966e63ce3Schristos mapp != NULL && mapp->addr > new_addr;
99066e63ce3Schristos mapp = mapp->prev)
99166e63ce3Schristos higher_prevp = &mapp->prev;
99266e63ce3Schristos
99366e63ce3Schristos /* Assert for consistency that we don't create duplicate maps. */
99466e63ce3Schristos if (is_mapped (sd, rootp, new_addr, len))
99566e63ce3Schristos abort ();
99666e63ce3Schristos
99766e63ce3Schristos /* Allocate the new page, on the next higher page from the last one
99866e63ce3Schristos allocated, and link in the new descriptor before previous ones. */
99966e63ce3Schristos mapp = malloc (sizeof (*mapp));
100066e63ce3Schristos
100166e63ce3Schristos if (mapp == NULL)
100266e63ce3Schristos return (USI) -ENOMEM;
100366e63ce3Schristos
100466e63ce3Schristos sim_core_attach (sd, NULL, 0, access_read_write_exec, 0,
100566e63ce3Schristos new_addr, len,
100666e63ce3Schristos 0, NULL, NULL);
100766e63ce3Schristos
100866e63ce3Schristos mapp->addr = new_addr;
100966e63ce3Schristos mapp->prev = *higher_prevp;
101066e63ce3Schristos *higher_prevp = mapp;
101166e63ce3Schristos
101266e63ce3Schristos return new_addr;
101366e63ce3Schristos }
101466e63ce3Schristos
101566e63ce3Schristos /* Unmap one or more pages. */
101666e63ce3Schristos
101766e63ce3Schristos static USI
unmap_pages(SIM_DESC sd,struct cris_sim_mmapped_page ** rootp,USI addr,USI len)101866e63ce3Schristos unmap_pages (SIM_DESC sd, struct cris_sim_mmapped_page **rootp, USI addr,
101966e63ce3Schristos USI len)
102066e63ce3Schristos {
102166e63ce3Schristos struct cris_sim_mmapped_page *mapp;
102266e63ce3Schristos struct cris_sim_mmapped_page **higher_prevp = rootp;
102366e63ce3Schristos
102466e63ce3Schristos if (len != 8192)
102566e63ce3Schristos {
102666e63ce3Schristos USI page_addr;
102766e63ce3Schristos int ret = 0;
102866e63ce3Schristos
102966e63ce3Schristos if (len & 8191)
103066e63ce3Schristos /* Which is better: return an error for this, or just round it up? */
103166e63ce3Schristos abort ();
103266e63ce3Schristos
103366e63ce3Schristos /* Loop backwards to make each call is O(1) over the number of pages
103466e63ce3Schristos allocated, if we're unmapping from the high end of the pages. */
103566e63ce3Schristos for (page_addr = addr + len - 8192;
103666e63ce3Schristos page_addr > addr;
103766e63ce3Schristos page_addr -= 8192)
103866e63ce3Schristos if (unmap_pages (sd, rootp, page_addr, 8192))
103966e63ce3Schristos ret = EINVAL;
104066e63ce3Schristos
104166e63ce3Schristos if (unmap_pages (sd, rootp, addr, 8192))
104266e63ce3Schristos ret = EINVAL;
104366e63ce3Schristos
104466e63ce3Schristos return ret;
104566e63ce3Schristos }
104666e63ce3Schristos
104766e63ce3Schristos for (mapp = *rootp; mapp != NULL && mapp->addr > addr; mapp = mapp->prev)
104866e63ce3Schristos higher_prevp = &mapp->prev;
104966e63ce3Schristos
105066e63ce3Schristos if (mapp == NULL || mapp->addr != addr)
105166e63ce3Schristos return EINVAL;
105266e63ce3Schristos
105366e63ce3Schristos *higher_prevp = mapp->prev;
105466e63ce3Schristos sim_core_detach (sd, NULL, 0, 0, addr);
105566e63ce3Schristos free (mapp);
105666e63ce3Schristos return 0;
105766e63ce3Schristos }
105866e63ce3Schristos
105966e63ce3Schristos /* The semantic code invokes this for illegal (unrecognized) instructions. */
106066e63ce3Schristos
106166e63ce3Schristos SEM_PC
sim_engine_invalid_insn(SIM_CPU * current_cpu,IADDR cia,SEM_PC vpc)106266e63ce3Schristos sim_engine_invalid_insn (SIM_CPU *current_cpu, IADDR cia, SEM_PC vpc)
106366e63ce3Schristos {
106466e63ce3Schristos SIM_DESC sd = CPU_STATE (current_cpu);
106566e63ce3Schristos
106666e63ce3Schristos sim_engine_halt (sd, current_cpu, NULL, cia, sim_stopped, SIM_SIGILL);
106766e63ce3Schristos return vpc;
106866e63ce3Schristos }
106966e63ce3Schristos
107066e63ce3Schristos /* Handlers from the CGEN description that should not be called. */
107166e63ce3Schristos
107266e63ce3Schristos USI
cris_bmod_handler(SIM_CPU * current_cpu ATTRIBUTE_UNUSED,UINT srcreg ATTRIBUTE_UNUSED,USI dstreg ATTRIBUTE_UNUSED)107366e63ce3Schristos cris_bmod_handler (SIM_CPU *current_cpu ATTRIBUTE_UNUSED,
107466e63ce3Schristos UINT srcreg ATTRIBUTE_UNUSED,
107566e63ce3Schristos USI dstreg ATTRIBUTE_UNUSED)
107666e63ce3Schristos {
107766e63ce3Schristos SIM_DESC sd = CPU_STATE (current_cpu);
107866e63ce3Schristos abort ();
107966e63ce3Schristos }
108066e63ce3Schristos
108166e63ce3Schristos void
h_supr_set_handler(SIM_CPU * current_cpu ATTRIBUTE_UNUSED,UINT index ATTRIBUTE_UNUSED,USI page ATTRIBUTE_UNUSED,USI newval ATTRIBUTE_UNUSED)108266e63ce3Schristos h_supr_set_handler (SIM_CPU *current_cpu ATTRIBUTE_UNUSED,
108366e63ce3Schristos UINT index ATTRIBUTE_UNUSED,
108466e63ce3Schristos USI page ATTRIBUTE_UNUSED,
108566e63ce3Schristos USI newval ATTRIBUTE_UNUSED)
108666e63ce3Schristos {
108766e63ce3Schristos SIM_DESC sd = CPU_STATE (current_cpu);
108866e63ce3Schristos abort ();
108966e63ce3Schristos }
109066e63ce3Schristos
109166e63ce3Schristos USI
h_supr_get_handler(SIM_CPU * current_cpu ATTRIBUTE_UNUSED,UINT index ATTRIBUTE_UNUSED,USI page ATTRIBUTE_UNUSED)109266e63ce3Schristos h_supr_get_handler (SIM_CPU *current_cpu ATTRIBUTE_UNUSED,
109366e63ce3Schristos UINT index ATTRIBUTE_UNUSED,
109466e63ce3Schristos USI page ATTRIBUTE_UNUSED)
109566e63ce3Schristos {
109666e63ce3Schristos SIM_DESC sd = CPU_STATE (current_cpu);
109766e63ce3Schristos abort ();
109866e63ce3Schristos }
109966e63ce3Schristos
110066e63ce3Schristos /* Swap one context for another. */
110166e63ce3Schristos
110266e63ce3Schristos static void
schedule(SIM_CPU * current_cpu,int next)110366e63ce3Schristos schedule (SIM_CPU *current_cpu, int next)
110466e63ce3Schristos {
110566e63ce3Schristos /* Need to mark context-switches in the trace output. */
110666e63ce3Schristos if ((CPU_CRIS_MISC_PROFILE (current_cpu)->flags
110766e63ce3Schristos & FLAG_CRIS_MISC_PROFILE_XSIM_TRACE))
110866e63ce3Schristos cris_trace_printf (CPU_STATE (current_cpu), current_cpu,
110966e63ce3Schristos "\t#:%d\n", next);
111066e63ce3Schristos
111166e63ce3Schristos /* Copy the current context (if there is one) to its slot. */
111266e63ce3Schristos if (current_cpu->thread_data[current_cpu->threadno].cpu_context)
111366e63ce3Schristos memcpy (current_cpu->thread_data[current_cpu->threadno].cpu_context,
111466e63ce3Schristos ¤t_cpu->cpu_data_placeholder,
111566e63ce3Schristos current_cpu->thread_cpu_data_size);
111666e63ce3Schristos
111766e63ce3Schristos /* Copy the new context from its slot. */
111866e63ce3Schristos memcpy (¤t_cpu->cpu_data_placeholder,
111966e63ce3Schristos current_cpu->thread_data[next].cpu_context,
112066e63ce3Schristos current_cpu->thread_cpu_data_size);
112166e63ce3Schristos
112266e63ce3Schristos /* Update needed stuff to indicate the new context. */
112366e63ce3Schristos current_cpu->threadno = next;
112466e63ce3Schristos
112566e63ce3Schristos /* Handle pending signals. */
112666e63ce3Schristos if (current_cpu->thread_data[next].sigpending
112766e63ce3Schristos /* We don't run nested signal handlers. This means that pause(2)
112866e63ce3Schristos and sigsuspend(2) do not work in sighandlers, but that
112966e63ce3Schristos shouldn't be too hard a restriction. It also greatly
113066e63ce3Schristos simplifies the code. */
113166e63ce3Schristos && current_cpu->thread_data[next].cpu_context_atsignal == NULL)
113266e63ce3Schristos {
113366e63ce3Schristos int sig;
113466e63ce3Schristos
113566e63ce3Schristos /* See if there's really a pending, non-blocked handler. We don't
113666e63ce3Schristos queue signals, so just use the first one in ascending order. */
113766e63ce3Schristos for (sig = 0; sig < 64; sig++)
113866e63ce3Schristos if (current_cpu->thread_data[next].sigdata[sig].pending
113966e63ce3Schristos && !current_cpu->thread_data[next].sigdata[sig].blocked)
114066e63ce3Schristos {
114166e63ce3Schristos bfd_byte regbuf[4];
114266e63ce3Schristos USI sp;
114366e63ce3Schristos int i;
114466e63ce3Schristos USI blocked;
114566e63ce3Schristos USI pc = sim_pc_get (current_cpu);
114666e63ce3Schristos
114766e63ce3Schristos /* It's simpler to save the CPU context inside the simulator
114866e63ce3Schristos than on the stack. */
114966e63ce3Schristos current_cpu->thread_data[next].cpu_context_atsignal
115066e63ce3Schristos = (*current_cpu
115166e63ce3Schristos ->make_thread_cpu_data) (current_cpu,
115266e63ce3Schristos current_cpu->thread_data[next]
115366e63ce3Schristos .cpu_context);
115466e63ce3Schristos
115566e63ce3Schristos (*CPU_REG_FETCH (current_cpu)) (current_cpu, H_GR_SP, regbuf, 4);
115666e63ce3Schristos sp = bfd_getl32 (regbuf);
115766e63ce3Schristos
115866e63ce3Schristos /* Make sure we have an aligned stack. */
115966e63ce3Schristos sp &= ~3;
116066e63ce3Schristos
116166e63ce3Schristos /* Make room for the signal frame, aligned. FIXME: Check that
116266e63ce3Schristos the memory exists, map it in if absent. (BTW, should also
116366e63ce3Schristos implement on-access automatic stack allocation). */
116466e63ce3Schristos sp -= 20;
116566e63ce3Schristos
116666e63ce3Schristos /* This isn't the same signal frame as the kernel uses, because
116766e63ce3Schristos we don't want to bother getting all registers on and off the
116866e63ce3Schristos stack. */
116966e63ce3Schristos
117066e63ce3Schristos /* First, we store the currently blocked signals. */
117166e63ce3Schristos blocked = 0;
117266e63ce3Schristos for (i = 0; i < 32; i++)
117366e63ce3Schristos blocked
117466e63ce3Schristos |= current_cpu->thread_data[next].sigdata[i + 1].blocked << i;
117566e63ce3Schristos sim_core_write_aligned_4 (current_cpu, pc, 0, sp, blocked);
117666e63ce3Schristos blocked = 0;
117766e63ce3Schristos for (i = 0; i < 31; i++)
117866e63ce3Schristos blocked
117966e63ce3Schristos |= current_cpu->thread_data[next].sigdata[i + 33].blocked << i;
118066e63ce3Schristos sim_core_write_aligned_4 (current_cpu, pc, 0, sp + 4, blocked);
118166e63ce3Schristos
118266e63ce3Schristos /* Then, the actual instructions. This is CPU-specific, but we
118366e63ce3Schristos use instructions from the common subset for v10 and v32 which
118466e63ce3Schristos should be safe for the time being but could be parametrized
118566e63ce3Schristos if need be. */
118666e63ce3Schristos /* MOVU.W [PC+],R9. */
118766e63ce3Schristos sim_core_write_aligned_2 (current_cpu, pc, 0, sp + 8, 0x9c5f);
118866e63ce3Schristos /* .WORD TARGET_SYS_sigreturn. */
118966e63ce3Schristos sim_core_write_aligned_2 (current_cpu, pc, 0, sp + 10,
119066e63ce3Schristos TARGET_SYS_sigreturn);
119166e63ce3Schristos /* BREAK 13. */
119266e63ce3Schristos sim_core_write_aligned_2 (current_cpu, pc, 0, sp + 12, 0xe93d);
119366e63ce3Schristos
119466e63ce3Schristos /* NOP (on v32; it's SETF on v10, but is the correct compatible
119566e63ce3Schristos instruction. Still, it doesn't matter because v10 has no
119666e63ce3Schristos delay slot for BREAK so it will not be executed). */
119766e63ce3Schristos sim_core_write_aligned_2 (current_cpu, pc, 0, sp + 16, 0x05b0);
119866e63ce3Schristos
119966e63ce3Schristos /* Modify registers to hold the right values for the sighandler
120066e63ce3Schristos context: updated stackpointer and return address pointing to
120166e63ce3Schristos the sigreturn stub. */
120266e63ce3Schristos bfd_putl32 (sp, regbuf);
120366e63ce3Schristos (*CPU_REG_STORE (current_cpu)) (current_cpu, H_GR_SP, regbuf, 4);
120466e63ce3Schristos bfd_putl32 (sp + 8, regbuf);
120566e63ce3Schristos (*CPU_REG_STORE (current_cpu)) (current_cpu, TARGET_SRP_REGNUM,
120666e63ce3Schristos regbuf, 4);
120766e63ce3Schristos
120866e63ce3Schristos current_cpu->thread_data[next].sigdata[sig].pending = 0;
120966e63ce3Schristos
121066e63ce3Schristos /* Block this signal (for the duration of the sighandler). */
121166e63ce3Schristos current_cpu->thread_data[next].sigdata[sig].blocked = 1;
121266e63ce3Schristos
121366e63ce3Schristos sim_pc_set (current_cpu, current_cpu->sighandler[sig]);
121466e63ce3Schristos bfd_putl32 (sig, regbuf);
121566e63ce3Schristos (*CPU_REG_STORE (current_cpu)) (current_cpu, H_GR_R10,
121666e63ce3Schristos regbuf, 4);
121766e63ce3Schristos
121866e63ce3Schristos /* We ignore a SA_SIGINFO flag in the sigaction call; the code I
121966e63ce3Schristos needed all this for, specifies a SA_SIGINFO call but treats it
122066e63ce3Schristos like an ordinary sighandler; only the signal number argument is
122166e63ce3Schristos inspected. To make future need to implement SA_SIGINFO
122266e63ce3Schristos correctly possible, we set the siginfo argument register to a
122366e63ce3Schristos magic (hopefully non-address) number. (NB: then, you should
122466e63ce3Schristos just need to pass the siginfo argument; it seems you probably
122566e63ce3Schristos don't need to implement the specific rt_sigreturn.) */
122666e63ce3Schristos bfd_putl32 (0xbad5161f, regbuf);
122766e63ce3Schristos (*CPU_REG_STORE (current_cpu)) (current_cpu, H_GR_R11,
122866e63ce3Schristos regbuf, 4);
122966e63ce3Schristos
123066e63ce3Schristos /* The third argument is unused and the kernel sets it to 0. */
123166e63ce3Schristos bfd_putl32 (0, regbuf);
123266e63ce3Schristos (*CPU_REG_STORE (current_cpu)) (current_cpu, H_GR_R12,
123366e63ce3Schristos regbuf, 4);
123466e63ce3Schristos return;
123566e63ce3Schristos }
123666e63ce3Schristos
123766e63ce3Schristos /* No, there actually was no pending signal for this thread. Reset
123866e63ce3Schristos this flag. */
123966e63ce3Schristos current_cpu->thread_data[next].sigpending = 0;
124066e63ce3Schristos }
124166e63ce3Schristos }
124266e63ce3Schristos
124366e63ce3Schristos /* Reschedule the simplest possible way until something else is absolutely
124466e63ce3Schristos necessary:
124566e63ce3Schristos - A. Find the next process (round-robin) that doesn't have at_syscall
124666e63ce3Schristos set, schedule it.
124766e63ce3Schristos - B. If there is none, just run the next process, round-robin.
124866e63ce3Schristos - Clear at_syscall for the current process. */
124966e63ce3Schristos
125066e63ce3Schristos static void
reschedule(SIM_CPU * current_cpu)125166e63ce3Schristos reschedule (SIM_CPU *current_cpu)
125266e63ce3Schristos {
125366e63ce3Schristos SIM_DESC sd = CPU_STATE (current_cpu);
125466e63ce3Schristos int i;
125566e63ce3Schristos
125666e63ce3Schristos /* Iterate over all thread slots, because after a few thread creations
125766e63ce3Schristos and exits, we don't know where the live ones are. */
125866e63ce3Schristos for (i = (current_cpu->threadno + 1) % SIM_TARGET_MAX_THREADS;
125966e63ce3Schristos i != current_cpu->threadno;
126066e63ce3Schristos i = (i + 1) % SIM_TARGET_MAX_THREADS)
126166e63ce3Schristos if (current_cpu->thread_data[i].cpu_context
126266e63ce3Schristos && current_cpu->thread_data[i].at_syscall == 0)
126366e63ce3Schristos {
126466e63ce3Schristos schedule (current_cpu, i);
126566e63ce3Schristos return;
126666e63ce3Schristos }
126766e63ce3Schristos
126866e63ce3Schristos /* Pick any next live thread. */
126966e63ce3Schristos for (i = (current_cpu->threadno + 1) % SIM_TARGET_MAX_THREADS;
127066e63ce3Schristos i != current_cpu->threadno;
127166e63ce3Schristos i = (i + 1) % SIM_TARGET_MAX_THREADS)
127266e63ce3Schristos if (current_cpu->thread_data[i].cpu_context)
127366e63ce3Schristos {
127466e63ce3Schristos schedule (current_cpu, i);
127566e63ce3Schristos return;
127666e63ce3Schristos }
127766e63ce3Schristos
127866e63ce3Schristos /* More than one live thread, but we couldn't find the next one? */
127966e63ce3Schristos abort ();
128066e63ce3Schristos }
128166e63ce3Schristos
128266e63ce3Schristos /* Set up everything to receive (or IGN) an incoming signal to the
128366e63ce3Schristos current context. */
128466e63ce3Schristos
128566e63ce3Schristos static int
deliver_signal(SIM_CPU * current_cpu,int sig,unsigned int pid)128666e63ce3Schristos deliver_signal (SIM_CPU *current_cpu, int sig, unsigned int pid)
128766e63ce3Schristos {
128866e63ce3Schristos int i;
128966e63ce3Schristos USI pc = sim_pc_get (current_cpu);
129066e63ce3Schristos
129166e63ce3Schristos /* Find the thread index of the pid. */
129266e63ce3Schristos for (i = 0; i < SIM_TARGET_MAX_THREADS; i++)
129366e63ce3Schristos /* Apparently it's ok to send signals to zombies (so a check for
129466e63ce3Schristos current_cpu->thread_data[i].cpu_context != NULL would be
129566e63ce3Schristos wrong). */
129666e63ce3Schristos if (current_cpu->thread_data[i].threadid == pid - TARGET_PID)
129766e63ce3Schristos {
129866e63ce3Schristos if (sig < 64)
129966e63ce3Schristos switch (current_cpu->sighandler[sig])
130066e63ce3Schristos {
130166e63ce3Schristos case TARGET_SIG_DFL:
130266e63ce3Schristos switch (sig)
130366e63ce3Schristos {
130466e63ce3Schristos /* The following according to the glibc
130566e63ce3Schristos documentation. (The kernel code has non-obvious
130666e63ce3Schristos execution paths.) */
130766e63ce3Schristos case TARGET_SIGFPE:
130866e63ce3Schristos case TARGET_SIGILL:
130966e63ce3Schristos case TARGET_SIGSEGV:
131066e63ce3Schristos case TARGET_SIGBUS:
131166e63ce3Schristos case TARGET_SIGABRT:
131266e63ce3Schristos case TARGET_SIGTRAP:
131366e63ce3Schristos case TARGET_SIGSYS:
131466e63ce3Schristos
131566e63ce3Schristos case TARGET_SIGTERM:
131666e63ce3Schristos case TARGET_SIGINT:
131766e63ce3Schristos case TARGET_SIGQUIT:
131866e63ce3Schristos case TARGET_SIGKILL:
131966e63ce3Schristos case TARGET_SIGHUP:
132066e63ce3Schristos
132166e63ce3Schristos case TARGET_SIGALRM:
132266e63ce3Schristos case TARGET_SIGVTALRM:
132366e63ce3Schristos case TARGET_SIGPROF:
132466e63ce3Schristos case TARGET_SIGSTOP:
132566e63ce3Schristos
132666e63ce3Schristos case TARGET_SIGPIPE:
132766e63ce3Schristos case TARGET_SIGLOST:
132866e63ce3Schristos case TARGET_SIGXCPU:
132966e63ce3Schristos case TARGET_SIGXFSZ:
133066e63ce3Schristos case TARGET_SIGUSR1:
133166e63ce3Schristos case TARGET_SIGUSR2:
133266e63ce3Schristos sim_io_eprintf (CPU_STATE (current_cpu),
133366e63ce3Schristos "Exiting pid %d due to signal %d\n",
133466e63ce3Schristos pid, sig);
133566e63ce3Schristos sim_engine_halt (CPU_STATE (current_cpu), current_cpu,
133666e63ce3Schristos NULL, pc, sim_stopped,
133766e63ce3Schristos sig == TARGET_SIGABRT
133866e63ce3Schristos ? SIM_SIGABRT : SIM_SIGILL);
133966e63ce3Schristos return 0;
134066e63ce3Schristos
134166e63ce3Schristos /* The default for all other signals is to be ignored. */
134266e63ce3Schristos default:
134366e63ce3Schristos return 0;
134466e63ce3Schristos }
134566e63ce3Schristos
134666e63ce3Schristos case TARGET_SIG_IGN:
134766e63ce3Schristos switch (sig)
134866e63ce3Schristos {
134966e63ce3Schristos case TARGET_SIGKILL:
135066e63ce3Schristos case TARGET_SIGSTOP:
135166e63ce3Schristos /* Can't ignore these signals. */
135266e63ce3Schristos sim_io_eprintf (CPU_STATE (current_cpu),
135366e63ce3Schristos "Exiting pid %d due to signal %d\n",
135466e63ce3Schristos pid, sig);
135566e63ce3Schristos sim_engine_halt (CPU_STATE (current_cpu), current_cpu,
135666e63ce3Schristos NULL, pc, sim_stopped, SIM_SIGILL);
135766e63ce3Schristos return 0;
135866e63ce3Schristos
135966e63ce3Schristos default:
136066e63ce3Schristos return 0;
136166e63ce3Schristos }
136266e63ce3Schristos break;
136366e63ce3Schristos
136466e63ce3Schristos default:
136566e63ce3Schristos /* Mark the signal as pending, making schedule () check
136666e63ce3Schristos closer. The signal will be handled when the thread is
136766e63ce3Schristos scheduled and the signal is unblocked. */
136866e63ce3Schristos current_cpu->thread_data[i].sigdata[sig].pending = 1;
136966e63ce3Schristos current_cpu->thread_data[i].sigpending = 1;
137066e63ce3Schristos return 0;
137166e63ce3Schristos }
137266e63ce3Schristos else
137366e63ce3Schristos {
137466e63ce3Schristos sim_io_eprintf (CPU_STATE (current_cpu),
137566e63ce3Schristos "Unimplemented signal: %d\n", sig);
137666e63ce3Schristos sim_engine_halt (CPU_STATE (current_cpu), current_cpu, NULL, pc,
137766e63ce3Schristos sim_stopped, SIM_SIGILL);
137866e63ce3Schristos }
137966e63ce3Schristos }
138066e63ce3Schristos
138166e63ce3Schristos return
138266e63ce3Schristos -cb_host_to_target_errno (STATE_CALLBACK (CPU_STATE (current_cpu)),
138366e63ce3Schristos ESRCH);
138466e63ce3Schristos }
138566e63ce3Schristos
138666e63ce3Schristos /* Make the vector and the first item, the main thread. */
138766e63ce3Schristos
138866e63ce3Schristos static void
make_first_thread(SIM_CPU * current_cpu)138966e63ce3Schristos make_first_thread (SIM_CPU *current_cpu)
139066e63ce3Schristos {
139166e63ce3Schristos SIM_DESC sd = CPU_STATE (current_cpu);
139266e63ce3Schristos current_cpu->thread_data
139366e63ce3Schristos = xcalloc (1,
139466e63ce3Schristos SIM_TARGET_MAX_THREADS
139566e63ce3Schristos * sizeof (current_cpu->thread_data[0]));
139666e63ce3Schristos current_cpu->thread_data[0].cpu_context
139766e63ce3Schristos = (*current_cpu->make_thread_cpu_data) (current_cpu,
139866e63ce3Schristos ¤t_cpu
139966e63ce3Schristos ->cpu_data_placeholder);
140066e63ce3Schristos current_cpu->thread_data[0].parent_threadid = -1;
140166e63ce3Schristos
140266e63ce3Schristos /* For good measure. */
140366e63ce3Schristos if (TARGET_SIG_DFL != 0)
140466e63ce3Schristos abort ();
140566e63ce3Schristos }
140666e63ce3Schristos
140766e63ce3Schristos /* Handle unknown system calls. Returns (if it does) the syscall
140866e63ce3Schristos return value. */
140966e63ce3Schristos
141066e63ce3Schristos static USI
cris_unknown_syscall(SIM_CPU * current_cpu,USI pc,char * s,...)141166e63ce3Schristos cris_unknown_syscall (SIM_CPU *current_cpu, USI pc, char *s, ...)
141266e63ce3Schristos {
141366e63ce3Schristos SIM_DESC sd = CPU_STATE (current_cpu);
141466e63ce3Schristos host_callback *cb = STATE_CALLBACK (sd);
141566e63ce3Schristos
141666e63ce3Schristos if (cris_unknown_syscall_action == CRIS_USYSC_MSG_STOP
141766e63ce3Schristos || cris_unknown_syscall_action == CRIS_USYSC_MSG_ENOSYS)
141866e63ce3Schristos {
141966e63ce3Schristos va_list ap;
142066e63ce3Schristos
142166e63ce3Schristos va_start (ap, s);
142266e63ce3Schristos sim_io_evprintf (sd, s, ap);
142366e63ce3Schristos va_end (ap);
142466e63ce3Schristos
142566e63ce3Schristos if (cris_unknown_syscall_action == CRIS_USYSC_MSG_STOP)
142666e63ce3Schristos sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGILL);
142766e63ce3Schristos }
142866e63ce3Schristos
142966e63ce3Schristos return -cb_host_to_target_errno (cb, ENOSYS);
143066e63ce3Schristos }
143166e63ce3Schristos
143266e63ce3Schristos /* Main function: the handler of the "break 13" syscall insn. */
143366e63ce3Schristos
143466e63ce3Schristos USI
cris_break_13_handler(SIM_CPU * current_cpu,USI callnum,USI arg1,USI arg2,USI arg3,USI arg4,USI arg5,USI arg6,USI pc)143566e63ce3Schristos cris_break_13_handler (SIM_CPU *current_cpu, USI callnum, USI arg1,
143666e63ce3Schristos USI arg2, USI arg3, USI arg4, USI arg5, USI arg6,
143766e63ce3Schristos USI pc)
143866e63ce3Schristos {
143966e63ce3Schristos CB_SYSCALL s;
144066e63ce3Schristos SIM_DESC sd = CPU_STATE (current_cpu);
144166e63ce3Schristos host_callback *cb = STATE_CALLBACK (sd);
144266e63ce3Schristos int retval;
144366e63ce3Schristos int threadno = current_cpu->threadno;
144466e63ce3Schristos
144566e63ce3Schristos current_cpu->syscalls++;
144666e63ce3Schristos
144766e63ce3Schristos CB_SYSCALL_INIT (&s);
144866e63ce3Schristos s.func = callnum;
144966e63ce3Schristos s.arg1 = arg1;
145066e63ce3Schristos s.arg2 = arg2;
145166e63ce3Schristos s.arg3 = arg3;
145266e63ce3Schristos
145366e63ce3Schristos /* The type of s.arg2 is long, so for hosts with 64-bit longs, we need
145466e63ce3Schristos to sign-extend the lseek offset to be passed as a signed number,
145566e63ce3Schristos else we'll truncate it to something > 2GB on hosts where sizeof
145666e63ce3Schristos long > sizeof USI. We avoid doing it for all syscalls, as arg2 is
145766e63ce3Schristos e.g. an address for some syscalls. */
145866e63ce3Schristos if (callnum == TARGET_SYS_lseek)
145966e63ce3Schristos s.arg2 = (SI) arg2;
146066e63ce3Schristos
146166e63ce3Schristos if (callnum == TARGET_SYS_exit_group
146266e63ce3Schristos || (callnum == TARGET_SYS_exit && current_cpu->m1threads == 0))
146366e63ce3Schristos {
146466e63ce3Schristos if (CPU_CRIS_MISC_PROFILE (current_cpu)->flags
146566e63ce3Schristos & FLAG_CRIS_MISC_PROFILE_ALL)
146666e63ce3Schristos dump_statistics (current_cpu);
146766e63ce3Schristos sim_engine_halt (sd, current_cpu, NULL, pc, sim_exited, arg1);
146866e63ce3Schristos }
146966e63ce3Schristos
147066e63ce3Schristos s.p1 = (PTR) sd;
147166e63ce3Schristos s.p2 = (PTR) current_cpu;
1472ed6a76a9Schristos s.read_mem = sim_syscall_read_mem;
1473ed6a76a9Schristos s.write_mem = sim_syscall_write_mem;
147466e63ce3Schristos
147566e63ce3Schristos current_cpu_for_cb_callback = current_cpu;
147666e63ce3Schristos
147766e63ce3Schristos if (cb_syscall (cb, &s) != CB_RC_OK)
147866e63ce3Schristos {
147966e63ce3Schristos abort ();
148066e63ce3Schristos sim_io_eprintf (sd, "Break 13: invalid %d? Returned %ld\n", callnum,
148166e63ce3Schristos s.result);
148266e63ce3Schristos sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGILL);
148366e63ce3Schristos }
148466e63ce3Schristos
148566e63ce3Schristos retval = s.result == -1 ? -s.errcode : s.result;
148666e63ce3Schristos
148766e63ce3Schristos if (s.errcode != 0 && s.errcode == cb_host_to_target_errno (cb, ENOSYS))
148866e63ce3Schristos {
148966e63ce3Schristos /* If the generic simulator call said ENOSYS, then let's try the
149066e63ce3Schristos ones we know ourselves.
149166e63ce3Schristos
149266e63ce3Schristos The convention is to provide *very limited* functionality on an
149366e63ce3Schristos as-needed basis, only what's covered by the test-suite, tests
149466e63ce3Schristos added when functionality changes and abort with a descriptive
149566e63ce3Schristos message for *everything* else. Where there's no test-case, we
149666e63ce3Schristos just abort. */
149766e63ce3Schristos switch (callnum)
149866e63ce3Schristos {
149966e63ce3Schristos case 0:
150066e63ce3Schristos /* It's a pretty safe bet that the "old setup() system call"
150166e63ce3Schristos number will not be re-used; we can't say the same for higher
150266e63ce3Schristos numbers. We treat this simulator-generated call as "wait
150366e63ce3Schristos forever"; we re-run this insn. The wait is ended by a
150466e63ce3Schristos callback. Sanity check that this is the reason we got
150566e63ce3Schristos here. */
150666e63ce3Schristos if (current_cpu->thread_data == NULL
150766e63ce3Schristos || (current_cpu->thread_data[threadno].pipe_write_fd == 0))
150866e63ce3Schristos goto unimplemented_syscall;
150966e63ce3Schristos
151066e63ce3Schristos sim_pc_set (current_cpu, pc);
151166e63ce3Schristos retval = arg1;
151266e63ce3Schristos break;
151366e63ce3Schristos
151466e63ce3Schristos case TARGET_SYS_fcntl64:
151566e63ce3Schristos case TARGET_SYS_fcntl:
151666e63ce3Schristos switch (arg2)
151766e63ce3Schristos {
151866e63ce3Schristos case 1:
151966e63ce3Schristos /* F_GETFD.
152066e63ce3Schristos Glibc checks stdin, stdout and stderr fd:s for
152166e63ce3Schristos close-on-exec security sanity. We just need to provide a
152266e63ce3Schristos OK return value. If we really need to have a
152366e63ce3Schristos close-on-exec flag true, we could just do a real fcntl
152466e63ce3Schristos here. */
152566e63ce3Schristos retval = 0;
152666e63ce3Schristos break;
152766e63ce3Schristos
152866e63ce3Schristos case 2:
152966e63ce3Schristos /* F_SETFD. Just ignore attempts to set the close-on-exec
153066e63ce3Schristos flag. */
153166e63ce3Schristos retval = 0;
153266e63ce3Schristos break;
153366e63ce3Schristos
153466e63ce3Schristos case 3:
153566e63ce3Schristos /* F_GETFL. Check for the special case for open+fdopen. */
153666e63ce3Schristos if (current_cpu->last_syscall == TARGET_SYS_open
153766e63ce3Schristos && arg1 == current_cpu->last_open_fd)
153866e63ce3Schristos {
153966e63ce3Schristos retval = current_cpu->last_open_flags & TARGET_O_ACCMODE;
154066e63ce3Schristos break;
154166e63ce3Schristos }
154266e63ce3Schristos else if (arg1 == 0)
154366e63ce3Schristos {
154466e63ce3Schristos /* Because we can't freopen fd:s 0, 1, 2 to mean
154566e63ce3Schristos something else than stdin, stdout and stderr
154666e63ce3Schristos (sim/common/syscall.c:cb_syscall special cases fd
154766e63ce3Schristos 0, 1 and 2), we know what flags that we can
154866e63ce3Schristos sanely return for these fd:s. */
154966e63ce3Schristos retval = TARGET_O_RDONLY;
155066e63ce3Schristos break;
155166e63ce3Schristos }
155266e63ce3Schristos else if (arg1 == 1 || arg1 == 2)
155366e63ce3Schristos {
155466e63ce3Schristos retval = TARGET_O_WRONLY;
155566e63ce3Schristos break;
155666e63ce3Schristos }
155766e63ce3Schristos /* FALLTHROUGH */
155866e63ce3Schristos default:
155966e63ce3Schristos /* Nothing else is implemented. */
156066e63ce3Schristos retval
156166e63ce3Schristos = cris_unknown_syscall (current_cpu, pc,
156266e63ce3Schristos "Unimplemented %s syscall "
156366e63ce3Schristos "(fd: 0x%lx: cmd: 0x%lx arg: "
156466e63ce3Schristos "0x%lx)\n",
156566e63ce3Schristos callnum == TARGET_SYS_fcntl
156666e63ce3Schristos ? "fcntl" : "fcntl64",
156766e63ce3Schristos (unsigned long) (USI) arg1,
156866e63ce3Schristos (unsigned long) (USI) arg2,
156966e63ce3Schristos (unsigned long) (USI) arg3);
157066e63ce3Schristos break;
157166e63ce3Schristos }
157266e63ce3Schristos break;
157366e63ce3Schristos
157466e63ce3Schristos case TARGET_SYS_uname:
157566e63ce3Schristos {
157666e63ce3Schristos /* Fill in a few constants to appease glibc. */
157766e63ce3Schristos static char sim_utsname[6][65] =
157866e63ce3Schristos {
157966e63ce3Schristos "Linux",
158066e63ce3Schristos "sim-target",
158166e63ce3Schristos "2.6.27",
158266e63ce3Schristos TARGET_UTSNAME,
158366e63ce3Schristos "cris", /* Overwritten below. */
158466e63ce3Schristos "localdomain"
158566e63ce3Schristos };
158666e63ce3Schristos
158766e63ce3Schristos /* Having the hardware type in Linux equal to the bfd
158866e63ce3Schristos printable name is deliberate: if you make config.guess
158966e63ce3Schristos work on your Linux-type system the usual way, it
159066e63ce3Schristos probably will; either the bfd printable_name or the
159166e63ce3Schristos ambiguous arch_name. */
159266e63ce3Schristos strcpy (sim_utsname[4], STATE_ARCHITECTURE (sd)->printable_name);
159366e63ce3Schristos
159466e63ce3Schristos if ((s.write_mem) (cb, &s, arg1, (const char *) sim_utsname,
159566e63ce3Schristos sizeof (sim_utsname))
159666e63ce3Schristos != sizeof (sim_utsname))
159766e63ce3Schristos retval = -cb_host_to_target_errno (cb, EFAULT);
159866e63ce3Schristos else
159966e63ce3Schristos retval = 0;
160066e63ce3Schristos break;
160166e63ce3Schristos }
160266e63ce3Schristos
160366e63ce3Schristos case TARGET_SYS_geteuid32:
160466e63ce3Schristos /* We tell the truth with these. Maybe we shouldn't, but it
160566e63ce3Schristos should match the "stat" information. */
160666e63ce3Schristos retval = geteuid ();
160766e63ce3Schristos break;
160866e63ce3Schristos
160966e63ce3Schristos case TARGET_SYS_getuid32:
161066e63ce3Schristos retval = getuid ();
161166e63ce3Schristos break;
161266e63ce3Schristos
161366e63ce3Schristos case TARGET_SYS_getegid32:
161466e63ce3Schristos retval = getegid ();
161566e63ce3Schristos break;
161666e63ce3Schristos
161766e63ce3Schristos case TARGET_SYS_getgid32:
161866e63ce3Schristos retval = getgid ();
161966e63ce3Schristos break;
162066e63ce3Schristos
162166e63ce3Schristos case TARGET_SYS_brk:
162266e63ce3Schristos /* Most often, we just return the argument, like the Linux
162366e63ce3Schristos kernel. */
162466e63ce3Schristos retval = arg1;
162566e63ce3Schristos
162666e63ce3Schristos if (arg1 == 0)
162766e63ce3Schristos retval = current_cpu->endbrk;
162866e63ce3Schristos else if (arg1 <= current_cpu->endmem)
162966e63ce3Schristos current_cpu->endbrk = arg1;
163066e63ce3Schristos else
163166e63ce3Schristos {
163266e63ce3Schristos USI new_end = (arg1 + 8191) & ~8191;
163366e63ce3Schristos
163466e63ce3Schristos /* If the simulator wants to brk more than a certain very
163566e63ce3Schristos large amount, something is wrong. FIXME: Return an error
163666e63ce3Schristos or abort? Have command-line selectable? */
163766e63ce3Schristos if (new_end - current_cpu->endmem > SIM_MAX_ALLOC_CHUNK)
163866e63ce3Schristos {
163966e63ce3Schristos current_cpu->endbrk = current_cpu->endmem;
164066e63ce3Schristos retval = current_cpu->endmem;
164166e63ce3Schristos break;
164266e63ce3Schristos }
164366e63ce3Schristos
164466e63ce3Schristos sim_core_attach (sd, NULL, 0, access_read_write_exec, 0,
164566e63ce3Schristos current_cpu->endmem,
164666e63ce3Schristos new_end - current_cpu->endmem,
164766e63ce3Schristos 0, NULL, NULL);
164866e63ce3Schristos current_cpu->endbrk = arg1;
164966e63ce3Schristos current_cpu->endmem = new_end;
165066e63ce3Schristos }
165166e63ce3Schristos break;
165266e63ce3Schristos
165366e63ce3Schristos case TARGET_SYS_getpid:
165466e63ce3Schristos /* Correct until CLONE_THREAD is implemented. */
165566e63ce3Schristos retval = current_cpu->thread_data == NULL
165666e63ce3Schristos ? TARGET_PID
165766e63ce3Schristos : TARGET_PID + current_cpu->thread_data[threadno].threadid;
165866e63ce3Schristos break;
165966e63ce3Schristos
166066e63ce3Schristos case TARGET_SYS_getppid:
166166e63ce3Schristos /* Correct until CLONE_THREAD is implemented. */
166266e63ce3Schristos retval = current_cpu->thread_data == NULL
166366e63ce3Schristos ? TARGET_PID - 1
166466e63ce3Schristos : (TARGET_PID
166566e63ce3Schristos + current_cpu->thread_data[threadno].parent_threadid);
166666e63ce3Schristos break;
166766e63ce3Schristos
166866e63ce3Schristos case TARGET_SYS_mmap2:
166966e63ce3Schristos {
167066e63ce3Schristos USI addr = arg1;
167166e63ce3Schristos USI len = arg2;
167266e63ce3Schristos USI prot = arg3;
167366e63ce3Schristos USI flags = arg4;
167466e63ce3Schristos USI fd = arg5;
167566e63ce3Schristos USI pgoff = arg6;
167666e63ce3Schristos
167766e63ce3Schristos /* At 2.6.27, Linux (many (all?) ports, in the mmap2 syscalls)
167866e63ce3Schristos still masked away this bit, so let's just ignore
167966e63ce3Schristos it. */
168066e63ce3Schristos flags &= ~TARGET_MAP_DENYWRITE;
168166e63ce3Schristos
168266e63ce3Schristos /* If the simulator wants to mmap more than the very large
168366e63ce3Schristos limit, something is wrong. FIXME: Return an error or
168466e63ce3Schristos abort? Have command-line selectable? */
168566e63ce3Schristos if (len > SIM_MAX_ALLOC_CHUNK)
168666e63ce3Schristos {
168766e63ce3Schristos retval = -cb_host_to_target_errno (cb, ENOMEM);
168866e63ce3Schristos break;
168966e63ce3Schristos }
169066e63ce3Schristos
169166e63ce3Schristos if ((prot != (TARGET_PROT_READ | TARGET_PROT_WRITE)
169266e63ce3Schristos && (prot
169366e63ce3Schristos != (TARGET_PROT_READ
169466e63ce3Schristos | TARGET_PROT_WRITE
169566e63ce3Schristos | TARGET_PROT_EXEC))
169666e63ce3Schristos && (prot != (TARGET_PROT_READ | TARGET_PROT_EXEC))
169766e63ce3Schristos && prot != TARGET_PROT_READ)
169866e63ce3Schristos || (flags != (TARGET_MAP_ANONYMOUS | TARGET_MAP_PRIVATE)
169966e63ce3Schristos && flags != TARGET_MAP_PRIVATE
170066e63ce3Schristos && flags != (TARGET_MAP_ANONYMOUS
170166e63ce3Schristos | TARGET_MAP_PRIVATE | TARGET_MAP_FIXED)
170266e63ce3Schristos && flags != (TARGET_MAP_PRIVATE | TARGET_MAP_FIXED)
170366e63ce3Schristos && flags != TARGET_MAP_SHARED)
170466e63ce3Schristos || (fd != (USI) -1
170566e63ce3Schristos && prot != TARGET_PROT_READ
170666e63ce3Schristos && prot != (TARGET_PROT_READ | TARGET_PROT_EXEC)
170766e63ce3Schristos && prot != (TARGET_PROT_READ | TARGET_PROT_WRITE))
170866e63ce3Schristos || (fd == (USI) -1 && pgoff != 0)
170966e63ce3Schristos || (fd != (USI) -1 && (flags & TARGET_MAP_ANONYMOUS)))
171066e63ce3Schristos {
171166e63ce3Schristos retval
171266e63ce3Schristos = cris_unknown_syscall (current_cpu, pc,
171366e63ce3Schristos "Unimplemented mmap2 call "
171466e63ce3Schristos "(0x%lx, 0x%lx, 0x%lx, "
171566e63ce3Schristos "0x%lx, 0x%lx, 0x%lx)\n",
171666e63ce3Schristos (unsigned long) arg1,
171766e63ce3Schristos (unsigned long) arg2,
171866e63ce3Schristos (unsigned long) arg3,
171966e63ce3Schristos (unsigned long) arg4,
172066e63ce3Schristos (unsigned long) arg5,
172166e63ce3Schristos (unsigned long) arg6);
172266e63ce3Schristos break;
172366e63ce3Schristos }
172466e63ce3Schristos else if (fd != (USI) -1)
172566e63ce3Schristos {
172666e63ce3Schristos /* Map a file. */
172766e63ce3Schristos
172866e63ce3Schristos USI newaddr;
172966e63ce3Schristos USI pos;
173066e63ce3Schristos
173166e63ce3Schristos /* A non-aligned argument is allowed for files. */
173266e63ce3Schristos USI newlen = (len + 8191) & ~8191;
173366e63ce3Schristos
173466e63ce3Schristos /* We only support read, read|exec, and read|write,
173566e63ce3Schristos which we should already have checked. Check again
173666e63ce3Schristos anyway. */
173766e63ce3Schristos if (prot != TARGET_PROT_READ
173866e63ce3Schristos && prot != (TARGET_PROT_READ | TARGET_PROT_EXEC)
173966e63ce3Schristos && prot != (TARGET_PROT_READ | TARGET_PROT_WRITE))
174066e63ce3Schristos abort ();
174166e63ce3Schristos
174266e63ce3Schristos if (flags & TARGET_MAP_FIXED)
174366e63ce3Schristos unmap_pages (sd, ¤t_cpu->highest_mmapped_page,
174466e63ce3Schristos addr, newlen);
174566e63ce3Schristos else if (is_mapped (sd, ¤t_cpu->highest_mmapped_page,
174666e63ce3Schristos addr, newlen))
174766e63ce3Schristos addr = 0;
174866e63ce3Schristos
174966e63ce3Schristos newaddr
175066e63ce3Schristos = create_map (sd, ¤t_cpu->highest_mmapped_page,
175166e63ce3Schristos addr != 0 || (flags & TARGET_MAP_FIXED)
175266e63ce3Schristos ? addr : -1,
175366e63ce3Schristos newlen);
175466e63ce3Schristos
175566e63ce3Schristos if (newaddr >= (USI) -8191)
175666e63ce3Schristos {
175766e63ce3Schristos abort ();
175866e63ce3Schristos retval = -cb_host_to_target_errno (cb, -(SI) newaddr);
175966e63ce3Schristos break;
176066e63ce3Schristos }
176166e63ce3Schristos
176266e63ce3Schristos /* We were asked for MAP_FIXED, but couldn't. */
176366e63ce3Schristos if ((flags & TARGET_MAP_FIXED) && newaddr != addr)
176466e63ce3Schristos {
176566e63ce3Schristos abort ();
176666e63ce3Schristos unmap_pages (sd, ¤t_cpu->highest_mmapped_page,
176766e63ce3Schristos newaddr, newlen);
176866e63ce3Schristos retval = -cb_host_to_target_errno (cb, EINVAL);
176966e63ce3Schristos break;
177066e63ce3Schristos }
177166e63ce3Schristos
177266e63ce3Schristos /* Find the current position in the file. */
177366e63ce3Schristos s.func = TARGET_SYS_lseek;
177466e63ce3Schristos s.arg1 = fd;
177566e63ce3Schristos s.arg2 = 0;
177666e63ce3Schristos s.arg3 = SEEK_CUR;
177766e63ce3Schristos if (cb_syscall (cb, &s) != CB_RC_OK)
177866e63ce3Schristos abort ();
177966e63ce3Schristos pos = s.result;
178066e63ce3Schristos
178166e63ce3Schristos if (s.result < 0)
178266e63ce3Schristos abort ();
178366e63ce3Schristos
178466e63ce3Schristos /* Move to the correct offset in the file. */
178566e63ce3Schristos s.func = TARGET_SYS_lseek;
178666e63ce3Schristos s.arg1 = fd;
178766e63ce3Schristos s.arg2 = pgoff*8192;
178866e63ce3Schristos s.arg3 = SEEK_SET;
178966e63ce3Schristos if (cb_syscall (cb, &s) != CB_RC_OK)
179066e63ce3Schristos abort ();
179166e63ce3Schristos
179266e63ce3Schristos if (s.result < 0)
179366e63ce3Schristos abort ();
179466e63ce3Schristos
179566e63ce3Schristos /* Use the standard read callback to read in "len"
179666e63ce3Schristos bytes. */
179766e63ce3Schristos s.func = TARGET_SYS_read;
179866e63ce3Schristos s.arg1 = fd;
179966e63ce3Schristos s.arg2 = newaddr;
180066e63ce3Schristos s.arg3 = len;
180166e63ce3Schristos if (cb_syscall (cb, &s) != CB_RC_OK)
180266e63ce3Schristos abort ();
180366e63ce3Schristos
180466e63ce3Schristos /* If the result is a page or more lesser than what
180566e63ce3Schristos was requested, something went wrong. */
180666e63ce3Schristos if (len >= 8192 && (USI) s.result <= len - 8192)
180766e63ce3Schristos abort ();
180866e63ce3Schristos
180966e63ce3Schristos /* After reading, we need to go back to the previous
181066e63ce3Schristos position in the file. */
181166e63ce3Schristos s.func = TARGET_SYS_lseek;
181266e63ce3Schristos s.arg1 = fd;
181366e63ce3Schristos s.arg2 = pos;
181466e63ce3Schristos s.arg3 = SEEK_SET;
181566e63ce3Schristos if (cb_syscall (cb, &s) != CB_RC_OK)
181666e63ce3Schristos abort ();
181766e63ce3Schristos if (pos != (USI) s.result)
181866e63ce3Schristos abort ();
181966e63ce3Schristos
182066e63ce3Schristos retval = newaddr;
182166e63ce3Schristos }
182266e63ce3Schristos else
182366e63ce3Schristos {
182466e63ce3Schristos USI newlen = (len + 8191) & ~8191;
182566e63ce3Schristos USI newaddr;
182666e63ce3Schristos
182766e63ce3Schristos if (flags & TARGET_MAP_FIXED)
182866e63ce3Schristos unmap_pages (sd, ¤t_cpu->highest_mmapped_page,
182966e63ce3Schristos addr, newlen);
183066e63ce3Schristos else if (is_mapped (sd, ¤t_cpu->highest_mmapped_page,
183166e63ce3Schristos addr, newlen))
183266e63ce3Schristos addr = 0;
183366e63ce3Schristos
183466e63ce3Schristos newaddr = create_map (sd, ¤t_cpu->highest_mmapped_page,
183566e63ce3Schristos addr != 0 || (flags & TARGET_MAP_FIXED)
183666e63ce3Schristos ? addr : -1,
183766e63ce3Schristos newlen);
183866e63ce3Schristos
183966e63ce3Schristos if (newaddr >= (USI) -8191)
184066e63ce3Schristos retval = -cb_host_to_target_errno (cb, -(SI) newaddr);
184166e63ce3Schristos else
184266e63ce3Schristos retval = newaddr;
184366e63ce3Schristos
184466e63ce3Schristos if ((flags & TARGET_MAP_FIXED) && newaddr != addr)
184566e63ce3Schristos {
184666e63ce3Schristos abort ();
184766e63ce3Schristos unmap_pages (sd, ¤t_cpu->highest_mmapped_page,
184866e63ce3Schristos newaddr, newlen);
184966e63ce3Schristos retval = -cb_host_to_target_errno (cb, EINVAL);
185066e63ce3Schristos break;
185166e63ce3Schristos }
185266e63ce3Schristos }
185366e63ce3Schristos break;
185466e63ce3Schristos }
185566e63ce3Schristos
185666e63ce3Schristos case TARGET_SYS_mprotect:
185766e63ce3Schristos {
185866e63ce3Schristos /* We only cover the case of linuxthreads mprotecting out
185966e63ce3Schristos its stack guard page and of dynamic loading mprotecting
186066e63ce3Schristos away the data (for some reason the whole library, then
186166e63ce3Schristos mprotects away the data part and mmap-FIX:es it again. */
186266e63ce3Schristos USI addr = arg1;
186366e63ce3Schristos USI len = arg2;
186466e63ce3Schristos USI prot = arg3;
186566e63ce3Schristos
186666e63ce3Schristos if (prot != TARGET_PROT_NONE
186766e63ce3Schristos || !is_mapped_only (sd, ¤t_cpu->highest_mmapped_page,
186866e63ce3Schristos addr, (len + 8191) & ~8191))
186966e63ce3Schristos {
187066e63ce3Schristos retval
187166e63ce3Schristos = cris_unknown_syscall (current_cpu, pc,
187266e63ce3Schristos "Unimplemented mprotect call "
187366e63ce3Schristos "(0x%lx, 0x%lx, 0x%lx)\n",
187466e63ce3Schristos (unsigned long) arg1,
187566e63ce3Schristos (unsigned long) arg2,
187666e63ce3Schristos (unsigned long) arg3);
187766e63ce3Schristos break;
187866e63ce3Schristos }
187966e63ce3Schristos
188066e63ce3Schristos /* Just ignore this. We could make this equal to munmap,
188166e63ce3Schristos but then we'd have to make sure no anon mmaps gets this
188266e63ce3Schristos address before a subsequent MAP_FIXED mmap intended to
188366e63ce3Schristos override it. */
188466e63ce3Schristos retval = 0;
188566e63ce3Schristos break;
188666e63ce3Schristos }
188766e63ce3Schristos
188866e63ce3Schristos case TARGET_SYS_ioctl:
188966e63ce3Schristos {
189066e63ce3Schristos /* We support only a very limited functionality: checking
189166e63ce3Schristos stdout with TCGETS to perform the isatty function. The
189266e63ce3Schristos TCGETS ioctl isn't actually performed or the result used by
189366e63ce3Schristos an isatty () caller in a "hello, world" program; only the
189466e63ce3Schristos return value is then used. Maybe we shouldn't care about
189566e63ce3Schristos the environment of the simulator regarding isatty, but
189666e63ce3Schristos that's been working before, in the xsim simulator. */
189766e63ce3Schristos if (arg2 == TARGET_TCGETS && arg1 == 1)
189866e63ce3Schristos retval = isatty (1) ? 0 : cb_host_to_target_errno (cb, EINVAL);
189966e63ce3Schristos else
190066e63ce3Schristos retval = -cb_host_to_target_errno (cb, EINVAL);
190166e63ce3Schristos break;
190266e63ce3Schristos }
190366e63ce3Schristos
190466e63ce3Schristos case TARGET_SYS_munmap:
190566e63ce3Schristos {
190666e63ce3Schristos USI addr = arg1;
190766e63ce3Schristos USI len = arg2;
190866e63ce3Schristos USI result
190966e63ce3Schristos = unmap_pages (sd, ¤t_cpu->highest_mmapped_page, addr,
191066e63ce3Schristos len);
191166e63ce3Schristos retval = result != 0 ? -cb_host_to_target_errno (cb, result) : 0;
191266e63ce3Schristos break;
191366e63ce3Schristos }
191466e63ce3Schristos
191566e63ce3Schristos case TARGET_SYS_wait4:
191666e63ce3Schristos {
191766e63ce3Schristos int i;
191866e63ce3Schristos USI pid = arg1;
191966e63ce3Schristos USI saddr = arg2;
192066e63ce3Schristos USI options = arg3;
192166e63ce3Schristos USI rusagep = arg4;
192266e63ce3Schristos
192366e63ce3Schristos /* FIXME: We're not properly implementing __WCLONE, and we
192466e63ce3Schristos don't really need the special casing so we might as well
192566e63ce3Schristos make this general. */
192666e63ce3Schristos if ((!(pid == (USI) -1
192766e63ce3Schristos && options == (TARGET___WCLONE | TARGET_WNOHANG)
192866e63ce3Schristos && saddr != 0)
192966e63ce3Schristos && !(pid > 0
193066e63ce3Schristos && (options == TARGET___WCLONE
193166e63ce3Schristos || options == TARGET___WALL)))
193266e63ce3Schristos || rusagep != 0
193366e63ce3Schristos || current_cpu->thread_data == NULL)
193466e63ce3Schristos {
193566e63ce3Schristos retval
193666e63ce3Schristos = cris_unknown_syscall (current_cpu, pc,
193766e63ce3Schristos "Unimplemented wait4 call "
193866e63ce3Schristos "(0x%lx, 0x%lx, 0x%lx, 0x%lx)\n",
193966e63ce3Schristos (unsigned long) arg1,
194066e63ce3Schristos (unsigned long) arg2,
194166e63ce3Schristos (unsigned long) arg3,
194266e63ce3Schristos (unsigned long) arg4);
194366e63ce3Schristos break;
194466e63ce3Schristos }
194566e63ce3Schristos
194666e63ce3Schristos if (pid == (USI) -1)
194766e63ce3Schristos for (i = 1; i < SIM_TARGET_MAX_THREADS; i++)
194866e63ce3Schristos {
194966e63ce3Schristos if (current_cpu->thread_data[threadno].threadid
195066e63ce3Schristos == current_cpu->thread_data[i].parent_threadid
195166e63ce3Schristos && current_cpu->thread_data[i].threadid != 0
195266e63ce3Schristos && current_cpu->thread_data[i].cpu_context == NULL)
195366e63ce3Schristos {
195466e63ce3Schristos /* A zombied child. Get the exit value and clear the
195566e63ce3Schristos zombied entry so it will be reused. */
195666e63ce3Schristos sim_core_write_unaligned_4 (current_cpu, pc, 0, saddr,
195766e63ce3Schristos current_cpu
195866e63ce3Schristos ->thread_data[i].exitval);
195966e63ce3Schristos retval
196066e63ce3Schristos = current_cpu->thread_data[i].threadid + TARGET_PID;
196166e63ce3Schristos memset (¤t_cpu->thread_data[i], 0,
196266e63ce3Schristos sizeof (current_cpu->thread_data[i]));
196366e63ce3Schristos goto outer_break;
196466e63ce3Schristos }
196566e63ce3Schristos }
196666e63ce3Schristos else
196766e63ce3Schristos {
196866e63ce3Schristos /* We're waiting for a specific PID. If we don't find
196966e63ce3Schristos it zombied on this run, rerun the syscall. */
197066e63ce3Schristos for (i = 1; i < SIM_TARGET_MAX_THREADS; i++)
197166e63ce3Schristos if (pid == current_cpu->thread_data[i].threadid + TARGET_PID
197266e63ce3Schristos && current_cpu->thread_data[i].cpu_context == NULL)
197366e63ce3Schristos {
197466e63ce3Schristos if (saddr != 0)
197566e63ce3Schristos /* Get the exit value if the caller wants it. */
197666e63ce3Schristos sim_core_write_unaligned_4 (current_cpu, pc, 0,
197766e63ce3Schristos saddr,
197866e63ce3Schristos current_cpu
197966e63ce3Schristos ->thread_data[i]
198066e63ce3Schristos .exitval);
198166e63ce3Schristos
198266e63ce3Schristos retval
198366e63ce3Schristos = current_cpu->thread_data[i].threadid + TARGET_PID;
198466e63ce3Schristos memset (¤t_cpu->thread_data[i], 0,
198566e63ce3Schristos sizeof (current_cpu->thread_data[i]));
198666e63ce3Schristos
198766e63ce3Schristos goto outer_break;
198866e63ce3Schristos }
198966e63ce3Schristos
199066e63ce3Schristos sim_pc_set (current_cpu, pc);
199166e63ce3Schristos }
199266e63ce3Schristos
199366e63ce3Schristos retval = -cb_host_to_target_errno (cb, ECHILD);
199466e63ce3Schristos outer_break:
199566e63ce3Schristos break;
199666e63ce3Schristos }
199766e63ce3Schristos
199866e63ce3Schristos case TARGET_SYS_rt_sigaction:
199966e63ce3Schristos {
200066e63ce3Schristos USI signum = arg1;
200166e63ce3Schristos USI old_sa = arg3;
200266e63ce3Schristos USI new_sa = arg2;
200366e63ce3Schristos
200466e63ce3Schristos /* The kernel says:
200566e63ce3Schristos struct sigaction {
200666e63ce3Schristos __sighandler_t sa_handler;
200766e63ce3Schristos unsigned long sa_flags;
200866e63ce3Schristos void (*sa_restorer)(void);
200966e63ce3Schristos sigset_t sa_mask;
201066e63ce3Schristos }; */
201166e63ce3Schristos
201266e63ce3Schristos if (old_sa != 0)
201366e63ce3Schristos {
201466e63ce3Schristos sim_core_write_unaligned_4 (current_cpu, pc, 0, old_sa + 0,
201566e63ce3Schristos current_cpu->sighandler[signum]);
201666e63ce3Schristos sim_core_write_unaligned_4 (current_cpu, pc, 0, arg3 + 4, 0);
201766e63ce3Schristos sim_core_write_unaligned_4 (current_cpu, pc, 0, arg3 + 8, 0);
201866e63ce3Schristos
201966e63ce3Schristos /* We'll assume _NSIG_WORDS is 2 for the kernel. */
202066e63ce3Schristos sim_core_write_unaligned_4 (current_cpu, pc, 0, arg3 + 12, 0);
202166e63ce3Schristos sim_core_write_unaligned_4 (current_cpu, pc, 0, arg3 + 16, 0);
202266e63ce3Schristos }
202366e63ce3Schristos if (new_sa != 0)
202466e63ce3Schristos {
202566e63ce3Schristos USI target_sa_handler
202666e63ce3Schristos = sim_core_read_unaligned_4 (current_cpu, pc, 0, new_sa);
202766e63ce3Schristos USI target_sa_flags
202866e63ce3Schristos = sim_core_read_unaligned_4 (current_cpu, pc, 0, new_sa + 4);
202966e63ce3Schristos USI target_sa_restorer
203066e63ce3Schristos = sim_core_read_unaligned_4 (current_cpu, pc, 0, new_sa + 8);
203166e63ce3Schristos USI target_sa_mask_low
203266e63ce3Schristos = sim_core_read_unaligned_4 (current_cpu, pc, 0, new_sa + 12);
203366e63ce3Schristos USI target_sa_mask_high
203466e63ce3Schristos = sim_core_read_unaligned_4 (current_cpu, pc, 0, new_sa + 16);
203566e63ce3Schristos
203666e63ce3Schristos /* We won't interrupt a syscall so we won't restart it,
203766e63ce3Schristos but a signal(2) call ends up syscalling rt_sigaction
203866e63ce3Schristos with this flag, so we have to handle it. The
203966e63ce3Schristos sa_restorer field contains garbage when not
204066e63ce3Schristos TARGET_SA_RESTORER, so don't look at it. For the
204166e63ce3Schristos time being, we don't nest sighandlers, so we
204266e63ce3Schristos ignore the sa_mask, which simplifies things. */
204366e63ce3Schristos if ((target_sa_flags != 0
204466e63ce3Schristos && target_sa_flags != TARGET_SA_RESTART
204566e63ce3Schristos && target_sa_flags != (TARGET_SA_RESTART|TARGET_SA_SIGINFO))
204666e63ce3Schristos || target_sa_handler == 0)
204766e63ce3Schristos {
204866e63ce3Schristos retval
204966e63ce3Schristos = cris_unknown_syscall (current_cpu, pc,
205066e63ce3Schristos "Unimplemented rt_sigaction "
205166e63ce3Schristos "syscall "
205266e63ce3Schristos "(0x%lx, 0x%lx: "
205366e63ce3Schristos "[0x%x, 0x%x, 0x%x, "
205466e63ce3Schristos "{0x%x, 0x%x}], 0x%lx)\n",
205566e63ce3Schristos (unsigned long) arg1,
205666e63ce3Schristos (unsigned long) arg2,
205766e63ce3Schristos target_sa_handler,
205866e63ce3Schristos target_sa_flags,
205966e63ce3Schristos target_sa_restorer,
206066e63ce3Schristos target_sa_mask_low,
206166e63ce3Schristos target_sa_mask_high,
206266e63ce3Schristos (unsigned long) arg3);
206366e63ce3Schristos break;
206466e63ce3Schristos }
206566e63ce3Schristos
206666e63ce3Schristos current_cpu->sighandler[signum] = target_sa_handler;
206766e63ce3Schristos
206866e63ce3Schristos /* Because we may have unblocked signals, one may now be
206966e63ce3Schristos pending, if there are threads, that is. */
207066e63ce3Schristos if (current_cpu->thread_data)
207166e63ce3Schristos current_cpu->thread_data[threadno].sigpending = 1;
207266e63ce3Schristos }
207366e63ce3Schristos retval = 0;
207466e63ce3Schristos break;
207566e63ce3Schristos }
207666e63ce3Schristos
207766e63ce3Schristos case TARGET_SYS_mremap:
207866e63ce3Schristos {
207966e63ce3Schristos USI addr = arg1;
208066e63ce3Schristos USI old_len = arg2;
208166e63ce3Schristos USI new_len = arg3;
208266e63ce3Schristos USI flags = arg4;
208366e63ce3Schristos USI new_addr = arg5;
208466e63ce3Schristos USI mapped_addr;
208566e63ce3Schristos
208666e63ce3Schristos if (new_len == old_len)
208766e63ce3Schristos /* The program and/or library is possibly confused but
208866e63ce3Schristos this is a valid call. Happens with ipps-1.40 on file
208966e63ce3Schristos svs_all. */
209066e63ce3Schristos retval = addr;
209166e63ce3Schristos else if (new_len < old_len)
209266e63ce3Schristos {
209366e63ce3Schristos /* Shrinking is easy. */
209466e63ce3Schristos if (unmap_pages (sd, ¤t_cpu->highest_mmapped_page,
209566e63ce3Schristos addr + new_len, old_len - new_len) != 0)
209666e63ce3Schristos retval = -cb_host_to_target_errno (cb, EINVAL);
209766e63ce3Schristos else
209866e63ce3Schristos retval = addr;
209966e63ce3Schristos }
210066e63ce3Schristos else if (! is_mapped (sd, ¤t_cpu->highest_mmapped_page,
210166e63ce3Schristos addr + old_len, new_len - old_len))
210266e63ce3Schristos {
210366e63ce3Schristos /* If the extension isn't mapped, we can just add it. */
210466e63ce3Schristos mapped_addr
210566e63ce3Schristos = create_map (sd, ¤t_cpu->highest_mmapped_page,
210666e63ce3Schristos addr + old_len, new_len - old_len);
210766e63ce3Schristos
210866e63ce3Schristos if (mapped_addr > (USI) -8192)
210966e63ce3Schristos retval = -cb_host_to_target_errno (cb, -(SI) mapped_addr);
211066e63ce3Schristos else
211166e63ce3Schristos retval = addr;
211266e63ce3Schristos }
211366e63ce3Schristos else if (flags & TARGET_MREMAP_MAYMOVE)
211466e63ce3Schristos {
211566e63ce3Schristos /* Create a whole new map and copy the contents
211666e63ce3Schristos block-by-block there. We ignore the new_addr argument
211766e63ce3Schristos for now. */
211866e63ce3Schristos char buf[8192];
211966e63ce3Schristos USI prev_addr = addr;
212066e63ce3Schristos USI prev_len = old_len;
212166e63ce3Schristos
212266e63ce3Schristos mapped_addr
212366e63ce3Schristos = create_map (sd, ¤t_cpu->highest_mmapped_page,
212466e63ce3Schristos -1, new_len);
212566e63ce3Schristos
212666e63ce3Schristos if (mapped_addr > (USI) -8192)
212766e63ce3Schristos {
212866e63ce3Schristos retval = -cb_host_to_target_errno (cb, -(SI) new_addr);
212966e63ce3Schristos break;
213066e63ce3Schristos }
213166e63ce3Schristos
213266e63ce3Schristos retval = mapped_addr;
213366e63ce3Schristos
213466e63ce3Schristos for (; old_len > 0;
213566e63ce3Schristos old_len -= 8192, mapped_addr += 8192, addr += 8192)
213666e63ce3Schristos {
213766e63ce3Schristos if (sim_core_read_buffer (sd, current_cpu, read_map, buf,
213866e63ce3Schristos addr, 8192) != 8192
213966e63ce3Schristos || sim_core_write_buffer (sd, current_cpu, 0, buf,
214066e63ce3Schristos mapped_addr, 8192) != 8192)
214166e63ce3Schristos abort ();
214266e63ce3Schristos }
214366e63ce3Schristos
214466e63ce3Schristos if (unmap_pages (sd, ¤t_cpu->highest_mmapped_page,
214566e63ce3Schristos prev_addr, prev_len) != 0)
214666e63ce3Schristos abort ();
214766e63ce3Schristos }
214866e63ce3Schristos else
214966e63ce3Schristos retval = -cb_host_to_target_errno (cb, -ENOMEM);
215066e63ce3Schristos break;
215166e63ce3Schristos }
215266e63ce3Schristos
215366e63ce3Schristos case TARGET_SYS_poll:
215466e63ce3Schristos {
215566e63ce3Schristos int npollfds = arg2;
215666e63ce3Schristos int timeout = arg3;
215766e63ce3Schristos SI ufds = arg1;
215866e63ce3Schristos SI fd = -1;
215966e63ce3Schristos HI events = -1;
216066e63ce3Schristos HI revents = 0;
216166e63ce3Schristos struct stat buf;
216266e63ce3Schristos int i;
216366e63ce3Schristos
216466e63ce3Schristos /* The kernel says:
216566e63ce3Schristos struct pollfd {
216666e63ce3Schristos int fd;
216766e63ce3Schristos short events;
216866e63ce3Schristos short revents;
216966e63ce3Schristos }; */
217066e63ce3Schristos
217166e63ce3Schristos /* Check that this is the expected poll call from
217266e63ce3Schristos linuxthreads/manager.c; we don't support anything else.
217366e63ce3Schristos Remember, fd == 0 isn't supported. */
217466e63ce3Schristos if (npollfds != 1
217566e63ce3Schristos || ((fd = sim_core_read_unaligned_4 (current_cpu, pc,
217666e63ce3Schristos 0, ufds)) <= 0)
217766e63ce3Schristos || ((events = sim_core_read_unaligned_2 (current_cpu, pc,
217866e63ce3Schristos 0, ufds + 4))
217966e63ce3Schristos != TARGET_POLLIN)
21805e098073Schristos || ((cb->to_fstat) (cb, fd, &buf) != 0
218166e63ce3Schristos || (buf.st_mode & S_IFIFO) == 0)
218266e63ce3Schristos || current_cpu->thread_data == NULL)
218366e63ce3Schristos {
218466e63ce3Schristos retval
218566e63ce3Schristos = cris_unknown_syscall (current_cpu, pc,
218666e63ce3Schristos "Unimplemented poll syscall "
218766e63ce3Schristos "(0x%lx: [0x%x, 0x%x, x], "
218866e63ce3Schristos "0x%lx, 0x%lx)\n",
218966e63ce3Schristos (unsigned long) arg1, fd, events,
219066e63ce3Schristos (unsigned long) arg2,
219166e63ce3Schristos (unsigned long) arg3);
219266e63ce3Schristos break;
219366e63ce3Schristos }
219466e63ce3Schristos
219566e63ce3Schristos retval = 0;
219666e63ce3Schristos
219766e63ce3Schristos /* Iterate over threads; find a marker that a writer is
219866e63ce3Schristos sleeping, waiting for a reader. */
219966e63ce3Schristos for (i = 0; i < SIM_TARGET_MAX_THREADS; i++)
220066e63ce3Schristos if (current_cpu->thread_data[i].cpu_context != NULL
220166e63ce3Schristos && current_cpu->thread_data[i].pipe_read_fd == fd)
220266e63ce3Schristos {
220366e63ce3Schristos revents = TARGET_POLLIN;
220466e63ce3Schristos retval = 1;
220566e63ce3Schristos break;
220666e63ce3Schristos }
220766e63ce3Schristos
220866e63ce3Schristos /* Timeout decreases with whatever time passed between the
220966e63ce3Schristos last syscall and this. That's not exactly right for the
221066e63ce3Schristos first call, but it's close enough that it isn't
221166e63ce3Schristos worthwhile to complicate matters by making that a special
221266e63ce3Schristos case. */
221366e63ce3Schristos timeout
221466e63ce3Schristos -= (TARGET_TIME_MS (current_cpu)
221566e63ce3Schristos - (current_cpu->thread_data[threadno].last_execution));
221666e63ce3Schristos
221766e63ce3Schristos /* Arrange to repeat this syscall until timeout or event,
221866e63ce3Schristos decreasing timeout at each iteration. */
221966e63ce3Schristos if (timeout > 0 && revents == 0)
222066e63ce3Schristos {
222166e63ce3Schristos bfd_byte timeout_buf[4];
222266e63ce3Schristos
222366e63ce3Schristos bfd_putl32 (timeout, timeout_buf);
222466e63ce3Schristos (*CPU_REG_STORE (current_cpu)) (current_cpu,
222566e63ce3Schristos H_GR_R12, timeout_buf, 4);
222666e63ce3Schristos sim_pc_set (current_cpu, pc);
222766e63ce3Schristos retval = arg1;
222866e63ce3Schristos break;
222966e63ce3Schristos }
223066e63ce3Schristos
223166e63ce3Schristos sim_core_write_unaligned_2 (current_cpu, pc, 0, ufds + 4 + 2,
223266e63ce3Schristos revents);
223366e63ce3Schristos break;
223466e63ce3Schristos }
223566e63ce3Schristos
223666e63ce3Schristos case TARGET_SYS_time:
223766e63ce3Schristos {
223866e63ce3Schristos retval = (int) (*cb->time) (cb, 0L);
223966e63ce3Schristos
224066e63ce3Schristos /* At time of this writing, CB_SYSCALL_time doesn't do the
224166e63ce3Schristos part of setting *arg1 to the return value. */
224266e63ce3Schristos if (arg1)
224366e63ce3Schristos sim_core_write_unaligned_4 (current_cpu, pc, 0, arg1, retval);
224466e63ce3Schristos break;
224566e63ce3Schristos }
224666e63ce3Schristos
224766e63ce3Schristos case TARGET_SYS_gettimeofday:
224866e63ce3Schristos if (arg1 != 0)
224966e63ce3Schristos {
225066e63ce3Schristos USI ts = TARGET_TIME (current_cpu);
225166e63ce3Schristos USI tms = TARGET_TIME_MS (current_cpu);
225266e63ce3Schristos
225366e63ce3Schristos /* First dword is seconds since TARGET_EPOCH. */
225466e63ce3Schristos sim_core_write_unaligned_4 (current_cpu, pc, 0, arg1, ts);
225566e63ce3Schristos
225666e63ce3Schristos /* Second dword is microseconds. */
225766e63ce3Schristos sim_core_write_unaligned_4 (current_cpu, pc, 0, arg1 + 4,
225866e63ce3Schristos (tms % 1000) * 1000);
225966e63ce3Schristos }
226066e63ce3Schristos if (arg2 != 0)
226166e63ce3Schristos {
226266e63ce3Schristos /* Time-zone info is always cleared. */
226366e63ce3Schristos sim_core_write_unaligned_4 (current_cpu, pc, 0, arg2, 0);
226466e63ce3Schristos sim_core_write_unaligned_4 (current_cpu, pc, 0, arg2 + 4, 0);
226566e63ce3Schristos }
226666e63ce3Schristos retval = 0;
226766e63ce3Schristos break;
226866e63ce3Schristos
226966e63ce3Schristos case TARGET_SYS_llseek:
227066e63ce3Schristos {
227166e63ce3Schristos /* If it fits, tweak parameters to fit the "generic" 32-bit
227266e63ce3Schristos lseek and use that. */
227366e63ce3Schristos SI fd = arg1;
227466e63ce3Schristos SI offs_hi = arg2;
227566e63ce3Schristos SI offs_lo = arg3;
227666e63ce3Schristos SI resultp = arg4;
227766e63ce3Schristos SI whence = arg5;
227866e63ce3Schristos retval = 0;
227966e63ce3Schristos
228066e63ce3Schristos if (!((offs_hi == 0 && offs_lo >= 0)
228166e63ce3Schristos || (offs_hi == -1 && offs_lo < 0)))
228266e63ce3Schristos {
228366e63ce3Schristos retval
228466e63ce3Schristos = cris_unknown_syscall (current_cpu, pc,
228566e63ce3Schristos "Unimplemented llseek offset,"
228666e63ce3Schristos " fd %d: 0x%x:0x%x\n",
228766e63ce3Schristos fd, (unsigned) arg2,
228866e63ce3Schristos (unsigned) arg3);
228966e63ce3Schristos break;
229066e63ce3Schristos }
229166e63ce3Schristos
229266e63ce3Schristos s.func = TARGET_SYS_lseek;
229366e63ce3Schristos s.arg2 = offs_lo;
229466e63ce3Schristos s.arg3 = whence;
229566e63ce3Schristos if (cb_syscall (cb, &s) != CB_RC_OK)
229666e63ce3Schristos {
229766e63ce3Schristos sim_io_eprintf (sd, "Break 13: invalid %d? Returned %ld\n", callnum,
229866e63ce3Schristos s.result);
229966e63ce3Schristos sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGILL);
230066e63ce3Schristos }
230166e63ce3Schristos if (s.result < 0)
230266e63ce3Schristos retval = -s.errcode;
230366e63ce3Schristos else
230466e63ce3Schristos {
230566e63ce3Schristos sim_core_write_unaligned_4 (current_cpu, pc, 0, resultp,
230666e63ce3Schristos s.result);
230766e63ce3Schristos sim_core_write_unaligned_4 (current_cpu, pc, 0, resultp + 4,
230866e63ce3Schristos s.result < 0 ? -1 : 0);
230966e63ce3Schristos }
231066e63ce3Schristos break;
231166e63ce3Schristos }
231266e63ce3Schristos
231366e63ce3Schristos /* ssize_t writev(int fd, const struct iovec *iov, int iovcnt);
231466e63ce3Schristos where:
231566e63ce3Schristos struct iovec {
231666e63ce3Schristos void *iov_base; Starting address
231766e63ce3Schristos size_t iov_len; Number of bytes to transfer
231866e63ce3Schristos }; */
231966e63ce3Schristos case TARGET_SYS_writev:
232066e63ce3Schristos {
232166e63ce3Schristos SI fd = arg1;
232266e63ce3Schristos SI iov = arg2;
232366e63ce3Schristos SI iovcnt = arg3;
232466e63ce3Schristos SI retcnt = 0;
232566e63ce3Schristos int i;
232666e63ce3Schristos
232766e63ce3Schristos /* We'll ignore strict error-handling and just do multiple write calls. */
232866e63ce3Schristos for (i = 0; i < iovcnt; i++)
232966e63ce3Schristos {
233066e63ce3Schristos int sysret;
233166e63ce3Schristos USI iov_base
233266e63ce3Schristos = sim_core_read_unaligned_4 (current_cpu, pc, 0,
233366e63ce3Schristos iov + 8*i);
233466e63ce3Schristos USI iov_len
233566e63ce3Schristos = sim_core_read_unaligned_4 (current_cpu, pc, 0,
233666e63ce3Schristos iov + 8*i + 4);
233766e63ce3Schristos
233866e63ce3Schristos s.func = TARGET_SYS_write;
233966e63ce3Schristos s.arg1 = fd;
234066e63ce3Schristos s.arg2 = iov_base;
234166e63ce3Schristos s.arg3 = iov_len;
234266e63ce3Schristos
234366e63ce3Schristos if (cb_syscall (cb, &s) != CB_RC_OK)
234466e63ce3Schristos abort ();
234566e63ce3Schristos sysret = s.result == -1 ? -s.errcode : s.result;
234666e63ce3Schristos
234766e63ce3Schristos if (sysret != iov_len)
234866e63ce3Schristos {
234966e63ce3Schristos if (i != 0)
235066e63ce3Schristos abort ();
235166e63ce3Schristos retcnt = sysret;
235266e63ce3Schristos break;
235366e63ce3Schristos }
235466e63ce3Schristos
235566e63ce3Schristos retcnt += iov_len;
235666e63ce3Schristos }
235766e63ce3Schristos
235866e63ce3Schristos retval = retcnt;
235966e63ce3Schristos }
236066e63ce3Schristos break;
236166e63ce3Schristos
236266e63ce3Schristos /* This one does have a generic callback function, but at the time
236366e63ce3Schristos of this writing, cb_syscall does not have code for it, and we
236466e63ce3Schristos need target-specific code for the threads implementation
236566e63ce3Schristos anyway. */
236666e63ce3Schristos case TARGET_SYS_kill:
236766e63ce3Schristos {
236866e63ce3Schristos USI pid = arg1;
236966e63ce3Schristos USI sig = arg2;
237066e63ce3Schristos
237166e63ce3Schristos retval = 0;
237266e63ce3Schristos
237366e63ce3Schristos /* At kill(2), glibc sets signal masks such that the thread
237466e63ce3Schristos machinery is initialized. Still, there is and was only
237566e63ce3Schristos one thread. */
237666e63ce3Schristos if (current_cpu->max_threadid == 0)
237766e63ce3Schristos {
237866e63ce3Schristos if (pid != TARGET_PID)
237966e63ce3Schristos {
238066e63ce3Schristos retval = -cb_host_to_target_errno (cb, EPERM);
238166e63ce3Schristos break;
238266e63ce3Schristos }
238366e63ce3Schristos
238466e63ce3Schristos /* FIXME: Signal infrastructure (target-to-sim mapping). */
238566e63ce3Schristos if (sig == TARGET_SIGABRT)
238666e63ce3Schristos /* A call "abort ()", i.e. "kill (getpid(), SIGABRT)" is
238766e63ce3Schristos the end-point for failing GCC test-cases. */
238866e63ce3Schristos sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped,
238966e63ce3Schristos SIM_SIGABRT);
239066e63ce3Schristos else
239166e63ce3Schristos {
239266e63ce3Schristos sim_io_eprintf (sd, "Unimplemented signal: %d\n", sig);
239366e63ce3Schristos sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped,
239466e63ce3Schristos SIM_SIGILL);
239566e63ce3Schristos }
239666e63ce3Schristos
239766e63ce3Schristos /* This will not be reached. */
239866e63ce3Schristos abort ();
239966e63ce3Schristos }
240066e63ce3Schristos else
240166e63ce3Schristos retval = deliver_signal (current_cpu, sig, pid);
240266e63ce3Schristos break;
240366e63ce3Schristos }
240466e63ce3Schristos
240566e63ce3Schristos case TARGET_SYS_rt_sigprocmask:
240666e63ce3Schristos {
240766e63ce3Schristos int i;
240866e63ce3Schristos USI how = arg1;
240966e63ce3Schristos USI newsetp = arg2;
241066e63ce3Schristos USI oldsetp = arg3;
241166e63ce3Schristos
241266e63ce3Schristos if (how != TARGET_SIG_BLOCK
241366e63ce3Schristos && how != TARGET_SIG_SETMASK
241466e63ce3Schristos && how != TARGET_SIG_UNBLOCK)
241566e63ce3Schristos {
241666e63ce3Schristos retval
241766e63ce3Schristos = cris_unknown_syscall (current_cpu, pc,
241866e63ce3Schristos "Unimplemented rt_sigprocmask "
241966e63ce3Schristos "syscall (0x%x, 0x%x, 0x%x)\n",
242066e63ce3Schristos arg1, arg2, arg3);
242166e63ce3Schristos break;
242266e63ce3Schristos }
242366e63ce3Schristos
242466e63ce3Schristos if (newsetp)
242566e63ce3Schristos {
242666e63ce3Schristos USI set_low
242766e63ce3Schristos = sim_core_read_unaligned_4 (current_cpu, pc, 0,
242866e63ce3Schristos newsetp);
242966e63ce3Schristos USI set_high
243066e63ce3Schristos = sim_core_read_unaligned_4 (current_cpu, pc, 0,
243166e63ce3Schristos newsetp + 4);
243266e63ce3Schristos
243366e63ce3Schristos /* The sigmask is kept in the per-thread data, so we may
243466e63ce3Schristos need to create the first one. */
243566e63ce3Schristos if (current_cpu->thread_data == NULL)
243666e63ce3Schristos make_first_thread (current_cpu);
243766e63ce3Schristos
243866e63ce3Schristos if (how == TARGET_SIG_SETMASK)
243966e63ce3Schristos for (i = 0; i < 64; i++)
244066e63ce3Schristos current_cpu->thread_data[threadno].sigdata[i].blocked = 0;
244166e63ce3Schristos
244266e63ce3Schristos for (i = 0; i < 32; i++)
244366e63ce3Schristos if ((set_low & (1 << i)))
244466e63ce3Schristos current_cpu->thread_data[threadno].sigdata[i + 1].blocked
244566e63ce3Schristos = (how != TARGET_SIG_UNBLOCK);
244666e63ce3Schristos
244766e63ce3Schristos for (i = 0; i < 31; i++)
244866e63ce3Schristos if ((set_high & (1 << i)))
244966e63ce3Schristos current_cpu->thread_data[threadno].sigdata[i + 33].blocked
245066e63ce3Schristos = (how != TARGET_SIG_UNBLOCK);
245166e63ce3Schristos
245266e63ce3Schristos /* The mask changed, so a signal may be unblocked for
245366e63ce3Schristos execution. */
245466e63ce3Schristos current_cpu->thread_data[threadno].sigpending = 1;
245566e63ce3Schristos }
245666e63ce3Schristos
245766e63ce3Schristos if (oldsetp != 0)
245866e63ce3Schristos {
245966e63ce3Schristos USI set_low = 0;
246066e63ce3Schristos USI set_high = 0;
246166e63ce3Schristos
246266e63ce3Schristos for (i = 0; i < 32; i++)
246366e63ce3Schristos if (current_cpu->thread_data[threadno]
246466e63ce3Schristos .sigdata[i + 1].blocked)
246566e63ce3Schristos set_low |= 1 << i;
246666e63ce3Schristos for (i = 0; i < 31; i++)
246766e63ce3Schristos if (current_cpu->thread_data[threadno]
246866e63ce3Schristos .sigdata[i + 33].blocked)
246966e63ce3Schristos set_high |= 1 << i;
247066e63ce3Schristos
247166e63ce3Schristos sim_core_write_unaligned_4 (current_cpu, pc, 0, oldsetp + 0, set_low);
247266e63ce3Schristos sim_core_write_unaligned_4 (current_cpu, pc, 0, oldsetp + 4, set_high);
247366e63ce3Schristos }
247466e63ce3Schristos
247566e63ce3Schristos retval = 0;
247666e63ce3Schristos break;
247766e63ce3Schristos }
247866e63ce3Schristos
247966e63ce3Schristos case TARGET_SYS_sigreturn:
248066e63ce3Schristos {
248166e63ce3Schristos int i;
248266e63ce3Schristos bfd_byte regbuf[4];
248366e63ce3Schristos int was_sigsuspended;
248466e63ce3Schristos
248566e63ce3Schristos if (current_cpu->thread_data == NULL
248666e63ce3Schristos /* The CPU context is saved with the simulator data, not
248766e63ce3Schristos on the stack as in the real world. */
248866e63ce3Schristos || (current_cpu->thread_data[threadno].cpu_context_atsignal
248966e63ce3Schristos == NULL))
249066e63ce3Schristos {
249166e63ce3Schristos retval
249266e63ce3Schristos = cris_unknown_syscall (current_cpu, pc,
249366e63ce3Schristos "Invalid sigreturn syscall: "
249466e63ce3Schristos "no signal handler active "
249566e63ce3Schristos "(0x%lx, 0x%lx, 0x%lx, 0x%lx, "
249666e63ce3Schristos "0x%lx, 0x%lx)\n",
249766e63ce3Schristos (unsigned long) arg1,
249866e63ce3Schristos (unsigned long) arg2,
249966e63ce3Schristos (unsigned long) arg3,
250066e63ce3Schristos (unsigned long) arg4,
250166e63ce3Schristos (unsigned long) arg5,
250266e63ce3Schristos (unsigned long) arg6);
250366e63ce3Schristos break;
250466e63ce3Schristos }
250566e63ce3Schristos
250666e63ce3Schristos was_sigsuspended
250766e63ce3Schristos = current_cpu->thread_data[threadno].sigsuspended;
250866e63ce3Schristos
250966e63ce3Schristos /* Restore the sigmask, either from the stack copy made when
251066e63ce3Schristos the sighandler was called, or from the saved state
251166e63ce3Schristos specifically for sigsuspend(2). */
251266e63ce3Schristos if (was_sigsuspended)
251366e63ce3Schristos {
251466e63ce3Schristos current_cpu->thread_data[threadno].sigsuspended = 0;
251566e63ce3Schristos for (i = 0; i < 64; i++)
251666e63ce3Schristos current_cpu->thread_data[threadno].sigdata[i].blocked
251766e63ce3Schristos = current_cpu->thread_data[threadno]
251866e63ce3Schristos .sigdata[i].blocked_suspendsave;
251966e63ce3Schristos }
252066e63ce3Schristos else
252166e63ce3Schristos {
252266e63ce3Schristos USI sp;
252366e63ce3Schristos USI set_low;
252466e63ce3Schristos USI set_high;
252566e63ce3Schristos
252666e63ce3Schristos (*CPU_REG_FETCH (current_cpu)) (current_cpu,
252766e63ce3Schristos H_GR_SP, regbuf, 4);
252866e63ce3Schristos sp = bfd_getl32 (regbuf);
252966e63ce3Schristos set_low
253066e63ce3Schristos = sim_core_read_unaligned_4 (current_cpu, pc, 0, sp);
253166e63ce3Schristos set_high
253266e63ce3Schristos = sim_core_read_unaligned_4 (current_cpu, pc, 0, sp + 4);
253366e63ce3Schristos
253466e63ce3Schristos for (i = 0; i < 32; i++)
253566e63ce3Schristos current_cpu->thread_data[threadno].sigdata[i + 1].blocked
253666e63ce3Schristos = (set_low & (1 << i)) != 0;
253766e63ce3Schristos for (i = 0; i < 31; i++)
253866e63ce3Schristos current_cpu->thread_data[threadno].sigdata[i + 33].blocked
253966e63ce3Schristos = (set_high & (1 << i)) != 0;
254066e63ce3Schristos }
254166e63ce3Schristos
254266e63ce3Schristos /* The mask changed, so a signal may be unblocked for
254366e63ce3Schristos execution. */
254466e63ce3Schristos current_cpu->thread_data[threadno].sigpending = 1;
254566e63ce3Schristos
254666e63ce3Schristos memcpy (¤t_cpu->cpu_data_placeholder,
254766e63ce3Schristos current_cpu->thread_data[threadno].cpu_context_atsignal,
254866e63ce3Schristos current_cpu->thread_cpu_data_size);
254966e63ce3Schristos free (current_cpu->thread_data[threadno].cpu_context_atsignal);
255066e63ce3Schristos current_cpu->thread_data[threadno].cpu_context_atsignal = NULL;
255166e63ce3Schristos
255266e63ce3Schristos /* The return value must come from the saved R10. */
255366e63ce3Schristos (*CPU_REG_FETCH (current_cpu)) (current_cpu, H_GR_R10, regbuf, 4);
255466e63ce3Schristos retval = bfd_getl32 (regbuf);
255566e63ce3Schristos
255666e63ce3Schristos /* We must also break the "sigsuspension loop". */
255766e63ce3Schristos if (was_sigsuspended)
255866e63ce3Schristos sim_pc_set (current_cpu, sim_pc_get (current_cpu) + 2);
255966e63ce3Schristos break;
256066e63ce3Schristos }
256166e63ce3Schristos
256266e63ce3Schristos case TARGET_SYS_rt_sigsuspend:
256366e63ce3Schristos {
256466e63ce3Schristos USI newsetp = arg1;
256566e63ce3Schristos USI setsize = arg2;
256666e63ce3Schristos
256766e63ce3Schristos if (setsize != 8)
256866e63ce3Schristos {
256966e63ce3Schristos retval
257066e63ce3Schristos = cris_unknown_syscall (current_cpu, pc,
257166e63ce3Schristos "Unimplemented rt_sigsuspend syscall"
257266e63ce3Schristos " arguments (0x%lx, 0x%lx)\n",
257366e63ce3Schristos (unsigned long) arg1,
257466e63ce3Schristos (unsigned long) arg2);
257566e63ce3Schristos break;
257666e63ce3Schristos }
257766e63ce3Schristos
257866e63ce3Schristos /* Don't change the signal mask if we're already in
257966e63ce3Schristos sigsuspend state (i.e. this syscall is a rerun). */
258066e63ce3Schristos else if (!current_cpu->thread_data[threadno].sigsuspended)
258166e63ce3Schristos {
258266e63ce3Schristos USI set_low
258366e63ce3Schristos = sim_core_read_unaligned_4 (current_cpu, pc, 0,
258466e63ce3Schristos newsetp);
258566e63ce3Schristos USI set_high
258666e63ce3Schristos = sim_core_read_unaligned_4 (current_cpu, pc, 0,
258766e63ce3Schristos newsetp + 4);
258866e63ce3Schristos int i;
258966e63ce3Schristos
259066e63ce3Schristos /* Save the current sigmask and insert the user-supplied
259166e63ce3Schristos one. */
259266e63ce3Schristos for (i = 0; i < 32; i++)
259366e63ce3Schristos {
259466e63ce3Schristos current_cpu->thread_data[threadno]
259566e63ce3Schristos .sigdata[i + 1].blocked_suspendsave
259666e63ce3Schristos = current_cpu->thread_data[threadno]
259766e63ce3Schristos .sigdata[i + 1].blocked;
259866e63ce3Schristos
259966e63ce3Schristos current_cpu->thread_data[threadno]
260066e63ce3Schristos .sigdata[i + 1].blocked = (set_low & (1 << i)) != 0;
260166e63ce3Schristos }
260266e63ce3Schristos for (i = 0; i < 31; i++)
260366e63ce3Schristos {
260466e63ce3Schristos current_cpu->thread_data[threadno]
260566e63ce3Schristos .sigdata[i + 33].blocked_suspendsave
260666e63ce3Schristos = current_cpu->thread_data[threadno]
260766e63ce3Schristos .sigdata[i + 33].blocked;
260866e63ce3Schristos current_cpu->thread_data[threadno]
260966e63ce3Schristos .sigdata[i + 33].blocked = (set_high & (1 << i)) != 0;
261066e63ce3Schristos }
261166e63ce3Schristos
261266e63ce3Schristos current_cpu->thread_data[threadno].sigsuspended = 1;
261366e63ce3Schristos
261466e63ce3Schristos /* The mask changed, so a signal may be unblocked for
261566e63ce3Schristos execution. */
261666e63ce3Schristos current_cpu->thread_data[threadno].sigpending = 1;
261766e63ce3Schristos }
261866e63ce3Schristos
261966e63ce3Schristos /* Because we don't use arg1 (newsetp) when this syscall is
262066e63ce3Schristos rerun, it doesn't matter that we overwrite it with the
262166e63ce3Schristos (constant) return value. */
262266e63ce3Schristos retval = -cb_host_to_target_errno (cb, EINTR);
262366e63ce3Schristos sim_pc_set (current_cpu, pc);
262466e63ce3Schristos break;
262566e63ce3Schristos }
262666e63ce3Schristos
262766e63ce3Schristos /* Add case labels here for other syscalls using the 32-bit
262866e63ce3Schristos "struct stat", provided they have a corresponding simulator
262966e63ce3Schristos function of course. */
263066e63ce3Schristos case TARGET_SYS_stat:
263166e63ce3Schristos case TARGET_SYS_fstat:
263266e63ce3Schristos {
263366e63ce3Schristos /* As long as the infrastructure doesn't cache anything
263466e63ce3Schristos related to the stat mapping, this trick gets us a dual
263566e63ce3Schristos "struct stat"-type mapping in the least error-prone way. */
263666e63ce3Schristos const char *saved_map = cb->stat_map;
263766e63ce3Schristos CB_TARGET_DEFS_MAP *saved_syscall_map = cb->syscall_map;
263866e63ce3Schristos
263966e63ce3Schristos cb->syscall_map = (CB_TARGET_DEFS_MAP *) syscall_stat32_map;
264066e63ce3Schristos cb->stat_map = stat32_map;
264166e63ce3Schristos
264266e63ce3Schristos if (cb_syscall (cb, &s) != CB_RC_OK)
264366e63ce3Schristos {
264466e63ce3Schristos abort ();
264566e63ce3Schristos sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped,
264666e63ce3Schristos SIM_SIGILL);
264766e63ce3Schristos }
264866e63ce3Schristos retval = s.result == -1 ? -s.errcode : s.result;
264966e63ce3Schristos
265066e63ce3Schristos cb->stat_map = saved_map;
265166e63ce3Schristos cb->syscall_map = saved_syscall_map;
265266e63ce3Schristos break;
265366e63ce3Schristos }
265466e63ce3Schristos
265566e63ce3Schristos case TARGET_SYS_getcwd:
265666e63ce3Schristos {
265766e63ce3Schristos USI buf = arg1;
265866e63ce3Schristos USI size = arg2;
265966e63ce3Schristos
266066e63ce3Schristos char *cwd = xmalloc (SIM_PATHMAX);
266166e63ce3Schristos if (cwd != getcwd (cwd, SIM_PATHMAX))
266266e63ce3Schristos abort ();
266366e63ce3Schristos
266466e63ce3Schristos /* FIXME: When and if we support chdir, we need something
266566e63ce3Schristos a bit more elaborate. */
266666e63ce3Schristos if (simulator_sysroot[0] != '\0')
266766e63ce3Schristos strcpy (cwd, "/");
266866e63ce3Schristos
266966e63ce3Schristos retval = -cb_host_to_target_errno (cb, ERANGE);
267066e63ce3Schristos if (strlen (cwd) + 1 <= size)
267166e63ce3Schristos {
267266e63ce3Schristos retval = strlen (cwd) + 1;
267366e63ce3Schristos if (sim_core_write_buffer (sd, current_cpu, 0, cwd,
267466e63ce3Schristos buf, retval)
267566e63ce3Schristos != (unsigned int) retval)
267666e63ce3Schristos retval = -cb_host_to_target_errno (cb, EFAULT);
267766e63ce3Schristos }
267866e63ce3Schristos free (cwd);
267966e63ce3Schristos break;
268066e63ce3Schristos }
268166e63ce3Schristos
268266e63ce3Schristos case TARGET_SYS_access:
268366e63ce3Schristos {
268466e63ce3Schristos SI path = arg1;
268566e63ce3Schristos SI mode = arg2;
268666e63ce3Schristos char *pbuf = xmalloc (SIM_PATHMAX);
268766e63ce3Schristos int i;
268866e63ce3Schristos int o = 0;
268966e63ce3Schristos int hmode = 0;
269066e63ce3Schristos
269166e63ce3Schristos if (sim_core_read_unaligned_1 (current_cpu, pc, 0, path) == '/')
269266e63ce3Schristos {
269366e63ce3Schristos strcpy (pbuf, simulator_sysroot);
269466e63ce3Schristos o += strlen (simulator_sysroot);
269566e63ce3Schristos }
269666e63ce3Schristos
269766e63ce3Schristos for (i = 0; i + o < SIM_PATHMAX; i++)
269866e63ce3Schristos {
269966e63ce3Schristos pbuf[i + o]
270066e63ce3Schristos = sim_core_read_unaligned_1 (current_cpu, pc, 0, path + i);
270166e63ce3Schristos if (pbuf[i + o] == 0)
270266e63ce3Schristos break;
270366e63ce3Schristos }
270466e63ce3Schristos
270566e63ce3Schristos if (i + o == SIM_PATHMAX)
270666e63ce3Schristos {
270766e63ce3Schristos retval = -cb_host_to_target_errno (cb, ENAMETOOLONG);
270866e63ce3Schristos break;
270966e63ce3Schristos }
271066e63ce3Schristos
271166e63ce3Schristos /* Assert that we don't get calls for files for which we
271266e63ce3Schristos don't have support. */
271366e63ce3Schristos if (strncmp (pbuf + strlen (simulator_sysroot),
271466e63ce3Schristos "/proc/", 6) == 0)
271566e63ce3Schristos abort ();
271666e63ce3Schristos #define X_AFLAG(x) if (mode & TARGET_ ## x) hmode |= x
271766e63ce3Schristos X_AFLAG (R_OK);
271866e63ce3Schristos X_AFLAG (W_OK);
271966e63ce3Schristos X_AFLAG (X_OK);
272066e63ce3Schristos X_AFLAG (F_OK);
272166e63ce3Schristos #undef X_AFLAG
272266e63ce3Schristos
272366e63ce3Schristos if (access (pbuf, hmode) != 0)
272466e63ce3Schristos retval = -cb_host_to_target_errno (cb, errno);
272566e63ce3Schristos else
272666e63ce3Schristos retval = 0;
272766e63ce3Schristos
272866e63ce3Schristos free (pbuf);
272966e63ce3Schristos break;
273066e63ce3Schristos }
273166e63ce3Schristos
273266e63ce3Schristos case TARGET_SYS_readlink:
273366e63ce3Schristos {
273466e63ce3Schristos SI path = arg1;
273566e63ce3Schristos SI buf = arg2;
273666e63ce3Schristos SI bufsiz = arg3;
273766e63ce3Schristos char *pbuf = xmalloc (SIM_PATHMAX);
273866e63ce3Schristos char *lbuf = xmalloc (SIM_PATHMAX);
273966e63ce3Schristos char *lbuf_alloc = lbuf;
274066e63ce3Schristos int nchars = -1;
274166e63ce3Schristos int i;
274266e63ce3Schristos int o = 0;
274366e63ce3Schristos
274466e63ce3Schristos if (sim_core_read_unaligned_1 (current_cpu, pc, 0, path) == '/')
274566e63ce3Schristos {
274666e63ce3Schristos strcpy (pbuf, simulator_sysroot);
274766e63ce3Schristos o += strlen (simulator_sysroot);
274866e63ce3Schristos }
274966e63ce3Schristos
275066e63ce3Schristos for (i = 0; i + o < SIM_PATHMAX; i++)
275166e63ce3Schristos {
275266e63ce3Schristos pbuf[i + o]
275366e63ce3Schristos = sim_core_read_unaligned_1 (current_cpu, pc, 0, path + i);
275466e63ce3Schristos if (pbuf[i + o] == 0)
275566e63ce3Schristos break;
275666e63ce3Schristos }
275766e63ce3Schristos
275866e63ce3Schristos if (i + o == SIM_PATHMAX)
275966e63ce3Schristos {
276066e63ce3Schristos retval = -cb_host_to_target_errno (cb, ENAMETOOLONG);
276166e63ce3Schristos break;
276266e63ce3Schristos }
276366e63ce3Schristos
276466e63ce3Schristos /* Intervene calls for certain files expected in the target
276566e63ce3Schristos proc file system. */
276666e63ce3Schristos if (strcmp (pbuf + strlen (simulator_sysroot),
276766e63ce3Schristos "/proc/" XSTRING (TARGET_PID) "/exe") == 0)
276866e63ce3Schristos {
276966e63ce3Schristos char *argv0
277066e63ce3Schristos = (STATE_PROG_ARGV (sd) != NULL
277166e63ce3Schristos ? *STATE_PROG_ARGV (sd) : NULL);
277266e63ce3Schristos
277366e63ce3Schristos if (argv0 == NULL || *argv0 == '.')
277466e63ce3Schristos {
277566e63ce3Schristos retval
277666e63ce3Schristos = cris_unknown_syscall (current_cpu, pc,
277766e63ce3Schristos "Unimplemented readlink syscall "
277866e63ce3Schristos "(0x%lx: [\"%s\"], 0x%lx)\n",
277966e63ce3Schristos (unsigned long) arg1, pbuf,
278066e63ce3Schristos (unsigned long) arg2);
278166e63ce3Schristos break;
278266e63ce3Schristos }
278366e63ce3Schristos else if (*argv0 == '/')
278466e63ce3Schristos {
278566e63ce3Schristos if (strncmp (simulator_sysroot, argv0,
278666e63ce3Schristos strlen (simulator_sysroot)) == 0)
278766e63ce3Schristos argv0 += strlen (simulator_sysroot);
278866e63ce3Schristos
278966e63ce3Schristos strcpy (lbuf, argv0);
279066e63ce3Schristos nchars = strlen (argv0) + 1;
279166e63ce3Schristos }
279266e63ce3Schristos else
279366e63ce3Schristos {
279466e63ce3Schristos if (getcwd (lbuf, SIM_PATHMAX) != NULL
279566e63ce3Schristos && strlen (lbuf) + 2 + strlen (argv0) < SIM_PATHMAX)
279666e63ce3Schristos {
279766e63ce3Schristos if (strncmp (simulator_sysroot, lbuf,
279866e63ce3Schristos strlen (simulator_sysroot)) == 0)
279966e63ce3Schristos lbuf += strlen (simulator_sysroot);
280066e63ce3Schristos
280166e63ce3Schristos strcat (lbuf, "/");
280266e63ce3Schristos strcat (lbuf, argv0);
280366e63ce3Schristos nchars = strlen (lbuf) + 1;
280466e63ce3Schristos }
280566e63ce3Schristos else
280666e63ce3Schristos abort ();
280766e63ce3Schristos }
280866e63ce3Schristos }
280966e63ce3Schristos else
281066e63ce3Schristos nchars = readlink (pbuf, lbuf, SIM_PATHMAX);
281166e63ce3Schristos
281266e63ce3Schristos /* We trust that the readlink result returns a *relative*
281366e63ce3Schristos link, or one already adjusted for the file-path-prefix.
281466e63ce3Schristos (We can't generally tell the difference, so we go with
281566e63ce3Schristos the easiest decision; no adjustment.) */
281666e63ce3Schristos
281766e63ce3Schristos if (nchars == -1)
281866e63ce3Schristos {
281966e63ce3Schristos retval = -cb_host_to_target_errno (cb, errno);
282066e63ce3Schristos break;
282166e63ce3Schristos }
282266e63ce3Schristos
282366e63ce3Schristos if (bufsiz < nchars)
282466e63ce3Schristos nchars = bufsiz;
282566e63ce3Schristos
282666e63ce3Schristos if (sim_core_write_buffer (sd, current_cpu, write_map, lbuf,
282766e63ce3Schristos buf, nchars) != (unsigned int) nchars)
282866e63ce3Schristos retval = -cb_host_to_target_errno (cb, EFAULT);
282966e63ce3Schristos else
283066e63ce3Schristos retval = nchars;
283166e63ce3Schristos
283266e63ce3Schristos free (pbuf);
283366e63ce3Schristos free (lbuf_alloc);
283466e63ce3Schristos break;
283566e63ce3Schristos }
283666e63ce3Schristos
283766e63ce3Schristos case TARGET_SYS_sched_getscheduler:
283866e63ce3Schristos {
283966e63ce3Schristos USI pid = arg1;
284066e63ce3Schristos
284166e63ce3Schristos /* FIXME: Search (other) existing threads. */
284266e63ce3Schristos if (pid != 0 && pid != TARGET_PID)
284366e63ce3Schristos retval = -cb_host_to_target_errno (cb, ESRCH);
284466e63ce3Schristos else
284566e63ce3Schristos retval = TARGET_SCHED_OTHER;
284666e63ce3Schristos break;
284766e63ce3Schristos }
284866e63ce3Schristos
284966e63ce3Schristos case TARGET_SYS_sched_getparam:
285066e63ce3Schristos {
285166e63ce3Schristos USI pid = arg1;
285266e63ce3Schristos USI paramp = arg2;
285366e63ce3Schristos
285466e63ce3Schristos /* The kernel says:
285566e63ce3Schristos struct sched_param {
285666e63ce3Schristos int sched_priority;
285766e63ce3Schristos }; */
285866e63ce3Schristos
285966e63ce3Schristos if (pid != 0 && pid != TARGET_PID)
286066e63ce3Schristos retval = -cb_host_to_target_errno (cb, ESRCH);
286166e63ce3Schristos else
286266e63ce3Schristos {
286366e63ce3Schristos /* FIXME: Save scheduler setting before threads are
286466e63ce3Schristos created too. */
286566e63ce3Schristos sim_core_write_unaligned_4 (current_cpu, pc, 0, paramp,
286666e63ce3Schristos current_cpu->thread_data != NULL
286766e63ce3Schristos ? (current_cpu
286866e63ce3Schristos ->thread_data[threadno]
286966e63ce3Schristos .priority)
287066e63ce3Schristos : 0);
287166e63ce3Schristos retval = 0;
287266e63ce3Schristos }
287366e63ce3Schristos break;
287466e63ce3Schristos }
287566e63ce3Schristos
287666e63ce3Schristos case TARGET_SYS_sched_setparam:
287766e63ce3Schristos {
287866e63ce3Schristos USI pid = arg1;
287966e63ce3Schristos USI paramp = arg2;
288066e63ce3Schristos
288166e63ce3Schristos if ((pid != 0 && pid != TARGET_PID)
288266e63ce3Schristos || sim_core_read_unaligned_4 (current_cpu, pc, 0,
288366e63ce3Schristos paramp) != 0)
288466e63ce3Schristos retval = -cb_host_to_target_errno (cb, EINVAL);
288566e63ce3Schristos else
288666e63ce3Schristos retval = 0;
288766e63ce3Schristos break;
288866e63ce3Schristos }
288966e63ce3Schristos
289066e63ce3Schristos case TARGET_SYS_sched_setscheduler:
289166e63ce3Schristos {
289266e63ce3Schristos USI pid = arg1;
289366e63ce3Schristos USI policy = arg2;
289466e63ce3Schristos USI paramp = arg3;
289566e63ce3Schristos
289666e63ce3Schristos if ((pid != 0 && pid != TARGET_PID)
289766e63ce3Schristos || policy != TARGET_SCHED_OTHER
289866e63ce3Schristos || sim_core_read_unaligned_4 (current_cpu, pc, 0,
289966e63ce3Schristos paramp) != 0)
290066e63ce3Schristos retval = -cb_host_to_target_errno (cb, EINVAL);
290166e63ce3Schristos else
290266e63ce3Schristos /* FIXME: Save scheduler setting to be read in later
290366e63ce3Schristos sched_getparam calls. */
290466e63ce3Schristos retval = 0;
290566e63ce3Schristos break;
290666e63ce3Schristos }
290766e63ce3Schristos
290866e63ce3Schristos case TARGET_SYS_sched_yield:
290966e63ce3Schristos /* We reschedule to the next thread after a syscall anyway, so
291066e63ce3Schristos we don't have to do anything here than to set the return
291166e63ce3Schristos value. */
291266e63ce3Schristos retval = 0;
291366e63ce3Schristos break;
291466e63ce3Schristos
291566e63ce3Schristos case TARGET_SYS_sched_get_priority_min:
291666e63ce3Schristos case TARGET_SYS_sched_get_priority_max:
291766e63ce3Schristos if (arg1 != 0)
291866e63ce3Schristos retval = -cb_host_to_target_errno (cb, EINVAL);
291966e63ce3Schristos else
292066e63ce3Schristos retval = 0;
292166e63ce3Schristos break;
292266e63ce3Schristos
292366e63ce3Schristos case TARGET_SYS_ugetrlimit:
292466e63ce3Schristos {
292566e63ce3Schristos unsigned int curlim, maxlim;
292666e63ce3Schristos if (arg1 != TARGET_RLIMIT_STACK && arg1 != TARGET_RLIMIT_NOFILE)
292766e63ce3Schristos {
292866e63ce3Schristos retval = -cb_host_to_target_errno (cb, EINVAL);
292966e63ce3Schristos break;
293066e63ce3Schristos }
293166e63ce3Schristos
293266e63ce3Schristos /* The kernel says:
293366e63ce3Schristos struct rlimit {
293466e63ce3Schristos unsigned long rlim_cur;
293566e63ce3Schristos unsigned long rlim_max;
293666e63ce3Schristos }; */
293766e63ce3Schristos if (arg1 == TARGET_RLIMIT_NOFILE)
293866e63ce3Schristos {
293966e63ce3Schristos /* Sadly a very low limit. Better not lie, though. */
294066e63ce3Schristos maxlim = curlim = MAX_CALLBACK_FDS;
294166e63ce3Schristos }
294266e63ce3Schristos else /* arg1 == TARGET_RLIMIT_STACK */
294366e63ce3Schristos {
294466e63ce3Schristos maxlim = 0xffffffff;
294566e63ce3Schristos curlim = 0x800000;
294666e63ce3Schristos }
294766e63ce3Schristos sim_core_write_unaligned_4 (current_cpu, pc, 0, arg2, curlim);
294866e63ce3Schristos sim_core_write_unaligned_4 (current_cpu, pc, 0, arg2 + 4, maxlim);
294966e63ce3Schristos retval = 0;
295066e63ce3Schristos break;
295166e63ce3Schristos }
295266e63ce3Schristos
295366e63ce3Schristos case TARGET_SYS_setrlimit:
295466e63ce3Schristos if (arg1 != TARGET_RLIMIT_STACK)
295566e63ce3Schristos {
295666e63ce3Schristos retval = -cb_host_to_target_errno (cb, EINVAL);
295766e63ce3Schristos break;
295866e63ce3Schristos }
295966e63ce3Schristos /* FIXME: Save values for future ugetrlimit calls. */
296066e63ce3Schristos retval = 0;
296166e63ce3Schristos break;
296266e63ce3Schristos
296366e63ce3Schristos /* Provide a very limited subset of the sysctl functions, and
296466e63ce3Schristos abort for the rest. */
296566e63ce3Schristos case TARGET_SYS__sysctl:
296666e63ce3Schristos {
296766e63ce3Schristos /* The kernel says:
296866e63ce3Schristos struct __sysctl_args {
296966e63ce3Schristos int *name;
297066e63ce3Schristos int nlen;
297166e63ce3Schristos void *oldval;
297266e63ce3Schristos size_t *oldlenp;
297366e63ce3Schristos void *newval;
297466e63ce3Schristos size_t newlen;
297566e63ce3Schristos unsigned long __unused[4];
297666e63ce3Schristos }; */
297766e63ce3Schristos SI name = sim_core_read_unaligned_4 (current_cpu, pc, 0, arg1);
297866e63ce3Schristos SI name0 = name == 0
297966e63ce3Schristos ? 0 : sim_core_read_unaligned_4 (current_cpu, pc, 0, name);
298066e63ce3Schristos SI name1 = name == 0
298166e63ce3Schristos ? 0 : sim_core_read_unaligned_4 (current_cpu, pc, 0, name + 4);
298266e63ce3Schristos SI nlen
298366e63ce3Schristos = sim_core_read_unaligned_4 (current_cpu, pc, 0, arg1 + 4);
298466e63ce3Schristos SI oldval
298566e63ce3Schristos = sim_core_read_unaligned_4 (current_cpu, pc, 0, arg1 + 8);
298666e63ce3Schristos SI oldlenp
298766e63ce3Schristos = sim_core_read_unaligned_4 (current_cpu, pc, 0, arg1 + 12);
298866e63ce3Schristos SI oldlen = oldlenp == 0
298966e63ce3Schristos ? 0 : sim_core_read_unaligned_4 (current_cpu, pc, 0, oldlenp);
299066e63ce3Schristos SI newval
299166e63ce3Schristos = sim_core_read_unaligned_4 (current_cpu, pc, 0, arg1 + 16);
299266e63ce3Schristos SI newlen
299366e63ce3Schristos = sim_core_read_unaligned_4 (current_cpu, pc, 0, arg1 + 20);
299466e63ce3Schristos
299566e63ce3Schristos if (name0 == TARGET_CTL_KERN && name1 == TARGET_CTL_KERN_VERSION)
299666e63ce3Schristos {
299766e63ce3Schristos SI to_write = oldlen < (SI) sizeof (TARGET_UTSNAME)
299866e63ce3Schristos ? oldlen : (SI) sizeof (TARGET_UTSNAME);
299966e63ce3Schristos
300066e63ce3Schristos sim_core_write_unaligned_4 (current_cpu, pc, 0, oldlenp,
300166e63ce3Schristos sizeof (TARGET_UTSNAME));
300266e63ce3Schristos
300366e63ce3Schristos if (sim_core_write_buffer (sd, current_cpu, write_map,
300466e63ce3Schristos TARGET_UTSNAME, oldval,
300566e63ce3Schristos to_write)
300666e63ce3Schristos != (unsigned int) to_write)
300766e63ce3Schristos retval = -cb_host_to_target_errno (cb, EFAULT);
300866e63ce3Schristos else
300966e63ce3Schristos retval = 0;
301066e63ce3Schristos break;
301166e63ce3Schristos }
301266e63ce3Schristos
301366e63ce3Schristos retval
301466e63ce3Schristos = cris_unknown_syscall (current_cpu, pc,
301566e63ce3Schristos "Unimplemented _sysctl syscall "
301666e63ce3Schristos "(0x%lx: [0x%lx, 0x%lx],"
301766e63ce3Schristos " 0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx)\n",
301866e63ce3Schristos (unsigned long) name,
301966e63ce3Schristos (unsigned long) name0,
302066e63ce3Schristos (unsigned long) name1,
302166e63ce3Schristos (unsigned long) nlen,
302266e63ce3Schristos (unsigned long) oldval,
302366e63ce3Schristos (unsigned long) oldlenp,
302466e63ce3Schristos (unsigned long) newval,
302566e63ce3Schristos (unsigned long) newlen);
302666e63ce3Schristos break;
302766e63ce3Schristos }
302866e63ce3Schristos
302966e63ce3Schristos case TARGET_SYS_exit:
303066e63ce3Schristos {
303166e63ce3Schristos /* Here for all but the last thread. */
303266e63ce3Schristos int i;
303366e63ce3Schristos int pid
303466e63ce3Schristos = current_cpu->thread_data[threadno].threadid + TARGET_PID;
303566e63ce3Schristos int ppid
303666e63ce3Schristos = (current_cpu->thread_data[threadno].parent_threadid
303766e63ce3Schristos + TARGET_PID);
303866e63ce3Schristos int exitsig = current_cpu->thread_data[threadno].exitsig;
303966e63ce3Schristos
304066e63ce3Schristos /* Any children are now all orphans. */
304166e63ce3Schristos for (i = 0; i < SIM_TARGET_MAX_THREADS; i++)
304266e63ce3Schristos if (current_cpu->thread_data[i].parent_threadid
304366e63ce3Schristos == current_cpu->thread_data[threadno].threadid)
304466e63ce3Schristos /* Make getppid(2) return 1 for them, poor little ones. */
304566e63ce3Schristos current_cpu->thread_data[i].parent_threadid = -TARGET_PID + 1;
304666e63ce3Schristos
304766e63ce3Schristos /* Free the cpu context data. When the parent has received
304866e63ce3Schristos the exit status, we'll clear the entry too. */
304966e63ce3Schristos free (current_cpu->thread_data[threadno].cpu_context);
305066e63ce3Schristos current_cpu->thread_data[threadno].cpu_context = NULL;
305166e63ce3Schristos current_cpu->m1threads--;
305266e63ce3Schristos if (arg1 != 0)
305366e63ce3Schristos {
305466e63ce3Schristos sim_io_eprintf (sd, "Thread %d exited with status %d\n",
305566e63ce3Schristos pid, arg1);
305666e63ce3Schristos sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped,
305766e63ce3Schristos SIM_SIGILL);
305866e63ce3Schristos }
305966e63ce3Schristos
306066e63ce3Schristos /* Still, we may want to support non-zero exit values. */
306166e63ce3Schristos current_cpu->thread_data[threadno].exitval = arg1 << 8;
306266e63ce3Schristos
306366e63ce3Schristos if (exitsig)
306466e63ce3Schristos deliver_signal (current_cpu, exitsig, ppid);
306566e63ce3Schristos break;
306666e63ce3Schristos }
306766e63ce3Schristos
306866e63ce3Schristos case TARGET_SYS_clone:
306966e63ce3Schristos {
307066e63ce3Schristos int nthreads = current_cpu->m1threads + 1;
307166e63ce3Schristos void *thread_cpu_data;
307266e63ce3Schristos bfd_byte old_sp_buf[4];
307366e63ce3Schristos bfd_byte sp_buf[4];
307466e63ce3Schristos const bfd_byte zeros[4] = { 0, 0, 0, 0 };
307566e63ce3Schristos int i;
307666e63ce3Schristos
307766e63ce3Schristos /* That's right, the syscall clone arguments are reversed
307866e63ce3Schristos compared to sys_clone notes in clone(2) and compared to
307966e63ce3Schristos other Linux ports (i.e. it's the same order as in the
308066e63ce3Schristos clone(2) libcall). */
308166e63ce3Schristos USI flags = arg2;
308266e63ce3Schristos USI newsp = arg1;
308366e63ce3Schristos
308466e63ce3Schristos if (nthreads == SIM_TARGET_MAX_THREADS)
308566e63ce3Schristos {
308666e63ce3Schristos retval = -cb_host_to_target_errno (cb, EAGAIN);
308766e63ce3Schristos break;
308866e63ce3Schristos }
308966e63ce3Schristos
309066e63ce3Schristos /* FIXME: Implement the low byte. */
309166e63ce3Schristos if ((flags & ~TARGET_CSIGNAL) !=
309266e63ce3Schristos (TARGET_CLONE_VM
309366e63ce3Schristos | TARGET_CLONE_FS
309466e63ce3Schristos | TARGET_CLONE_FILES
309566e63ce3Schristos | TARGET_CLONE_SIGHAND)
309666e63ce3Schristos || newsp == 0)
309766e63ce3Schristos {
309866e63ce3Schristos retval
309966e63ce3Schristos = cris_unknown_syscall (current_cpu, pc,
310066e63ce3Schristos "Unimplemented clone syscall "
310166e63ce3Schristos "(0x%lx, 0x%lx)\n",
310266e63ce3Schristos (unsigned long) arg1,
310366e63ce3Schristos (unsigned long) arg2);
310466e63ce3Schristos break;
310566e63ce3Schristos }
310666e63ce3Schristos
310766e63ce3Schristos if (current_cpu->thread_data == NULL)
310866e63ce3Schristos make_first_thread (current_cpu);
310966e63ce3Schristos
311066e63ce3Schristos /* The created thread will get the new SP and a cleared R10.
311166e63ce3Schristos Since it's created out of a copy of the old thread and we
311266e63ce3Schristos don't have a set-register-function that just take the
311366e63ce3Schristos cpu_data as a parameter, we set the childs values first,
311466e63ce3Schristos and write back or overwrite them in the parent after the
311566e63ce3Schristos copy. */
311666e63ce3Schristos (*CPU_REG_FETCH (current_cpu)) (current_cpu,
311766e63ce3Schristos H_GR_SP, old_sp_buf, 4);
311866e63ce3Schristos bfd_putl32 (newsp, sp_buf);
311966e63ce3Schristos (*CPU_REG_STORE (current_cpu)) (current_cpu,
312066e63ce3Schristos H_GR_SP, sp_buf, 4);
312166e63ce3Schristos (*CPU_REG_STORE (current_cpu)) (current_cpu,
312266e63ce3Schristos H_GR_R10, (bfd_byte *) zeros, 4);
312366e63ce3Schristos thread_cpu_data
312466e63ce3Schristos = (*current_cpu
312566e63ce3Schristos ->make_thread_cpu_data) (current_cpu,
312666e63ce3Schristos ¤t_cpu->cpu_data_placeholder);
312766e63ce3Schristos (*CPU_REG_STORE (current_cpu)) (current_cpu,
312866e63ce3Schristos H_GR_SP, old_sp_buf, 4);
312966e63ce3Schristos
313066e63ce3Schristos retval = ++current_cpu->max_threadid + TARGET_PID;
313166e63ce3Schristos
313266e63ce3Schristos /* Find an unused slot. After a few threads have been created
313366e63ce3Schristos and exited, the array is expected to be a bit fragmented.
313466e63ce3Schristos We don't reuse the first entry, though, that of the
313566e63ce3Schristos original thread. */
313666e63ce3Schristos for (i = 1; i < SIM_TARGET_MAX_THREADS; i++)
313766e63ce3Schristos if (current_cpu->thread_data[i].cpu_context == NULL
313866e63ce3Schristos /* Don't reuse a zombied entry. */
313966e63ce3Schristos && current_cpu->thread_data[i].threadid == 0)
314066e63ce3Schristos break;
314166e63ce3Schristos
314266e63ce3Schristos memcpy (¤t_cpu->thread_data[i],
314366e63ce3Schristos ¤t_cpu->thread_data[threadno],
314466e63ce3Schristos sizeof (current_cpu->thread_data[i]));
314566e63ce3Schristos current_cpu->thread_data[i].cpu_context = thread_cpu_data;
314666e63ce3Schristos current_cpu->thread_data[i].cpu_context_atsignal = NULL;
314766e63ce3Schristos current_cpu->thread_data[i].threadid = current_cpu->max_threadid;
314866e63ce3Schristos current_cpu->thread_data[i].parent_threadid
314966e63ce3Schristos = current_cpu->thread_data[threadno].threadid;
315066e63ce3Schristos current_cpu->thread_data[i].pipe_read_fd = 0;
315166e63ce3Schristos current_cpu->thread_data[i].pipe_write_fd = 0;
315266e63ce3Schristos current_cpu->thread_data[i].at_syscall = 0;
315366e63ce3Schristos current_cpu->thread_data[i].sigpending = 0;
315466e63ce3Schristos current_cpu->thread_data[i].sigsuspended = 0;
315566e63ce3Schristos current_cpu->thread_data[i].exitsig = flags & TARGET_CSIGNAL;
315666e63ce3Schristos current_cpu->m1threads = nthreads;
315766e63ce3Schristos break;
315866e63ce3Schristos }
315966e63ce3Schristos
316066e63ce3Schristos /* Better watch these in case they do something necessary. */
316166e63ce3Schristos case TARGET_SYS_socketcall:
316266e63ce3Schristos retval = -cb_host_to_target_errno (cb, ENOSYS);
316366e63ce3Schristos break;
316466e63ce3Schristos
316566e63ce3Schristos case TARGET_SYS_set_thread_area:
316666e63ce3Schristos /* Do the same error check as Linux. */
316766e63ce3Schristos if (arg1 & 255)
316866e63ce3Schristos {
316966e63ce3Schristos retval = -cb_host_to_target_errno (cb, EINVAL);
317066e63ce3Schristos break;
317166e63ce3Schristos }
317266e63ce3Schristos (*current_cpu->set_target_thread_data) (current_cpu, arg1);
317366e63ce3Schristos retval = 0;
317466e63ce3Schristos break;
317566e63ce3Schristos
317666e63ce3Schristos unimplemented_syscall:
317766e63ce3Schristos default:
317866e63ce3Schristos retval
317966e63ce3Schristos = cris_unknown_syscall (current_cpu, pc,
318066e63ce3Schristos "Unimplemented syscall: %d "
318166e63ce3Schristos "(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n",
318266e63ce3Schristos callnum, arg1, arg2, arg3, arg4, arg5,
318366e63ce3Schristos arg6);
318466e63ce3Schristos }
318566e63ce3Schristos }
318666e63ce3Schristos
318766e63ce3Schristos /* Minimal support for fcntl F_GETFL as used in open+fdopen. */
318866e63ce3Schristos if (callnum == TARGET_SYS_open)
318966e63ce3Schristos {
319066e63ce3Schristos current_cpu->last_open_fd = retval;
319166e63ce3Schristos current_cpu->last_open_flags = arg2;
319266e63ce3Schristos }
319366e63ce3Schristos
319466e63ce3Schristos current_cpu->last_syscall = callnum;
319566e63ce3Schristos
319666e63ce3Schristos /* A system call is a rescheduling point. For the time being, we don't
319766e63ce3Schristos reschedule anywhere else. */
319866e63ce3Schristos if (current_cpu->m1threads != 0
319966e63ce3Schristos /* We need to schedule off from an exiting thread that is the
320066e63ce3Schristos second-last one. */
320166e63ce3Schristos || (current_cpu->thread_data != NULL
320266e63ce3Schristos && current_cpu->thread_data[threadno].cpu_context == NULL))
320366e63ce3Schristos {
320466e63ce3Schristos bfd_byte retval_buf[4];
320566e63ce3Schristos
320666e63ce3Schristos current_cpu->thread_data[threadno].last_execution
320766e63ce3Schristos = TARGET_TIME_MS (current_cpu);
320866e63ce3Schristos bfd_putl32 (retval, retval_buf);
320966e63ce3Schristos (*CPU_REG_STORE (current_cpu)) (current_cpu, H_GR_R10, retval_buf, 4);
321066e63ce3Schristos
321166e63ce3Schristos current_cpu->thread_data[threadno].at_syscall = 1;
321266e63ce3Schristos reschedule (current_cpu);
321366e63ce3Schristos
321466e63ce3Schristos (*CPU_REG_FETCH (current_cpu)) (current_cpu, H_GR_R10, retval_buf, 4);
321566e63ce3Schristos retval = bfd_getl32 (retval_buf);
321666e63ce3Schristos }
321766e63ce3Schristos
321866e63ce3Schristos return retval;
321966e63ce3Schristos }
322066e63ce3Schristos
322166e63ce3Schristos /* Callback from simulator write saying that the pipe at (reader, writer)
322266e63ce3Schristos is now non-empty (so the writer should wait until the pipe is empty, at
322366e63ce3Schristos least not write to this or any other pipe). Simplest is to just wait
322466e63ce3Schristos until the pipe is empty. */
322566e63ce3Schristos
322666e63ce3Schristos static void
cris_pipe_nonempty(host_callback * cb ATTRIBUTE_UNUSED,int reader,int writer)322766e63ce3Schristos cris_pipe_nonempty (host_callback *cb ATTRIBUTE_UNUSED,
322866e63ce3Schristos int reader, int writer)
322966e63ce3Schristos {
323066e63ce3Schristos SIM_CPU *cpu = current_cpu_for_cb_callback;
323166e63ce3Schristos const bfd_byte zeros[4] = { 0, 0, 0, 0 };
323266e63ce3Schristos
323366e63ce3Schristos /* It's the current thread: we just have to re-run the current
323466e63ce3Schristos syscall instruction (presumably "break 13") and change the syscall
323566e63ce3Schristos to the special simulator-wait code. Oh, and set a marker that
323666e63ce3Schristos we're waiting, so we can disambiguate the special call from a
323766e63ce3Schristos program error.
323866e63ce3Schristos
323966e63ce3Schristos This function may be called multiple times between cris_pipe_empty,
324066e63ce3Schristos but we must avoid e.g. decreasing PC every time. Check fd markers
324166e63ce3Schristos to tell. */
324266e63ce3Schristos if (cpu->thread_data == NULL)
324366e63ce3Schristos {
324466e63ce3Schristos sim_io_eprintf (CPU_STATE (cpu),
324566e63ce3Schristos "Terminating simulation due to writing pipe rd:wr %d:%d"
324666e63ce3Schristos " from one single thread\n", reader, writer);
324766e63ce3Schristos sim_engine_halt (CPU_STATE (cpu), cpu,
324866e63ce3Schristos NULL, sim_pc_get (cpu), sim_stopped, SIM_SIGILL);
324966e63ce3Schristos }
325066e63ce3Schristos else if (cpu->thread_data[cpu->threadno].pipe_write_fd == 0)
325166e63ce3Schristos {
325266e63ce3Schristos cpu->thread_data[cpu->threadno].pipe_write_fd = writer;
325366e63ce3Schristos cpu->thread_data[cpu->threadno].pipe_read_fd = reader;
325466e63ce3Schristos /* FIXME: We really shouldn't change registers other than R10 in
325566e63ce3Schristos syscalls (like R9), here or elsewhere. */
325666e63ce3Schristos (*CPU_REG_STORE (cpu)) (cpu, H_GR_R9, (bfd_byte *) zeros, 4);
325766e63ce3Schristos sim_pc_set (cpu, sim_pc_get (cpu) - 2);
325866e63ce3Schristos }
325966e63ce3Schristos }
326066e63ce3Schristos
326166e63ce3Schristos /* Callback from simulator close or read call saying that the pipe at
326266e63ce3Schristos (reader, writer) is now empty (so the writer can write again, perhaps
326366e63ce3Schristos leave a waiting state). If there are bytes remaining, they couldn't be
326466e63ce3Schristos consumed (perhaps due to the pipe closing). */
326566e63ce3Schristos
326666e63ce3Schristos static void
cris_pipe_empty(host_callback * cb,int reader,int writer)326766e63ce3Schristos cris_pipe_empty (host_callback *cb,
326866e63ce3Schristos int reader,
326966e63ce3Schristos int writer)
327066e63ce3Schristos {
327166e63ce3Schristos int i;
327266e63ce3Schristos SIM_CPU *cpu = current_cpu_for_cb_callback;
327366e63ce3Schristos SIM_DESC sd = CPU_STATE (current_cpu_for_cb_callback);
327466e63ce3Schristos bfd_byte r10_buf[4];
327566e63ce3Schristos int remaining
327666e63ce3Schristos = cb->pipe_buffer[writer].size - cb->pipe_buffer[reader].size;
327766e63ce3Schristos
327866e63ce3Schristos /* We need to find the thread that waits for this pipe. */
327966e63ce3Schristos for (i = 0; i < SIM_TARGET_MAX_THREADS; i++)
328066e63ce3Schristos if (cpu->thread_data[i].cpu_context
328166e63ce3Schristos && cpu->thread_data[i].pipe_write_fd == writer)
328266e63ce3Schristos {
328366e63ce3Schristos int retval;
328466e63ce3Schristos
328566e63ce3Schristos /* Temporarily switch to this cpu context, so we can change the
328666e63ce3Schristos PC by ordinary calls. */
328766e63ce3Schristos
328866e63ce3Schristos memcpy (cpu->thread_data[cpu->threadno].cpu_context,
328966e63ce3Schristos &cpu->cpu_data_placeholder,
329066e63ce3Schristos cpu->thread_cpu_data_size);
329166e63ce3Schristos memcpy (&cpu->cpu_data_placeholder,
329266e63ce3Schristos cpu->thread_data[i].cpu_context,
329366e63ce3Schristos cpu->thread_cpu_data_size);
329466e63ce3Schristos
329566e63ce3Schristos /* The return value is supposed to contain the number of
329666e63ce3Schristos written bytes, which is the number of bytes requested and
329766e63ce3Schristos returned at the write call. You might think the right
329866e63ce3Schristos thing is to adjust the return-value to be only the
329966e63ce3Schristos *consumed* number of bytes, but it isn't. We're only
330066e63ce3Schristos called if the pipe buffer is fully consumed or it is being
330166e63ce3Schristos closed, possibly with remaining bytes. For the latter
330266e63ce3Schristos case, the writer is still supposed to see success for
330366e63ce3Schristos PIPE_BUF bytes (a constant which we happen to know and is
330466e63ce3Schristos unlikely to change). The return value may also be a
330566e63ce3Schristos negative number; an error value. This case is covered
330666e63ce3Schristos because "remaining" is always >= 0. */
330766e63ce3Schristos (*CPU_REG_FETCH (cpu)) (cpu, H_GR_R10, r10_buf, 4);
330866e63ce3Schristos retval = (int) bfd_getl_signed_32 (r10_buf);
330966e63ce3Schristos if (retval - remaining > TARGET_PIPE_BUF)
331066e63ce3Schristos {
331166e63ce3Schristos bfd_putl32 (retval - remaining, r10_buf);
331266e63ce3Schristos (*CPU_REG_STORE (cpu)) (cpu, H_GR_R10, r10_buf, 4);
331366e63ce3Schristos }
331466e63ce3Schristos sim_pc_set (cpu, sim_pc_get (cpu) + 2);
331566e63ce3Schristos memcpy (cpu->thread_data[i].cpu_context,
331666e63ce3Schristos &cpu->cpu_data_placeholder,
331766e63ce3Schristos cpu->thread_cpu_data_size);
331866e63ce3Schristos memcpy (&cpu->cpu_data_placeholder,
331966e63ce3Schristos cpu->thread_data[cpu->threadno].cpu_context,
332066e63ce3Schristos cpu->thread_cpu_data_size);
332166e63ce3Schristos cpu->thread_data[i].pipe_read_fd = 0;
332266e63ce3Schristos cpu->thread_data[i].pipe_write_fd = 0;
332366e63ce3Schristos return;
332466e63ce3Schristos }
332566e63ce3Schristos
332666e63ce3Schristos abort ();
332766e63ce3Schristos }
332866e63ce3Schristos
332966e63ce3Schristos /* We have a simulator-specific notion of time. See TARGET_TIME. */
333066e63ce3Schristos
333166e63ce3Schristos static long
cris_time(host_callback * cb ATTRIBUTE_UNUSED,long * t)333266e63ce3Schristos cris_time (host_callback *cb ATTRIBUTE_UNUSED, long *t)
333366e63ce3Schristos {
333466e63ce3Schristos long retval = TARGET_TIME (current_cpu_for_cb_callback);
333566e63ce3Schristos if (t)
333666e63ce3Schristos *t = retval;
333766e63ce3Schristos return retval;
333866e63ce3Schristos }
333966e63ce3Schristos
334066e63ce3Schristos /* Set target-specific callback data. */
334166e63ce3Schristos
334266e63ce3Schristos void
cris_set_callbacks(host_callback * cb)334366e63ce3Schristos cris_set_callbacks (host_callback *cb)
334466e63ce3Schristos {
334566e63ce3Schristos /* Yeargh, have to cast away constness to avoid warnings. */
334666e63ce3Schristos cb->syscall_map = (CB_TARGET_DEFS_MAP *) syscall_map;
334766e63ce3Schristos cb->errno_map = (CB_TARGET_DEFS_MAP *) errno_map;
334866e63ce3Schristos
334966e63ce3Schristos /* The kernel stat64 layout. If we see a file > 2G, the "long"
335066e63ce3Schristos parameter to cb_store_target_endian will make st_size negative.
335166e63ce3Schristos Similarly for st_ino. FIXME: Find a 64-bit type, and use it
335266e63ce3Schristos *unsigned*, and/or add syntax for signed-ness. */
335366e63ce3Schristos cb->stat_map = stat_map;
335466e63ce3Schristos cb->open_map = (CB_TARGET_DEFS_MAP *) open_map;
335566e63ce3Schristos cb->pipe_nonempty = cris_pipe_nonempty;
335666e63ce3Schristos cb->pipe_empty = cris_pipe_empty;
335766e63ce3Schristos cb->time = cris_time;
335866e63ce3Schristos }
335966e63ce3Schristos
336066e63ce3Schristos /* Process an address exception. */
336166e63ce3Schristos
336266e63ce3Schristos void
cris_core_signal(SIM_DESC sd,SIM_CPU * current_cpu,sim_cia cia,unsigned int map,int nr_bytes,address_word addr,transfer_type transfer,sim_core_signals sig)336366e63ce3Schristos cris_core_signal (SIM_DESC sd, SIM_CPU *current_cpu, sim_cia cia,
336466e63ce3Schristos unsigned int map, int nr_bytes, address_word addr,
336566e63ce3Schristos transfer_type transfer, sim_core_signals sig)
336666e63ce3Schristos {
336766e63ce3Schristos sim_core_signal (sd, current_cpu, cia, map, nr_bytes, addr,
336866e63ce3Schristos transfer, sig);
336966e63ce3Schristos }
3370