/* m32r exception, interrupt, and trap (EIT) support Copyright (C) 1998-2019 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 . */ #include "sim-main.h" #include "sim-syscall.h" #include "syscall.h" #include "targ-vals.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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.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 __NR_exit: sim_engine_halt (sd, current_cpu, NULL, pc, sim_exited, arg1); break; case __NR_read: result = read(arg1, t2h_addr(cb, &s, arg2), arg3); errcode = errno; break; case __NR_write: result = write(arg1, t2h_addr(cb, &s, arg2), arg3); errcode = errno; break; case __NR_open: result = open((char *) t2h_addr(cb, &s, arg1), arg2, arg3); errcode = errno; break; case __NR_close: result = close(arg1); errcode = errno; break; case __NR_creat: result = creat((char *) t2h_addr(cb, &s, arg1), arg2); errcode = errno; break; case __NR_link: result = link((char *) t2h_addr(cb, &s, arg1), (char *) t2h_addr(cb, &s, arg2)); errcode = errno; break; case __NR_unlink: result = unlink((char *) t2h_addr(cb, &s, arg1)); errcode = errno; break; case __NR_chdir: result = chdir((char *) t2h_addr(cb, &s, arg1)); errcode = errno; break; case __NR_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 __NR_mknod: result = mknod((char *) t2h_addr(cb, &s, arg1), (mode_t) arg2, (dev_t) arg3); errcode = errno; break; case __NR_chmod: result = chmod((char *) t2h_addr(cb, &s, arg1), (mode_t) arg2); errcode = errno; break; case __NR_lchown32: case __NR_lchown: result = lchown((char *) t2h_addr(cb, &s, arg1), (uid_t) arg2, (gid_t) arg3); errcode = errno; break; case __NR_lseek: result = (int) lseek(arg1, (off_t) arg2, arg3); errcode = errno; break; case __NR_getpid: result = getpid(); errcode = errno; break; case __NR_getuid32: case __NR_getuid: result = getuid(); errcode = errno; break; case __NR_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 __NR_access: result = access((char *) t2h_addr(cb, &s, arg1), arg2); errcode = errno; break; case __NR_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 __NR_sync: sync(); result = 0; break; case __NR_rename: result = rename((char *) t2h_addr(cb, &s, arg1), (char *) t2h_addr(cb, &s, arg2)); errcode = errno; break; case __NR_mkdir: result = mkdir((char *) t2h_addr(cb, &s, arg1), arg2); errcode = errno; break; case __NR_rmdir: result = rmdir((char *) t2h_addr(cb, &s, arg1)); errcode = errno; break; case __NR_dup: result = dup(arg1); errcode = errno; break; case __NR_brk: result = brk((void *) arg1); errcode = errno; //result = arg1; break; case __NR_getgid32: case __NR_getgid: result = getgid(); errcode = errno; break; case __NR_geteuid32: case __NR_geteuid: result = geteuid(); errcode = errno; break; case __NR_getegid32: case __NR_getegid: result = getegid(); errcode = errno; break; case __NR_ioctl: result = ioctl(arg1, arg2, arg3); errcode = errno; break; case __NR_fcntl: result = fcntl(arg1, arg2, arg3); errcode = errno; break; case __NR_dup2: result = dup2(arg1, arg2); errcode = errno; break; case __NR_getppid: result = getppid(); errcode = errno; break; case __NR_getpgrp: result = getpgrp(); errcode = errno; break; case __NR_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 __NR_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 __NR_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 __NR_getgroups32: case __NR_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 __NR_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 __NR_symlink: result = symlink((char *) t2h_addr(cb, &s, arg1), (char *) t2h_addr(cb, &s, arg2)); errcode = errno; break; case __NR_readlink: result = readlink((char *) t2h_addr(cb, &s, arg1), (char *) t2h_addr(cb, &s, arg2), arg3); errcode = errno; break; case __NR_readdir: result = (int) readdir((DIR *) t2h_addr(cb, &s, arg1)); errcode = errno; break; #if 0 case __NR_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 __NR_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 __NR_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 __NR_munmap: { result = munmap((void *)arg1, arg2); errcode = errno; if (result != -1) { sim_core_detach (sd, NULL, 0, arg2, result); } } break; case __NR_truncate: result = truncate((char *) t2h_addr(cb, &s, arg1), arg2); errcode = errno; break; case __NR_ftruncate: result = ftruncate(arg1, arg2); errcode = errno; break; case __NR_fchmod: result = fchmod(arg1, arg2); errcode = errno; break; case __NR_fchown32: case __NR_fchown: result = fchown(arg1, arg2, arg3); errcode = errno; break; case __NR_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 __NR_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 __NR_syslog: result = syslog(arg1, (char *) t2h_addr(cb, &s, arg2)); errcode = errno; break; case __NR_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 __NR_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 __NR_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 __NR_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 __NR_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 __NR_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 __NR_ipc: { result = ipc(arg1, arg2, arg3, arg4, (void *) t2h_addr(cb, &s, arg5), arg6); errcode = errno; } break; #endif case __NR_fsync: result = fsync(arg1); errcode = errno; break; case __NR_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 __NR_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 __NR_mprotect: result = mprotect((void *) arg1, arg2, arg3); errcode = errno; break; case __NR_fchdir: result = fchdir(arg1); errcode = errno; break; case __NR_setfsuid32: case __NR_setfsuid: result = setfsuid(arg1); errcode = errno; break; case __NR_setfsgid32: case __NR_setfsgid: result = setfsgid(arg1); errcode = errno; break; #if 0 case __NR__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 __NR_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 __NR_flock: result = flock(arg1, arg2); errcode = errno; break; case __NR_msync: result = msync((void *) arg1, arg2, arg3); errcode = errno; break; case __NR_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 __NR_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 __NR_fdatasync: result = fdatasync(arg1); errcode = errno; break; case __NR_mlock: result = mlock((void *) t2h_addr(cb, &s, arg1), arg2); errcode = errno; break; case __NR_munlock: result = munlock((void *) t2h_addr(cb, &s, arg1), arg2); errcode = errno; break; case __NR_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 __NR_mremap: /* FIXME */ result = (int) mremap((void *) t2h_addr(cb, &s, arg1), arg2, arg3, arg4); errcode = errno; break; case __NR_getresuid32: case __NR_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 __NR_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 __NR_getresgid32: case __NR_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 __NR_pread: result = pread(arg1, (void *) t2h_addr(cb, &s, arg2), arg3, arg4); errcode = errno; break; case __NR_pwrite: result = pwrite(arg1, (void *) t2h_addr(cb, &s, arg2), arg3, arg4); errcode = errno; break; case __NR_chown32: case __NR_chown: result = chown((char *) t2h_addr(cb, &s, arg1), arg2, arg3); errcode = errno; break; case __NR_getcwd: result = (int) getcwd((char *) t2h_addr(cb, &s, arg1), arg2); errcode = errno; break; case __NR_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; }