/* m32r exception, interrupt, and trap (EIT) support Copyright (C) 1998-2023 Free Software Foundation, Inc. Contributed by Cygnus Solutions & 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 . */ /* 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 #include #include #include #include #include #include /* TODO: The Linux syscall emulation needs work to support non-Linux hosts. Use an OS hack for now so the CPU emulation is available everywhere. NB: The emulation is also missing argument conversion (endian & bitsize) even on Linux hosts. */ #ifdef __linux__ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #endif #include "m32r-sim.h" #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 pc) { 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 pc; } /* 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)); switch (MACH_NUM (CPU_MACH (current_cpu))) { case 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); break; case 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); break; case MACH_M32R2: 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); break; default: abort (); } 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); } /* TODO: These functions are a big hack and assume that the host runtime has type sizes and struct layouts that match the target. So the Linux emulation probaly only really works in 32-bit runtimes. */ static void translate_endian_h2t (void *addr, size_t size) { unsigned int *p = (unsigned int *) addr; int i; for (i = 0; i <= size - 4; i += 4,p++) *p = H2T_4 (*p); if (i <= size - 2) *((unsigned short *) p) = H2T_2 (*((unsigned short *) p)); } static void translate_endian_t2h (void *addr, size_t size) { unsigned int *p = (unsigned int *) addr; int i; for (i = 0; i <= size - 4; i += 4,p++) *p = T2H_4 (*p); if (i <= size - 2) *((unsigned short *) p) = T2H_2 (*((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); if (STATE_ENVIRONMENT (sd) == OPERATING_ENVIRONMENT) goto case_default; switch (num) { case TRAP_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; } #ifdef __linux__ 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) != USER_ENVIRONMENT) goto case_default; 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 = sd; s.p2 = 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; t = H2T_4 (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_t2h (&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 = H2T_4 (t.time); t.millitm = H2T_2 (t.millitm); t.timezone = H2T_2 (t.timezone); t.dstflag = H2T_2 (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_h2t (&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_h2t (&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_h2t (&tv, sizeof(tv)); if ((s.write_mem) (cb, &s, arg1, (char *) &tv, sizeof(tv)) != sizeof(tv)) { result = -1; errcode = EINVAL; } translate_endian_h2t (&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 = NULL; if (arg1 > 0) list = (gid_t *) malloc (arg1 * sizeof(gid_t)); result = getgroups (arg1, list); errcode = errno; if (result != 0) break; translate_endian_h2t (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_t2h (&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_t2h (&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_t2h (&exceptfds, sizeof(exceptfds)); hexceptfdsp = &exceptfds; } else hexceptfdsp = NULL; ttimeoutp = (struct timeval *) arg5; timeout = *((struct timeval *) t2h_addr (cb, &s, (unsigned int) ttimeoutp)); translate_endian_t2h (&timeout, sizeof(timeout)); result = select (n, hreadfdsp, hwritefdsp, hexceptfdsp, &timeout); errcode = errno; if (result != 0) break; if (treadfdsp != NULL) { translate_endian_h2t (&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_h2t (&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_h2t (&exceptfds, sizeof(exceptfds)); if ((s.write_mem) (cb, &s, (unsigned long) texceptfdsp, (char *) &exceptfds, sizeof(exceptfds)) != sizeof(exceptfds)) { result = -1; errcode = EINVAL; } } translate_endian_h2t (&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 *) T2H_4 ((unsigned int) addr); len = T2H_4 (len); prot = T2H_4 (prot); flags = T2H_4 (flags); fildes = T2H_4 (fildes); off = T2H_4 (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_h2t (&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_h2t (&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_t2h (&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_h2t (&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_h2t (&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 = H2T_4 (info.uptime); info.loads[0] = H2T_4 (info.loads[0]); info.loads[1] = H2T_4 (info.loads[1]); info.loads[2] = H2T_4 (info.loads[2]); info.totalram = H2T_4 (info.totalram); info.freeram = H2T_4 (info.freeram); info.sharedram = H2T_4 (info.sharedram); info.bufferram = H2T_4 (info.bufferram); info.totalswap = H2T_4 (info.totalswap); info.freeswap = H2T_4 (info.freeswap); info.procs = H2T_2 (info.procs); #if LINUX_VERSION_CODE >= 0x20400 info.totalhigh = H2T_4 (info.totalhigh); info.freehigh = H2T_4 (info.freehigh); info.mem_unit = H2T_4 (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_h2t (&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_h2t (&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 = H2T_4 (dir.d_ino); dir.d_off = H2T_4 (dir.d_off); dir.d_reclen = H2T_2 (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_t2h (&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_t2h (&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_t2h (&req, sizeof(req)); result = nanosleep (&req, &rem); errcode = errno; if (result != 0) break; translate_endian_h2t (&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)) = H2T_4 (ruid); *((uid_t *) t2h_addr (cb, &s, arg2)) = H2T_4 (euid); *((uid_t *) t2h_addr (cb, &s, arg3)) = H2T_4 (suid); } break; case TARGET_LINUX_SYS_poll: { struct pollfd ufds; ufds = *((struct pollfd *) t2h_addr (cb, &s, arg1)); ufds.fd = T2H_4 (ufds.fd); ufds.events = T2H_2 (ufds.events); ufds.revents = T2H_2 (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)) = H2T_4 (rgid); *((uid_t *) t2h_addr (cb, &s, arg2)) = H2T_4 (egid); *((uid_t *) t2h_addr (cb, &s, arg3)) = H2T_4 (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 = T2H_4 (offset); result = sendfile (arg1, arg2, &offset, arg3); errcode = errno; if (result != 0) break; *((off_t *) t2h_addr (cb, &s, arg3)) = H2T_4 (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; } #endif case TRAP_BREAKPOINT: sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGTRAP); break; case TRAP_FLUSH_CACHE: /* Do nothing. */ break; case_default: default: { /* 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 = EIT_TRAP_BASE_ADDR + num * 4; */ 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; }