/* This file is part of the program psim. Copyright (C) 1996-1998, Andrew Cagney 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 . */ #ifndef _EMUL_UNIX_C_ #define _EMUL_UNIX_C_ /* Note: this module is called via a table. There is no benefit in making it inline */ #include "defs.h" #include #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_TYPES_H #include #else #undef HAVE_STAT #undef HAVE_LSTAT #undef HAVE_FSTAT #endif #include #include #include #ifdef HAVE_FCNTL_H #include #endif #ifdef HAVE_SYS_PARAM_H #include #endif #include #ifndef HAVE_TERMIOS_STRUCTURE #undef HAVE_SYS_TERMIOS_H #undef HAVE_TCGETATTR #else #ifndef HAVE_SYS_TERMIOS_H #undef HAVE_TERMIOS_STRUCTURE #endif #endif #ifdef HAVE_TERMIOS_STRUCTURE #include /* If we have TERMIOS, use that for the termio structure, since some systems don't like including both sys/termios.h and sys/termio.h at the same time. */ #undef HAVE_TERMIO_STRUCTURE #undef TCGETA #undef termio #define termio termios #endif #ifndef HAVE_TERMIO_STRUCTURE #undef HAVE_SYS_TERMIO_H #else #ifndef HAVE_SYS_TERMIO_H #undef HAVE_TERMIO_STRUCTURE #endif #endif #ifdef HAVE_TERMIO_STRUCTURE #include #endif #ifdef HAVE_GETRUSAGE #ifndef HAVE_SYS_RESOURCE_H #undef HAVE_GETRUSAGE #endif #endif #ifdef HAVE_GETRUSAGE #include int getrusage(); #endif #if HAVE_DIRENT_H # include # define NAMLEN(dirent) strlen((dirent)->d_name) #else # define dirent direct # define NAMLEN(dirent) (dirent)->d_namlen # if HAVE_SYS_NDIR_H # include # endif # if HAVE_SYS_DIR_H # include # endif # if HAVE_NDIR_H # include # endif #endif #ifdef HAVE_UNISTD_H #undef MAXPATHLEN /* sys/param.h might define this also */ #include #endif #include #include #include "emul_generic.h" #include "emul_unix.h" #ifndef STATIC_INLINE_EMUL_UNIX #define STATIC_INLINE_EMUL_UNIX STATIC_INLINE #endif #ifndef PATH_MAX #define PATH_MAX 1024 #endif #ifndef EINVAL #define EINVAL -1 #endif /* UNIX's idea of what is needed to implement emulations */ struct _os_emul_data { device *vm; emul_syscall *syscalls; }; /* Emulation of simple UNIX system calls that are common on all systems. */ /* Structures that are common agmonst the UNIX varients */ struct unix_timeval { int32_t tv_sec; /* seconds */ int32_t tv_usec; /* microseconds */ }; struct unix_timezone { int32_t tz_minuteswest; /* minutes west of Greenwich */ int32_t tz_dsttime; /* type of dst correction */ }; #define UNIX_RUSAGE_SELF 0 #define UNIX_RUSAGE_CHILDREN (-1) #define UNIX_RUSAGE_BOTH (-2) /* sys_wait4() uses this */ struct unix_rusage { struct unix_timeval ru_utime; /* user time used */ struct unix_timeval ru_stime; /* system time used */ int32_t ru_maxrss; /* maximum resident set size */ int32_t ru_ixrss; /* integral shared memory size */ int32_t ru_idrss; /* integral unshared data size */ int32_t ru_isrss; /* integral unshared stack size */ int32_t ru_minflt; /* any page faults not requiring I/O */ int32_t ru_majflt; /* any page faults requiring I/O */ int32_t ru_nswap; /* swaps */ int32_t ru_inblock; /* block input operations */ int32_t ru_oublock; /* block output operations */ int32_t ru_msgsnd; /* messages sent */ int32_t ru_msgrcv; /* messages received */ int32_t ru_nsignals; /* signals received */ int32_t ru_nvcsw; /* voluntary context switches */ int32_t ru_nivcsw; /* involuntary " */ }; /* File descriptors 0, 1, and 2 should not be closed. fd_closed[] tracks whether these descriptors have been closed in do_close() below. */ static int fd_closed[3]; /* Check for some occurrences of bad file descriptors. We only check whether fd 0, 1, or 2 are "closed". By "closed" we mean that these descriptors aren't actually closed, but are considered to be closed by this layer. Other checks are performed by the underlying OS call. */ static int fdbad (int fd) { if (fd >=0 && fd <= 2 && fd_closed[fd]) { errno = EBADF; return -1; } return 0; } static void do_unix_exit(os_emul_data *emul, unsigned call, const int arg0, cpu *processor, unsigned_word cia) { int status = (int)cpu_registers(processor)->gpr[arg0]; if (WITH_TRACE && ppc_trace[trace_os_emul]) printf_filtered ("%d)\n", status); cpu_halt(processor, cia, was_exited, status); } static void do_unix_read(os_emul_data *emul, unsigned call, const int arg0, cpu *processor, unsigned_word cia) { void *scratch_buffer; int d = (int)cpu_registers(processor)->gpr[arg0]; unsigned_word buf = cpu_registers(processor)->gpr[arg0+1]; int nbytes = cpu_registers(processor)->gpr[arg0+2]; int status; if (WITH_TRACE && ppc_trace[trace_os_emul]) printf_filtered ("%d, 0x%lx, %d", d, (long)buf, nbytes); /* get a tempoary bufer */ scratch_buffer = zalloc(nbytes); /* check if buffer exists by reading it */ emul_read_buffer(scratch_buffer, buf, nbytes, processor, cia); status = fdbad (d); /* read */ if (status == 0) status = read (d, scratch_buffer, nbytes); emul_write_status(processor, status, errno); if (status > 0) emul_write_buffer(scratch_buffer, buf, status, processor, cia); free(scratch_buffer); } static void do_unix_write(os_emul_data *emul, unsigned call, const int arg0, cpu *processor, unsigned_word cia) { void *scratch_buffer = NULL; int d = (int)cpu_registers(processor)->gpr[arg0]; unsigned_word buf = cpu_registers(processor)->gpr[arg0+1]; int nbytes = cpu_registers(processor)->gpr[arg0+2]; int status; if (WITH_TRACE && ppc_trace[trace_os_emul]) printf_filtered ("%d, 0x%lx, %d", d, (long)buf, nbytes); /* get a tempoary bufer */ scratch_buffer = zalloc(nbytes); /* FIXME - nbytes == 0 */ /* copy in */ emul_read_buffer(scratch_buffer, buf, nbytes, processor, cia); status = fdbad (d); /* write */ if (status == 0) status = write(d, scratch_buffer, nbytes); emul_write_status(processor, status, errno); free(scratch_buffer); flush_stdoutput(); } static void do_unix_open(os_emul_data *emul, unsigned call, const int arg0, cpu *processor, unsigned_word cia) { unsigned_word path_addr = cpu_registers(processor)->gpr[arg0]; char path_buf[PATH_MAX]; char *path = emul_read_string(path_buf, path_addr, PATH_MAX, processor, cia); int flags = (int)cpu_registers(processor)->gpr[arg0+1]; int mode = (int)cpu_registers(processor)->gpr[arg0+2]; int status; if (WITH_TRACE && ppc_trace[trace_os_emul]) printf_filtered ("0x%lx [%s], 0x%x, 0x%x", (long)path_addr, path, flags, mode); status = open(path, flags, mode); emul_write_status(processor, status, errno); } static void do_unix_close(os_emul_data *emul, unsigned call, const int arg0, cpu *processor, unsigned_word cia) { int d = (int)cpu_registers(processor)->gpr[arg0]; int status; if (WITH_TRACE && ppc_trace[trace_os_emul]) printf_filtered ("%d", d); status = fdbad (d); if (status == 0) { /* Do not close stdin, stdout, or stderr. GDB may still need access to these descriptors. */ if (d == 0 || d == 1 || d == 2) { fd_closed[d] = 1; status = 0; } else status = close(d); } emul_write_status(processor, status, errno); } static void do_unix_break(os_emul_data *emul, unsigned call, const int arg0, cpu *processor, unsigned_word cia) { /* just pass this onto the `vm' device */ unsigned_word new_break = cpu_registers(processor)->gpr[arg0]; int status; if (WITH_TRACE && ppc_trace[trace_os_emul]) printf_filtered ("0x%lx", (long)cpu_registers(processor)->gpr[arg0]); status = device_ioctl(emul->vm, processor, cia, device_ioctl_break, new_break); /*ioctl-data*/ emul_write_status(processor, 0, status); } #ifndef HAVE_ACCESS #define do_unix_access 0 #else static void do_unix_access(os_emul_data *emul, unsigned call, const int arg0, cpu *processor, unsigned_word cia) { unsigned_word path_addr = cpu_registers(processor)->gpr[arg0]; char path_buf[PATH_MAX]; char *path = emul_read_string(path_buf, path_addr, PATH_MAX, processor, cia); int mode = (int)cpu_registers(processor)->gpr[arg0+1]; int status; if (WITH_TRACE && ppc_trace[trace_os_emul]) printf_filtered ("0x%lx [%s], 0x%x [0%o]", (long)path_addr, path, mode, mode); status = access(path, mode); emul_write_status(processor, status, errno); } #endif #ifndef HAVE_GETPID #define do_unix_getpid 0 #else static void do_unix_getpid(os_emul_data *emul, unsigned call, const int arg0, cpu *processor, unsigned_word cia) { pid_t status = getpid(); emul_write_status(processor, (int)status, errno); } #endif #ifndef HAVE_GETPPID #define do_unix_getppid 0 #else static void do_unix_getppid(os_emul_data *emul, unsigned call, const int arg0, cpu *processor, unsigned_word cia) { pid_t status = getppid(); emul_write_status(processor, (int)status, errno); } #endif #if !defined(HAVE_GETPID) || !defined(HAVE_GETPPID) #define do_unix_getpid2 0 #else static void do_unix_getpid2(os_emul_data *emul, unsigned call, const int arg0, cpu *processor, unsigned_word cia) { int pid = (int)getpid(); int ppid = (int)getppid(); emul_write2_status(processor, pid, ppid, errno); } #endif #if !defined(HAVE_GETUID) || !defined(HAVE_GETEUID) #define do_unix_getuid2 0 #else static void do_unix_getuid2(os_emul_data *emul, unsigned call, const int arg0, cpu *processor, unsigned_word cia) { uid_t uid = getuid(); uid_t euid = geteuid(); emul_write2_status(processor, (int)uid, (int)euid, errno); } #endif #ifndef HAVE_GETUID #define do_unix_getuid 0 #else static void do_unix_getuid(os_emul_data *emul, unsigned call, const int arg0, cpu *processor, unsigned_word cia) { uid_t status = getuid(); emul_write_status(processor, (int)status, errno); } #endif #ifndef HAVE_GETEUID #define do_unix_geteuid 0 #else static void do_unix_geteuid(os_emul_data *emul, unsigned call, const int arg0, cpu *processor, unsigned_word cia) { uid_t status = geteuid(); emul_write_status(processor, (int)status, errno); } #endif #if 0 #ifndef HAVE_KILL #define do_unix_kill 0 #else static void do_unix_kill(os_emul_data *emul, unsigned call, const int arg0, cpu *processor, unsigned_word cia) { pid_t pid = cpu_registers(processor)->gpr[arg0]; int sig = cpu_registers(processor)->gpr[arg0+1]; if (WITH_TRACE && ppc_trace[trace_os_emul]) printf_filtered ("%d, %d", (int)pid, sig); printf_filtered("SYS_kill at 0x%lx - more to this than just being killed\n", (long)cia); cpu_halt(processor, cia, was_signalled, sig); } #endif #endif #ifndef HAVE_DUP #define do_unix_dup 0 #else static void do_unix_dup(os_emul_data *emul, unsigned call, const int arg0, cpu *processor, unsigned_word cia) { int oldd = cpu_registers(processor)->gpr[arg0]; int status = (fdbad (oldd) < 0) ? -1 : dup(oldd); int err = errno; if (WITH_TRACE && ppc_trace[trace_os_emul]) printf_filtered ("%d", oldd); emul_write_status(processor, status, err); } #endif #ifndef HAVE_DUP2 #define do_unix_dup2 0 #else static void do_unix_dup2(os_emul_data *emul, unsigned call, const int arg0, cpu *processor, unsigned_word cia) { int oldd = cpu_registers(processor)->gpr[arg0]; int newd = cpu_registers(processor)->gpr[arg0+1]; int status = (fdbad (oldd) < 0) ? -1 : dup2(oldd, newd); int err = errno; if (WITH_TRACE && ppc_trace[trace_os_emul]) printf_filtered ("%d, %d", oldd, newd); emul_write_status(processor, status, err); } #endif #ifndef HAVE_LSEEK #define do_unix_lseek 0 #else static void do_unix_lseek(os_emul_data *emul, unsigned call, const int arg0, cpu *processor, unsigned_word cia) { int fildes = (int)cpu_registers(processor)->gpr[arg0]; off_t offset = (off_t)cpu_registers(processor)->gpr[arg0+1]; int whence = (int)cpu_registers(processor)->gpr[arg0+2]; off_t status; if (WITH_TRACE && ppc_trace[trace_os_emul]) printf_filtered ("%d %ld %d", fildes, (long)offset, whence); status = fdbad (fildes); if (status == 0) status = lseek(fildes, offset, whence); emul_write_status(processor, (int)status, errno); } #endif #if !defined(HAVE_GETGID) || !defined(HAVE_GETEGID) #define do_unix_getgid2 0 #else static void do_unix_getgid2(os_emul_data *emul, unsigned call, const int arg0, cpu *processor, unsigned_word cia) { gid_t gid = getgid(); gid_t egid = getegid(); emul_write2_status(processor, (int)gid, (int)egid, errno); } #endif #ifndef HAVE_GETGID #define do_unix_getgid 0 #else static void do_unix_getgid(os_emul_data *emul, unsigned call, const int arg0, cpu *processor, unsigned_word cia) { gid_t status = getgid(); emul_write_status(processor, (int)status, errno); } #endif #ifndef HAVE_GETEGID #define do_unix_getegid 0 #else static void do_unix_getegid(os_emul_data *emul, unsigned call, const int arg0, cpu *processor, unsigned_word cia) { gid_t status = getegid(); emul_write_status(processor, (int)status, errno); } #endif #ifndef HAVE_UMASK #define do_unix_umask 0 #else static void do_unix_umask(os_emul_data *emul, unsigned call, const int arg0, cpu *processor, unsigned_word cia) { mode_t mask = (mode_t)cpu_registers(processor)->gpr[arg0]; int status = umask(mask); if (WITH_TRACE && ppc_trace[trace_os_emul]) printf_filtered ("0%o", (unsigned int)mask); emul_write_status(processor, status, errno); } #endif #ifndef HAVE_CHDIR #define do_unix_chdir 0 #else static void do_unix_chdir(os_emul_data *emul, unsigned call, const int arg0, cpu *processor, unsigned_word cia) { unsigned_word path_addr = cpu_registers(processor)->gpr[arg0]; char path_buf[PATH_MAX]; char *path = emul_read_string(path_buf, path_addr, PATH_MAX, processor, cia); int status; if (WITH_TRACE && ppc_trace[trace_os_emul]) printf_filtered ("0x%lx [%s]", (long)path_addr, path); status = chdir(path); emul_write_status(processor, status, errno); } #endif #ifndef HAVE_LINK #define do_unix_link 0 #else static void do_unix_link(os_emul_data *emul, unsigned call, const int arg0, cpu *processor, unsigned_word cia) { unsigned_word path1_addr = cpu_registers(processor)->gpr[arg0]; char path1_buf[PATH_MAX]; char *path1 = emul_read_string(path1_buf, path1_addr, PATH_MAX, processor, cia); unsigned_word path2_addr = cpu_registers(processor)->gpr[arg0+1]; char path2_buf[PATH_MAX]; char *path2 = emul_read_string(path2_buf, path2_addr, PATH_MAX, processor, cia); int status; if (WITH_TRACE && ppc_trace[trace_os_emul]) printf_filtered ("0x%lx [%s], 0x%lx [%s]", (long)path1_addr, path1, (long)path2_addr, path2); status = link(path1, path2); emul_write_status(processor, status, errno); } #endif #ifndef HAVE_SYMLINK #define do_unix_symlink 0 #else static void do_unix_symlink(os_emul_data *emul, unsigned call, const int arg0, cpu *processor, unsigned_word cia) { unsigned_word path1_addr = cpu_registers(processor)->gpr[arg0]; char path1_buf[PATH_MAX]; char *path1 = emul_read_string(path1_buf, path1_addr, PATH_MAX, processor, cia); unsigned_word path2_addr = cpu_registers(processor)->gpr[arg0+1]; char path2_buf[PATH_MAX]; char *path2 = emul_read_string(path2_buf, path2_addr, PATH_MAX, processor, cia); int status; if (WITH_TRACE && ppc_trace[trace_os_emul]) printf_filtered ("0x%lx [%s], 0x%lx [%s]", (long)path1_addr, path1, (long)path2_addr, path2); status = symlink(path1, path2); emul_write_status(processor, status, errno); } #endif #ifndef HAVE_UNLINK #define do_unix_unlink 0 #else static void do_unix_unlink(os_emul_data *emul, unsigned call, const int arg0, cpu *processor, unsigned_word cia) { unsigned_word path_addr = cpu_registers(processor)->gpr[arg0]; char path_buf[PATH_MAX]; char *path = emul_read_string(path_buf, path_addr, PATH_MAX, processor, cia); int status; if (WITH_TRACE && ppc_trace[trace_os_emul]) printf_filtered ("0x%lx [%s]", (long)path_addr, path); status = unlink(path); emul_write_status(processor, status, errno); } #endif #ifndef HAVE_MKDIR #define do_unix_mkdir 0 #else static void do_unix_mkdir(os_emul_data *emul, unsigned call, const int arg0, cpu *processor, unsigned_word cia) { unsigned_word path_addr = cpu_registers(processor)->gpr[arg0]; char path_buf[PATH_MAX]; char *path = emul_read_string(path_buf, path_addr, PATH_MAX, processor, cia); int mode = (int)cpu_registers(processor)->gpr[arg0+1]; int status; if (WITH_TRACE && ppc_trace[trace_os_emul]) printf_filtered ("0x%lx [%s], 0%3o", (long)path_addr, path, mode); status = mkdir(path, mode); emul_write_status(processor, status, errno); } #endif #ifndef HAVE_RMDIR #define do_unix_rmdir 0 #else static void do_unix_rmdir(os_emul_data *emul, unsigned call, const int arg0, cpu *processor, unsigned_word cia) { unsigned_word path_addr = cpu_registers(processor)->gpr[arg0]; char path_buf[PATH_MAX]; char *path = emul_read_string(path_buf, path_addr, PATH_MAX, processor, cia); int status; if (WITH_TRACE && ppc_trace[trace_os_emul]) printf_filtered ("0x%lx [%s]", (long)path_addr, path); status = rmdir(path); emul_write_status(processor, status, errno); } #endif #ifndef HAVE_TIME #define do_unix_time 0 #else static void do_unix_time(os_emul_data *emul, unsigned call, const int arg0, cpu *processor, unsigned_word cia) { unsigned_word tp = cpu_registers(processor)->gpr[arg0]; time_t now = time ((time_t *)0); unsigned_word status = H2T_4(now); if (WITH_TRACE && ppc_trace[trace_os_emul]) printf_filtered ("0x%lx", (long)tp); emul_write_status(processor, (int)status, errno); if (tp) emul_write_buffer(&status, tp, sizeof(status), processor, cia); } #endif #if !defined(HAVE_GETTIMEOFDAY) #define do_unix_gettimeofday 0 #else static void do_unix_gettimeofday(os_emul_data *emul, unsigned call, const int arg0, cpu *processor, unsigned_word cia) { unsigned_word tv = cpu_registers(processor)->gpr[arg0]; unsigned_word tz = cpu_registers(processor)->gpr[arg0+1]; struct unix_timeval target_timeval; struct timeval host_timeval; struct unix_timezone target_timezone; struct timezone host_timezone; int status; if (WITH_TRACE && ppc_trace[trace_os_emul]) printf_filtered ("0x%lx, 0x%lx", (long)tv, (long)tz); /* Just in case the system doesn't set the timezone structure */ host_timezone.tz_minuteswest = 0; host_timezone.tz_dsttime = 0; status = gettimeofday(&host_timeval, &host_timezone); if (status >= 0) { if (tv) { target_timeval.tv_sec = H2T_4(host_timeval.tv_sec); target_timeval.tv_usec = H2T_4(host_timeval.tv_usec); emul_write_buffer((void *) &target_timeval, tv, sizeof(target_timeval), processor, cia); } if (tz) { target_timezone.tz_minuteswest = H2T_4(host_timezone.tz_minuteswest); target_timezone.tz_dsttime = H2T_4(host_timezone.tz_dsttime); emul_write_buffer((void *) &target_timezone, tv, sizeof(target_timezone), processor, cia); } } emul_write_status(processor, (int)status, errno); } #endif #ifndef HAVE_GETRUSAGE #define do_unix_getrusage 0 #else static void do_unix_getrusage(os_emul_data *emul, unsigned call, const int arg0, cpu *processor, unsigned_word cia) { signed_word who = (signed_word)cpu_registers(processor)->gpr[arg0]; unsigned_word usage = cpu_registers(processor)->gpr[arg0+1]; struct rusage host_rusage, host_rusage2; struct unix_rusage target_rusage; int status; if (WITH_TRACE && ppc_trace[trace_os_emul]) printf_filtered ("%ld, 0x%lx", (long)who, (long)usage); switch (who) { default: status = -1; errno = EINVAL; break; case UNIX_RUSAGE_SELF: status = getrusage(RUSAGE_SELF, &host_rusage); break; case UNIX_RUSAGE_CHILDREN: status = getrusage(RUSAGE_CHILDREN, &host_rusage); break; case UNIX_RUSAGE_BOTH: status = getrusage(RUSAGE_SELF, &host_rusage); if (status >= 0) { status = getrusage(RUSAGE_CHILDREN, &host_rusage2); if (status >= 0) { host_rusage.ru_utime.tv_sec += host_rusage2.ru_utime.tv_sec; host_rusage.ru_utime.tv_usec += host_rusage2.ru_utime.tv_usec; host_rusage.ru_stime.tv_sec += host_rusage2.ru_stime.tv_sec; host_rusage.ru_stime.tv_usec += host_rusage2.ru_stime.tv_usec; host_rusage.ru_maxrss += host_rusage2.ru_maxrss; host_rusage.ru_ixrss += host_rusage2.ru_ixrss; host_rusage.ru_idrss += host_rusage2.ru_idrss; host_rusage.ru_isrss += host_rusage2.ru_isrss; host_rusage.ru_minflt += host_rusage2.ru_minflt; host_rusage.ru_majflt += host_rusage2.ru_majflt; host_rusage.ru_nswap += host_rusage2.ru_nswap; host_rusage.ru_inblock += host_rusage2.ru_inblock; host_rusage.ru_oublock += host_rusage2.ru_oublock; host_rusage.ru_msgsnd += host_rusage2.ru_msgsnd; host_rusage.ru_msgrcv += host_rusage2.ru_msgrcv; host_rusage.ru_nsignals += host_rusage2.ru_nsignals; host_rusage.ru_nvcsw += host_rusage2.ru_nvcsw; host_rusage.ru_nivcsw += host_rusage2.ru_nivcsw; } } } if (status >= 0) { target_rusage.ru_utime.tv_sec = H2T_4(host_rusage2.ru_utime.tv_sec); target_rusage.ru_utime.tv_usec = H2T_4(host_rusage2.ru_utime.tv_usec); target_rusage.ru_stime.tv_sec = H2T_4(host_rusage2.ru_stime.tv_sec); target_rusage.ru_stime.tv_usec = H2T_4(host_rusage2.ru_stime.tv_usec); target_rusage.ru_maxrss = H2T_4(host_rusage2.ru_maxrss); target_rusage.ru_ixrss = H2T_4(host_rusage2.ru_ixrss); target_rusage.ru_idrss = H2T_4(host_rusage2.ru_idrss); target_rusage.ru_isrss = H2T_4(host_rusage2.ru_isrss); target_rusage.ru_minflt = H2T_4(host_rusage2.ru_minflt); target_rusage.ru_majflt = H2T_4(host_rusage2.ru_majflt); target_rusage.ru_nswap = H2T_4(host_rusage2.ru_nswap); target_rusage.ru_inblock = H2T_4(host_rusage2.ru_inblock); target_rusage.ru_oublock = H2T_4(host_rusage2.ru_oublock); target_rusage.ru_msgsnd = H2T_4(host_rusage2.ru_msgsnd); target_rusage.ru_msgrcv = H2T_4(host_rusage2.ru_msgrcv); target_rusage.ru_nsignals = H2T_4(host_rusage2.ru_nsignals); target_rusage.ru_nvcsw = H2T_4(host_rusage2.ru_nvcsw); target_rusage.ru_nivcsw = H2T_4(host_rusage2.ru_nivcsw); emul_write_buffer((void *) &target_rusage, usage, sizeof(target_rusage), processor, cia); } emul_write_status(processor, status, errno); } #endif static void do_unix_nop(os_emul_data *emul, unsigned call, const int arg0, cpu *processor, unsigned_word cia) { if (WITH_TRACE && ppc_trace[trace_os_emul]) printf_filtered ("0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx", (long)cpu_registers(processor)->gpr[arg0], (long)cpu_registers(processor)->gpr[arg0+1], (long)cpu_registers(processor)->gpr[arg0+2], (long)cpu_registers(processor)->gpr[arg0+3], (long)cpu_registers(processor)->gpr[arg0+4], (long)cpu_registers(processor)->gpr[arg0+5]); emul_write_status(processor, 0, errno); } /* Common code for initializing the system call stuff */ static os_emul_data * emul_unix_create(device *root, bfd *image, const char *name, emul_syscall *syscall) { unsigned_word top_of_stack; unsigned stack_size; int elf_binary; os_emul_data *data; device *vm; char *filename; /* merge any emulation specific entries into the device tree */ /* establish a few defaults */ if (image->xvec->flavour == bfd_target_elf_flavour) { elf_binary = 1; top_of_stack = 0xe0000000; stack_size = 0x00100000; } else { elf_binary = 0; top_of_stack = 0x20000000; stack_size = 0x00100000; } /* options */ emul_add_tree_options(root, image, name, (WITH_ENVIRONMENT == USER_ENVIRONMENT ? "user" : "virtual"), 0 /*oea-interrupt-prefix*/); /* virtual memory - handles growth of stack/heap */ vm = tree_parse(root, "/openprom/vm@0x%lx", (unsigned long)(top_of_stack - stack_size)); tree_parse(vm, "./stack-base 0x%lx", (unsigned long)(top_of_stack - stack_size)); tree_parse(vm, "./nr-bytes 0x%x", stack_size); filename = tree_quote_property (bfd_get_filename(image)); tree_parse(root, "/openprom/vm/map-binary/file-name %s", filename); free (filename); /* finish the init */ tree_parse(root, "/openprom/init/register/pc 0x%lx", (unsigned long)bfd_get_start_address(image)); tree_parse(root, "/openprom/init/register/sp 0x%lx", (unsigned long)top_of_stack); tree_parse(root, "/openprom/init/register/msr 0x%x", ((tree_find_boolean_property(root, "/options/little-endian?") ? msr_little_endian_mode : 0) | (tree_find_boolean_property(root, "/openprom/options/floating-point?") ? (msr_floating_point_available | msr_floating_point_exception_mode_0 | msr_floating_point_exception_mode_1) : 0))); tree_parse(root, "/openprom/init/stack/stack-type %s", (elf_binary ? "ppc-elf" : "ppc-xcoff")); /* finally our emulation data */ data = ZALLOC(os_emul_data); data->vm = vm; data->syscalls = syscall; return data; } /* EMULATION Solaris - Emulation of user programs for Solaris/PPC DESCRIPTION */ /* Solaris specific implementation */ typedef int32_t solaris_uid_t; typedef int32_t solaris_gid_t; typedef int32_t solaris_off_t; typedef int32_t solaris_pid_t; typedef int32_t solaris_time_t; typedef uint32_t solaris_dev_t; typedef uint32_t solaris_ino_t; typedef uint32_t solaris_mode_t; typedef uint32_t solaris_nlink_t; #ifdef HAVE_SYS_STAT_H #define SOLARIS_ST_FSTYPSZ 16 /* array size for file system type name */ /* AIX 7.1 defines st_pad[123] to st_[amc]tim.tv_pad, respectively */ #undef st_pad1 #undef st_pad2 #undef st_pad3 struct solaris_stat { solaris_dev_t st_dev; int32_t st_pad1[3]; /* reserved for network id */ solaris_ino_t st_ino; solaris_mode_t st_mode; solaris_nlink_t st_nlink; solaris_uid_t st_uid; solaris_gid_t st_gid; solaris_dev_t st_rdev; int32_t st_pad2[2]; solaris_off_t st_size; int32_t st_pad3; /* future off_t expansion */ struct unix_timeval st_atim; struct unix_timeval st_mtim; struct unix_timeval st_ctim; int32_t st_blksize; int32_t st_blocks; char st_fstype[SOLARIS_ST_FSTYPSZ]; int32_t st_pad4[8]; /* expansion area */ }; /* Convert from host stat structure to solaris stat structure */ STATIC_INLINE_EMUL_UNIX void convert_to_solaris_stat(unsigned_word addr, struct stat *host, cpu *processor, unsigned_word cia) { struct solaris_stat target; int i; target.st_dev = H2T_4(host->st_dev); target.st_ino = H2T_4(host->st_ino); target.st_mode = H2T_4(host->st_mode); target.st_nlink = H2T_4(host->st_nlink); target.st_uid = H2T_4(host->st_uid); target.st_gid = H2T_4(host->st_gid); target.st_size = H2T_4(host->st_size); #ifdef HAVE_ST_RDEV target.st_rdev = H2T_4(host->st_rdev); #else target.st_rdev = 0; #endif #ifdef HAVE_ST_BLKSIZE target.st_blksize = H2T_4(host->st_blksize); #else target.st_blksize = 0; #endif #ifdef HAVE_ST_BLOCKS target.st_blocks = H2T_4(host->st_blocks); #else target.st_blocks = 0; #endif target.st_atim.tv_sec = H2T_4(host->st_atime); target.st_atim.tv_usec = 0; target.st_ctim.tv_sec = H2T_4(host->st_ctime); target.st_ctim.tv_usec = 0; target.st_mtim.tv_sec = H2T_4(host->st_mtime); target.st_mtim.tv_usec = 0; for (i = 0; i < ARRAY_SIZE (target.st_pad1); i++) target.st_pad1[i] = 0; for (i = 0; i < ARRAY_SIZE (target.st_pad2); i++) target.st_pad2[i] = 0; target.st_pad3 = 0; for (i = 0; i < ARRAY_SIZE (target.st_pad4); i++) target.st_pad4[i] = 0; /* For now, just punt and always say it is a ufs file */ strcpy (target.st_fstype, "ufs"); emul_write_buffer(&target, addr, sizeof(target), processor, cia); } #endif /* HAVE_SYS_STAT_H */ #ifndef HAVE_STAT #define do_solaris_stat 0 #else static void do_solaris_stat(os_emul_data *emul, unsigned call, const int arg0, cpu *processor, unsigned_word cia) { unsigned_word path_addr = cpu_registers(processor)->gpr[arg0]; unsigned_word stat_pkt = cpu_registers(processor)->gpr[arg0+1]; char path_buf[PATH_MAX]; struct stat buf; char *path = emul_read_string(path_buf, path_addr, PATH_MAX, processor, cia); int status; if (WITH_TRACE && ppc_trace[trace_os_emul]) printf_filtered ("0x%lx [%s], 0x%lx", (long)path_addr, path, (long)stat_pkt); status = stat (path, &buf); if (status == 0) convert_to_solaris_stat (stat_pkt, &buf, processor, cia); emul_write_status(processor, status, errno); } #endif #ifndef HAVE_LSTAT #define do_solaris_lstat 0 #else static void do_solaris_lstat(os_emul_data *emul, unsigned call, const int arg0, cpu *processor, unsigned_word cia) { unsigned_word path_addr = cpu_registers(processor)->gpr[arg0]; unsigned_word stat_pkt = cpu_registers(processor)->gpr[arg0+1]; char path_buf[PATH_MAX]; struct stat buf; char *path = emul_read_string(path_buf, path_addr, PATH_MAX, processor, cia); int status; if (WITH_TRACE && ppc_trace[trace_os_emul]) printf_filtered ("0x%lx [%s], 0x%lx", (long)path_addr, path, (long)stat_pkt); status = lstat (path, &buf); if (status == 0) convert_to_solaris_stat (stat_pkt, &buf, processor, cia); emul_write_status(processor, status, errno); } #endif #ifndef HAVE_FSTAT #define do_solaris_fstat 0 #else static void do_solaris_fstat(os_emul_data *emul, unsigned call, const int arg0, cpu *processor, unsigned_word cia) { int fildes = (int)cpu_registers(processor)->gpr[arg0]; unsigned_word stat_pkt = cpu_registers(processor)->gpr[arg0+1]; struct stat buf; int status; if (WITH_TRACE && ppc_trace[trace_os_emul]) printf_filtered ("%d, 0x%lx", fildes, (long)stat_pkt); status = fdbad (fildes); if (status == 0) status = fstat (fildes, &buf); if (status == 0) convert_to_solaris_stat (stat_pkt, &buf, processor, cia); emul_write_status(processor, status, errno); } #endif #if defined(HAVE_TERMIO_STRUCTURE) || defined(HAVE_TERMIOS_STRUCTURE) #define SOLARIS_TIOC ('T'<<8) #define SOLARIS_NCC 8 #define SOLARIS_NCCS 19 #define SOLARIS_VINTR 0 #define SOLARIS_VQUIT 1 #define SOLARIS_VERASE 2 #define SOLARIS_VKILL 3 #define SOLARIS_VEOF 4 #define SOLARIS_VEOL 5 #define SOLARIS_VEOL2 6 #define SOLARIS_VSWTCH 7 #define SOLARIS_VSTART 8 #define SOLARIS_VSTOP 9 #define SOLARIS_VSUSP 10 #define SOLARIS_VDSUSP 11 #define SOLARIS_VREPRINT 12 #define SOLARIS_VDISCARD 13 #define SOLARIS_VWERASE 14 #define SOLARIS_VLNEXT 15 #endif #if defined(HAVE_TERMIO_STRUCTURE) || defined(HAVE_TERMIOS_STRUCTURE) /* Convert to/from host termio structure */ struct solaris_termio { uint16_t c_iflag; /* input modes */ uint16_t c_oflag; /* output modes */ uint16_t c_cflag; /* control modes */ uint16_t c_lflag; /* line discipline modes */ uint8_t c_line; /* line discipline */ uint8_t c_cc[SOLARIS_NCC]; /* control chars */ }; STATIC_INLINE_EMUL_UNIX void convert_to_solaris_termio(unsigned_word addr, struct termio *host, cpu *processor, unsigned_word cia) { struct solaris_termio target; int i; target.c_iflag = H2T_2 (host->c_iflag); target.c_oflag = H2T_2 (host->c_oflag); target.c_cflag = H2T_2 (host->c_cflag); target.c_lflag = H2T_2 (host->c_lflag); #if defined(HAVE_TERMIO_CLINE) || defined(HAVE_TERMIOS_CLINE) target.c_line = host->c_line; #else target.c_line = 0; #endif for (i = 0; i < SOLARIS_NCC; i++) target.c_cc[i] = 0; #ifdef VINTR target.c_cc[SOLARIS_VINTR] = host->c_cc[VINTR]; #endif #ifdef VQUIT target.c_cc[SOLARIS_VQUIT] = host->c_cc[VQUIT]; #endif #ifdef VERASE target.c_cc[SOLARIS_VERASE] = host->c_cc[VERASE]; #endif #ifdef VKILL target.c_cc[SOLARIS_VKILL] = host->c_cc[VKILL]; #endif #ifdef VEOF target.c_cc[SOLARIS_VEOF] = host->c_cc[VEOF]; #endif #ifdef VEOL target.c_cc[SOLARIS_VEOL] = host->c_cc[VEOL]; #endif #ifdef VEOL2 target.c_cc[SOLARIS_VEOL2] = host->c_cc[VEOL2]; #endif #ifdef VSWTCH target.c_cc[SOLARIS_VSWTCH] = host->c_cc[VSWTCH]; #else #ifdef VSWTC target.c_cc[SOLARIS_VSWTCH] = host->c_cc[VSWTC]; #endif #endif emul_write_buffer(&target, addr, sizeof(target), processor, cia); } #endif /* HAVE_TERMIO_STRUCTURE || HAVE_TERMIOS_STRUCTURE */ #ifdef HAVE_TERMIOS_STRUCTURE /* Convert to/from host termios structure */ typedef uint32_t solaris_tcflag_t; typedef uint8_t solaris_cc_t; typedef uint32_t solaris_speed_t; struct solaris_termios { solaris_tcflag_t c_iflag; solaris_tcflag_t c_oflag; solaris_tcflag_t c_cflag; solaris_tcflag_t c_lflag; solaris_cc_t c_cc[SOLARIS_NCCS]; }; STATIC_INLINE_EMUL_UNIX void convert_to_solaris_termios(unsigned_word addr, struct termios *host, cpu *processor, unsigned_word cia) { struct solaris_termios target; int i; target.c_iflag = H2T_4 (host->c_iflag); target.c_oflag = H2T_4 (host->c_oflag); target.c_cflag = H2T_4 (host->c_cflag); target.c_lflag = H2T_4 (host->c_lflag); for (i = 0; i < SOLARIS_NCCS; i++) target.c_cc[i] = 0; #ifdef VINTR target.c_cc[SOLARIS_VINTR] = host->c_cc[VINTR]; #endif #ifdef VQUIT target.c_cc[SOLARIS_VQUIT] = host->c_cc[VQUIT]; #endif #ifdef VERASE target.c_cc[SOLARIS_VERASE] = host->c_cc[VERASE]; #endif #ifdef VKILL target.c_cc[SOLARIS_VKILL] = host->c_cc[VKILL]; #endif #ifdef VEOF target.c_cc[SOLARIS_VEOF] = host->c_cc[VEOF]; #endif #ifdef VEOL target.c_cc[SOLARIS_VEOL] = host->c_cc[VEOL]; #endif #ifdef VEOL2 target.c_cc[SOLARIS_VEOL2] = host->c_cc[VEOL2]; #endif #ifdef VSWTCH target.c_cc[SOLARIS_VSWTCH] = host->c_cc[VSWTCH]; #else #ifdef VSWTC target.c_cc[SOLARIS_VSWTCH] = host->c_cc[VSWTC]; #endif #endif #ifdef VSTART target.c_cc[SOLARIS_VSTART] = host->c_cc[VSTART]; #endif #ifdef VSTOP target.c_cc[SOLARIS_VSTOP] = host->c_cc[VSTOP]; #endif #ifdef VSUSP target.c_cc[SOLARIS_VSUSP] = host->c_cc[VSUSP]; #endif #ifdef VDSUSP target.c_cc[SOLARIS_VDSUSP] = host->c_cc[VDSUSP]; #endif #ifdef VREPRINT target.c_cc[SOLARIS_VREPRINT] = host->c_cc[VREPRINT]; #endif #ifdef VDISCARD target.c_cc[SOLARIS_VDISCARD] = host->c_cc[VDISCARD]; #endif #ifdef VWERASE target.c_cc[SOLARIS_VWERASE] = host->c_cc[VWERASE]; #endif #ifdef VLNEXT target.c_cc[SOLARIS_VLNEXT] = host->c_cc[VLNEXT]; #endif emul_write_buffer(&target, addr, sizeof(target), processor, cia); } #endif /* HAVE_TERMIOS_STRUCTURE */ #ifndef HAVE_IOCTL #define do_solaris_ioctl 0 #else static void do_solaris_ioctl(os_emul_data *emul, unsigned call, const int arg0, cpu *processor, unsigned_word cia) { int fildes = cpu_registers(processor)->gpr[arg0]; unsigned request = cpu_registers(processor)->gpr[arg0+1]; unsigned_word argp_addr = cpu_registers(processor)->gpr[arg0+2]; int status = 0; const char *name = ""; #ifdef HAVE_TERMIOS_STRUCTURE struct termios host_termio; #else #ifdef HAVE_TERMIO_STRUCTURE struct termio host_termio; #endif #endif status = fdbad (fildes); if (status != 0) goto done; switch (request) { case 0: /* make sure we have at least one case */ default: status = -1; errno = EINVAL; break; #if defined(HAVE_TERMIO_STRUCTURE) || defined(HAVE_TERMIOS_STRUCTURE) #if defined(TCGETA) || defined(TCGETS) || defined(HAVE_TCGETATTR) case SOLARIS_TIOC | 1: /* TCGETA */ name = "TCGETA"; #ifdef HAVE_TCGETATTR status = tcgetattr(fildes, &host_termio); #elif defined(TCGETS) status = ioctl (fildes, TCGETS, &host_termio); #else status = ioctl (fildes, TCGETA, &host_termio); #endif if (status == 0) convert_to_solaris_termio (argp_addr, &host_termio, processor, cia); break; #endif /* TCGETA */ #endif /* HAVE_TERMIO_STRUCTURE */ #ifdef HAVE_TERMIOS_STRUCTURE #if defined(TCGETS) || defined(HAVE_TCGETATTR) case SOLARIS_TIOC | 13: /* TCGETS */ name = "TCGETS"; #ifdef HAVE_TCGETATTR status = tcgetattr(fildes, &host_termio); #else status = ioctl (fildes, TCGETS, &host_termio); #endif if (status == 0) convert_to_solaris_termios (argp_addr, &host_termio, processor, cia); break; #endif /* TCGETS */ #endif /* HAVE_TERMIOS_STRUCTURE */ } done: emul_write_status(processor, status, errno); if (WITH_TRACE && ppc_trace[trace_os_emul]) printf_filtered ("%d, 0x%x [%s], 0x%lx", fildes, request, name, (long)argp_addr); } #endif /* HAVE_IOCTL */ static emul_syscall_descriptor solaris_descriptors[] = { /* 0 */ { 0, "syscall" }, /* 1 */ { do_unix_exit, "exit" }, /* 2 */ { 0, "fork" }, /* 3 */ { do_unix_read, "read" }, /* 4 */ { do_unix_write, "write" }, /* 5 */ { do_unix_open, "open" }, /* 6 */ { do_unix_close, "close" }, /* 7 */ { 0, "wait" }, /* 8 */ { 0, "creat" }, /* 9 */ { do_unix_link, "link" }, /* 10 */ { do_unix_unlink, "unlink" }, /* 11 */ { 0, "exec" }, /* 12 */ { do_unix_chdir, "chdir" }, /* 13 */ { do_unix_time, "time" }, /* 14 */ { 0, "mknod" }, /* 15 */ { 0, "chmod" }, /* 16 */ { 0, "chown" }, /* 17 */ { do_unix_break, "brk" }, /* 18 */ { do_solaris_stat, "stat" }, /* 19 */ { do_unix_lseek, "lseek" }, /* 20 */ { do_unix_getpid2, "getpid" }, /* 21 */ { 0, "mount" }, /* 22 */ { 0, "umount" }, /* 23 */ { 0, "setuid" }, /* 24 */ { do_unix_getuid2, "getuid" }, /* 25 */ { 0, "stime" }, /* 26 */ { 0, "ptrace" }, /* 27 */ { 0, "alarm" }, /* 28 */ { do_solaris_fstat, "fstat" }, /* 29 */ { 0, "pause" }, /* 30 */ { 0, "utime" }, /* 31 */ { 0, "stty" }, /* 32 */ { 0, "gtty" }, /* 33 */ { do_unix_access, "access" }, /* 34 */ { 0, "nice" }, /* 35 */ { 0, "statfs" }, /* 36 */ { 0, "sync" }, /* 37 */ { 0, "kill" }, /* 38 */ { 0, "fstatfs" }, /* 39 */ { 0, "pgrpsys" }, /* 40 */ { 0, "xenix" }, /* 41 */ { do_unix_dup, "dup" }, /* 42 */ { 0, "pipe" }, /* 43 */ { 0, "times" }, /* 44 */ { 0, "profil" }, /* 45 */ { 0, "plock" }, /* 46 */ { 0, "setgid" }, /* 47 */ { do_unix_getgid2, "getgid" }, /* 48 */ { 0, "signal" }, /* 49 */ { 0, "msgsys" }, /* 50 */ { 0, "syssun" }, /* 51 */ { 0, "acct" }, /* 52 */ { 0, "shmsys" }, /* 53 */ { 0, "semsys" }, /* 54 */ { do_solaris_ioctl, "ioctl" }, /* 55 */ { 0, "uadmin" }, /* 56 */ { 0, 0 /* reserved for exch */ }, /* 57 */ { 0, "utssys" }, /* 58 */ { 0, "fdsync" }, /* 59 */ { 0, "execve" }, /* 60 */ { do_unix_umask, "umask" }, /* 61 */ { 0, "chroot" }, /* 62 */ { 0, "fcntl" }, /* 63 */ { 0, "ulimit" }, /* 64 */ { 0, 0 /* reserved for UNIX PC */ }, /* 64 */ { 0, 0 /* reserved for UNIX PC */ }, /* 65 */ { 0, 0 /* reserved for UNIX PC */ }, /* 66 */ { 0, 0 /* reserved for UNIX PC */ }, /* 67 */ { 0, 0 /* reserved for UNIX PC */ }, /* 68 */ { 0, 0 /* reserved for UNIX PC */ }, /* 69 */ { 0, 0 /* reserved for UNIX PC */ }, /* 70 */ { 0, 0 /* was advfs */ }, /* 71 */ { 0, 0 /* was unadvfs */ }, /* 72 */ { 0, 0 /* was rmount */ }, /* 73 */ { 0, 0 /* was rumount */ }, /* 74 */ { 0, 0 /* was rfstart */ }, /* 75 */ { 0, 0 /* was sigret */ }, /* 76 */ { 0, 0 /* was rdebug */ }, /* 77 */ { 0, 0 /* was rfstop */ }, /* 78 */ { 0, 0 /* was rfsys */ }, /* 79 */ { do_unix_rmdir, "rmdir" }, /* 80 */ { do_unix_mkdir, "mkdir" }, /* 81 */ { 0, "getdents" }, /* 82 */ { 0, 0 /* was libattach */ }, /* 83 */ { 0, 0 /* was libdetach */ }, /* 84 */ { 0, "sysfs" }, /* 85 */ { 0, "getmsg" }, /* 86 */ { 0, "putmsg" }, /* 87 */ { 0, "poll" }, /* 88 */ { do_solaris_lstat, "lstat" }, /* 89 */ { do_unix_symlink, "symlink" }, /* 90 */ { 0, "readlink" }, /* 91 */ { 0, "setgroups" }, /* 92 */ { 0, "getgroups" }, /* 93 */ { 0, "fchmod" }, /* 94 */ { 0, "fchown" }, /* 95 */ { 0, "sigprocmask" }, /* 96 */ { 0, "sigsuspend" }, /* 97 */ { do_unix_nop, "sigaltstack" }, /* 98 */ { do_unix_nop, "sigaction" }, /* 99 */ { 0, "sigpending" }, /* 100 */ { 0, "context" }, /* 101 */ { 0, "evsys" }, /* 102 */ { 0, "evtrapret" }, /* 103 */ { 0, "statvfs" }, /* 104 */ { 0, "fstatvfs" }, /* 105 */ { 0, 0 /* reserved */ }, /* 106 */ { 0, "nfssys" }, /* 107 */ { 0, "waitsys" }, /* 108 */ { 0, "sigsendsys" }, /* 109 */ { 0, "hrtsys" }, /* 110 */ { 0, "acancel" }, /* 111 */ { 0, "async" }, /* 112 */ { 0, "priocntlsys" }, /* 113 */ { 0, "pathconf" }, /* 114 */ { 0, "mincore" }, /* 115 */ { 0, "mmap" }, /* 116 */ { 0, "mprotect" }, /* 117 */ { 0, "munmap" }, /* 118 */ { 0, "fpathconf" }, /* 119 */ { 0, "vfork" }, /* 120 */ { 0, "fchdir" }, /* 121 */ { 0, "readv" }, /* 122 */ { 0, "writev" }, /* 123 */ { 0, "xstat" }, /* 124 */ { 0, "lxstat" }, /* 125 */ { 0, "fxstat" }, /* 126 */ { 0, "xmknod" }, /* 127 */ { 0, "clocal" }, /* 128 */ { 0, "setrlimit" }, /* 129 */ { 0, "getrlimit" }, /* 130 */ { 0, "lchown" }, /* 131 */ { 0, "memcntl" }, /* 132 */ { 0, "getpmsg" }, /* 133 */ { 0, "putpmsg" }, /* 134 */ { 0, "rename" }, /* 135 */ { 0, "uname" }, /* 136 */ { 0, "setegid" }, /* 137 */ { 0, "sysconfig" }, /* 138 */ { 0, "adjtime" }, /* 139 */ { 0, "systeminfo" }, /* 140 */ { 0, 0 /* reserved */ }, /* 141 */ { 0, "seteuid" }, /* 142 */ { 0, "vtrace" }, /* 143 */ { 0, "fork1" }, /* 144 */ { 0, "sigtimedwait" }, /* 145 */ { 0, "lwp_info" }, /* 146 */ { 0, "yield" }, /* 147 */ { 0, "lwp_sema_wait" }, /* 148 */ { 0, "lwp_sema_post" }, /* 149 */ { 0, 0 /* reserved */ }, /* 150 */ { 0, 0 /* reserved */ }, /* 151 */ { 0, 0 /* reserved */ }, /* 152 */ { 0, "modctl" }, /* 153 */ { 0, "fchroot" }, /* 154 */ { 0, "utimes" }, /* 155 */ { 0, "vhangup" }, /* 156 */ { do_unix_gettimeofday, "gettimeofday" }, /* 157 */ { 0, "getitimer" }, /* 158 */ { 0, "setitimer" }, /* 159 */ { 0, "lwp_create" }, /* 160 */ { 0, "lwp_exit" }, /* 161 */ { 0, "lwp_suspend" }, /* 162 */ { 0, "lwp_continue" }, /* 163 */ { 0, "lwp_kill" }, /* 164 */ { 0, "lwp_self" }, /* 165 */ { 0, "lwp_setprivate" }, /* 166 */ { 0, "lwp_getprivate" }, /* 167 */ { 0, "lwp_wait" }, /* 168 */ { 0, "lwp_mutex_unlock" }, /* 169 */ { 0, "lwp_mutex_lock" }, /* 170 */ { 0, "lwp_cond_wait" }, /* 171 */ { 0, "lwp_cond_signal" }, /* 172 */ { 0, "lwp_cond_broadcast" }, /* 173 */ { 0, "pread" }, /* 174 */ { 0, "pwrite" }, /* 175 */ { 0, "llseek" }, /* 176 */ { 0, "inst_sync" }, /* 177 */ { 0, 0 /* reserved */ }, /* 178 */ { 0, "kaio" }, /* 179 */ { 0, 0 /* reserved */ }, /* 180 */ { 0, 0 /* reserved */ }, /* 181 */ { 0, 0 /* reserved */ }, /* 182 */ { 0, 0 /* reserved */ }, /* 183 */ { 0, 0 /* reserved */ }, /* 184 */ { 0, "tsolsys" }, /* 185 */ { 0, "acl" }, /* 186 */ { 0, "auditsys" }, /* 187 */ { 0, "processor_bind" }, /* 188 */ { 0, "processor_info" }, /* 189 */ { 0, "p_online" }, /* 190 */ { 0, "sigqueue" }, /* 191 */ { 0, "clock_gettime" }, /* 192 */ { 0, "clock_settime" }, /* 193 */ { 0, "clock_getres" }, /* 194 */ { 0, "timer_create" }, /* 195 */ { 0, "timer_delete" }, /* 196 */ { 0, "timer_settime" }, /* 197 */ { 0, "timer_gettime" }, /* 198 */ { 0, "timer_getoverrun" }, /* 199 */ { 0, "nanosleep" }, /* 200 */ { 0, "facl" }, /* 201 */ { 0, "door" }, /* 202 */ { 0, "setreuid" }, /* 203 */ { 0, "setregid" }, /* 204 */ { 0, "install_utrap" }, /* 205 */ { 0, 0 /* reserved */ }, /* 206 */ { 0, 0 /* reserved */ }, /* 207 */ { 0, 0 /* reserved */ }, /* 208 */ { 0, 0 /* reserved */ }, /* 209 */ { 0, 0 /* reserved */ }, /* 210 */ { 0, "signotifywait" }, /* 211 */ { 0, "lwp_sigredirect" }, /* 212 */ { 0, "lwp_alarm" }, }; static char *(solaris_error_names[]) = { /* 0 */ "ESUCCESS", /* 1 */ "EPERM", /* 2 */ "ENOENT", /* 3 */ "ESRCH", /* 4 */ "EINTR", /* 5 */ "EIO", /* 6 */ "ENXIO", /* 7 */ "E2BIG", /* 8 */ "ENOEXEC", /* 9 */ "EBADF", /* 10 */ "ECHILD", /* 11 */ "EAGAIN", /* 12 */ "ENOMEM", /* 13 */ "EACCES", /* 14 */ "EFAULT", /* 15 */ "ENOTBLK", /* 16 */ "EBUSY", /* 17 */ "EEXIST", /* 18 */ "EXDEV", /* 19 */ "ENODEV", /* 20 */ "ENOTDIR", /* 21 */ "EISDIR", /* 22 */ "EINVAL", /* 23 */ "ENFILE", /* 24 */ "EMFILE", /* 25 */ "ENOTTY", /* 26 */ "ETXTBSY", /* 27 */ "EFBIG", /* 28 */ "ENOSPC", /* 29 */ "ESPIPE", /* 30 */ "EROFS", /* 31 */ "EMLINK", /* 32 */ "EPIPE", /* 33 */ "EDOM", /* 34 */ "ERANGE", /* 35 */ "ENOMSG", /* 36 */ "EIDRM", /* 37 */ "ECHRNG", /* 38 */ "EL2NSYNC", /* 39 */ "EL3HLT", /* 40 */ "EL3RST", /* 41 */ "ELNRNG", /* 42 */ "EUNATCH", /* 43 */ "ENOCSI", /* 44 */ "EL2HLT", /* 45 */ "EDEADLK", /* 46 */ "ENOLCK", /* 47 */ "ECANCELED", /* 48 */ "ENOTSUP", /* 49 */ "EDQUOT", /* 50 */ "EBADE", /* 51 */ "EBADR", /* 52 */ "EXFULL", /* 53 */ "ENOANO", /* 54 */ "EBADRQC", /* 55 */ "EBADSLT", /* 56 */ "EDEADLOCK", /* 57 */ "EBFONT", /* 58 */ "Error code 58", /* 59 */ "Error code 59", /* 60 */ "ENOSTR", /* 61 */ "ENODATA", /* 62 */ "ETIME", /* 63 */ "ENOSR", /* 64 */ "ENONET", /* 65 */ "ENOPKG", /* 66 */ "EREMOTE", /* 67 */ "ENOLINK", /* 68 */ "EADV", /* 69 */ "ESRMNT", /* 70 */ "ECOMM", /* 71 */ "EPROTO", /* 72 */ "Error code 72", /* 73 */ "Error code 73", /* 74 */ "EMULTIHOP", /* 75 */ "Error code 75", /* 76 */ "Error code 76", /* 77 */ "EBADMSG", /* 78 */ "ENAMETOOLONG", /* 79 */ "EOVERFLOW", /* 80 */ "ENOTUNIQ", /* 81 */ "EBADFD", /* 82 */ "EREMCHG", /* 83 */ "ELIBACC", /* 84 */ "ELIBBAD", /* 85 */ "ELIBSCN", /* 86 */ "ELIBMAX", /* 87 */ "ELIBEXEC", /* 88 */ "EILSEQ", /* 89 */ "ENOSYS", /* 90 */ "ELOOP", /* 91 */ "ERESTART", /* 92 */ "ESTRPIPE", /* 93 */ "ENOTEMPTY", /* 94 */ "EUSERS", /* 95 */ "ENOTSOCK", /* 96 */ "EDESTADDRREQ", /* 97 */ "EMSGSIZE", /* 98 */ "EPROTOTYPE", /* 99 */ "ENOPROTOOPT", /* 100 */ "Error code 100", /* 101 */ "Error code 101", /* 102 */ "Error code 102", /* 103 */ "Error code 103", /* 104 */ "Error code 104", /* 105 */ "Error code 105", /* 106 */ "Error code 106", /* 107 */ "Error code 107", /* 108 */ "Error code 108", /* 109 */ "Error code 109", /* 110 */ "Error code 110", /* 111 */ "Error code 111", /* 112 */ "Error code 112", /* 113 */ "Error code 113", /* 114 */ "Error code 114", /* 115 */ "Error code 115", /* 116 */ "Error code 116", /* 117 */ "Error code 117", /* 118 */ "Error code 118", /* 119 */ "Error code 119", /* 120 */ "EPROTONOSUPPORT", /* 121 */ "ESOCKTNOSUPPORT", /* 122 */ "EOPNOTSUPP", /* 123 */ "EPFNOSUPPORT", /* 124 */ "EAFNOSUPPORT", /* 125 */ "EADDRINUSE", /* 126 */ "EADDRNOTAVAIL", /* 127 */ "ENETDOWN", /* 128 */ "ENETUNREACH", /* 129 */ "ENETRESET", /* 130 */ "ECONNABORTED", /* 131 */ "ECONNRESET", /* 132 */ "ENOBUFS", /* 133 */ "EISCONN", /* 134 */ "ENOTCONN", /* 135 */ "Error code 135", /* XENIX has 135 - 142 */ /* 136 */ "Error code 136", /* 137 */ "Error code 137", /* 138 */ "Error code 138", /* 139 */ "Error code 139", /* 140 */ "Error code 140", /* 141 */ "Error code 141", /* 142 */ "Error code 142", /* 143 */ "ESHUTDOWN", /* 144 */ "ETOOMANYREFS", /* 145 */ "ETIMEDOUT", /* 146 */ "ECONNREFUSED", /* 147 */ "EHOSTDOWN", /* 148 */ "EHOSTUNREACH", /* 149 */ "EALREADY", /* 150 */ "EINPROGRESS", /* 151 */ "ESTALE", }; static char *(solaris_signal_names[]) = { /* 0 */ 0, /* 1 */ "SIGHUP", /* 2 */ "SIGINT", /* 3 */ "SIGQUIT", /* 4 */ "SIGILL", /* 5 */ "SIGTRAP", /* 6 */ "SIGABRT", /* 7 */ "SIGEMT", /* 8 */ "SIGFPE", /* 9 */ "SIGKILL", /* 10 */ "SIGBUS", /* 11 */ "SIGSEGV", /* 12 */ "SIGSYS", /* 13 */ "SIGPIPE", /* 14 */ "SIGALRM", /* 15 */ "SIGTERM", /* 16 */ "SIGUSR1", /* 17 */ "SIGUSR2", /* 18 */ "SIGCHLD", /* 19 */ "SIGPWR", /* 20 */ "SIGWINCH", /* 21 */ "SIGURG", /* 22 */ "SIGPOLL", /* 23 */ "SIGSTOP", /* 24 */ "SIGTSTP", /* 25 */ "SIGCONT", /* 26 */ "SIGTTIN", /* 27 */ "SIGTTOU", /* 28 */ "SIGVTALRM", /* 29 */ "SIGPROF", /* 30 */ "SIGXCPU", /* 31 */ "SIGXFSZ", /* 32 */ "SIGWAITING", /* 33 */ "SIGLWP", /* 34 */ "SIGFREEZE", /* 35 */ "SIGTHAW", /* 36 */ "SIGCANCEL", }; static emul_syscall emul_solaris_syscalls = { solaris_descriptors, ARRAY_SIZE (solaris_descriptors), solaris_error_names, ARRAY_SIZE (solaris_error_names), solaris_signal_names, ARRAY_SIZE (solaris_signal_names), }; /* Solaris's os_emul interface, most are just passed on to the generic syscall stuff */ static os_emul_data * emul_solaris_create(device *root, bfd *image, const char *name) { /* check that this emulation is really for us */ if (name != NULL && strcmp(name, "solaris") != 0) return NULL; if (image == NULL) return NULL; return emul_unix_create(root, image, "solaris", &emul_solaris_syscalls); } static void emul_solaris_init(os_emul_data *emul_data, int nr_cpus) { fd_closed[0] = 0; fd_closed[1] = 0; fd_closed[2] = 0; } static void emul_solaris_system_call(cpu *processor, unsigned_word cia, os_emul_data *emul_data) { emul_do_system_call(emul_data, emul_data->syscalls, cpu_registers(processor)->gpr[0], 3, /*r3 contains arg0*/ processor, cia); } const os_emul emul_solaris = { "solaris", emul_solaris_create, emul_solaris_init, emul_solaris_system_call, 0, /*instruction_call*/ 0 /*data*/ }; /* EMULATION Linux - Emulation of user programs for Linux/PPC DESCRIPTION */ /* Linux specific implementation */ typedef uint32_t linux_dev_t; typedef uint32_t linux_ino_t; typedef uint32_t linux_mode_t; typedef uint16_t linux_nlink_t; typedef int32_t linux_off_t; typedef int32_t linux_pid_t; typedef uint32_t linux_uid_t; typedef uint32_t linux_gid_t; typedef uint32_t linux_size_t; typedef int32_t linux_ssize_t; typedef int32_t linux_ptrdiff_t; typedef int32_t linux_time_t; typedef int32_t linux_clock_t; typedef int32_t linux_daddr_t; #ifdef HAVE_SYS_STAT_H /* For the PowerPC, don't both with the 'old' stat structure, since there should be no extant binaries with that structure. */ struct linux_stat { linux_dev_t st_dev; linux_ino_t st_ino; linux_mode_t st_mode; linux_nlink_t st_nlink; linux_uid_t st_uid; linux_gid_t st_gid; linux_dev_t st_rdev; linux_off_t st_size; uint32_t st_blksize; uint32_t st_blocks; uint32_t st_atimx; /* don't use st_{a,c,m}time, that might a macro */ uint32_t __unused1; /* defined by the host's stat.h */ uint32_t st_mtimx; uint32_t __unused2; uint32_t st_ctimx; uint32_t __unused3; uint32_t __unused4; uint32_t __unused5; }; /* Convert from host stat structure to solaris stat structure */ STATIC_INLINE_EMUL_UNIX void convert_to_linux_stat(unsigned_word addr, struct stat *host, cpu *processor, unsigned_word cia) { struct linux_stat target; target.st_dev = H2T_4(host->st_dev); target.st_ino = H2T_4(host->st_ino); target.st_mode = H2T_4(host->st_mode); target.st_nlink = H2T_2(host->st_nlink); target.st_uid = H2T_4(host->st_uid); target.st_gid = H2T_4(host->st_gid); target.st_size = H2T_4(host->st_size); #ifdef HAVE_ST_RDEV target.st_rdev = H2T_4(host->st_rdev); #else target.st_rdev = 0; #endif #ifdef HAVE_ST_BLKSIZE target.st_blksize = H2T_4(host->st_blksize); #else target.st_blksize = 0; #endif #ifdef HAVE_ST_BLOCKS target.st_blocks = H2T_4(host->st_blocks); #else target.st_blocks = 0; #endif target.st_atimx = H2T_4(host->st_atime); target.st_ctimx = H2T_4(host->st_ctime); target.st_mtimx = H2T_4(host->st_mtime); target.__unused1 = 0; target.__unused2 = 0; target.__unused3 = 0; target.__unused4 = 0; target.__unused5 = 0; emul_write_buffer(&target, addr, sizeof(target), processor, cia); } #endif /* HAVE_SYS_STAT_H */ #ifndef HAVE_STAT #define do_linux_stat 0 #else static void do_linux_stat(os_emul_data *emul, unsigned call, const int arg0, cpu *processor, unsigned_word cia) { unsigned_word path_addr = cpu_registers(processor)->gpr[arg0]; unsigned_word stat_pkt = cpu_registers(processor)->gpr[arg0+1]; char path_buf[PATH_MAX]; struct stat buf; char *path = emul_read_string(path_buf, path_addr, PATH_MAX, processor, cia); int status; if (WITH_TRACE && ppc_trace[trace_os_emul]) printf_filtered ("0x%lx [%s], 0x%lx", (long)path_addr, path, (long)stat_pkt); status = stat (path, &buf); if (status == 0) convert_to_linux_stat (stat_pkt, &buf, processor, cia); emul_write_status(processor, status, errno); } #endif #ifndef HAVE_LSTAT #define do_linux_lstat 0 #else static void do_linux_lstat(os_emul_data *emul, unsigned call, const int arg0, cpu *processor, unsigned_word cia) { unsigned_word path_addr = cpu_registers(processor)->gpr[arg0]; unsigned_word stat_pkt = cpu_registers(processor)->gpr[arg0+1]; char path_buf[PATH_MAX]; struct stat buf; char *path = emul_read_string(path_buf, path_addr, PATH_MAX, processor, cia); int status; if (WITH_TRACE && ppc_trace[trace_os_emul]) printf_filtered ("0x%lx [%s], 0x%lx", (long)path_addr, path, (long)stat_pkt); status = lstat (path, &buf); if (status == 0) convert_to_linux_stat (stat_pkt, &buf, processor, cia); emul_write_status(processor, status, errno); } #endif #ifndef HAVE_FSTAT #define do_linux_fstat 0 #else static void do_linux_fstat(os_emul_data *emul, unsigned call, const int arg0, cpu *processor, unsigned_word cia) { int fildes = (int)cpu_registers(processor)->gpr[arg0]; unsigned_word stat_pkt = cpu_registers(processor)->gpr[arg0+1]; struct stat buf; int status; if (WITH_TRACE && ppc_trace[trace_os_emul]) printf_filtered ("%d, 0x%lx", fildes, (long)stat_pkt); status = fdbad (fildes); if (status == 0) status = fstat (fildes, &buf); if (status == 0) convert_to_linux_stat (stat_pkt, &buf, processor, cia); emul_write_status(processor, status, errno); } #endif #if defined(HAVE_TERMIO_STRUCTURE) || defined(HAVE_TERMIOS_STRUCTURE) #define LINUX_NCC 10 #define LINUX_NCCS 19 #define LINUX_VINTR 0 #define LINUX_VQUIT 1 #define LINUX_VERASE 2 #define LINUX_VKILL 3 #define LINUX_VEOF 4 #define LINUX_VMIN 5 #define LINUX_VEOL 6 #define LINUX_VTIME 7 #define LINUX_VEOL2 8 #define LINUX_VSWTC 9 #define LINUX_VWERASE 10 #define LINUX_VREPRINT 11 #define LINUX_VSUSP 12 #define LINUX_VSTART 13 #define LINUX_VSTOP 14 #define LINUX_VLNEXT 15 #define LINUX_VDISCARD 16 #define LINUX_IOC_NRBITS 8 #define LINUX_IOC_TYPEBITS 8 #define LINUX_IOC_SIZEBITS 13 #define LINUX_IOC_DIRBITS 3 #define LINUX_IOC_NRMASK ((1 << LINUX_IOC_NRBITS)-1) #define LINUX_IOC_TYPEMASK ((1 << LINUX_IOC_TYPEBITS)-1) #define LINUX_IOC_SIZEMASK ((1 << LINUX_IOC_SIZEBITS)-1) #define LINUX_IOC_DIRMASK ((1 << LINUX_IOC_DIRBITS)-1) #define LINUX_IOC_NRSHIFT 0 #define LINUX_IOC_TYPESHIFT (LINUX_IOC_NRSHIFT+LINUX_IOC_NRBITS) #define LINUX_IOC_SIZESHIFT (LINUX_IOC_TYPESHIFT+LINUX_IOC_TYPEBITS) #define LINUX_IOC_DIRSHIFT (LINUX_IOC_SIZESHIFT+LINUX_IOC_SIZEBITS) /* * Direction bits _IOC_NONE could be 0, but OSF/1 gives it a bit. * And this turns out useful to catch old ioctl numbers in header * files for us. */ #define LINUX_IOC_NONE 1U #define LINUX_IOC_READ 2U #define LINUX_IOC_WRITE 4U #define LINUX_IOC(dir,type,nr,size) \ (((dir) << LINUX_IOC_DIRSHIFT) | \ ((type) << LINUX_IOC_TYPESHIFT) | \ ((nr) << LINUX_IOC_NRSHIFT) | \ ((size) << LINUX_IOC_SIZESHIFT)) /* used to create numbers */ #define LINUX_IO(type,nr) LINUX_IOC(LINUX_IOC_NONE,(type),(nr),0) #define LINUX_IOR(type,nr,size) LINUX_IOC(LINUX_IOC_READ,(type),(nr),sizeof(size)) #define LINUX_IOW(type,nr,size) LINUX_IOC(LINUX_IOC_WRITE,(type),(nr),sizeof(size)) #define LINUX_IOWR(type,nr,size) LINUX_IOC(LINUX_IOC_READ|LINUX_IOC_WRITE,(type),(nr),sizeof(size)) #endif #if defined(HAVE_TERMIO_STRUCTURE) || defined(HAVE_TERMIOS_STRUCTURE) /* Convert to/from host termio structure */ struct linux_termio { uint16_t c_iflag; /* input modes */ uint16_t c_oflag; /* output modes */ uint16_t c_cflag; /* control modes */ uint16_t c_lflag; /* line discipline modes */ uint8_t c_line; /* line discipline */ uint8_t c_cc[LINUX_NCC]; /* control chars */ }; STATIC_INLINE_EMUL_UNIX void convert_to_linux_termio(unsigned_word addr, struct termio *host, cpu *processor, unsigned_word cia) { struct linux_termio target; int i; target.c_iflag = H2T_2 (host->c_iflag); target.c_oflag = H2T_2 (host->c_oflag); target.c_cflag = H2T_2 (host->c_cflag); target.c_lflag = H2T_2 (host->c_lflag); #if defined(HAVE_TERMIO_CLINE) || defined(HAVE_TERMIOS_CLINE) target.c_line = host->c_line; #else target.c_line = 0; #endif for (i = 0; i < LINUX_NCC; i++) target.c_cc[i] = 0; #ifdef VINTR target.c_cc[LINUX_VINTR] = host->c_cc[VINTR]; #endif #ifdef VQUIT target.c_cc[LINUX_VQUIT] = host->c_cc[VQUIT]; #endif #ifdef VERASE target.c_cc[LINUX_VERASE] = host->c_cc[VERASE]; #endif #ifdef VKILL target.c_cc[LINUX_VKILL] = host->c_cc[VKILL]; #endif #ifdef VEOF target.c_cc[LINUX_VEOF] = host->c_cc[VEOF]; #endif #ifdef VMIN target.c_cc[LINUX_VMIN] = host->c_cc[VMIN]; #endif #ifdef VEOL target.c_cc[LINUX_VEOL] = host->c_cc[VEOL]; #endif #ifdef VTIME target.c_cc[LINUX_VTIME] = host->c_cc[VTIME]; #endif #ifdef VEOL2 target.c_cc[LINUX_VEOL2] = host->c_cc[VEOL2]; #endif #ifdef VSWTC target.c_cc[LINUX_VSWTC] = host->c_cc[VSWTC]; #endif #ifdef VSWTCH target.c_cc[LINUX_VSWTC] = host->c_cc[VSWTCH]; #endif emul_write_buffer(&target, addr, sizeof(target), processor, cia); } #endif /* HAVE_TERMIO_STRUCTURE */ #ifdef HAVE_TERMIOS_STRUCTURE /* Convert to/from host termios structure */ typedef uint32_t linux_tcflag_t; typedef uint8_t linux_cc_t; typedef uint32_t linux_speed_t; struct linux_termios { linux_tcflag_t c_iflag; linux_tcflag_t c_oflag; linux_tcflag_t c_cflag; linux_tcflag_t c_lflag; linux_cc_t c_cc[LINUX_NCCS]; linux_cc_t c_line; int32_t c_ispeed; int32_t c_ospeed; }; STATIC_INLINE_EMUL_UNIX void convert_to_linux_termios(unsigned_word addr, struct termios *host, cpu *processor, unsigned_word cia) { struct linux_termios target; int i; target.c_iflag = H2T_4 (host->c_iflag); target.c_oflag = H2T_4 (host->c_oflag); target.c_cflag = H2T_4 (host->c_cflag); target.c_lflag = H2T_4 (host->c_lflag); for (i = 0; i < LINUX_NCCS; i++) target.c_cc[i] = 0; #ifdef VINTR target.c_cc[LINUX_VINTR] = host->c_cc[VINTR]; #endif #ifdef VQUIT target.c_cc[LINUX_VQUIT] = host->c_cc[VQUIT]; #endif #ifdef VERASE target.c_cc[LINUX_VERASE] = host->c_cc[VERASE]; #endif #ifdef VKILL target.c_cc[LINUX_VKILL] = host->c_cc[VKILL]; #endif #ifdef VEOF target.c_cc[LINUX_VEOF] = host->c_cc[VEOF]; #endif #ifdef VEOL target.c_cc[LINUX_VEOL] = host->c_cc[VEOL]; #endif #ifdef VEOL2 target.c_cc[LINUX_VEOL2] = host->c_cc[VEOL2]; #endif #ifdef VSWTCH target.c_cc[LINUX_VSWTC] = host->c_cc[VSWTCH]; #endif #ifdef HAVE_TERMIOS_CLINE target.c_line = host->c_line; #else target.c_line = 0; #endif #ifdef HAVE_CFGETISPEED target.c_ispeed = cfgetispeed (host); #else target.c_ispeed = 0; #endif #ifdef HAVE_CFGETOSPEED target.c_ospeed = cfgetospeed (host); #else target.c_ospeed = 0; #endif emul_write_buffer(&target, addr, sizeof(target), processor, cia); } #endif /* HAVE_TERMIOS_STRUCTURE */ #ifndef HAVE_IOCTL #define do_linux_ioctl 0 #else static void do_linux_ioctl(os_emul_data *emul, unsigned call, const int arg0, cpu *processor, unsigned_word cia) { int fildes = cpu_registers(processor)->gpr[arg0]; unsigned request = cpu_registers(processor)->gpr[arg0+1]; unsigned_word argp_addr = cpu_registers(processor)->gpr[arg0+2]; int status = 0; const char *name = ""; #ifdef HAVE_TERMIOS_STRUCTURE struct termios host_termio; #else #ifdef HAVE_TERMIO_STRUCTURE struct termio host_termio; #endif #endif status = fdbad (fildes); if (status != 0) goto done; switch (request) { case 0: /* make sure we have at least one case */ default: status = -1; errno = EINVAL; break; #if defined(HAVE_TERMIO_STRUCTURE) || defined(HAVE_TERMIOS_STRUCTURE) #if defined(TCGETA) || defined(TCGETS) || defined(HAVE_TCGETATTR) case LINUX_IOR('t', 23, struct linux_termio): /* TCGETA */ name = "TCGETA"; #ifdef HAVE_TCGETATTR status = tcgetattr(fildes, &host_termio); #elif defined(TCGETS) status = ioctl (fildes, TCGETS, &host_termio); #else status = ioctl (fildes, TCGETA, &host_termio); #endif if (status == 0) convert_to_linux_termio (argp_addr, &host_termio, processor, cia); break; #endif /* TCGETA */ #endif /* HAVE_TERMIO_STRUCTURE */ #ifdef HAVE_TERMIOS_STRUCTURE #if defined(TCGETS) || defined(HAVE_TCGETATTR) case LINUX_IOR('t', 19, struct linux_termios): /* TCGETS */ name = "TCGETS"; #ifdef HAVE_TCGETATTR status = tcgetattr(fildes, &host_termio); #else status = ioctl (fildes, TCGETS, &host_termio); #endif if (status == 0) convert_to_linux_termios (argp_addr, &host_termio, processor, cia); break; #endif /* TCGETS */ #endif /* HAVE_TERMIOS_STRUCTURE */ } done: emul_write_status(processor, status, errno); if (WITH_TRACE && ppc_trace[trace_os_emul]) printf_filtered ("%d, 0x%x [%s], 0x%lx", fildes, request, name, (long)argp_addr); } #endif /* HAVE_IOCTL */ static emul_syscall_descriptor linux_descriptors[] = { /* 0 */ { 0, "setup" }, /* 1 */ { do_unix_exit, "exit" }, /* 2 */ { 0, "fork" }, /* 3 */ { do_unix_read, "read" }, /* 4 */ { do_unix_write, "write" }, /* 5 */ { do_unix_open, "open" }, /* 6 */ { do_unix_close, "close" }, /* 7 */ { 0, "waitpid" }, /* 8 */ { 0, "creat" }, /* 9 */ { do_unix_link, "link" }, /* 10 */ { do_unix_unlink, "unlink" }, /* 11 */ { 0, "execve" }, /* 12 */ { do_unix_chdir, "chdir" }, /* 13 */ { do_unix_time, "time" }, /* 14 */ { 0, "mknod" }, /* 15 */ { 0, "chmod" }, /* 16 */ { 0, "chown" }, /* 17 */ { 0, "break" }, /* 18 */ { 0, "stat" }, /* 19 */ { do_unix_lseek, "lseek" }, /* 20 */ { do_unix_getpid, "getpid" }, /* 21 */ { 0, "mount" }, /* 22 */ { 0, "umount" }, /* 23 */ { 0, "setuid" }, /* 24 */ { do_unix_getuid, "getuid" }, /* 25 */ { 0, "stime" }, /* 26 */ { 0, "ptrace" }, /* 27 */ { 0, "alarm" }, /* 28 */ { 0, "fstat" }, /* 29 */ { 0, "pause" }, /* 30 */ { 0, "utime" }, /* 31 */ { 0, "stty" }, /* 32 */ { 0, "gtty" }, /* 33 */ { do_unix_access, "access" }, /* 34 */ { 0, "nice" }, /* 35 */ { 0, "ftime" }, /* 36 */ { 0, "sync" }, /* 37 */ { 0, "kill" }, /* 38 */ { 0, "rename" }, /* 39 */ { do_unix_mkdir, "mkdir" }, /* 40 */ { do_unix_rmdir, "rmdir" }, /* 41 */ { do_unix_dup, "dup" }, /* 42 */ { 0, "pipe" }, /* 43 */ { 0, "times" }, /* 44 */ { 0, "prof" }, /* 45 */ { do_unix_break, "brk" }, /* 46 */ { 0, "setgid" }, /* 47 */ { do_unix_getgid, "getgid" }, /* 48 */ { 0, "signal" }, /* 49 */ { do_unix_geteuid, "geteuid" }, /* 50 */ { do_unix_getegid, "getegid" }, /* 51 */ { 0, "acct" }, /* 52 */ { 0, "phys" }, /* 53 */ { 0, "lock" }, /* 54 */ { do_linux_ioctl, "ioctl" }, /* 55 */ { 0, "fcntl" }, /* 56 */ { 0, "mpx" }, /* 57 */ { 0, "setpgid" }, /* 58 */ { 0, "ulimit" }, /* 59 */ { 0, "olduname" }, /* 60 */ { do_unix_umask, "umask" }, /* 61 */ { 0, "chroot" }, /* 62 */ { 0, "ustat" }, /* 63 */ { do_unix_dup2, "dup2" }, /* 64 */ { do_unix_getppid, "getppid" }, /* 65 */ { 0, "getpgrp" }, /* 66 */ { 0, "setsid" }, /* 67 */ { 0, "sigaction" }, /* 68 */ { 0, "sgetmask" }, /* 69 */ { 0, "ssetmask" }, /* 70 */ { 0, "setreuid" }, /* 71 */ { 0, "setregid" }, /* 72 */ { 0, "sigsuspend" }, /* 73 */ { 0, "sigpending" }, /* 74 */ { 0, "sethostname" }, /* 75 */ { 0, "setrlimit" }, /* 76 */ { 0, "getrlimit" }, /* 77 */ { do_unix_getrusage, "getrusage" }, /* 78 */ { do_unix_gettimeofday, "gettimeofday" }, /* 79 */ { 0, "settimeofday" }, /* 80 */ { 0, "getgroups" }, /* 81 */ { 0, "setgroups" }, /* 82 */ { 0, "select" }, /* 83 */ { do_unix_symlink, "symlink" }, /* 84 */ { 0, "lstat" }, /* 85 */ { 0, "readlink" }, /* 86 */ { 0, "uselib" }, /* 87 */ { 0, "swapon" }, /* 88 */ { 0, "reboot" }, /* 89 */ { 0, "readdir" }, /* 90 */ { 0, "mmap" }, /* 91 */ { 0, "munmap" }, /* 92 */ { 0, "truncate" }, /* 93 */ { 0, "ftruncate" }, /* 94 */ { 0, "fchmod" }, /* 95 */ { 0, "fchown" }, /* 96 */ { 0, "getpriority" }, /* 97 */ { 0, "setpriority" }, /* 98 */ { 0, "profil" }, /* 99 */ { 0, "statfs" }, /* 100 */ { 0, "fstatfs" }, /* 101 */ { 0, "ioperm" }, /* 102 */ { 0, "socketcall" }, /* 103 */ { 0, "syslog" }, /* 104 */ { 0, "setitimer" }, /* 105 */ { 0, "getitimer" }, /* 106 */ { do_linux_stat, "newstat" }, /* 107 */ { do_linux_lstat, "newlstat" }, /* 108 */ { do_linux_fstat, "newfstat" }, /* 109 */ { 0, "uname" }, /* 110 */ { 0, "iopl" }, /* 111 */ { 0, "vhangup" }, /* 112 */ { 0, "idle" }, /* 113 */ { 0, "vm86" }, /* 114 */ { 0, "wait4" }, /* 115 */ { 0, "swapoff" }, /* 116 */ { 0, "sysinfo" }, /* 117 */ { 0, "ipc" }, /* 118 */ { 0, "fsync" }, /* 119 */ { 0, "sigreturn" }, /* 120 */ { 0, "clone" }, /* 121 */ { 0, "setdomainname" }, /* 122 */ { 0, "newuname" }, /* 123 */ { 0, "modify_ldt" }, /* 124 */ { 0, "adjtimex" }, /* 125 */ { 0, "mprotect" }, /* 126 */ { 0, "sigprocmask" }, /* 127 */ { 0, "create_module" }, /* 128 */ { 0, "init_module" }, /* 129 */ { 0, "delete_module" }, /* 130 */ { 0, "get_kernel_syms" }, /* 131 */ { 0, "quotactl" }, /* 132 */ { 0, "getpgid" }, /* 133 */ { 0, "fchdir" }, /* 134 */ { 0, "bdflush" }, /* 135 */ { 0, "sysfs" }, /* 136 */ { 0, "personality" }, /* 137 */ { 0, "afs_syscall" }, /* 138 */ { 0, "setfsuid" }, /* 139 */ { 0, "setfsgid" }, /* 140 */ { 0, "llseek" }, /* 141 */ { 0, "getdents" }, /* 142 */ { 0, "newselect" }, /* 143 */ { 0, "flock" }, /* 144 */ { 0, "msync" }, /* 145 */ { 0, "readv" }, /* 146 */ { 0, "writev" }, /* 147 */ { 0, "getsid" }, /* 148 */ { 0, "fdatasync" }, /* 149 */ { 0, "sysctl" }, /* 150 */ { 0, "mlock" }, /* 151 */ { 0, "munlock" }, /* 152 */ { 0, "mlockall" }, /* 153 */ { 0, "munlockall" }, /* 154 */ { 0, "sched_setparam" }, /* 155 */ { 0, "sched_getparam" }, /* 156 */ { 0, "sched_setscheduler" }, /* 157 */ { 0, "sched_getscheduler" }, /* 158 */ { 0, "sched_yield" }, /* 159 */ { 0, "sched_get_priority_max" }, /* 160 */ { 0, "sched_get_priority_min" }, /* 161 */ { 0, "sched_rr_get_interval" }, }; static char *(linux_error_names[]) = { /* 0 */ "ESUCCESS", /* 1 */ "EPERM", /* 2 */ "ENOENT", /* 3 */ "ESRCH", /* 4 */ "EINTR", /* 5 */ "EIO", /* 6 */ "ENXIO", /* 7 */ "E2BIG", /* 8 */ "ENOEXEC", /* 9 */ "EBADF", /* 10 */ "ECHILD", /* 11 */ "EAGAIN", /* 12 */ "ENOMEM", /* 13 */ "EACCES", /* 14 */ "EFAULT", /* 15 */ "ENOTBLK", /* 16 */ "EBUSY", /* 17 */ "EEXIST", /* 18 */ "EXDEV", /* 19 */ "ENODEV", /* 20 */ "ENOTDIR", /* 21 */ "EISDIR", /* 22 */ "EINVAL", /* 23 */ "ENFILE", /* 24 */ "EMFILE", /* 25 */ "ENOTTY", /* 26 */ "ETXTBSY", /* 27 */ "EFBIG", /* 28 */ "ENOSPC", /* 29 */ "ESPIPE", /* 30 */ "EROFS", /* 31 */ "EMLINK", /* 32 */ "EPIPE", /* 33 */ "EDOM", /* 34 */ "ERANGE", /* 35 */ "EDEADLK", /* 36 */ "ENAMETOOLONG", /* 37 */ "ENOLCK", /* 38 */ "ENOSYS", /* 39 */ "ENOTEMPTY", /* 40 */ "ELOOP", /* 41 */ 0, /* 42 */ "ENOMSG", /* 43 */ "EIDRM", /* 44 */ "ECHRNG", /* 45 */ "EL2NSYNC", /* 46 */ "EL3HLT", /* 47 */ "EL3RST", /* 48 */ "ELNRNG", /* 49 */ "EUNATCH", /* 50 */ "ENOCSI", /* 51 */ "EL2HLT", /* 52 */ "EBADE", /* 53 */ "EBADR", /* 54 */ "EXFULL", /* 55 */ "ENOANO", /* 56 */ "EBADRQC", /* 57 */ "EBADSLT", /* 58 */ "EDEADLOCK", /* 59 */ "EBFONT", /* 60 */ "ENOSTR", /* 61 */ "ENODATA", /* 62 */ "ETIME", /* 63 */ "ENOSR", /* 64 */ "ENONET", /* 65 */ "ENOPKG", /* 66 */ "EREMOTE", /* 67 */ "ENOLINK", /* 68 */ "EADV", /* 69 */ "ESRMNT", /* 70 */ "ECOMM", /* 71 */ "EPROTO", /* 72 */ "EMULTIHOP", /* 73 */ "EDOTDOT", /* 74 */ "EBADMSG", /* 75 */ "EOVERFLOW", /* 76 */ "ENOTUNIQ", /* 77 */ "EBADFD", /* 78 */ "EREMCHG", /* 79 */ "ELIBACC", /* 80 */ "ELIBBAD", /* 81 */ "ELIBSCN", /* 82 */ "ELIBMAX", /* 83 */ "ELIBEXEC", /* 84 */ "EILSEQ", /* 85 */ "ERESTART", /* 86 */ "ESTRPIPE", /* 87 */ "EUSERS", /* 88 */ "ENOTSOCK", /* 89 */ "EDESTADDRREQ", /* 90 */ "EMSGSIZE", /* 91 */ "EPROTOTYPE", /* 92 */ "ENOPROTOOPT", /* 93 */ "EPROTONOSUPPORT", /* 94 */ "ESOCKTNOSUPPORT", /* 95 */ "EOPNOTSUPP", /* 96 */ "EPFNOSUPPORT", /* 97 */ "EAFNOSUPPORT", /* 98 */ "EADDRINUSE", /* 99 */ "EADDRNOTAVAIL", /* 100 */ "ENETDOWN", /* 101 */ "ENETUNREACH", /* 102 */ "ENETRESET", /* 103 */ "ECONNABORTED", /* 104 */ "ECONNRESET", /* 105 */ "ENOBUFS", /* 106 */ "EISCONN", /* 107 */ "ENOTCONN", /* 108 */ "ESHUTDOWN", /* 109 */ "ETOOMANYREFS", /* 110 */ "ETIMEDOUT", /* 111 */ "ECONNREFUSED", /* 112 */ "EHOSTDOWN", /* 113 */ "EHOSTUNREACH", /* 114 */ "EALREADY", /* 115 */ "EINPROGRESS", /* 116 */ "ESTALE", /* 117 */ "EUCLEAN", /* 118 */ "ENOTNAM", /* 119 */ "ENAVAIL", /* 120 */ "EISNAM", /* 121 */ "EREMOTEIO", /* 122 */ "EDQUOT", }; static char *(linux_signal_names[]) = { /* 0 */ 0, /* 1 */ "SIGHUP", /* 2 */ "SIGINT", /* 3 */ "SIGQUIT", /* 4 */ "SIGILL", /* 5 */ "SIGTRAP", /* 6 */ "SIGABRT", /* 6 */ "SIGIOT", /* 7 */ "SIGBUS", /* 8 */ "SIGFPE", /* 9 */ "SIGKILL", /* 10 */ "SIGUSR1", /* 11 */ "SIGSEGV", /* 12 */ "SIGUSR2", /* 13 */ "SIGPIPE", /* 14 */ "SIGALRM", /* 15 */ "SIGTERM", /* 16 */ "SIGSTKFLT", /* 17 */ "SIGCHLD", /* 18 */ "SIGCONT", /* 19 */ "SIGSTOP", /* 20 */ "SIGTSTP", /* 21 */ "SIGTTIN", /* 22 */ "SIGTTOU", /* 23 */ "SIGURG", /* 24 */ "SIGXCPU", /* 25 */ "SIGXFSZ", /* 26 */ "SIGVTALRM", /* 27 */ "SIGPROF", /* 28 */ "SIGWINCH", /* 29 */ "SIGIO", /* 30 */ "SIGPWR", /* 31 */ "SIGUNUSED", }; static emul_syscall emul_linux_syscalls = { linux_descriptors, ARRAY_SIZE (linux_descriptors), linux_error_names, ARRAY_SIZE (linux_error_names), linux_signal_names, ARRAY_SIZE (linux_signal_names), }; /* Linux's os_emul interface, most are just passed on to the generic syscall stuff */ static os_emul_data * emul_linux_create(device *root, bfd *image, const char *name) { /* check that this emulation is really for us */ if (name != NULL && strcmp(name, "linux") != 0) return NULL; if (image == NULL) return NULL; return emul_unix_create(root, image, "linux", &emul_linux_syscalls); } static void emul_linux_init(os_emul_data *emul_data, int nr_cpus) { fd_closed[0] = 0; fd_closed[1] = 0; fd_closed[2] = 0; } static void emul_linux_system_call(cpu *processor, unsigned_word cia, os_emul_data *emul_data) { emul_do_system_call(emul_data, emul_data->syscalls, cpu_registers(processor)->gpr[0], 3, /*r3 contains arg0*/ processor, cia); } const os_emul emul_linux = { "linux", emul_linux_create, emul_linux_init, emul_linux_system_call, 0, /*instruction_call*/ 0 /*data*/ }; #endif /* _EMUL_UNIX_C_ */