static int os_get_errno (host_callback *p) { return cb_host_to_target_errno (p, p->last_errno); }
void bfin_syscall (SIM_CPU *cpu) { SIM_DESC sd = CPU_STATE (cpu); const char * const *argv = (void *)STATE_PROG_ARGV (sd); host_callback *cb = STATE_CALLBACK (sd); bu32 args[6]; CB_SYSCALL sc; char *p; char _tbuf[1024 * 3], *tbuf = _tbuf, tstr[1024]; int fmt_ret_hex = 0; CB_SYSCALL_INIT (&sc); if (STATE_ENVIRONMENT (sd) == USER_ENVIRONMENT) { /* Linux syscall. */ sc.func = PREG (0); sc.arg1 = args[0] = DREG (0); sc.arg2 = args[1] = DREG (1); sc.arg3 = args[2] = DREG (2); sc.arg4 = args[3] = DREG (3); /*sc.arg5 =*/ args[4] = DREG (4); /*sc.arg6 =*/ args[5] = DREG (5); } else { /* libgloss syscall. */ sc.func = PREG (0); sc.arg1 = args[0] = GET_LONG (DREG (0)); sc.arg2 = args[1] = GET_LONG (DREG (0) + 4); sc.arg3 = args[2] = GET_LONG (DREG (0) + 8); sc.arg4 = args[3] = GET_LONG (DREG (0) + 12); /*sc.arg5 =*/ args[4] = GET_LONG (DREG (0) + 16); /*sc.arg6 =*/ args[5] = GET_LONG (DREG (0) + 20); } sc.p1 = (PTR) sd; sc.p2 = (PTR) cpu; sc.read_mem = sim_syscall_read_mem; sc.write_mem = sim_syscall_write_mem; /* Common cb_syscall() handles most functions. */ switch (cb_target_to_host_syscall (cb, sc.func)) { case CB_SYS_exit: tbuf += sprintf (tbuf, "exit(%i)", args[0]); sim_engine_halt (sd, cpu, NULL, PCREG, sim_exited, sc.arg1); #ifdef CB_SYS_argc case CB_SYS_argc: tbuf += sprintf (tbuf, "argc()"); sc.result = count_argc (argv); break; case CB_SYS_argnlen: { tbuf += sprintf (tbuf, "argnlen(%u)", args[0]); if (sc.arg1 < count_argc (argv)) sc.result = strlen (argv[sc.arg1]); else sc.result = -1; } break; case CB_SYS_argn: { tbuf += sprintf (tbuf, "argn(%u)", args[0]); if (sc.arg1 < count_argc (argv)) { const char *argn = argv[sc.arg1]; int len = strlen (argn); int written = sc.write_mem (cb, &sc, sc.arg2, argn, len + 1); if (written == len + 1) sc.result = sc.arg2; else sc.result = -1; } else sc.result = -1; } break; #endif case CB_SYS_gettimeofday: { struct timeval _tv, *tv = &_tv; struct timezone _tz, *tz = &_tz; tbuf += sprintf (tbuf, "gettimeofday(%#x, %#x)", args[0], args[1]); if (sc.arg1 == 0) tv = NULL; if (sc.arg2 == 0) tz = NULL; sc.result = gettimeofday (tv, tz); if (sc.result == 0) { bu32 t; if (tv) { t = tv->tv_sec; sc.write_mem (cb, &sc, sc.arg1, (void *)&t, 4); t = tv->tv_usec; sc.write_mem (cb, &sc, sc.arg1 + 4, (void *)&t, 4); } if (sc.arg2) { t = tz->tz_minuteswest; sc.write_mem (cb, &sc, sc.arg1, (void *)&t, 4); t = tz->tz_dsttime; sc.write_mem (cb, &sc, sc.arg1 + 4, (void *)&t, 4); } } else goto sys_finish; } break; case CB_SYS_ioctl: /* XXX: hack just enough to get basic stdio w/uClibc ... */ tbuf += sprintf (tbuf, "ioctl(%i, %#x, %u)", args[0], args[1], args[2]); if (sc.arg2 == 0x5401) { sc.result = !isatty (sc.arg1); sc.errcode = 0; } else { sc.result = -1; sc.errcode = TARGET_EINVAL; } break; case CB_SYS_mmap2: { static bu32 heap = BFIN_DEFAULT_MEM_SIZE / 2; fmt_ret_hex = 1; tbuf += sprintf (tbuf, "mmap2(%#x, %u, %#x, %#x, %i, %u)", args[0], args[1], args[2], args[3], args[4], args[5]); sc.errcode = 0; if (sc.arg4 & 0x20 /*MAP_ANONYMOUS*/) /* XXX: We don't handle zeroing, but default is all zeros. */; else if (args[4] >= MAX_CALLBACK_FDS) sc.errcode = TARGET_ENOSYS; else { #ifdef HAVE_PREAD char *data = xmalloc (sc.arg2); /* XXX: Should add a cb->pread. */ if (pread (cb->fdmap[args[4]], data, sc.arg2, args[5] << 12) == sc.arg2) sc.write_mem (cb, &sc, heap, data, sc.arg2); else sc.errcode = TARGET_EINVAL; free (data); #else sc.errcode = TARGET_ENOSYS; #endif } if (sc.errcode) { sc.result = -1; break; } sc.result = heap; heap += sc.arg2; /* Keep it page aligned. */ heap = ALIGN (heap, 4096); break; } case CB_SYS_munmap: /* XXX: meh, just lie for mmap(). */ tbuf += sprintf (tbuf, "munmap(%#x, %u)", args[0], args[1]); sc.result = 0; break; case CB_SYS_dup2: tbuf += sprintf (tbuf, "dup2(%i, %i)", args[0], args[1]); if (sc.arg1 >= MAX_CALLBACK_FDS || sc.arg2 >= MAX_CALLBACK_FDS) { sc.result = -1; sc.errcode = TARGET_EINVAL; } else { sc.result = dup2 (cb->fdmap[sc.arg1], cb->fdmap[sc.arg2]); goto sys_finish; } break; case CB_SYS__llseek: tbuf += sprintf (tbuf, "llseek(%i, %u, %u, %#x, %u)", args[0], args[1], args[2], args[3], args[4]); sc.func = TARGET_LINUX_SYS_lseek; if (sc.arg2) { sc.result = -1; sc.errcode = TARGET_EINVAL; } else { sc.arg2 = sc.arg3; sc.arg3 = args[4]; cb_syscall (cb, &sc); if (sc.result != -1) { bu32 z = 0; sc.write_mem (cb, &sc, args[3], (void *)&sc.result, 4); sc.write_mem (cb, &sc, args[3] + 4, (void *)&z, 4); } } break; /* XXX: Should add a cb->pread. */ case CB_SYS_pread: tbuf += sprintf (tbuf, "pread(%i, %#x, %u, %i)", args[0], args[1], args[2], args[3]); if (sc.arg1 >= MAX_CALLBACK_FDS) { sc.result = -1; sc.errcode = TARGET_EINVAL; } else { long old_pos, read_result, read_errcode; /* Get current filepos. */ sc.func = TARGET_LINUX_SYS_lseek; sc.arg2 = 0; sc.arg3 = SEEK_CUR; cb_syscall (cb, &sc); if (sc.result == -1) break; old_pos = sc.result; /* Move to the new pos. */ sc.func = TARGET_LINUX_SYS_lseek; sc.arg2 = args[3]; sc.arg3 = SEEK_SET; cb_syscall (cb, &sc); if (sc.result == -1) break; /* Read the data. */ sc.func = TARGET_LINUX_SYS_read; sc.arg2 = args[1]; sc.arg3 = args[2]; cb_syscall (cb, &sc); read_result = sc.result; read_errcode = sc.errcode; /* Move back to the old pos. */ sc.func = TARGET_LINUX_SYS_lseek; sc.arg2 = old_pos; sc.arg3 = SEEK_SET; cb_syscall (cb, &sc); sc.result = read_result; sc.errcode = read_errcode; } break; case CB_SYS_getcwd: tbuf += sprintf (tbuf, "getcwd(%#x, %u)", args[0], args[1]); p = alloca (sc.arg2); if (getcwd (p, sc.arg2) == NULL) { sc.result = -1; sc.errcode = TARGET_EINVAL; } else { sc.write_mem (cb, &sc, sc.arg1, p, sc.arg2); sc.result = sc.arg1; } break; case CB_SYS_stat64: if (cb_get_string (cb, &sc, tstr, sizeof (tstr), args[0])) strcpy (tstr, "???"); tbuf += sprintf (tbuf, "stat64(%#x:\"%s\", %u)", args[0], tstr, args[1]); cb->stat_map = stat_map_64; sc.func = TARGET_LINUX_SYS_stat; cb_syscall (cb, &sc); cb->stat_map = stat_map_32; break; case CB_SYS_lstat64: if (cb_get_string (cb, &sc, tstr, sizeof (tstr), args[0])) strcpy (tstr, "???"); tbuf += sprintf (tbuf, "lstat64(%#x:\"%s\", %u)", args[0], tstr, args[1]); cb->stat_map = stat_map_64; sc.func = TARGET_LINUX_SYS_lstat; cb_syscall (cb, &sc); cb->stat_map = stat_map_32; break; case CB_SYS_fstat64: tbuf += sprintf (tbuf, "fstat64(%#x, %u)", args[0], args[1]); cb->stat_map = stat_map_64; sc.func = TARGET_LINUX_SYS_fstat; cb_syscall (cb, &sc); cb->stat_map = stat_map_32; break; case CB_SYS_ftruncate64: tbuf += sprintf (tbuf, "ftruncate64(%u, %u)", args[0], args[1]); sc.func = TARGET_LINUX_SYS_ftruncate; cb_syscall (cb, &sc); break; case CB_SYS_getuid: case CB_SYS_getuid32: tbuf += sprintf (tbuf, "getuid()"); sc.result = getuid (); goto sys_finish; case CB_SYS_getgid: case CB_SYS_getgid32: tbuf += sprintf (tbuf, "getgid()"); sc.result = getgid (); goto sys_finish; case CB_SYS_setuid: sc.arg1 &= 0xffff; case CB_SYS_setuid32: tbuf += sprintf (tbuf, "setuid(%u)", args[0]); sc.result = setuid (sc.arg1); goto sys_finish; case CB_SYS_setgid: sc.arg1 &= 0xffff; case CB_SYS_setgid32: tbuf += sprintf (tbuf, "setgid(%u)", args[0]); sc.result = setgid (sc.arg1); goto sys_finish; case CB_SYS_getpid: tbuf += sprintf (tbuf, "getpid()"); sc.result = getpid (); goto sys_finish; case CB_SYS_kill: tbuf += sprintf (tbuf, "kill(%u, %i)", args[0], args[1]); /* Only let the app kill itself. */ if (sc.arg1 != getpid ()) { sc.result = -1; sc.errcode = TARGET_EPERM; } else { #ifdef HAVE_KILL sc.result = kill (sc.arg1, sc.arg2); goto sys_finish; #else sc.result = -1; sc.errcode = TARGET_ENOSYS; #endif } break; case CB_SYS_open: if (cb_get_string (cb, &sc, tstr, sizeof (tstr), args[0])) strcpy (tstr, "???"); tbuf += sprintf (tbuf, "open(%#x:\"%s\", %#x, %o)", args[0], tstr, args[1], args[2]); goto case_default; case CB_SYS_close: tbuf += sprintf (tbuf, "close(%i)", args[0]); goto case_default; case CB_SYS_read: tbuf += sprintf (tbuf, "read(%i, %#x, %u)", args[0], args[1], args[2]); goto case_default; case CB_SYS_write: if (cb_get_string (cb, &sc, tstr, sizeof (tstr), args[1])) strcpy (tstr, "???"); tbuf += sprintf (tbuf, "write(%i, %#x:\"%s\", %u)", args[0], args[1], tstr, args[2]); goto case_default; case CB_SYS_lseek: tbuf += sprintf (tbuf, "lseek(%i, %i, %i)", args[0], args[1], args[2]); goto case_default; case CB_SYS_unlink: if (cb_get_string (cb, &sc, tstr, sizeof (tstr), args[0])) strcpy (tstr, "???"); tbuf += sprintf (tbuf, "unlink(%#x:\"%s\")", args[0], tstr); goto case_default; case CB_SYS_truncate: if (cb_get_string (cb, &sc, tstr, sizeof (tstr), args[0])) strcpy (tstr, "???"); tbuf += sprintf (tbuf, "truncate(%#x:\"%s\", %i)", args[0], tstr, args[1]); goto case_default; case CB_SYS_ftruncate: tbuf += sprintf (tbuf, "ftruncate(%i, %i)", args[0], args[1]); goto case_default; case CB_SYS_rename: if (cb_get_string (cb, &sc, tstr, sizeof (tstr), args[0])) strcpy (tstr, "???"); tbuf += sprintf (tbuf, "rename(%#x:\"%s\", ", args[0], tstr); if (cb_get_string (cb, &sc, tstr, sizeof (tstr), args[1])) strcpy (tstr, "???"); tbuf += sprintf (tbuf, "%#x:\"%s\")", args[1], tstr); goto case_default; case CB_SYS_stat: if (cb_get_string (cb, &sc, tstr, sizeof (tstr), args[0])) strcpy (tstr, "???"); tbuf += sprintf (tbuf, "stat(%#x:\"%s\", %#x)", args[0], tstr, args[1]); goto case_default; case CB_SYS_fstat: tbuf += sprintf (tbuf, "fstat(%i, %#x)", args[0], args[1]); goto case_default; case CB_SYS_lstat: if (cb_get_string (cb, &sc, tstr, sizeof (tstr), args[0])) strcpy (tstr, "???"); tbuf += sprintf (tbuf, "lstat(%#x:\"%s\", %#x)", args[0], tstr, args[1]); goto case_default; case CB_SYS_pipe: tbuf += sprintf (tbuf, "pipe(%#x, %#x)", args[0], args[1]); goto case_default; default: tbuf += sprintf (tbuf, "???_%i(%#x, %#x, %#x, %#x, %#x, %#x)", sc.func, args[0], args[1], args[2], args[3], args[4], args[5]); case_default: cb_syscall (cb, &sc); break; sys_finish: if (sc.result == -1) { cb->last_errno = errno; sc.errcode = cb->get_errno (cb); } } TRACE_EVENTS (cpu, "syscall_%i(%#x, %#x, %#x, %#x, %#x, %#x) = %li (error = %i)", sc.func, args[0], args[1], args[2], args[3], args[4], args[5], sc.result, sc.errcode); tbuf += sprintf (tbuf, " = "); if (STATE_ENVIRONMENT (sd) == USER_ENVIRONMENT) { if (sc.result == -1) { tbuf += sprintf (tbuf, "-1 (error = %i)", sc.errcode); if (sc.errcode == cb_host_to_target_errno (cb, ENOSYS)) { sim_io_eprintf (sd, "bfin-sim: %#x: unimplemented syscall %i\n", PCREG, sc.func); } SET_DREG (0, -sc.errcode); } else { if (fmt_ret_hex) tbuf += sprintf (tbuf, "%#lx", sc.result); else tbuf += sprintf (tbuf, "%lu", sc.result); SET_DREG (0, sc.result); } } else { tbuf += sprintf (tbuf, "%lu (error = %i)", sc.result, sc.errcode); SET_DREG (0, sc.result); SET_DREG (1, sc.result2); SET_DREG (2, sc.errcode); } TRACE_SYSCALL (cpu, "%s", _tbuf); }