/* CRIS exception, interrupt, and trap (EIT) support
- Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation, Inc.
Contributed by Axis Communications.
This file is part of the GNU simulators.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+the Free Software Foundation; either version 3 of the License, or
+(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-You should have received a copy of the GNU General Public License along
-with this program; if not, write to the Free Software Foundation, Inc.,
-59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "sim-main.h"
#include "sim-options.h"
#include "bfd.h"
/* FIXME: get rid of targ-vals.h usage everywhere else. */
+#include <stdarg.h>
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
+/* For PATH_MAX, originally. */
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+/* From ld/sysdep.h. */
+#ifdef PATH_MAX
+# define SIM_PATHMAX PATH_MAX
+#else
+# ifdef MAXPATHLEN
+# define SIM_PATHMAX MAXPATHLEN
+# else
+# define SIM_PATHMAX 1024
+# endif
+#endif
/* The verbatim values are from asm-cris/unistd.h. */
#define TARGET_SYS_time 13
#define TARGET_SYS_lseek 19
#define TARGET_SYS_getpid 20
+#define TARGET_SYS_access 33
#define TARGET_SYS_kill 37
#define TARGET_SYS_rename 38
#define TARGET_SYS_pipe 42
#define TARGET_SYS_uname 122
#define TARGET_SYS_mprotect 125
#define TARGET_SYS_llseek 140
+#define TARGET_SYS_writev 146
#define TARGET_SYS__sysctl 149
#define TARGET_SYS_sched_setparam 154
#define TARGET_SYS_sched_getparam 155
#define TARGET_SYS_getegid32 202
#define TARGET_SYS_getgid32 200
#define TARGET_SYS_fcntl64 221
+#define TARGET_SYS_set_thread_area 243
+#define TARGET_SYS_exit_group 252
#define TARGET_PROT_READ 0x1
#define TARGET_PROT_WRITE 0x2
#define TARGET_MAP_TYPE 0x0f
#define TARGET_MAP_FIXED 0x10
#define TARGET_MAP_ANONYMOUS 0x20
+#define TARGET_MAP_DENYWRITE 0x800
#define TARGET_CTL_KERN 1
#define TARGET_CTL_VM 2
#define TARGET_TCGETS 0x5401
-#define TARGET_UTSNAME "#38 Sun Apr 1 00:00:00 MET 2001"
+#define TARGET_UTSNAME "#7 Thu Jan 1 00:00:00 MET 2009"
-/* Seconds since the above date + 10 minutes. */
-#define TARGET_EPOCH 986080200
+/* Seconds since 1970-01-01 to the above date + 10 minutes;
+ 'date -d "Thu Jan 1 00:00:10 MET 2009" +%s'. */
+#define TARGET_EPOCH 1230764410
/* Milliseconds since start of run. We use the number of syscalls to
avoid introducing noise in the execution time. */
#define TARGET___WALL 0x40000000
#define TARGET___WCLONE 0x80000000
+/* From linux/limits.h. */
+#define TARGET_PIPE_BUF 4096
+
+/* From unistd.h. */
+#define TARGET_R_OK 4
+#define TARGET_W_OK 2
+#define TARGET_X_OK 1
+#define TARGET_F_OK 0
+
static const char stat_map[] =
"st_dev,2:space,10:space,4:st_mode,4:st_nlink,4:st_uid,4"
":st_gid,4:st_rdev,2:space,10:st_size,8:st_blksize,4:st_blocks,4"
{ -1, -1 }
};
+/* Let's be less drastic and more traceable. FIXME: mark as noreturn. */
+#define abort() \
+ sim_io_error (sd, "simulator unhandled condition at %s:%d", \
+ __FUNCTION__, __LINE__)
+
/* Needed for the cris_pipe_nonempty and cris_pipe_empty syscalls. */
static SIM_CPU *current_cpu_for_cb_callback;
/* For v32, unaligned_mem_dword_count should always be 0. For
v10, memsrc_stall_count should always be 0. */
- sim_io_eprintf (sd, "Memory source stall cycles: %lld\n",
- profp->memsrc_stall_count
- + profp->unaligned_mem_dword_count);
- sim_io_eprintf (sd, "Memory read-after-write stall cycles: %lld\n",
- profp->memraw_stall_count);
- sim_io_eprintf (sd, "Movem source stall cycles: %lld\n",
- profp->movemsrc_stall_count);
- sim_io_eprintf (sd, "Movem destination stall cycles: %lld\n",
- profp->movemdst_stall_count);
- sim_io_eprintf (sd, "Movem address stall cycles: %lld\n",
- profp->movemaddr_stall_count);
- sim_io_eprintf (sd, "Multiplication source stall cycles: %lld\n",
- profp->mulsrc_stall_count);
- sim_io_eprintf (sd, "Jump source stall cycles: %lld\n",
- profp->jumpsrc_stall_count);
- sim_io_eprintf (sd, "Branch misprediction stall cycles: %lld\n",
- profp->branch_stall_count);
- sim_io_eprintf (sd, "Jump target stall cycles: %lld\n",
- profp->jumptarget_stall_count);
+ sim_io_eprintf (sd, "Memory source stall cycles: %llu\n",
+ (unsigned long long) (profp->memsrc_stall_count
+ + profp->unaligned_mem_dword_count));
+ sim_io_eprintf (sd, "Memory read-after-write stall cycles: %llu\n",
+ (unsigned long long) profp->memraw_stall_count);
+ sim_io_eprintf (sd, "Movem source stall cycles: %llu\n",
+ (unsigned long long) profp->movemsrc_stall_count);
+ sim_io_eprintf (sd, "Movem destination stall cycles: %llu\n",
+ (unsigned long long) profp->movemdst_stall_count);
+ sim_io_eprintf (sd, "Movem address stall cycles: %llu\n",
+ (unsigned long long) profp->movemaddr_stall_count);
+ sim_io_eprintf (sd, "Multiplication source stall cycles: %llu\n",
+ (unsigned long long) profp->mulsrc_stall_count);
+ sim_io_eprintf (sd, "Jump source stall cycles: %llu\n",
+ (unsigned long long) profp->jumpsrc_stall_count);
+ sim_io_eprintf (sd, "Branch misprediction stall cycles: %llu\n",
+ (unsigned long long) profp->branch_stall_count);
+ sim_io_eprintf (sd, "Jump target stall cycles: %llu\n",
+ (unsigned long long) profp->jumptarget_stall_count);
}
/* Check whether any part of [addr .. addr + len - 1] is already mapped.
return 0;
}
-/* Create mmapped memory. */
+/* Check whether any part of [addr .. addr + len - 1] is *un*mapped.
+ Return 1 if the whole area is mapped, 0 otherwise. */
+
+static USI
+is_mapped_only (SIM_DESC sd ATTRIBUTE_UNUSED,
+ struct cris_sim_mmapped_page **rootp,
+ USI addr, USI len)
+{
+ struct cris_sim_mmapped_page *mapp;
+
+ if (len == 0 || (len & 8191))
+ abort ();
+
+ /* Iterate over the reverse-address sorted pages until we find a page
+ lower than the checked area. */
+ for (mapp = *rootp; mapp != NULL && mapp->addr >= addr; mapp = mapp->prev)
+ if (addr == mapp->addr && len == 8192)
+ return 1;
+ else if (addr + len > mapp->addr)
+ len -= 8192;
+
+ return 0;
+}
+
+/* Debug helper; to be run from gdb. */
+
+void
+cris_dump_map (SIM_CPU *current_cpu)
+{
+ struct cris_sim_mmapped_page *mapp;
+ USI start, end;
+
+ for (mapp = current_cpu->highest_mmapped_page,
+ start = mapp == NULL ? 0 : mapp->addr + 8192,
+ end = mapp == NULL ? 0 : mapp->addr + 8191;
+ mapp != NULL;
+ mapp = mapp->prev)
+ {
+ if (mapp->addr != start - 8192)
+ {
+ sim_io_eprintf (CPU_STATE (current_cpu), "0x%x..0x%x\n", start, end);
+ end = mapp->addr + 8191;
+ }
+
+ start = mapp->addr;
+ }
+
+ if (current_cpu->highest_mmapped_page != NULL)
+ sim_io_eprintf (CPU_STATE (current_cpu), "0x%x..0x%x\n", start, end);
+}
+
+/* Create mmapped memory. ADDR is -1 if any address will do. Caller
+ must make sure that the address isn't already mapped. */
static USI
create_map (SIM_DESC sd, struct cris_sim_mmapped_page **rootp, USI addr,
struct cris_sim_mmapped_page **higher_prevp = rootp;
USI new_addr = 0x40000000;
- if (addr != 0)
+ if (addr != (USI) -1)
new_addr = addr;
- else if (*rootp)
+ else if (*rootp && rootp[0]->addr >= new_addr)
new_addr = rootp[0]->addr + 8192;
if (len != 8192)
mapp = mapp->prev)
higher_prevp = &mapp->prev;
+ /* Assert for consistency that we don't create duplicate maps. */
+ if (is_mapped (sd, rootp, new_addr, len))
+ abort ();
+
/* Allocate the new page, on the next higher page from the last one
allocated, and link in the new descriptor before previous ones. */
mapp = malloc (sizeof (*mapp));
if (len != 8192)
{
USI page_addr;
+ int ret = 0;
if (len & 8191)
/* Which is better: return an error for this, or just round it up? */
/* Loop backwards to make each call is O(1) over the number of pages
allocated, if we're unmapping from the high end of the pages. */
for (page_addr = addr + len - 8192;
- page_addr >= addr;
+ page_addr > addr;
page_addr -= 8192)
- if (unmap_pages (sd, rootp, page_addr, 8192) != 0)
- abort ();
+ if (unmap_pages (sd, rootp, page_addr, 8192))
+ ret = EINVAL;
+
+ if (unmap_pages (sd, rootp, addr, 8192))
+ ret = EINVAL;
- return 0;
+ return ret;
}
for (mapp = *rootp; mapp != NULL && mapp->addr > addr; mapp = mapp->prev)
UINT srcreg ATTRIBUTE_UNUSED,
USI dstreg ATTRIBUTE_UNUSED)
{
+ SIM_DESC sd = CPU_STATE (current_cpu);
abort ();
}
USI page ATTRIBUTE_UNUSED,
USI newval ATTRIBUTE_UNUSED)
{
+ SIM_DESC sd = CPU_STATE (current_cpu);
abort ();
}
UINT index ATTRIBUTE_UNUSED,
USI page ATTRIBUTE_UNUSED)
{
+ SIM_DESC sd = CPU_STATE (current_cpu);
abort ();
}
static void
reschedule (SIM_CPU *current_cpu)
{
+ SIM_DESC sd = CPU_STATE (current_cpu);
int i;
/* Iterate over all thread slots, because after a few thread creations
static void
make_first_thread (SIM_CPU *current_cpu)
{
+ SIM_DESC sd = CPU_STATE (current_cpu);
current_cpu->thread_data
= xcalloc (1,
SIM_TARGET_MAX_THREADS
abort ();
}
+/* Handle unknown system calls. Returns (if it does) the syscall
+ return value. */
+
+static USI
+cris_unknown_syscall (SIM_CPU *current_cpu, USI pc, char *s, ...)
+{
+ SIM_DESC sd = CPU_STATE (current_cpu);
+ host_callback *cb = STATE_CALLBACK (sd);
+
+ if (cris_unknown_syscall_action == CRIS_USYSC_MSG_STOP
+ || cris_unknown_syscall_action == CRIS_USYSC_MSG_ENOSYS)
+ {
+ va_list ap;
+
+ va_start (ap, s);
+ sim_io_evprintf (sd, s, ap);
+ va_end (ap);
+
+ if (cris_unknown_syscall_action == CRIS_USYSC_MSG_STOP)
+ sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGILL);
+ }
+
+ return -cb_host_to_target_errno (cb, ENOSYS);
+}
+
/* Main function: the handler of the "break 13" syscall insn. */
USI
s.arg2 = arg2;
s.arg3 = arg3;
- if (callnum == TARGET_SYS_exit && current_cpu->m1threads == 0)
+ if (callnum == TARGET_SYS_exit_group
+ || (callnum == TARGET_SYS_exit && current_cpu->m1threads == 0))
{
if (CPU_CRIS_MISC_PROFILE (current_cpu)->flags
& FLAG_CRIS_MISC_PROFILE_ALL)
}
/* FALLTHROUGH */
default:
- /* Abort for all other cases. */
- sim_io_eprintf (sd, "Unimplemented %s syscall "
- "(fd: 0x%lx: cmd: 0x%lx arg: 0x%lx)\n",
- callnum == TARGET_SYS_fcntl
- ? "fcntl" : "fcntl64",
- (unsigned long) (USI) arg1,
- (unsigned long) (USI) arg2,
- (unsigned long) (USI) arg3);
- sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped,
- SIM_SIGILL);
+ /* Nothing else is implemented. */
+ retval
+ = cris_unknown_syscall (current_cpu, pc,
+ "Unimplemented %s syscall "
+ "(fd: 0x%lx: cmd: 0x%lx arg: "
+ "0x%lx)\n",
+ callnum == TARGET_SYS_fcntl
+ ? "fcntl" : "fcntl64",
+ (unsigned long) (USI) arg1,
+ (unsigned long) (USI) arg2,
+ (unsigned long) (USI) arg3);
break;
}
break;
case TARGET_SYS_uname:
{
/* Fill in a few constants to appease glibc. */
- static const char sim_utsname[6][65] =
+ static char sim_utsname[6][65] =
{
"Linux",
"sim-target",
- "2.4.5",
+ "2.6.27",
TARGET_UTSNAME,
- "cris",
+ "cris", /* Overwritten below. */
"localdomain"
};
+ /* Having the hardware type in Linux equal to the bfd
+ printable name is deliberate: if you make config.guess
+ work on your Linux-type system the usual way, it
+ probably will; either the bfd printable_name or the
+ ambiguous arch_name. */
+ strcpy (sim_utsname[4], STATE_ARCHITECTURE (sd)->printable_name);
+
if ((s.write_mem) (cb, &s, arg1, (const char *) sim_utsname,
sizeof (sim_utsname))
!= sizeof (sim_utsname))
USI fd = arg5;
USI pgoff = arg6;
+ /* At 2.6.27, Linux (many (all?) ports, in the mmap2 syscalls)
+ still masked away this bit, so let's just ignore
+ it. */
+ flags &= ~TARGET_MAP_DENYWRITE;
+
/* If the simulator wants to mmap more than the very large
limit, something is wrong. FIXME: Return an error or
abort? Have command-line selectable? */
!= (TARGET_PROT_READ
| TARGET_PROT_WRITE
| TARGET_PROT_EXEC))
+ && (prot != (TARGET_PROT_READ | TARGET_PROT_EXEC))
&& prot != TARGET_PROT_READ)
|| (flags != (TARGET_MAP_ANONYMOUS | TARGET_MAP_PRIVATE)
&& flags != TARGET_MAP_PRIVATE
+ && flags != (TARGET_MAP_ANONYMOUS
+ | TARGET_MAP_PRIVATE | TARGET_MAP_FIXED)
+ && flags != (TARGET_MAP_PRIVATE | TARGET_MAP_FIXED)
&& flags != TARGET_MAP_SHARED)
- || (fd != (USI) -1 && prot != TARGET_PROT_READ)
- || pgoff != 0)
+ || (fd != (USI) -1
+ && prot != TARGET_PROT_READ
+ && prot != (TARGET_PROT_READ | TARGET_PROT_EXEC)
+ && prot != (TARGET_PROT_READ | TARGET_PROT_WRITE))
+ || (fd == (USI) -1 && pgoff != 0)
+ || (fd != (USI) -1 && (flags & TARGET_MAP_ANONYMOUS)))
{
- sim_io_eprintf (sd, "Unimplemented mmap2 call "
- "(0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx)\n",
- (unsigned long) arg1,
- (unsigned long) arg2,
- (unsigned long) arg3,
- (unsigned long) arg4,
- (unsigned long) arg5,
- (unsigned long) arg6);
- sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped,
- SIM_SIGILL);
+ retval
+ = cris_unknown_syscall (current_cpu, pc,
+ "Unimplemented mmap2 call "
+ "(0x%lx, 0x%lx, 0x%lx, "
+ "0x%lx, 0x%lx, 0x%lx)\n",
+ (unsigned long) arg1,
+ (unsigned long) arg2,
+ (unsigned long) arg3,
+ (unsigned long) arg4,
+ (unsigned long) arg5,
+ (unsigned long) arg6);
break;
}
else if (fd != (USI) -1)
/* A non-aligned argument is allowed for files. */
USI newlen = (len + 8191) & ~8191;
- /* We only support read, which we should already have
- checked. Check again anyway. */
- if (prot != TARGET_PROT_READ)
+ /* We only support read, read|exec, and read|write,
+ which we should already have checked. Check again
+ anyway. */
+ if (prot != TARGET_PROT_READ
+ && prot != (TARGET_PROT_READ | TARGET_PROT_EXEC)
+ && prot != (TARGET_PROT_READ | TARGET_PROT_WRITE))
abort ();
+ if (flags & TARGET_MAP_FIXED)
+ unmap_pages (sd, ¤t_cpu->highest_mmapped_page,
+ addr, newlen);
+ else if (is_mapped (sd, ¤t_cpu->highest_mmapped_page,
+ addr, newlen))
+ addr = 0;
+
newaddr
- = create_map (sd, ¤t_cpu->highest_mmapped_page, addr,
+ = create_map (sd, ¤t_cpu->highest_mmapped_page,
+ addr != 0 || (flags & TARGET_MAP_FIXED)
+ ? addr : -1,
newlen);
if (newaddr >= (USI) -8191)
break;
}
+ /* We were asked for MAP_FIXED, but couldn't. */
+ if ((flags & TARGET_MAP_FIXED) && newaddr != addr)
+ {
+ abort ();
+ unmap_pages (sd, ¤t_cpu->highest_mmapped_page,
+ newaddr, newlen);
+ retval = -cb_host_to_target_errno (cb, EINVAL);
+ break;
+ }
+
/* Find the current position in the file. */
s.func = TARGET_SYS_lseek;
s.arg1 = fd;
abort ();
pos = s.result;
+ if (s.result < 0)
+ abort ();
+
+ /* Move to the correct offset in the file. */
+ s.func = TARGET_SYS_lseek;
+ s.arg1 = fd;
+ s.arg2 = pgoff*8192;
+ s.arg3 = SEEK_SET;
+ if (cb_syscall (cb, &s) != CB_RC_OK)
+ abort ();
+
if (s.result < 0)
abort ();
if (cb_syscall (cb, &s) != CB_RC_OK)
abort ();
- if ((USI) s.result != len)
+ /* If the result is a page or more lesser than what
+ was requested, something went wrong. */
+ if (len >= 8192 && (USI) s.result <= len - 8192)
abort ();
/* After reading, we need to go back to the previous
}
else
{
- USI newaddr
- = create_map (sd, ¤t_cpu->highest_mmapped_page, addr,
- (len + 8191) & ~8191);
+ USI newlen = (len + 8191) & ~8191;
+ USI newaddr;
+
+ if (flags & TARGET_MAP_FIXED)
+ unmap_pages (sd, ¤t_cpu->highest_mmapped_page,
+ addr, newlen);
+ else if (is_mapped (sd, ¤t_cpu->highest_mmapped_page,
+ addr, newlen))
+ addr = 0;
+
+ newaddr = create_map (sd, ¤t_cpu->highest_mmapped_page,
+ addr != 0 || (flags & TARGET_MAP_FIXED)
+ ? addr : -1,
+ newlen);
if (newaddr >= (USI) -8191)
retval = -cb_host_to_target_errno (cb, -(SI) newaddr);
else
retval = newaddr;
+
+ if ((flags & TARGET_MAP_FIXED) && newaddr != addr)
+ {
+ abort ();
+ unmap_pages (sd, ¤t_cpu->highest_mmapped_page,
+ newaddr, newlen);
+ retval = -cb_host_to_target_errno (cb, EINVAL);
+ break;
+ }
}
break;
}
case TARGET_SYS_mprotect:
{
- /* We only cover the case of linuxthreads mprotecting out its
- stack guard page. */
+ /* We only cover the case of linuxthreads mprotecting out
+ its stack guard page and of dynamic loading mprotecting
+ away the data (for some reason the whole library, then
+ mprotects away the data part and mmap-FIX:es it again. */
USI addr = arg1;
USI len = arg2;
USI prot = arg3;
- if ((addr & 8191) != 0
- || len != 8192
- || prot != TARGET_PROT_NONE
- || !is_mapped (sd, ¤t_cpu->highest_mmapped_page, addr,
- len))
+ if (prot != TARGET_PROT_NONE
+ || !is_mapped_only (sd, ¤t_cpu->highest_mmapped_page,
+ addr, (len + 8191) & ~8191))
{
- sim_io_eprintf (sd, "Unimplemented mprotect call "
- "(0x%lx, 0x%lx, 0x%lx)\n",
- (unsigned long) arg1,
- (unsigned long) arg2,
- (unsigned long) arg3);
- sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped,
- SIM_SIGILL);
+ retval
+ = cris_unknown_syscall (current_cpu, pc,
+ "Unimplemented mprotect call "
+ "(0x%lx, 0x%lx, 0x%lx)\n",
+ (unsigned long) arg1,
+ (unsigned long) arg2,
+ (unsigned long) arg3);
break;
}
- /* FIXME: We should account for pages like this that are
- "mprotected out". For now, we just tell the simulator
- core to remove that page from its map. */
- sim_core_detach (sd, NULL, 0, 0, addr);
+ /* Just ignore this. We could make this equal to munmap,
+ but then we'd have to make sure no anon mmaps gets this
+ address before a subsequent MAP_FIXED mmap intended to
+ override it. */
retval = 0;
break;
}
|| rusagep != 0
|| current_cpu->thread_data == NULL)
{
- sim_io_eprintf (sd, "Unimplemented wait4 call "
- "(0x%lx, 0x%lx, 0x%lx, 0x%lx)\n",
- (unsigned long) arg1,
- (unsigned long) arg2,
- (unsigned long) arg3,
- (unsigned long) arg4);
- sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped,
- SIM_SIGILL);
+ retval
+ = cris_unknown_syscall (current_cpu, pc,
+ "Unimplemented wait4 call "
+ "(0x%lx, 0x%lx, 0x%lx, 0x%lx)\n",
+ (unsigned long) arg1,
+ (unsigned long) arg2,
+ (unsigned long) arg3,
+ (unsigned long) arg4);
break;
}
&& target_sa_flags != (TARGET_SA_RESTART|TARGET_SA_SIGINFO))
|| target_sa_handler == 0)
{
- sim_io_eprintf (sd, "Unimplemented rt_sigaction "
- "syscall (0x%lx, "
- "0x%lx: [0x%x, 0x%x, 0x%x, "
- "{0x%x, 0x%x}], "
- "0x%lx)\n",
- (unsigned long) arg1,
- (unsigned long) arg2,
- target_sa_handler, target_sa_flags,
- target_sa_restorer,
- target_sa_mask_low, target_sa_mask_high,
- (unsigned long) arg3);
- sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped,
- SIM_SIGILL);
+ retval
+ = cris_unknown_syscall (current_cpu, pc,
+ "Unimplemented rt_sigaction "
+ "syscall "
+ "(0x%lx, 0x%lx: "
+ "[0x%x, 0x%x, 0x%x, "
+ "{0x%x, 0x%x}], 0x%lx)\n",
+ (unsigned long) arg1,
+ (unsigned long) arg2,
+ target_sa_handler,
+ target_sa_flags,
+ target_sa_restorer,
+ target_sa_mask_low,
+ target_sa_mask_high,
+ (unsigned long) arg3);
+ break;
}
current_cpu->sighandler[signum] = target_sa_handler;
mapped_addr
= create_map (sd, ¤t_cpu->highest_mmapped_page,
- 0, new_len);
+ -1, new_len);
if (mapped_addr > (USI) -8192)
{
|| (buf.st_mode & S_IFIFO) == 0)
|| current_cpu->thread_data == NULL)
{
- sim_io_eprintf (sd, "Unimplemented poll syscall "
- "(0x%lx: [0x%x, 0x%x, x], 0x%lx, 0x%lx)\n",
- (unsigned long) arg1, fd, events,
- (unsigned long) arg2, (unsigned long) arg3);
- sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGILL);
+ retval
+ = cris_unknown_syscall (current_cpu, pc,
+ "Unimplemented poll syscall "
+ "(0x%lx: [0x%x, 0x%x, x], "
+ "0x%lx, 0x%lx)\n",
+ (unsigned long) arg1, fd, events,
+ (unsigned long) arg2,
+ (unsigned long) arg3);
break;
}
if (!((offs_hi == 0 && offs_lo >= 0)
|| (offs_hi == -1 && offs_lo < 0)))
{
- sim_io_eprintf (sd,
- "Unimplemented llseek offset,"
- " fd %d: 0x%x:0x%x\n",
- fd, (unsigned) arg2, (unsigned) arg3);
- sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped,
- SIM_SIGILL);
+ retval
+ = cris_unknown_syscall (current_cpu, pc,
+ "Unimplemented llseek offset,"
+ " fd %d: 0x%x:0x%x\n",
+ fd, (unsigned) arg2,
+ (unsigned) arg3);
+ break;
}
s.func = TARGET_SYS_lseek;
break;
}
+ /* ssize_t writev(int fd, const struct iovec *iov, int iovcnt);
+ where:
+ struct iovec {
+ void *iov_base; Starting address
+ size_t iov_len; Number of bytes to transfer
+ }; */
+ case TARGET_SYS_writev:
+ {
+ SI fd = arg1;
+ SI iov = arg2;
+ SI iovcnt = arg3;
+ SI retcnt = 0;
+ int i;
+
+ /* We'll ignore strict error-handling and just do multiple write calls. */
+ for (i = 0; i < iovcnt; i++)
+ {
+ int sysret;
+ USI iov_base
+ = sim_core_read_unaligned_4 (current_cpu, pc, 0,
+ iov + 8*i);
+ USI iov_len
+ = sim_core_read_unaligned_4 (current_cpu, pc, 0,
+ iov + 8*i + 4);
+
+ s.func = TARGET_SYS_write;
+ s.arg1 = fd;
+ s.arg2 = iov_base;
+ s.arg3 = iov_len;
+
+ if (cb_syscall (cb, &s) != CB_RC_OK)
+ abort ();
+ sysret = s.result == -1 ? -s.errcode : s.result;
+
+ if (sysret != iov_len)
+ {
+ if (i != 0)
+ abort ();
+ retcnt = sysret;
+ break;
+ }
+
+ retcnt += iov_len;
+ }
+
+ retval = retcnt;
+ }
+ break;
+
/* This one does have a generic callback function, but at the time
of this writing, cb_syscall does not have code for it, and we
need target-specific code for the threads implementation
&& how != TARGET_SIG_SETMASK
&& how != TARGET_SIG_UNBLOCK)
{
- sim_io_eprintf (sd, "Unimplemented rt_sigprocmask syscall "
- "(0x%x, 0x%x, 0x%x)\n", arg1, arg2, arg3);
- sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped,
- SIM_SIGILL);
- retval = 0;
+ retval
+ = cris_unknown_syscall (current_cpu, pc,
+ "Unimplemented rt_sigprocmask "
+ "syscall (0x%x, 0x%x, 0x%x)\n",
+ arg1, arg2, arg3);
break;
}
|| (current_cpu->thread_data[threadno].cpu_context_atsignal
== NULL))
{
- sim_io_eprintf (sd, "Invalid sigreturn syscall: no signal"
- " handler active "
- "(0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx)\n",
- (unsigned long) arg1,
- (unsigned long) arg2,
- (unsigned long) arg3,
- (unsigned long) arg4,
- (unsigned long) arg5,
- (unsigned long) arg6);
- sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped,
- SIM_SIGILL);
+ retval
+ = cris_unknown_syscall (current_cpu, pc,
+ "Invalid sigreturn syscall: "
+ "no signal handler active "
+ "(0x%lx, 0x%lx, 0x%lx, 0x%lx, "
+ "0x%lx, 0x%lx)\n",
+ (unsigned long) arg1,
+ (unsigned long) arg2,
+ (unsigned long) arg3,
+ (unsigned long) arg4,
+ (unsigned long) arg5,
+ (unsigned long) arg6);
+ break;
}
was_sigsuspended
if (setsize != 8)
{
- sim_io_eprintf (sd, "Unimplemented rt_sigsuspend syscall"
- " arguments (0x%lx, 0x%lx)\n",
- (unsigned long) arg1, (unsigned long) arg2);
- sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped,
- SIM_SIGILL);
+ retval
+ = cris_unknown_syscall (current_cpu, pc,
+ "Unimplemented rt_sigsuspend syscall"
+ " arguments (0x%lx, 0x%lx)\n",
+ (unsigned long) arg1,
+ (unsigned long) arg2);
+ break;
}
/* Don't change the signal mask if we're already in
USI buf = arg1;
USI size = arg2;
- char *cwd = xmalloc (MAXPATHLEN);
- if (cwd != getcwd (cwd, MAXPATHLEN))
+ char *cwd = xmalloc (SIM_PATHMAX);
+ if (cwd != getcwd (cwd, SIM_PATHMAX))
abort ();
/* FIXME: When and if we support chdir, we need something
break;
}
+ case TARGET_SYS_access:
+ {
+ SI path = arg1;
+ SI mode = arg2;
+ char *pbuf = xmalloc (SIM_PATHMAX);
+ int i;
+ int o = 0;
+ int hmode = 0;
+
+ if (sim_core_read_unaligned_1 (current_cpu, pc, 0, path) == '/')
+ {
+ strcpy (pbuf, simulator_sysroot);
+ o += strlen (simulator_sysroot);
+ }
+
+ for (i = 0; i + o < SIM_PATHMAX; i++)
+ {
+ pbuf[i + o]
+ = sim_core_read_unaligned_1 (current_cpu, pc, 0, path + i);
+ if (pbuf[i + o] == 0)
+ break;
+ }
+
+ if (i + o == SIM_PATHMAX)
+ {
+ retval = -cb_host_to_target_errno (cb, ENAMETOOLONG);
+ break;
+ }
+
+ /* Assert that we don't get calls for files for which we
+ don't have support. */
+ if (strncmp (pbuf + strlen (simulator_sysroot),
+ "/proc/", 6) == 0)
+ abort ();
+#define X_AFLAG(x) if (mode & TARGET_ ## x) hmode |= x
+ X_AFLAG (R_OK);
+ X_AFLAG (W_OK);
+ X_AFLAG (X_OK);
+ X_AFLAG (F_OK);
+#undef X_AFLAG
+
+ if (access (pbuf, hmode) != 0)
+ retval = -cb_host_to_target_errno (cb, errno);
+ else
+ retval = 0;
+
+ free (pbuf);
+ break;
+ }
+
case TARGET_SYS_readlink:
{
SI path = arg1;
SI buf = arg2;
SI bufsiz = arg3;
- char *pbuf = xmalloc (MAXPATHLEN);
- char *lbuf = xmalloc (MAXPATHLEN);
+ char *pbuf = xmalloc (SIM_PATHMAX);
+ char *lbuf = xmalloc (SIM_PATHMAX);
char *lbuf_alloc = lbuf;
int nchars = -1;
int i;
o += strlen (simulator_sysroot);
}
- for (i = 0; i + o < MAXPATHLEN; i++)
+ for (i = 0; i + o < SIM_PATHMAX; i++)
{
pbuf[i + o]
= sim_core_read_unaligned_1 (current_cpu, pc, 0, path + i);
break;
}
- if (i + o == MAXPATHLEN)
+ if (i + o == SIM_PATHMAX)
{
retval = -cb_host_to_target_errno (cb, ENAMETOOLONG);
break;
if (argv0 == NULL || *argv0 == '.')
{
- sim_io_eprintf (sd, "Unimplemented readlink syscall "
- "(0x%lx: [\"%s\"], 0x%lx)\n",
- (unsigned long) arg1, pbuf,
- (unsigned long) arg2);
- sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped,
- SIM_SIGILL);
+ retval
+ = cris_unknown_syscall (current_cpu, pc,
+ "Unimplemented readlink syscall "
+ "(0x%lx: [\"%s\"], 0x%lx)\n",
+ (unsigned long) arg1, pbuf,
+ (unsigned long) arg2);
break;
}
else if (*argv0 == '/')
}
else
{
- if (getcwd (lbuf, MAXPATHLEN) != NULL
- && strlen (lbuf) + 2 + strlen (argv0) < MAXPATHLEN)
+ if (getcwd (lbuf, SIM_PATHMAX) != NULL
+ && strlen (lbuf) + 2 + strlen (argv0) < SIM_PATHMAX)
{
if (strncmp (simulator_sysroot, lbuf,
strlen (simulator_sysroot)) == 0)
}
}
else
- nchars = readlink (pbuf, lbuf, MAXPATHLEN);
+ nchars = readlink (pbuf, lbuf, SIM_PATHMAX);
/* We trust that the readlink result returns a *relative*
link, or one already adjusted for the file-path-prefix.
break;
}
- sim_io_eprintf (sd, "Unimplemented _sysctl syscall "
- "(0x%lx: [0x%lx, 0x%lx],"
- " 0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx)\n",
- (unsigned long) name,
- (unsigned long) name0,
- (unsigned long) name1,
- (unsigned long) nlen,
- (unsigned long) oldval,
- (unsigned long) oldlenp,
- (unsigned long) newval,
- (unsigned long) newlen);
- sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped,
- SIM_SIGILL);
+ retval
+ = cris_unknown_syscall (current_cpu, pc,
+ "Unimplemented _sysctl syscall "
+ "(0x%lx: [0x%lx, 0x%lx],"
+ " 0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx)\n",
+ (unsigned long) name,
+ (unsigned long) name0,
+ (unsigned long) name1,
+ (unsigned long) nlen,
+ (unsigned long) oldval,
+ (unsigned long) oldlenp,
+ (unsigned long) newval,
+ (unsigned long) newlen);
break;
}
| TARGET_CLONE_SIGHAND)
|| newsp == 0)
{
- sim_io_eprintf (sd,
- "Unimplemented clone syscall (0x%lx, 0x%lx)\n",
- (unsigned long) arg1, (unsigned long) arg2);
- sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped,
- SIM_SIGILL);
+ retval
+ = cris_unknown_syscall (current_cpu, pc,
+ "Unimplemented clone syscall "
+ "(0x%lx, 0x%lx)\n",
+ (unsigned long) arg1,
+ (unsigned long) arg2);
+ break;
}
if (current_cpu->thread_data == NULL)
retval = -cb_host_to_target_errno (cb, ENOSYS);
break;
+ case TARGET_SYS_set_thread_area:
+ /* Do the same error check as Linux. */
+ if (arg1 & 255)
+ {
+ retval = -cb_host_to_target_errno (cb, EINVAL);
+ break;
+ }
+ (*current_cpu->set_target_thread_data) (current_cpu, arg1);
+ retval = 0;
+ break;
+
unimplemented_syscall:
default:
- sim_io_eprintf (sd, "Unimplemented syscall: %d "
- "(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n", callnum,
- arg1, arg2, arg3, arg4, arg5, arg6);
- sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped,
- SIM_SIGILL);
+ retval
+ = cris_unknown_syscall (current_cpu, pc,
+ "Unimplemented syscall: %d "
+ "(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n",
+ callnum, arg1, arg2, arg3, arg4, arg5,
+ arg6);
}
}
current_cpu->last_open_fd = retval;
current_cpu->last_open_flags = arg2;
}
+
current_cpu->last_syscall = callnum;
/* A system call is a rescheduling point. For the time being, we don't
static void
cris_pipe_empty (host_callback *cb,
- int reader ATTRIBUTE_UNUSED,
+ int reader,
int writer)
{
int i;
SIM_CPU *cpu = current_cpu_for_cb_callback;
+ SIM_DESC sd = CPU_STATE (current_cpu_for_cb_callback);
bfd_byte r10_buf[4];
- int remaining = cb->pipe_buffer[writer].size;
+ int remaining
+ = cb->pipe_buffer[writer].size - cb->pipe_buffer[reader].size;
/* We need to find the thread that waits for this pipe. */
for (i = 0; i < SIM_TARGET_MAX_THREADS; i++)
&& cpu->thread_data[i].pipe_write_fd == writer)
{
int retval;
+
/* Temporarily switch to this cpu context, so we can change the
PC by ordinary calls. */
cpu->thread_data[i].cpu_context,
cpu->thread_cpu_data_size);
- /* The return value is supposed to contain the number of written
- bytes, which is the number of bytes requested and returned at
- the write call. We subtract the remaining bytes from that,
- but making sure we still get a positive number.
- The return value may also be a negative number; an error
- value. We cover this case by comparing against remaining,
- which is always >= 0. */
+ /* The return value is supposed to contain the number of
+ written bytes, which is the number of bytes requested and
+ returned at the write call. You might think the right
+ thing is to adjust the return-value to be only the
+ *consumed* number of bytes, but it isn't. We're only
+ called if the pipe buffer is fully consumed or it is being
+ closed, possibly with remaining bytes. For the latter
+ case, the writer is still supposed to see success for
+ PIPE_BUF bytes (a constant which we happen to know and is
+ unlikely to change). The return value may also be a
+ negative number; an error value. This case is covered
+ because "remaining" is always >= 0. */
(*CPU_REG_FETCH (cpu)) (cpu, H_GR_R10, r10_buf, 4);
retval = (int) bfd_getl_signed_32 (r10_buf);
- if (retval >= remaining)
- bfd_putl32 (retval - remaining, r10_buf);
- (*CPU_REG_STORE (cpu)) (cpu, H_GR_R10, r10_buf, 4);
-
+ if (retval - remaining > TARGET_PIPE_BUF)
+ {
+ bfd_putl32 (retval - remaining, r10_buf);
+ (*CPU_REG_STORE (cpu)) (cpu, H_GR_R10, r10_buf, 4);
+ }
sim_pc_set (cpu, sim_pc_get (cpu) + 2);
memcpy (cpu->thread_data[i].cpu_context,
&cpu->cpu_data_placeholder,