
The use of __NR_ defines in here conflicts a lot with the standard host syscalls, sometimes leading to build errors (when the numbers happen to be the same we get duplicate case handlers), and other times leading to misbehavior (where the m32r syscall # is not what is actually checked). Namespace these using the standard that we already use: change the __NR_ to TARGET_LINUX_SYS_ with a simple `sed`. Also add a few missing includes so the code at least compiles.
1358 lines
40 KiB
C
1358 lines
40 KiB
C
/* m32r exception, interrupt, and trap (EIT) support
|
||
Copyright (C) 1998-2021 Free Software Foundation, Inc.
|
||
Contributed by Renesas.
|
||
|
||
This file is part of GDB, the GNU debugger.
|
||
|
||
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 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, see <http://www.gnu.org/licenses/>. */
|
||
|
||
/* This must come before any other includes. */
|
||
#include "defs.h"
|
||
|
||
#include "portability.h"
|
||
#include "sim-main.h"
|
||
#include "sim-signal.h"
|
||
#include "sim-syscall.h"
|
||
#include "sim/callback.h"
|
||
#include "syscall.h"
|
||
#include "targ-vals.h"
|
||
#include <dirent.h>
|
||
#include <errno.h>
|
||
#include <fcntl.h>
|
||
#include <stdlib.h>
|
||
#include <time.h>
|
||
#include <unistd.h>
|
||
#include <utime.h>
|
||
#include <sys/mman.h>
|
||
#include <sys/poll.h>
|
||
#include <sys/resource.h>
|
||
#include <sys/sysinfo.h>
|
||
#include <sys/stat.h>
|
||
#include <sys/time.h>
|
||
#include <sys/timeb.h>
|
||
#include <sys/timex.h>
|
||
#include <sys/types.h>
|
||
#include <sys/uio.h>
|
||
#include <sys/utsname.h>
|
||
#include <sys/vfs.h>
|
||
#include <linux/sysctl.h>
|
||
#include <linux/types.h>
|
||
#include <linux/unistd.h>
|
||
|
||
#define TRAP_ELF_SYSCALL 0
|
||
#define TRAP_LINUX_SYSCALL 2
|
||
#define TRAP_FLUSH_CACHE 12
|
||
|
||
/* The semantic code invokes this for invalid (unrecognized) instructions. */
|
||
|
||
SEM_PC
|
||
sim_engine_invalid_insn (SIM_CPU *current_cpu, IADDR cia, SEM_PC vpc)
|
||
{
|
||
SIM_DESC sd = CPU_STATE (current_cpu);
|
||
|
||
#if 0
|
||
if (STATE_ENVIRONMENT (sd) == OPERATING_ENVIRONMENT)
|
||
{
|
||
h_bsm_set (current_cpu, h_sm_get (current_cpu));
|
||
h_bie_set (current_cpu, h_ie_get (current_cpu));
|
||
h_bcond_set (current_cpu, h_cond_get (current_cpu));
|
||
/* sm not changed */
|
||
h_ie_set (current_cpu, 0);
|
||
h_cond_set (current_cpu, 0);
|
||
|
||
h_bpc_set (current_cpu, cia);
|
||
|
||
sim_engine_restart (CPU_STATE (current_cpu), current_cpu, NULL,
|
||
EIT_RSVD_INSN_ADDR);
|
||
}
|
||
else
|
||
#endif
|
||
sim_engine_halt (sd, current_cpu, NULL, cia, sim_stopped, SIM_SIGILL);
|
||
return vpc;
|
||
}
|
||
|
||
/* Process an address exception. */
|
||
|
||
void
|
||
m32r_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)
|
||
{
|
||
if (STATE_ENVIRONMENT (sd) == OPERATING_ENVIRONMENT)
|
||
{
|
||
m32rbf_h_cr_set (current_cpu, H_CR_BBPC,
|
||
m32rbf_h_cr_get (current_cpu, H_CR_BPC));
|
||
if (MACH_NUM (CPU_MACH (current_cpu)) == MACH_M32R)
|
||
{
|
||
m32rbf_h_bpsw_set (current_cpu, m32rbf_h_psw_get (current_cpu));
|
||
/* sm not changed */
|
||
m32rbf_h_psw_set (current_cpu, m32rbf_h_psw_get (current_cpu) & 0x80);
|
||
}
|
||
else if (MACH_NUM (CPU_MACH (current_cpu)) == MACH_M32RX)
|
||
{
|
||
m32rxf_h_bpsw_set (current_cpu, m32rxf_h_psw_get (current_cpu));
|
||
/* sm not changed */
|
||
m32rxf_h_psw_set (current_cpu, m32rxf_h_psw_get (current_cpu) & 0x80);
|
||
}
|
||
else
|
||
{
|
||
m32r2f_h_bpsw_set (current_cpu, m32r2f_h_psw_get (current_cpu));
|
||
/* sm not changed */
|
||
m32r2f_h_psw_set (current_cpu, m32r2f_h_psw_get (current_cpu) & 0x80);
|
||
}
|
||
m32rbf_h_cr_set (current_cpu, H_CR_BPC, cia);
|
||
|
||
sim_engine_restart (CPU_STATE (current_cpu), current_cpu, NULL,
|
||
EIT_ADDR_EXCP_ADDR);
|
||
}
|
||
else
|
||
sim_core_signal (sd, current_cpu, cia, map, nr_bytes, addr,
|
||
transfer, sig);
|
||
}
|
||
|
||
/* Translate target's address to host's address. */
|
||
|
||
static void *
|
||
t2h_addr (host_callback *cb, struct cb_syscall *sc,
|
||
unsigned long taddr)
|
||
{
|
||
void *addr;
|
||
SIM_DESC sd = (SIM_DESC) sc->p1;
|
||
SIM_CPU *cpu = (SIM_CPU *) sc->p2;
|
||
|
||
if (taddr == 0)
|
||
return NULL;
|
||
|
||
return sim_core_trans_addr (sd, cpu, read_map, taddr);
|
||
}
|
||
|
||
static unsigned int
|
||
conv_endian (unsigned int tvalue)
|
||
{
|
||
unsigned int hvalue;
|
||
unsigned int t1, t2, t3, t4;
|
||
|
||
if (HOST_BYTE_ORDER == BFD_ENDIAN_LITTLE)
|
||
{
|
||
t1 = tvalue & 0xff000000;
|
||
t2 = tvalue & 0x00ff0000;
|
||
t3 = tvalue & 0x0000ff00;
|
||
t4 = tvalue & 0x000000ff;
|
||
|
||
hvalue = t1 >> 24;
|
||
hvalue += t2 >> 8;
|
||
hvalue += t3 << 8;
|
||
hvalue += t4 << 24;
|
||
}
|
||
else
|
||
hvalue = tvalue;
|
||
|
||
return hvalue;
|
||
}
|
||
|
||
static unsigned short
|
||
conv_endian16 (unsigned short tvalue)
|
||
{
|
||
unsigned short hvalue;
|
||
unsigned short t1, t2;
|
||
|
||
if (HOST_BYTE_ORDER == BFD_ENDIAN_LITTLE)
|
||
{
|
||
t1 = tvalue & 0xff00;
|
||
t2 = tvalue & 0x00ff;
|
||
|
||
hvalue = t1 >> 8;
|
||
hvalue += t2 << 8;
|
||
}
|
||
else
|
||
hvalue = tvalue;
|
||
|
||
return hvalue;
|
||
}
|
||
|
||
static void
|
||
translate_endian(void *addr, size_t size)
|
||
{
|
||
unsigned int *p = (unsigned int *) addr;
|
||
int i;
|
||
|
||
for (i = 0; i <= size - 4; i += 4,p++)
|
||
*p = conv_endian(*p);
|
||
|
||
if (i <= size - 2)
|
||
*((unsigned short *) p) = conv_endian16(*((unsigned short *) p));
|
||
}
|
||
|
||
/* Trap support.
|
||
The result is the pc address to continue at.
|
||
Preprocessing like saving the various registers has already been done. */
|
||
|
||
USI
|
||
m32r_trap (SIM_CPU *current_cpu, PCADDR pc, int num)
|
||
{
|
||
SIM_DESC sd = CPU_STATE (current_cpu);
|
||
host_callback *cb = STATE_CALLBACK (sd);
|
||
|
||
switch (num)
|
||
{
|
||
case TRAP_ELF_SYSCALL :
|
||
{
|
||
long result, result2;
|
||
int errcode;
|
||
|
||
sim_syscall_multi (current_cpu,
|
||
m32rbf_h_gr_get (current_cpu, 0),
|
||
m32rbf_h_gr_get (current_cpu, 1),
|
||
m32rbf_h_gr_get (current_cpu, 2),
|
||
m32rbf_h_gr_get (current_cpu, 3),
|
||
m32rbf_h_gr_get (current_cpu, 4),
|
||
&result, &result2, &errcode);
|
||
|
||
m32rbf_h_gr_set (current_cpu, 2, errcode);
|
||
m32rbf_h_gr_set (current_cpu, 0, result);
|
||
m32rbf_h_gr_set (current_cpu, 1, result2);
|
||
break;
|
||
}
|
||
|
||
case TRAP_LINUX_SYSCALL :
|
||
{
|
||
CB_SYSCALL s;
|
||
unsigned int func, arg1, arg2, arg3, arg4, arg5, arg6, arg7;
|
||
int result, result2, errcode;
|
||
|
||
if (STATE_ENVIRONMENT (sd) == OPERATING_ENVIRONMENT)
|
||
{
|
||
/* The new pc is the trap vector entry.
|
||
We assume there's a branch there to some handler.
|
||
Use cr5 as EVB (EIT Vector Base) register. */
|
||
USI new_pc = m32rbf_h_cr_get (current_cpu, 5) + 0x40 + num * 4;
|
||
return new_pc;
|
||
}
|
||
|
||
func = m32rbf_h_gr_get (current_cpu, 7);
|
||
arg1 = m32rbf_h_gr_get (current_cpu, 0);
|
||
arg2 = m32rbf_h_gr_get (current_cpu, 1);
|
||
arg3 = m32rbf_h_gr_get (current_cpu, 2);
|
||
arg4 = m32rbf_h_gr_get (current_cpu, 3);
|
||
arg5 = m32rbf_h_gr_get (current_cpu, 4);
|
||
arg6 = m32rbf_h_gr_get (current_cpu, 5);
|
||
arg7 = m32rbf_h_gr_get (current_cpu, 6);
|
||
|
||
CB_SYSCALL_INIT (&s);
|
||
s.func = func;
|
||
s.arg1 = arg1;
|
||
s.arg2 = arg2;
|
||
s.arg3 = arg3;
|
||
s.arg4 = arg4;
|
||
s.arg5 = arg5;
|
||
s.arg6 = arg6;
|
||
s.arg7 = arg7;
|
||
|
||
s.p1 = (PTR) sd;
|
||
s.p2 = (PTR) current_cpu;
|
||
s.read_mem = sim_syscall_read_mem;
|
||
s.write_mem = sim_syscall_write_mem;
|
||
|
||
result = 0;
|
||
result2 = 0;
|
||
errcode = 0;
|
||
|
||
switch (func)
|
||
{
|
||
case TARGET_LINUX_SYS_exit:
|
||
sim_engine_halt (sd, current_cpu, NULL, pc, sim_exited, arg1);
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_read:
|
||
result = read(arg1, t2h_addr(cb, &s, arg2), arg3);
|
||
errcode = errno;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_write:
|
||
result = write(arg1, t2h_addr(cb, &s, arg2), arg3);
|
||
errcode = errno;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_open:
|
||
result = open((char *) t2h_addr(cb, &s, arg1), arg2, arg3);
|
||
errcode = errno;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_close:
|
||
result = close(arg1);
|
||
errcode = errno;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_creat:
|
||
result = creat((char *) t2h_addr(cb, &s, arg1), arg2);
|
||
errcode = errno;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_link:
|
||
result = link((char *) t2h_addr(cb, &s, arg1),
|
||
(char *) t2h_addr(cb, &s, arg2));
|
||
errcode = errno;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_unlink:
|
||
result = unlink((char *) t2h_addr(cb, &s, arg1));
|
||
errcode = errno;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_chdir:
|
||
result = chdir((char *) t2h_addr(cb, &s, arg1));
|
||
errcode = errno;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_time:
|
||
{
|
||
time_t t;
|
||
|
||
if (arg1 == 0)
|
||
{
|
||
result = (int) time(NULL);
|
||
errcode = errno;
|
||
}
|
||
else
|
||
{
|
||
result = (int) time(&t);
|
||
errcode = errno;
|
||
|
||
if (result != 0)
|
||
break;
|
||
|
||
translate_endian((void *) &t, sizeof(t));
|
||
if ((s.write_mem) (cb, &s, arg1, (char *) &t, sizeof(t)) != sizeof(t))
|
||
{
|
||
result = -1;
|
||
errcode = EINVAL;
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_mknod:
|
||
result = mknod((char *) t2h_addr(cb, &s, arg1),
|
||
(mode_t) arg2, (dev_t) arg3);
|
||
errcode = errno;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_chmod:
|
||
result = chmod((char *) t2h_addr(cb, &s, arg1), (mode_t) arg2);
|
||
errcode = errno;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_lchown32:
|
||
case TARGET_LINUX_SYS_lchown:
|
||
result = lchown((char *) t2h_addr(cb, &s, arg1),
|
||
(uid_t) arg2, (gid_t) arg3);
|
||
errcode = errno;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_lseek:
|
||
result = (int) lseek(arg1, (off_t) arg2, arg3);
|
||
errcode = errno;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_getpid:
|
||
result = getpid();
|
||
errcode = errno;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_getuid32:
|
||
case TARGET_LINUX_SYS_getuid:
|
||
result = getuid();
|
||
errcode = errno;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_utime:
|
||
{
|
||
struct utimbuf buf;
|
||
|
||
if (arg2 == 0)
|
||
{
|
||
result = utime((char *) t2h_addr(cb, &s, arg1), NULL);
|
||
errcode = errno;
|
||
}
|
||
else
|
||
{
|
||
buf = *((struct utimbuf *) t2h_addr(cb, &s, arg2));
|
||
translate_endian((void *) &buf, sizeof(buf));
|
||
result = utime((char *) t2h_addr(cb, &s, arg1), &buf);
|
||
errcode = errno;
|
||
}
|
||
}
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_access:
|
||
result = access((char *) t2h_addr(cb, &s, arg1), arg2);
|
||
errcode = errno;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_ftime:
|
||
{
|
||
struct timeb t;
|
||
|
||
result = ftime(&t);
|
||
errcode = errno;
|
||
|
||
if (result != 0)
|
||
break;
|
||
|
||
t.time = conv_endian(t.time);
|
||
t.millitm = conv_endian16(t.millitm);
|
||
t.timezone = conv_endian16(t.timezone);
|
||
t.dstflag = conv_endian16(t.dstflag);
|
||
if ((s.write_mem) (cb, &s, arg1, (char *) &t, sizeof(t))
|
||
!= sizeof(t))
|
||
{
|
||
result = -1;
|
||
errcode = EINVAL;
|
||
}
|
||
}
|
||
|
||
case TARGET_LINUX_SYS_sync:
|
||
sync();
|
||
result = 0;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_rename:
|
||
result = rename((char *) t2h_addr(cb, &s, arg1),
|
||
(char *) t2h_addr(cb, &s, arg2));
|
||
errcode = errno;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_mkdir:
|
||
result = mkdir((char *) t2h_addr(cb, &s, arg1), arg2);
|
||
errcode = errno;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_rmdir:
|
||
result = rmdir((char *) t2h_addr(cb, &s, arg1));
|
||
errcode = errno;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_dup:
|
||
result = dup(arg1);
|
||
errcode = errno;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_brk:
|
||
result = brk((void *) arg1);
|
||
errcode = errno;
|
||
//result = arg1;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_getgid32:
|
||
case TARGET_LINUX_SYS_getgid:
|
||
result = getgid();
|
||
errcode = errno;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_geteuid32:
|
||
case TARGET_LINUX_SYS_geteuid:
|
||
result = geteuid();
|
||
errcode = errno;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_getegid32:
|
||
case TARGET_LINUX_SYS_getegid:
|
||
result = getegid();
|
||
errcode = errno;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_ioctl:
|
||
result = ioctl(arg1, arg2, arg3);
|
||
errcode = errno;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_fcntl:
|
||
result = fcntl(arg1, arg2, arg3);
|
||
errcode = errno;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_dup2:
|
||
result = dup2(arg1, arg2);
|
||
errcode = errno;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_getppid:
|
||
result = getppid();
|
||
errcode = errno;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_getpgrp:
|
||
result = getpgrp();
|
||
errcode = errno;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_getrlimit:
|
||
{
|
||
struct rlimit rlim;
|
||
|
||
result = getrlimit(arg1, &rlim);
|
||
errcode = errno;
|
||
|
||
if (result != 0)
|
||
break;
|
||
|
||
translate_endian((void *) &rlim, sizeof(rlim));
|
||
if ((s.write_mem) (cb, &s, arg2, (char *) &rlim, sizeof(rlim))
|
||
!= sizeof(rlim))
|
||
{
|
||
result = -1;
|
||
errcode = EINVAL;
|
||
}
|
||
}
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_getrusage:
|
||
{
|
||
struct rusage usage;
|
||
|
||
result = getrusage(arg1, &usage);
|
||
errcode = errno;
|
||
|
||
if (result != 0)
|
||
break;
|
||
|
||
translate_endian((void *) &usage, sizeof(usage));
|
||
if ((s.write_mem) (cb, &s, arg2, (char *) &usage, sizeof(usage))
|
||
!= sizeof(usage))
|
||
{
|
||
result = -1;
|
||
errcode = EINVAL;
|
||
}
|
||
}
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_gettimeofday:
|
||
{
|
||
struct timeval tv;
|
||
struct timezone tz;
|
||
|
||
result = gettimeofday(&tv, &tz);
|
||
errcode = errno;
|
||
|
||
if (result != 0)
|
||
break;
|
||
|
||
translate_endian((void *) &tv, sizeof(tv));
|
||
if ((s.write_mem) (cb, &s, arg1, (char *) &tv, sizeof(tv))
|
||
!= sizeof(tv))
|
||
{
|
||
result = -1;
|
||
errcode = EINVAL;
|
||
}
|
||
|
||
translate_endian((void *) &tz, sizeof(tz));
|
||
if ((s.write_mem) (cb, &s, arg2, (char *) &tz, sizeof(tz))
|
||
!= sizeof(tz))
|
||
{
|
||
result = -1;
|
||
errcode = EINVAL;
|
||
}
|
||
}
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_getgroups32:
|
||
case TARGET_LINUX_SYS_getgroups:
|
||
{
|
||
gid_t *list;
|
||
|
||
if (arg1 > 0)
|
||
list = (gid_t *) malloc(arg1 * sizeof(gid_t));
|
||
|
||
result = getgroups(arg1, list);
|
||
errcode = errno;
|
||
|
||
if (result != 0)
|
||
break;
|
||
|
||
translate_endian((void *) list, arg1 * sizeof(gid_t));
|
||
if (arg1 > 0)
|
||
if ((s.write_mem) (cb, &s, arg2, (char *) list, arg1 * sizeof(gid_t))
|
||
!= arg1 * sizeof(gid_t))
|
||
{
|
||
result = -1;
|
||
errcode = EINVAL;
|
||
}
|
||
}
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_select:
|
||
{
|
||
int n;
|
||
fd_set readfds;
|
||
fd_set *treadfdsp;
|
||
fd_set *hreadfdsp;
|
||
fd_set writefds;
|
||
fd_set *twritefdsp;
|
||
fd_set *hwritefdsp;
|
||
fd_set exceptfds;
|
||
fd_set *texceptfdsp;
|
||
fd_set *hexceptfdsp;
|
||
struct timeval *ttimeoutp;
|
||
struct timeval timeout;
|
||
|
||
n = arg1;
|
||
|
||
treadfdsp = (fd_set *) arg2;
|
||
if (treadfdsp != NULL)
|
||
{
|
||
readfds = *((fd_set *) t2h_addr(cb, &s, (unsigned int) treadfdsp));
|
||
translate_endian((void *) &readfds, sizeof(readfds));
|
||
hreadfdsp = &readfds;
|
||
}
|
||
else
|
||
hreadfdsp = NULL;
|
||
|
||
twritefdsp = (fd_set *) arg3;
|
||
if (twritefdsp != NULL)
|
||
{
|
||
writefds = *((fd_set *) t2h_addr(cb, &s, (unsigned int) twritefdsp));
|
||
translate_endian((void *) &writefds, sizeof(writefds));
|
||
hwritefdsp = &writefds;
|
||
}
|
||
else
|
||
hwritefdsp = NULL;
|
||
|
||
texceptfdsp = (fd_set *) arg4;
|
||
if (texceptfdsp != NULL)
|
||
{
|
||
exceptfds = *((fd_set *) t2h_addr(cb, &s, (unsigned int) texceptfdsp));
|
||
translate_endian((void *) &exceptfds, sizeof(exceptfds));
|
||
hexceptfdsp = &exceptfds;
|
||
}
|
||
else
|
||
hexceptfdsp = NULL;
|
||
|
||
ttimeoutp = (struct timeval *) arg5;
|
||
timeout = *((struct timeval *) t2h_addr(cb, &s, (unsigned int) ttimeoutp));
|
||
translate_endian((void *) &timeout, sizeof(timeout));
|
||
|
||
result = select(n, hreadfdsp, hwritefdsp, hexceptfdsp, &timeout);
|
||
errcode = errno;
|
||
|
||
if (result != 0)
|
||
break;
|
||
|
||
if (treadfdsp != NULL)
|
||
{
|
||
translate_endian((void *) &readfds, sizeof(readfds));
|
||
if ((s.write_mem) (cb, &s, (unsigned long) treadfdsp,
|
||
(char *) &readfds, sizeof(readfds)) != sizeof(readfds))
|
||
{
|
||
result = -1;
|
||
errcode = EINVAL;
|
||
}
|
||
}
|
||
|
||
if (twritefdsp != NULL)
|
||
{
|
||
translate_endian((void *) &writefds, sizeof(writefds));
|
||
if ((s.write_mem) (cb, &s, (unsigned long) twritefdsp,
|
||
(char *) &writefds, sizeof(writefds)) != sizeof(writefds))
|
||
{
|
||
result = -1;
|
||
errcode = EINVAL;
|
||
}
|
||
}
|
||
|
||
if (texceptfdsp != NULL)
|
||
{
|
||
translate_endian((void *) &exceptfds, sizeof(exceptfds));
|
||
if ((s.write_mem) (cb, &s, (unsigned long) texceptfdsp,
|
||
(char *) &exceptfds, sizeof(exceptfds)) != sizeof(exceptfds))
|
||
{
|
||
result = -1;
|
||
errcode = EINVAL;
|
||
}
|
||
}
|
||
|
||
translate_endian((void *) &timeout, sizeof(timeout));
|
||
if ((s.write_mem) (cb, &s, (unsigned long) ttimeoutp,
|
||
(char *) &timeout, sizeof(timeout)) != sizeof(timeout))
|
||
{
|
||
result = -1;
|
||
errcode = EINVAL;
|
||
}
|
||
}
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_symlink:
|
||
result = symlink((char *) t2h_addr(cb, &s, arg1),
|
||
(char *) t2h_addr(cb, &s, arg2));
|
||
errcode = errno;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_readlink:
|
||
result = readlink((char *) t2h_addr(cb, &s, arg1),
|
||
(char *) t2h_addr(cb, &s, arg2),
|
||
arg3);
|
||
errcode = errno;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_readdir:
|
||
result = (int) readdir((DIR *) t2h_addr(cb, &s, arg1));
|
||
errcode = errno;
|
||
break;
|
||
|
||
#if 0
|
||
case TARGET_LINUX_SYS_mmap:
|
||
{
|
||
result = (int) mmap((void *) t2h_addr(cb, &s, arg1),
|
||
arg2, arg3, arg4, arg5, arg6);
|
||
errcode = errno;
|
||
|
||
if (errno == 0)
|
||
{
|
||
sim_core_attach (sd, NULL,
|
||
0, access_read_write_exec, 0,
|
||
result, arg2, 0, NULL, NULL);
|
||
}
|
||
}
|
||
break;
|
||
#endif
|
||
case TARGET_LINUX_SYS_mmap2:
|
||
{
|
||
void *addr;
|
||
size_t len;
|
||
int prot, flags, fildes;
|
||
off_t off;
|
||
|
||
addr = (void *) t2h_addr(cb, &s, arg1);
|
||
len = arg2;
|
||
prot = arg3;
|
||
flags = arg4;
|
||
fildes = arg5;
|
||
off = arg6 << 12;
|
||
|
||
result = (int) mmap(addr, len, prot, flags, fildes, off);
|
||
errcode = errno;
|
||
if (result != -1)
|
||
{
|
||
char c;
|
||
if (sim_core_read_buffer (sd, NULL, read_map, &c, result, 1) == 0)
|
||
sim_core_attach (sd, NULL,
|
||
0, access_read_write_exec, 0,
|
||
result, len, 0, NULL, NULL);
|
||
}
|
||
}
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_mmap:
|
||
{
|
||
void *addr;
|
||
size_t len;
|
||
int prot, flags, fildes;
|
||
off_t off;
|
||
|
||
addr = *((void **) t2h_addr(cb, &s, arg1));
|
||
len = *((size_t *) t2h_addr(cb, &s, arg1 + 4));
|
||
prot = *((int *) t2h_addr(cb, &s, arg1 + 8));
|
||
flags = *((int *) t2h_addr(cb, &s, arg1 + 12));
|
||
fildes = *((int *) t2h_addr(cb, &s, arg1 + 16));
|
||
off = *((off_t *) t2h_addr(cb, &s, arg1 + 20));
|
||
|
||
addr = (void *) conv_endian((unsigned int) addr);
|
||
len = conv_endian(len);
|
||
prot = conv_endian(prot);
|
||
flags = conv_endian(flags);
|
||
fildes = conv_endian(fildes);
|
||
off = conv_endian(off);
|
||
|
||
//addr = (void *) t2h_addr(cb, &s, (unsigned int) addr);
|
||
result = (int) mmap(addr, len, prot, flags, fildes, off);
|
||
errcode = errno;
|
||
|
||
//if (errno == 0)
|
||
if (result != -1)
|
||
{
|
||
char c;
|
||
if (sim_core_read_buffer (sd, NULL, read_map, &c, result, 1) == 0)
|
||
sim_core_attach (sd, NULL,
|
||
0, access_read_write_exec, 0,
|
||
result, len, 0, NULL, NULL);
|
||
}
|
||
}
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_munmap:
|
||
{
|
||
result = munmap((void *)arg1, arg2);
|
||
errcode = errno;
|
||
if (result != -1)
|
||
{
|
||
sim_core_detach (sd, NULL, 0, arg2, result);
|
||
}
|
||
}
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_truncate:
|
||
result = truncate((char *) t2h_addr(cb, &s, arg1), arg2);
|
||
errcode = errno;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_ftruncate:
|
||
result = ftruncate(arg1, arg2);
|
||
errcode = errno;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_fchmod:
|
||
result = fchmod(arg1, arg2);
|
||
errcode = errno;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_fchown32:
|
||
case TARGET_LINUX_SYS_fchown:
|
||
result = fchown(arg1, arg2, arg3);
|
||
errcode = errno;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_statfs:
|
||
{
|
||
struct statfs statbuf;
|
||
|
||
result = statfs((char *) t2h_addr(cb, &s, arg1), &statbuf);
|
||
errcode = errno;
|
||
|
||
if (result != 0)
|
||
break;
|
||
|
||
translate_endian((void *) &statbuf, sizeof(statbuf));
|
||
if ((s.write_mem) (cb, &s, arg2, (char *) &statbuf, sizeof(statbuf))
|
||
!= sizeof(statbuf))
|
||
{
|
||
result = -1;
|
||
errcode = EINVAL;
|
||
}
|
||
}
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_fstatfs:
|
||
{
|
||
struct statfs statbuf;
|
||
|
||
result = fstatfs(arg1, &statbuf);
|
||
errcode = errno;
|
||
|
||
if (result != 0)
|
||
break;
|
||
|
||
translate_endian((void *) &statbuf, sizeof(statbuf));
|
||
if ((s.write_mem) (cb, &s, arg2, (char *) &statbuf, sizeof(statbuf))
|
||
!= sizeof(statbuf))
|
||
{
|
||
result = -1;
|
||
errcode = EINVAL;
|
||
}
|
||
}
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_syslog:
|
||
result = syslog(arg1, (char *) t2h_addr(cb, &s, arg2));
|
||
errcode = errno;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_setitimer:
|
||
{
|
||
struct itimerval value, ovalue;
|
||
|
||
value = *((struct itimerval *) t2h_addr(cb, &s, arg2));
|
||
translate_endian((void *) &value, sizeof(value));
|
||
|
||
if (arg2 == 0)
|
||
{
|
||
result = setitimer(arg1, &value, NULL);
|
||
errcode = errno;
|
||
}
|
||
else
|
||
{
|
||
result = setitimer(arg1, &value, &ovalue);
|
||
errcode = errno;
|
||
|
||
if (result != 0)
|
||
break;
|
||
|
||
translate_endian((void *) &ovalue, sizeof(ovalue));
|
||
if ((s.write_mem) (cb, &s, arg3, (char *) &ovalue, sizeof(ovalue))
|
||
!= sizeof(ovalue))
|
||
{
|
||
result = -1;
|
||
errcode = EINVAL;
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_getitimer:
|
||
{
|
||
struct itimerval value;
|
||
|
||
result = getitimer(arg1, &value);
|
||
errcode = errno;
|
||
|
||
if (result != 0)
|
||
break;
|
||
|
||
translate_endian((void *) &value, sizeof(value));
|
||
if ((s.write_mem) (cb, &s, arg2, (char *) &value, sizeof(value))
|
||
!= sizeof(value))
|
||
{
|
||
result = -1;
|
||
errcode = EINVAL;
|
||
}
|
||
}
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_stat:
|
||
{
|
||
char *buf;
|
||
int buflen;
|
||
struct stat statbuf;
|
||
|
||
result = stat((char *) t2h_addr(cb, &s, arg1), &statbuf);
|
||
errcode = errno;
|
||
if (result < 0)
|
||
break;
|
||
|
||
buflen = cb_host_to_target_stat (cb, NULL, NULL);
|
||
buf = xmalloc (buflen);
|
||
if (cb_host_to_target_stat (cb, &statbuf, buf) != buflen)
|
||
{
|
||
/* The translation failed. This is due to an internal
|
||
host program error, not the target's fault. */
|
||
free (buf);
|
||
result = -1;
|
||
errcode = ENOSYS;
|
||
break;
|
||
}
|
||
if ((s.write_mem) (cb, &s, arg2, buf, buflen) != buflen)
|
||
{
|
||
free (buf);
|
||
result = -1;
|
||
errcode = EINVAL;
|
||
break;
|
||
}
|
||
free (buf);
|
||
}
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_lstat:
|
||
{
|
||
char *buf;
|
||
int buflen;
|
||
struct stat statbuf;
|
||
|
||
result = lstat((char *) t2h_addr(cb, &s, arg1), &statbuf);
|
||
errcode = errno;
|
||
if (result < 0)
|
||
break;
|
||
|
||
buflen = cb_host_to_target_stat (cb, NULL, NULL);
|
||
buf = xmalloc (buflen);
|
||
if (cb_host_to_target_stat (cb, &statbuf, buf) != buflen)
|
||
{
|
||
/* The translation failed. This is due to an internal
|
||
host program error, not the target's fault. */
|
||
free (buf);
|
||
result = -1;
|
||
errcode = ENOSYS;
|
||
break;
|
||
}
|
||
if ((s.write_mem) (cb, &s, arg2, buf, buflen) != buflen)
|
||
{
|
||
free (buf);
|
||
result = -1;
|
||
errcode = EINVAL;
|
||
break;
|
||
}
|
||
free (buf);
|
||
}
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_fstat:
|
||
{
|
||
char *buf;
|
||
int buflen;
|
||
struct stat statbuf;
|
||
|
||
result = fstat(arg1, &statbuf);
|
||
errcode = errno;
|
||
if (result < 0)
|
||
break;
|
||
|
||
buflen = cb_host_to_target_stat (cb, NULL, NULL);
|
||
buf = xmalloc (buflen);
|
||
if (cb_host_to_target_stat (cb, &statbuf, buf) != buflen)
|
||
{
|
||
/* The translation failed. This is due to an internal
|
||
host program error, not the target's fault. */
|
||
free (buf);
|
||
result = -1;
|
||
errcode = ENOSYS;
|
||
break;
|
||
}
|
||
if ((s.write_mem) (cb, &s, arg2, buf, buflen) != buflen)
|
||
{
|
||
free (buf);
|
||
result = -1;
|
||
errcode = EINVAL;
|
||
break;
|
||
}
|
||
free (buf);
|
||
}
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_sysinfo:
|
||
{
|
||
struct sysinfo info;
|
||
|
||
result = sysinfo(&info);
|
||
errcode = errno;
|
||
|
||
if (result != 0)
|
||
break;
|
||
|
||
info.uptime = conv_endian(info.uptime);
|
||
info.loads[0] = conv_endian(info.loads[0]);
|
||
info.loads[1] = conv_endian(info.loads[1]);
|
||
info.loads[2] = conv_endian(info.loads[2]);
|
||
info.totalram = conv_endian(info.totalram);
|
||
info.freeram = conv_endian(info.freeram);
|
||
info.sharedram = conv_endian(info.sharedram);
|
||
info.bufferram = conv_endian(info.bufferram);
|
||
info.totalswap = conv_endian(info.totalswap);
|
||
info.freeswap = conv_endian(info.freeswap);
|
||
info.procs = conv_endian16(info.procs);
|
||
#if LINUX_VERSION_CODE >= 0x20400
|
||
info.totalhigh = conv_endian(info.totalhigh);
|
||
info.freehigh = conv_endian(info.freehigh);
|
||
info.mem_unit = conv_endian(info.mem_unit);
|
||
#endif
|
||
if ((s.write_mem) (cb, &s, arg1, (char *) &info, sizeof(info))
|
||
!= sizeof(info))
|
||
{
|
||
result = -1;
|
||
errcode = EINVAL;
|
||
}
|
||
}
|
||
break;
|
||
|
||
#if 0
|
||
case TARGET_LINUX_SYS_ipc:
|
||
{
|
||
result = ipc(arg1, arg2, arg3, arg4,
|
||
(void *) t2h_addr(cb, &s, arg5), arg6);
|
||
errcode = errno;
|
||
}
|
||
break;
|
||
#endif
|
||
|
||
case TARGET_LINUX_SYS_fsync:
|
||
result = fsync(arg1);
|
||
errcode = errno;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_uname:
|
||
/* utsname contains only arrays of char, so it is not necessary
|
||
to translate endian. */
|
||
result = uname((struct utsname *) t2h_addr(cb, &s, arg1));
|
||
errcode = errno;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_adjtimex:
|
||
{
|
||
struct timex buf;
|
||
|
||
result = adjtimex(&buf);
|
||
errcode = errno;
|
||
|
||
if (result != 0)
|
||
break;
|
||
|
||
translate_endian((void *) &buf, sizeof(buf));
|
||
if ((s.write_mem) (cb, &s, arg1, (char *) &buf, sizeof(buf))
|
||
!= sizeof(buf))
|
||
{
|
||
result = -1;
|
||
errcode = EINVAL;
|
||
}
|
||
}
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_mprotect:
|
||
result = mprotect((void *) arg1, arg2, arg3);
|
||
errcode = errno;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_fchdir:
|
||
result = fchdir(arg1);
|
||
errcode = errno;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_setfsuid32:
|
||
case TARGET_LINUX_SYS_setfsuid:
|
||
result = setfsuid(arg1);
|
||
errcode = errno;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_setfsgid32:
|
||
case TARGET_LINUX_SYS_setfsgid:
|
||
result = setfsgid(arg1);
|
||
errcode = errno;
|
||
break;
|
||
|
||
#if 0
|
||
case TARGET_LINUX_SYS__llseek:
|
||
{
|
||
loff_t buf;
|
||
|
||
result = _llseek(arg1, arg2, arg3, &buf, arg5);
|
||
errcode = errno;
|
||
|
||
if (result != 0)
|
||
break;
|
||
|
||
translate_endian((void *) &buf, sizeof(buf));
|
||
if ((s.write_mem) (cb, &s, t2h_addr(cb, &s, arg4),
|
||
(char *) &buf, sizeof(buf)) != sizeof(buf))
|
||
{
|
||
result = -1;
|
||
errcode = EINVAL;
|
||
}
|
||
}
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_getdents:
|
||
{
|
||
struct dirent dir;
|
||
|
||
result = getdents(arg1, &dir, arg3);
|
||
errcode = errno;
|
||
|
||
if (result != 0)
|
||
break;
|
||
|
||
dir.d_ino = conv_endian(dir.d_ino);
|
||
dir.d_off = conv_endian(dir.d_off);
|
||
dir.d_reclen = conv_endian16(dir.d_reclen);
|
||
if ((s.write_mem) (cb, &s, arg2, (char *) &dir, sizeof(dir))
|
||
!= sizeof(dir))
|
||
{
|
||
result = -1;
|
||
errcode = EINVAL;
|
||
}
|
||
}
|
||
break;
|
||
#endif
|
||
|
||
case TARGET_LINUX_SYS_flock:
|
||
result = flock(arg1, arg2);
|
||
errcode = errno;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_msync:
|
||
result = msync((void *) arg1, arg2, arg3);
|
||
errcode = errno;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_readv:
|
||
{
|
||
struct iovec vector;
|
||
|
||
vector = *((struct iovec *) t2h_addr(cb, &s, arg2));
|
||
translate_endian((void *) &vector, sizeof(vector));
|
||
|
||
result = readv(arg1, &vector, arg3);
|
||
errcode = errno;
|
||
}
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_writev:
|
||
{
|
||
struct iovec vector;
|
||
|
||
vector = *((struct iovec *) t2h_addr(cb, &s, arg2));
|
||
translate_endian((void *) &vector, sizeof(vector));
|
||
|
||
result = writev(arg1, &vector, arg3);
|
||
errcode = errno;
|
||
}
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_fdatasync:
|
||
result = fdatasync(arg1);
|
||
errcode = errno;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_mlock:
|
||
result = mlock((void *) t2h_addr(cb, &s, arg1), arg2);
|
||
errcode = errno;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_munlock:
|
||
result = munlock((void *) t2h_addr(cb, &s, arg1), arg2);
|
||
errcode = errno;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_nanosleep:
|
||
{
|
||
struct timespec req, rem;
|
||
|
||
req = *((struct timespec *) t2h_addr(cb, &s, arg2));
|
||
translate_endian((void *) &req, sizeof(req));
|
||
|
||
result = nanosleep(&req, &rem);
|
||
errcode = errno;
|
||
|
||
if (result != 0)
|
||
break;
|
||
|
||
translate_endian((void *) &rem, sizeof(rem));
|
||
if ((s.write_mem) (cb, &s, arg2, (char *) &rem, sizeof(rem))
|
||
!= sizeof(rem))
|
||
{
|
||
result = -1;
|
||
errcode = EINVAL;
|
||
}
|
||
}
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_mremap: /* FIXME */
|
||
result = (int) mremap((void *) t2h_addr(cb, &s, arg1), arg2, arg3, arg4);
|
||
errcode = errno;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_getresuid32:
|
||
case TARGET_LINUX_SYS_getresuid:
|
||
{
|
||
uid_t ruid, euid, suid;
|
||
|
||
result = getresuid(&ruid, &euid, &suid);
|
||
errcode = errno;
|
||
|
||
if (result != 0)
|
||
break;
|
||
|
||
*((uid_t *) t2h_addr(cb, &s, arg1)) = conv_endian(ruid);
|
||
*((uid_t *) t2h_addr(cb, &s, arg2)) = conv_endian(euid);
|
||
*((uid_t *) t2h_addr(cb, &s, arg3)) = conv_endian(suid);
|
||
}
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_poll:
|
||
{
|
||
struct pollfd ufds;
|
||
|
||
ufds = *((struct pollfd *) t2h_addr(cb, &s, arg1));
|
||
ufds.fd = conv_endian(ufds.fd);
|
||
ufds.events = conv_endian16(ufds.events);
|
||
ufds.revents = conv_endian16(ufds.revents);
|
||
|
||
result = poll(&ufds, arg2, arg3);
|
||
errcode = errno;
|
||
}
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_getresgid32:
|
||
case TARGET_LINUX_SYS_getresgid:
|
||
{
|
||
uid_t rgid, egid, sgid;
|
||
|
||
result = getresgid(&rgid, &egid, &sgid);
|
||
errcode = errno;
|
||
|
||
if (result != 0)
|
||
break;
|
||
|
||
*((uid_t *) t2h_addr(cb, &s, arg1)) = conv_endian(rgid);
|
||
*((uid_t *) t2h_addr(cb, &s, arg2)) = conv_endian(egid);
|
||
*((uid_t *) t2h_addr(cb, &s, arg3)) = conv_endian(sgid);
|
||
}
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_pread:
|
||
result = pread(arg1, (void *) t2h_addr(cb, &s, arg2), arg3, arg4);
|
||
errcode = errno;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_pwrite:
|
||
result = pwrite(arg1, (void *) t2h_addr(cb, &s, arg2), arg3, arg4);
|
||
errcode = errno;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_chown32:
|
||
case TARGET_LINUX_SYS_chown:
|
||
result = chown((char *) t2h_addr(cb, &s, arg1), arg2, arg3);
|
||
errcode = errno;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_getcwd:
|
||
result = (int) getcwd((char *) t2h_addr(cb, &s, arg1), arg2);
|
||
errcode = errno;
|
||
break;
|
||
|
||
case TARGET_LINUX_SYS_sendfile:
|
||
{
|
||
off_t offset;
|
||
|
||
offset = *((off_t *) t2h_addr(cb, &s, arg3));
|
||
offset = conv_endian(offset);
|
||
|
||
result = sendfile(arg1, arg2, &offset, arg3);
|
||
errcode = errno;
|
||
|
||
if (result != 0)
|
||
break;
|
||
|
||
*((off_t *) t2h_addr(cb, &s, arg3)) = conv_endian(offset);
|
||
}
|
||
break;
|
||
|
||
default:
|
||
result = -1;
|
||
errcode = ENOSYS;
|
||
break;
|
||
}
|
||
|
||
if (result == -1)
|
||
m32rbf_h_gr_set (current_cpu, 0, -errcode);
|
||
else
|
||
m32rbf_h_gr_set (current_cpu, 0, result);
|
||
break;
|
||
}
|
||
|
||
case TRAP_BREAKPOINT:
|
||
sim_engine_halt (sd, current_cpu, NULL, pc,
|
||
sim_stopped, SIM_SIGTRAP);
|
||
break;
|
||
|
||
case TRAP_FLUSH_CACHE:
|
||
/* Do nothing. */
|
||
break;
|
||
|
||
default :
|
||
{
|
||
/* Use cr5 as EVB (EIT Vector Base) register. */
|
||
USI new_pc = m32rbf_h_cr_get (current_cpu, 5) + 0x40 + num * 4;
|
||
return new_pc;
|
||
}
|
||
}
|
||
|
||
/* Fake an "rte" insn. */
|
||
/* FIXME: Should duplicate all of rte processing. */
|
||
return (pc & -4) + 4;
|
||
}
|