From 9984b2bd6ccee7e24843236315c19f0f0c83f685 Mon Sep 17 00:00:00 2001 From: Steve Reinhardt Date: Mon, 1 Dec 2003 22:39:27 -0800 Subject: Formatting & doxygen docs for new syscall emulation code. arch/alpha/alpha_linux_process.cc: arch/alpha/alpha_linux_process.hh: arch/alpha/alpha_tru64_process.cc: arch/alpha/alpha_tru64_process.hh: sim/syscall_emul.cc: sim/syscall_emul.hh: Formatting & doxygen. --HG-- extra : convert_revision : 4f07dd37e254120800dd0d5c0eb47acc9c00cb3f --- arch/alpha/alpha_linux_process.cc | 588 +++++----- arch/alpha/alpha_linux_process.hh | 4 + arch/alpha/alpha_tru64_process.cc | 2202 ++++++++++++++++++------------------- arch/alpha/alpha_tru64_process.hh | 3 + 4 files changed, 1392 insertions(+), 1405 deletions(-) (limited to 'arch/alpha') diff --git a/arch/alpha/alpha_linux_process.cc b/arch/alpha/alpha_linux_process.cc index 13d1f5366..d8a05849d 100644 --- a/arch/alpha/alpha_linux_process.cc +++ b/arch/alpha/alpha_linux_process.cc @@ -52,327 +52,326 @@ using namespace std; +/// +/// This class encapsulates the types, structures, constants, +/// functions, and syscall-number mappings specific to the Alpha Linux +/// syscall interface. +/// class Linux { -public: - -// -// basic Linux types -// - -typedef uint64_t size_t; -typedef uint64_t off_t; -typedef int64_t time_t; -typedef uint32_t uid_t; -typedef uint32_t gid_t; - -// open(2) flags -static const int TGT_O_RDONLY = 00000000; -static const int TGT_O_WRONLY = 00000001; -static const int TGT_O_RDWR = 00000002; -static const int TGT_O_NONBLOCK = 00000004; -static const int TGT_O_APPEND = 00000010; -static const int TGT_O_CREAT = 00001000; -static const int TGT_O_TRUNC = 00002000; -static const int TGT_O_EXCL = 00004000; -static const int TGT_O_NOCTTY = 00010000; -static const int TGT_O_SYNC = 00040000; -static const int TGT_O_DRD = 00100000; -static const int TGT_O_DIRECTIO = 00200000; -static const int TGT_O_CACHE = 00400000; -static const int TGT_O_DSYNC = 02000000; -static const int TGT_O_RSYNC = 04000000; - -static OpenFlagTransTable openFlagTable[]; -static const int NUM_OPEN_FLAGS; - -// -// Stat buffer. -// - -struct tgt_stat { - uint32_t st_dev; - uint32_t st_ino; - uint32_t st_mode; - uint32_t st_nlink; - uint32_t st_uid; - uint32_t st_gid; - uint32_t st_rdev; - int64_t st_size; - uint64_t st_atimeX; - uint64_t st_mtimeX; - uint64_t st_ctimeX; - uint32_t st_blksize; - int32_t st_blocks; - uint32_t st_flags; - uint32_t st_gen; -}; - - -// -// for uname() -// - -static const int _SYS_NMLN = 65; - -struct utsname { - char sysname[_SYS_NMLN]; - char nodename[_SYS_NMLN]; - char release[_SYS_NMLN]; - char version[_SYS_NMLN]; - char machine[_SYS_NMLN]; -}; - - -// -// for ioctl() -// - -static const unsigned TIOCGETP = 0x40067408; -static const unsigned TIOCSETP = 0x80067409; -static const unsigned TIOCSETN = 0x8006740a; -static const unsigned TIOCSETC = 0x80067411; -static const unsigned TIOCGETC = 0x40067412; -static const unsigned FIONREAD = 0x4004667f; -static const unsigned TIOCISATTY = 0x2000745e; - -// -// for getrlimit() -// - -enum rlimit_resources { - RLIMIT_CPU = 0, - RLIMIT_FSIZE = 1, - RLIMIT_DATA = 2, - RLIMIT_STACK = 3, - RLIMIT_CORE = 4, - RLIMIT_RSS = 5, - RLIMIT_NOFILE = 6, - RLIMIT_AS = 7, - RLIMIT_VMEM = 7, - RLIMIT_NPROC = 8, - RLIMIT_MEMLOCK = 9, - RLIMIT_LOCKS = 10 -}; - -struct rlimit { - uint64_t rlim_cur; // soft limit - uint64_t rlim_max; // hard limit -}; - - -// -// for mmap() -// + public: + + //@{ + /// Basic Linux types. + typedef uint64_t size_t; + typedef uint64_t off_t; + typedef int64_t time_t; + typedef uint32_t uid_t; + typedef uint32_t gid_t; + //@} + + //@{ + /// open(2) flag values. + static const int TGT_O_RDONLY = 00000000; //!< O_RDONLY + static const int TGT_O_WRONLY = 00000001; //!< O_WRONLY + static const int TGT_O_RDWR = 00000002; //!< O_RDWR + static const int TGT_O_NONBLOCK = 00000004; //!< O_NONBLOCK + static const int TGT_O_APPEND = 00000010; //!< O_APPEND + static const int TGT_O_CREAT = 00001000; //!< O_CREAT + static const int TGT_O_TRUNC = 00002000; //!< O_TRUNC + static const int TGT_O_EXCL = 00004000; //!< O_EXCL + static const int TGT_O_NOCTTY = 00010000; //!< O_NOCTTY + static const int TGT_O_SYNC = 00040000; //!< O_SYNC + static const int TGT_O_DRD = 00100000; //!< O_DRD + static const int TGT_O_DIRECTIO = 00200000; //!< O_DIRECTIO + static const int TGT_O_CACHE = 00400000; //!< O_CACHE + static const int TGT_O_DSYNC = 02000000; //!< O_DSYNC + static const int TGT_O_RSYNC = 04000000; //!< O_RSYNC + //@} + + /// This table maps the target open() flags to the corresponding + /// host open() flags. + static OpenFlagTransTable openFlagTable[]; + + /// Number of entries in openFlagTable[]. + static const int NUM_OPEN_FLAGS; + + /// Stat buffer. Note that we can't call it 'stat' since that + /// gets #defined to something else on some systems. + struct tgt_stat { + uint32_t st_dev; //!< device + uint32_t st_ino; //!< inode + uint32_t st_mode; //!< mode + uint32_t st_nlink; //!< link count + uint32_t st_uid; //!< owner's user ID + uint32_t st_gid; //!< owner's group ID + uint32_t st_rdev; //!< device number + int64_t st_size; //!< file size in bytes + uint64_t st_atimeX; //!< time of last access + uint64_t st_mtimeX; //!< time of last modification + uint64_t st_ctimeX; //!< time of last status change + uint32_t st_blksize; //!< optimal I/O block size + int32_t st_blocks; //!< number of blocks allocated + uint32_t st_flags; //!< flags + uint32_t st_gen; //!< unknown + }; + + + /// Length of strings in struct utsname (plus 1 for null char). + static const int _SYS_NMLN = 65; + + /// Interface struct for uname(). + struct utsname { + char sysname[_SYS_NMLN]; //!< System name. + char nodename[_SYS_NMLN]; //!< Node name. + char release[_SYS_NMLN]; //!< OS release. + char version[_SYS_NMLN]; //!< OS version. + char machine[_SYS_NMLN]; //!< Machine type. + }; + + + //@{ + /// ioctl() command codes. + static const unsigned TIOCGETP = 0x40067408; + static const unsigned TIOCSETP = 0x80067409; + static const unsigned TIOCSETN = 0x8006740a; + static const unsigned TIOCSETC = 0x80067411; + static const unsigned TIOCGETC = 0x40067412; + static const unsigned FIONREAD = 0x4004667f; + static const unsigned TIOCISATTY = 0x2000745e; + //@} + + /// Resource enumeration for getrlimit(). + enum rlimit_resources { + RLIMIT_CPU = 0, + RLIMIT_FSIZE = 1, + RLIMIT_DATA = 2, + RLIMIT_STACK = 3, + RLIMIT_CORE = 4, + RLIMIT_RSS = 5, + RLIMIT_NOFILE = 6, + RLIMIT_AS = 7, + RLIMIT_VMEM = 7, + RLIMIT_NPROC = 8, + RLIMIT_MEMLOCK = 9, + RLIMIT_LOCKS = 10 + }; + + /// Limit struct for getrlimit/setrlimit. + struct rlimit { + uint64_t rlim_cur; //!< soft limit + uint64_t rlim_max; //!< hard limit + }; + + + /// For mmap(). static const unsigned TGT_MAP_ANONYMOUS = 0x10; -// -// for gettimeofday -// - -struct timeval { - int64_t tv_sec; - int64_t tv_usec; -}; - -// -// for getrusage -// - - -static const int RUSAGE_SELF = 0; -static const int RUSAGE_CHILDREN = -1; -static const int RUSAGE_BOTH = -2; - -struct rusage { - struct timeval ru_utime; // user time used - struct timeval ru_stime; // system time used - int64_t ru_maxrss; - int64_t ru_ixrss; // integral shared memory size - int64_t ru_idrss; // integral unshared data " - int64_t ru_isrss; // integral unshared stack " - int64_t ru_minflt; // page reclaims - total vmfaults - int64_t ru_majflt; // page faults - int64_t ru_nswap; // swaps - int64_t ru_inblock; // block input operations - int64_t ru_oublock; // block output operations - int64_t ru_msgsnd; // messages sent - int64_t ru_msgrcv; // messages received - int64_t ru_nsignals; // signals received - int64_t ru_nvcsw; // voluntary context switches - int64_t ru_nivcsw; // involuntary " -}; - -static -void -copyOutStatBuf(FunctionalMemory *mem, Addr addr, struct stat *host) -{ - TypedBufferArg tgt(addr); - - tgt->st_dev = host->st_dev; - tgt->st_ino = host->st_ino; - tgt->st_mode = host->st_mode; - tgt->st_nlink = host->st_nlink; - tgt->st_uid = host->st_uid; - tgt->st_gid = host->st_gid; - tgt->st_rdev = host->st_rdev; - tgt->st_size = host->st_size; - tgt->st_atimeX = host->st_atime; - tgt->st_mtimeX = host->st_mtime; - tgt->st_ctimeX = host->st_ctime; - tgt->st_blksize = host->st_blksize; - tgt->st_blocks = host->st_blocks; - - tgt.copyOut(mem); -} - - -static const char *hostname; - -static -int -unameFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - TypedBufferArg name(xc->getSyscallArg(0)); - - strcpy(name->sysname, "Linux"); - strcpy(name->nodename, hostname); - strcpy(name->release, "2.4.20"); - strcpy(name->version, "#1 Mon Aug 18 11:32:15 EDT 2003"); - strcpy(name->machine, "alpha"); - - name.copyOut(xc->mem); - return 0; -} - - -static -int -osf_getsysinfoFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - unsigned op = xc->getSyscallArg(0); - // unsigned nbytes = xc->getSyscallArg(2); - - switch (op) { - - case 45: { // GSI_IEEE_FP_CONTROL - TypedBufferArg fpcr(xc->getSyscallArg(1)); - // I don't think this exactly matches the HW FPCR - *fpcr = 0; - fpcr.copyOut(xc->mem); - return 1; - } - - default: - cerr << "osf_getsysinfo: unknown op " << op << endl; - abort(); - break; + /// For gettimeofday(). + struct timeval { + int64_t tv_sec; //!< seconds + int64_t tv_usec; //!< microseconds + }; + + //@{ + /// For getrusage(). + static const int RUSAGE_SELF = 0; + static const int RUSAGE_CHILDREN = -1; + static const int RUSAGE_BOTH = -2; + //@} + + /// For getrusage(). + struct rusage { + struct timeval ru_utime; //!< user time used + struct timeval ru_stime; //!< system time used + int64_t ru_maxrss; //!< max rss + int64_t ru_ixrss; //!< integral shared memory size + int64_t ru_idrss; //!< integral unshared data " + int64_t ru_isrss; //!< integral unshared stack " + int64_t ru_minflt; //!< page reclaims - total vmfaults + int64_t ru_majflt; //!< page faults + int64_t ru_nswap; //!< swaps + int64_t ru_inblock; //!< block input operations + int64_t ru_oublock; //!< block output operations + int64_t ru_msgsnd; //!< messages sent + int64_t ru_msgrcv; //!< messages received + int64_t ru_nsignals; //!< signals received + int64_t ru_nvcsw; //!< voluntary context switches + int64_t ru_nivcsw; //!< involuntary " + }; + + /// Helper function to convert a host stat buffer to a target stat + /// buffer. Also copies the target buffer out to the simulated + /// memorty space. Used by stat(), fstat(), and lstat(). + static void + copyOutStatBuf(FunctionalMemory *mem, Addr addr, struct stat *host) + { + TypedBufferArg tgt(addr); + + tgt->st_dev = host->st_dev; + tgt->st_ino = host->st_ino; + tgt->st_mode = host->st_mode; + tgt->st_nlink = host->st_nlink; + tgt->st_uid = host->st_uid; + tgt->st_gid = host->st_gid; + tgt->st_rdev = host->st_rdev; + tgt->st_size = host->st_size; + tgt->st_atimeX = host->st_atime; + tgt->st_mtimeX = host->st_mtime; + tgt->st_ctimeX = host->st_ctime; + tgt->st_blksize = host->st_blksize; + tgt->st_blocks = host->st_blocks; + + tgt.copyOut(mem); } - return 0; -} + /// The target system's hostname. + static const char *hostname; + /// Target uname() handler. + static int + unameFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) + { + TypedBufferArg name(xc->getSyscallArg(0)); -static -int -osf_setsysinfoFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - unsigned op = xc->getSyscallArg(0); - // unsigned nbytes = xc->getSyscallArg(2); - - switch (op) { - - case 14: { // SSI_IEEE_FP_CONTROL - TypedBufferArg fpcr(xc->getSyscallArg(1)); - // I don't think this exactly matches the HW FPCR - fpcr.copyIn(xc->mem); - DPRINTFR(SyscallVerbose, "osf_setsysinfo(SSI_IEEE_FP_CONTROL): " - " setting FPCR to 0x%x\n", *(uint64_t*)fpcr); - return 1; - } - - default: - cerr << "osf_getsysinfo: unknown op " << op << endl; - abort(); - break; - } - - return 0; -} - - -static -int -fcntlFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - int fd = xc->getSyscallArg(0); + strcpy(name->sysname, "Linux"); + strcpy(name->nodename, hostname); + strcpy(name->release, "2.4.20"); + strcpy(name->version, "#1 Mon Aug 18 11:32:15 EDT 2003"); + strcpy(name->machine, "alpha"); - if (fd < 0 || process->sim_fd(fd) < 0) - return -EBADF; + name.copyOut(xc->mem); + return 0; + } - int cmd = xc->getSyscallArg(1); - switch (cmd) { - case 0: // F_DUPFD - // if we really wanted to support this, we'd need to do it - // in the target fd space. - warn("fcntl(%d, F_DUPFD) not supported, error returned\n", fd); - return -EMFILE; + /// Target osf_getsysyinfo() handler. Even though this call is + /// borrowed from Tru64, the subcases that get used appear to be + /// different in practice from those used by Tru64 processes. + static int + osf_getsysinfoFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) + { + unsigned op = xc->getSyscallArg(0); + // unsigned nbytes = xc->getSyscallArg(2); + + switch (op) { + + case 45: { // GSI_IEEE_FP_CONTROL + TypedBufferArg fpcr(xc->getSyscallArg(1)); + // I don't think this exactly matches the HW FPCR + *fpcr = 0; + fpcr.copyOut(xc->mem); + return 1; + } + + default: + cerr << "osf_getsysinfo: unknown op " << op << endl; + abort(); + break; + } - case 1: // F_GETFD (get close-on-exec flag) - case 2: // F_SETFD (set close-on-exec flag) return 0; + } - case 3: // F_GETFL (get file flags) - case 4: // F_SETFL (set file flags) - // not sure if this is totally valid, but we'll pass it through - // to the underlying OS - warn("fcntl(%d, %d) passed through to host\n", fd, cmd); - return fcntl(process->sim_fd(fd), cmd); - // return 0; - - case 7: // F_GETLK (get lock) - case 8: // F_SETLK (set lock) - case 9: // F_SETLKW (set lock and wait) - // don't mess with file locking... just act like it's OK - warn("File lock call (fcntl(%d, %d)) ignored.\n", fd, cmd); - return 0; + /// Target osf_setsysinfo() handler. + static int + osf_setsysinfoFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) + { + unsigned op = xc->getSyscallArg(0); + // unsigned nbytes = xc->getSyscallArg(2); + + switch (op) { + + case 14: { // SSI_IEEE_FP_CONTROL + TypedBufferArg fpcr(xc->getSyscallArg(1)); + // I don't think this exactly matches the HW FPCR + fpcr.copyIn(xc->mem); + DPRINTFR(SyscallVerbose, "osf_setsysinfo(SSI_IEEE_FP_CONTROL): " + " setting FPCR to 0x%x\n", *(uint64_t*)fpcr); + return 1; + } + + default: + cerr << "osf_getsysinfo: unknown op " << op << endl; + abort(); + break; + } - default: - warn("Unknown fcntl command %d\n", cmd); return 0; } -} - -static SyscallDesc syscallDescs[]; -static const int Num_Syscall_Descs; + /// Target fnctl() handler. + static int + fcntlFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) + { + int fd = xc->getSyscallArg(0); + + if (fd < 0 || process->sim_fd(fd) < 0) + return -EBADF; + + int cmd = xc->getSyscallArg(1); + switch (cmd) { + case 0: // F_DUPFD + // if we really wanted to support this, we'd need to do it + // in the target fd space. + warn("fcntl(%d, F_DUPFD) not supported, error returned\n", fd); + return -EMFILE; + + case 1: // F_GETFD (get close-on-exec flag) + case 2: // F_SETFD (set close-on-exec flag) + return 0; + + case 3: // F_GETFL (get file flags) + case 4: // F_SETFL (set file flags) + // not sure if this is totally valid, but we'll pass it through + // to the underlying OS + warn("fcntl(%d, %d) passed through to host\n", fd, cmd); + return fcntl(process->sim_fd(fd), cmd); + // return 0; + + case 7: // F_GETLK (get lock) + case 8: // F_SETLK (set lock) + case 9: // F_SETLKW (set lock and wait) + // don't mess with file locking... just act like it's OK + warn("File lock call (fcntl(%d, %d)) ignored.\n", fd, cmd); + return 0; + + default: + warn("Unknown fcntl command %d\n", cmd); + return 0; + } + } -static const int Max_Syscall_Desc; + /// Array of syscall descriptors, indexed by call number. + static SyscallDesc syscallDescs[]; -static -void -doSyscall(int callnum, Process *process, ExecContext *xc) -{ - if (callnum < 0 || callnum > Max_Syscall_Desc) { - fatal("Syscall %d out of range", callnum); - } + /// Number of syscalls in syscallDescs[]. + static const int Num_Syscall_Descs; - SyscallDesc *desc = &syscallDescs[callnum]; + /// Max supported syscall number. + static const int Max_Syscall_Desc; - desc->doSyscall(callnum, process, xc); -} + /// Do the specified syscall. Just looks the call number up in + /// the table and invokes the appropriate handler. + static void + doSyscall(int callnum, Process *process, ExecContext *xc) + { + if (callnum < 0 || callnum > Max_Syscall_Desc) { + fatal("Syscall %d out of range", callnum); + } + SyscallDesc *desc = &syscallDescs[callnum]; + desc->doSyscall(callnum, process, xc); + } }; // class Linux // open(2) flags translation table OpenFlagTransTable Linux::openFlagTable[] = { - /* target flag */ /* host flag */ #ifdef _MSC_VER { Linux::TGT_O_RDONLY, _O_RDONLY }, { Linux::TGT_O_WRONLY, _O_WRONLY }, @@ -406,7 +405,8 @@ OpenFlagTransTable Linux::openFlagTable[] = { #endif /* _MSC_VER */ }; -const int Linux::NUM_OPEN_FLAGS = (sizeof(Linux::openFlagTable)/sizeof(Linux::openFlagTable[0])); +const int Linux::NUM_OPEN_FLAGS = + (sizeof(Linux::openFlagTable)/sizeof(Linux::openFlagTable[0])); const char *Linux::hostname = "m5.eecs.umich.edu"; diff --git a/arch/alpha/alpha_linux_process.hh b/arch/alpha/alpha_linux_process.hh index 0d2f7641f..4b8936192 100644 --- a/arch/alpha/alpha_linux_process.hh +++ b/arch/alpha/alpha_linux_process.hh @@ -31,15 +31,19 @@ #include "sim/process.hh" + +/// A process with emulated Alpha/Linux syscalls. class AlphaLinuxProcess : public LiveProcess { public: + /// Constructor. AlphaLinuxProcess(const std::string &name, ObjectFile *objFile, int stdin_fd, int stdout_fd, int stderr_fd, std::vector &argv, std::vector &envp); + /// Syscall emulation function. virtual void syscall(ExecContext *xc); }; diff --git a/arch/alpha/alpha_tru64_process.cc b/arch/alpha/alpha_tru64_process.cc index 85648e68c..aece4de5a 100644 --- a/arch/alpha/alpha_tru64_process.cc +++ b/arch/alpha/alpha_tru64_process.cc @@ -51,316 +51,299 @@ using namespace std; +/// +/// This class encapsulates the types, structures, constants, +/// functions, and syscall-number mappings specific to the Alpha Tru64 +/// syscall interface. +/// class Tru64 { -public: - -// -// basic Tru64 types -// - -typedef uint64_t size_t; -typedef uint64_t off_t; -typedef uint16_t nlink_t; -typedef int32_t dev_t; -typedef uint32_t uid_t; -typedef uint32_t gid_t; -typedef uint32_t time_t; -typedef uint32_t mode_t; -typedef uint32_t ino_t; - -// open(2) flags -static const int TGT_O_RDONLY = 00000000; -static const int TGT_O_WRONLY = 00000001; -static const int TGT_O_RDWR = 00000002; -static const int TGT_O_NONBLOCK = 00000004; -static const int TGT_O_APPEND = 00000010; -static const int TGT_O_CREAT = 00001000; -static const int TGT_O_TRUNC = 00002000; -static const int TGT_O_EXCL = 00004000; -static const int TGT_O_NOCTTY = 00010000; -static const int TGT_O_SYNC = 00040000; -static const int TGT_O_DRD = 00100000; -static const int TGT_O_DIRECTIO = 00200000; -static const int TGT_O_CACHE = 00400000; -static const int TGT_O_DSYNC = 02000000; -static const int TGT_O_RSYNC = 04000000; - -static OpenFlagTransTable openFlagTable[]; -static const int NUM_OPEN_FLAGS; - -// -// Stat buffer. Note that Tru64 v5.0+ use a new "F64" stat structure, -// and a new set of syscall numbers for stat calls. Backwards -// compatibility with v4.x should be feasible by implementing another -// set of stat functions using the old structure definition and -// binding them to the old syscall numbers, but we haven't done that -// yet. -// - -struct F64_stat { - dev_t st_dev; - int32_t st_retired1; - mode_t st_mode; - nlink_t st_nlink; - uint16_t st_nlink_reserved; - uid_t st_uid; - gid_t st_gid; - dev_t st_rdev; - dev_t st_ldev; - off_t st_size; - time_t st_retired2; - int32_t st_uatime; - time_t st_retired3; - int32_t st_umtime; - time_t st_retired4; - int32_t st_uctime; - int32_t st_retired5; - int32_t st_retired6; - uint32_t st_flags; - uint32_t st_gen; - uint64_t st_spare[4]; - ino_t st_ino; - int32_t st_ino_reserved; - time_t st_atimeX; - int32_t st_atime_reserved; - time_t st_mtimeX; - int32_t st_mtime_reserved; - time_t st_ctimeX; - int32_t st_ctime_reserved; - uint64_t st_blksize; - uint64_t st_blocks; -}; - - -// -// for getdirentries() -// - -struct dirent -{ - ino_t d_ino; /* file number of entry */ - uint16_t d_reclen; /* length of this record */ - uint16_t d_namlen; /* length of string in d_name */ - char d_name[256]; /* dummy name length */ -}; - - -// -// for uname() -// - -static const int _SYS_NMLN = 32; - -struct utsname { - char sysname[_SYS_NMLN]; - char nodename[_SYS_NMLN]; - char release[_SYS_NMLN]; - char version[_SYS_NMLN]; - char machine[_SYS_NMLN]; -}; - - -// -// for ioctl() -// - -static const unsigned TIOCGETP = 0x40067408; -static const unsigned TIOCSETP = 0x80067409; -static const unsigned TIOCSETN = 0x8006740a; -static const unsigned TIOCSETC = 0x80067411; -static const unsigned TIOCGETC = 0x40067412; -static const unsigned FIONREAD = 0x4004667f; -static const unsigned TIOCISATTY = 0x2000745e; - -// -// for getrlimit() -// - -enum rlimit_resources { - RLIMIT_CPU = 0, - RLIMIT_FSIZE = 1, - RLIMIT_DATA = 2, - RLIMIT_STACK = 3, - RLIMIT_CORE = 4, - RLIMIT_RSS = 5, - RLIMIT_NOFILE = 6, - RLIMIT_AS = 7, - RLIMIT_VMEM = 7 -}; - -struct rlimit { - uint64_t rlim_cur; // soft limit - uint64_t rlim_max; // hard limit -}; - - -// -// for mmap() -// + public: + + //@{ + /// Basic Tru64 types. + typedef uint64_t size_t; + typedef uint64_t off_t; + typedef uint16_t nlink_t; + typedef int32_t dev_t; + typedef uint32_t uid_t; + typedef uint32_t gid_t; + typedef uint32_t time_t; + typedef uint32_t mode_t; + typedef uint32_t ino_t; + //@} + + //@{ + /// open(2) flag values. + static const int TGT_O_RDONLY = 00000000; + static const int TGT_O_WRONLY = 00000001; + static const int TGT_O_RDWR = 00000002; + static const int TGT_O_NONBLOCK = 00000004; + static const int TGT_O_APPEND = 00000010; + static const int TGT_O_CREAT = 00001000; + static const int TGT_O_TRUNC = 00002000; + static const int TGT_O_EXCL = 00004000; + static const int TGT_O_NOCTTY = 00010000; + static const int TGT_O_SYNC = 00040000; + static const int TGT_O_DRD = 00100000; + static const int TGT_O_DIRECTIO = 00200000; + static const int TGT_O_CACHE = 00400000; + static const int TGT_O_DSYNC = 02000000; + static const int TGT_O_RSYNC = 04000000; + //@} + + /// This table maps the target open() flags to the corresponding + /// host open() flags. + static OpenFlagTransTable openFlagTable[]; + + /// Number of entries in openFlagTable[]. + static const int NUM_OPEN_FLAGS; + + /// Stat buffer. Note that Tru64 v5.0+ use a new "F64" stat structure, + /// and a new set of syscall numbers for stat calls. Backwards + /// compatibility with v4.x should be feasible by implementing + /// another set of stat functions using the old structure + /// definition and binding them to the old syscall numbers, but we + /// haven't done that yet. + struct F64_stat { + dev_t st_dev; //!< st_dev + int32_t st_retired1; //!< st_retired1 + mode_t st_mode; //!< st_mode + nlink_t st_nlink; //!< st_nlink + uint16_t st_nlink_reserved; //!< st_nlink_reserved + uid_t st_uid; //!< st_uid + gid_t st_gid; //!< st_gid + dev_t st_rdev; //!< st_rdev + dev_t st_ldev; //!< st_ldev + off_t st_size; //!< st_size + time_t st_retired2; //!< st_retired2 + int32_t st_uatime; //!< st_uatime + time_t st_retired3; //!< st_retired3 + int32_t st_umtime; //!< st_umtime + time_t st_retired4; //!< st_retired4 + int32_t st_uctime; //!< st_uctime + int32_t st_retired5; //!< st_retired5 + int32_t st_retired6; //!< st_retired6 + uint32_t st_flags; //!< st_flags + uint32_t st_gen; //!< st_gen + uint64_t st_spare[4]; //!< st_spare[4] + ino_t st_ino; //!< st_ino + int32_t st_ino_reserved; //!< st_ino_reserved + time_t st_atimeX; //!< st_atime + int32_t st_atime_reserved; //!< st_atime_reserved + time_t st_mtimeX; //!< st_mtime + int32_t st_mtime_reserved; //!< st_mtime_reserved + time_t st_ctimeX; //!< st_ctime + int32_t st_ctime_reserved; //!< st_ctime_reserved + uint64_t st_blksize; //!< st_blksize + uint64_t st_blocks; //!< st_blocks + }; + + + /// For getdirentries(). + struct dirent + { + ino_t d_ino; //!< file number of entry + uint16_t d_reclen; //!< length of this record + uint16_t d_namlen; //!< length of string in d_name + char d_name[256]; //!< dummy name length + }; + + + /// Length of strings in struct utsname (plus 1 for null char). + static const int _SYS_NMLN = 32; + + /// Interface struct for uname(). + struct utsname { + char sysname[_SYS_NMLN]; //!< System name. + char nodename[_SYS_NMLN]; //!< Node name. + char release[_SYS_NMLN]; //!< OS release. + char version[_SYS_NMLN]; //!< OS version. + char machine[_SYS_NMLN]; //!< Machine type. + }; + + //@{ + /// ioctl() command codes. + static const unsigned TIOCGETP = 0x40067408; + static const unsigned TIOCSETP = 0x80067409; + static const unsigned TIOCSETN = 0x8006740a; + static const unsigned TIOCSETC = 0x80067411; + static const unsigned TIOCGETC = 0x40067412; + static const unsigned FIONREAD = 0x4004667f; + static const unsigned TIOCISATTY = 0x2000745e; + //@} + + /// Resource enumeration for getrlimit(). + enum rlimit_resources { + RLIMIT_CPU = 0, + RLIMIT_FSIZE = 1, + RLIMIT_DATA = 2, + RLIMIT_STACK = 3, + RLIMIT_CORE = 4, + RLIMIT_RSS = 5, + RLIMIT_NOFILE = 6, + RLIMIT_AS = 7, + RLIMIT_VMEM = 7 + }; + + /// Limit struct for getrlimit/setrlimit. + struct rlimit { + uint64_t rlim_cur; //!< soft limit + uint64_t rlim_max; //!< hard limit + }; + + + /// For mmap(). static const unsigned TGT_MAP_ANONYMOUS = 0x10; -// -// for getsysinfo() -// - -static const unsigned GSI_PLATFORM_NAME = 103; // get platform name as string -static const unsigned GSI_CPU_INFO = 59; // CPU information -static const unsigned GSI_PROC_TYPE = 60; // get proc_type -static const unsigned GSI_MAX_CPU = 30; // max # cpu's on this machine -static const unsigned GSI_CPUS_IN_BOX = 55; // number of processors in system -static const unsigned GSI_PHYSMEM = 19; // Amount of physical memory in KB -static const unsigned GSI_CLK_TCK = 42; // clock freq in Hz - -struct cpu_info { - uint32_t current_cpu; - uint32_t cpus_in_box; - uint32_t cpu_type; - uint32_t ncpus; - uint64_t cpus_present; - uint64_t cpus_running; - uint64_t cpu_binding; - uint64_t cpu_ex_binding; - uint32_t mhz; - uint32_t unused[3]; // future expansion -}; - -// -// for gettimeofday -// - -struct timeval { - uint32_t tv_sec; - uint32_t tv_usec; -}; - -// -// for getrusage -// - - -static const int RUSAGE_THREAD = 1; -static const int RUSAGE_SELF = 0; -static const int RUSAGE_CHILDREN = -1; - -struct rusage { - struct timeval ru_utime; // user time used - struct timeval ru_stime; // system time used - uint64_t ru_maxrss; - uint64_t ru_ixrss; // integral shared memory size - uint64_t ru_idrss; // integral unshared data " - uint64_t ru_isrss; // integral unshared stack " - uint64_t ru_minflt; // page reclaims - total vmfaults - uint64_t ru_majflt; // page faults - uint64_t ru_nswap; // swaps - uint64_t ru_inblock; // block input operations - uint64_t ru_oublock; // block output operations - uint64_t ru_msgsnd; // messages sent - uint64_t ru_msgrcv; // messages received - uint64_t ru_nsignals; // signals received - uint64_t ru_nvcsw; // voluntary context switches - uint64_t ru_nivcsw; // involuntary " -}; - -// -// for sigreturn -// - -struct sigcontext { - int64_t sc_onstack; // sigstack state to restore - int64_t sc_mask; // signal mask to restore - int64_t sc_pc; // pc at time of signal - int64_t sc_ps; // psl to retore - int64_t sc_regs[32]; // processor regs 0 to 31 - int64_t sc_ownedfp; // fp has been used - int64_t sc_fpregs[32]; // fp regs 0 to 31 - uint64_t sc_fpcr; // floating point control reg - uint64_t sc_fp_control; // software fpcr - int64_t sc_reserved1; // reserved for kernel - uint32_t sc_kreserved1; // reserved for kernel - uint32_t sc_kreserved2; // reserved for kernel - size_t sc_ssize; // stack size - caddr_t sc_sbase; // stack start - uint64_t sc_traparg_a0; // a0 argument to trap on exc - uint64_t sc_traparg_a1; // a1 argument to trap on exc - uint64_t sc_traparg_a2; // a2 argument to trap on exc - uint64_t sc_fp_trap_pc; // imprecise pc - uint64_t sc_fp_trigger_sum; // Exception summary at trigg - uint64_t sc_fp_trigger_inst; // Instruction at trigger pc -}; - - -// -// for table -// -static const int TBL_SYSINFO = 12; - -struct tbl_sysinfo { - uint64_t si_user; // User time - uint64_t si_nice; // Nice time - uint64_t si_sys; // System time - uint64_t si_idle; // Idle time - uint64_t si_hz; - uint64_t si_phz; - uint64_t si_boottime; // Boot time in seconds - uint64_t wait; // Wait time - uint32_t si_max_procs; // rpb->rpb_numprocs - uint32_t pad; -}; - - -// -// for stack_create -// - -struct vm_stack { - // void * - Addr address; // address hint - size_t rsize; // red zone size - size_t ysize; // yellow zone size - size_t gsize; // green zone size - size_t swap; // amount of swap to reserve - size_t incr; // growth increment - uint64_t align; // address alignment - uint64_t flags; // MAP_FIXED etc. - // struct memalloc_attr * - Addr attr; // allocation policy - uint64_t reserved; -}; - -// -// return values for nxm calls -// -enum { - KERN_NOT_RECEIVER = 7, - KERN_NOT_IN_SET = 12 -}; - -// -// for nxm_task_init -// - -static const int NXM_TASK_INIT_VP = 2; // initial thread is VP - -struct nxm_task_attr { - int64_t nxm_callback; - unsigned int nxm_version; - unsigned short nxm_uniq_offset; - unsigned short flags; - int nxm_quantum; - int pad1; - int64_t pad2; -}; - -typedef uint64_t sigset_t; - -struct ushared_state { - sigset_t sigmask; // thread signal mask - sigset_t sig; // thread pending mask - // struct nxm_pth_state * - Addr pth_id; // out-of-line state - int flags; // shared flags + //@{ + /// For getsysinfo(). + static const unsigned GSI_PLATFORM_NAME = 103; //!< platform name as string + static const unsigned GSI_CPU_INFO = 59; //!< CPU information + static const unsigned GSI_PROC_TYPE = 60; //!< get proc_type + static const unsigned GSI_MAX_CPU = 30; //!< max # cpu's on this machine + static const unsigned GSI_CPUS_IN_BOX = 55; //!< number of CPUs in system + static const unsigned GSI_PHYSMEM = 19; //!< Physical memory in KB + static const unsigned GSI_CLK_TCK = 42; //!< clock freq in Hz + //@} + + /// For getsysinfo() GSI_CPU_INFO option. + struct cpu_info { + uint32_t current_cpu; //!< current_cpu + uint32_t cpus_in_box; //!< cpus_in_box + uint32_t cpu_type; //!< cpu_type + uint32_t ncpus; //!< ncpus + uint64_t cpus_present; //!< cpus_present + uint64_t cpus_running; //!< cpus_running + uint64_t cpu_binding; //!< cpu_binding + uint64_t cpu_ex_binding; //!< cpu_ex_binding + uint32_t mhz; //!< mhz + uint32_t unused[3]; //!< future expansion + }; + + /// For gettimeofday. + struct timeval { + uint32_t tv_sec; //!< seconds + uint32_t tv_usec; //!< microseconds + }; + + //@{ + /// For getrusage(). + static const int RUSAGE_THREAD = 1; + static const int RUSAGE_SELF = 0; + static const int RUSAGE_CHILDREN = -1; + //@} + + /// For getrusage(). + struct rusage { + struct timeval ru_utime; //!< user time used + struct timeval ru_stime; //!< system time used + uint64_t ru_maxrss; //!< ru_maxrss + uint64_t ru_ixrss; //!< integral shared memory size + uint64_t ru_idrss; //!< integral unshared data " + uint64_t ru_isrss; //!< integral unshared stack " + uint64_t ru_minflt; //!< page reclaims - total vmfaults + uint64_t ru_majflt; //!< page faults + uint64_t ru_nswap; //!< swaps + uint64_t ru_inblock; //!< block input operations + uint64_t ru_oublock; //!< block output operations + uint64_t ru_msgsnd; //!< messages sent + uint64_t ru_msgrcv; //!< messages received + uint64_t ru_nsignals; //!< signals received + uint64_t ru_nvcsw; //!< voluntary context switches + uint64_t ru_nivcsw; //!< involuntary " + }; + + /// For sigreturn(). + struct sigcontext { + int64_t sc_onstack; //!< sigstack state to restore + int64_t sc_mask; //!< signal mask to restore + int64_t sc_pc; //!< pc at time of signal + int64_t sc_ps; //!< psl to retore + int64_t sc_regs[32]; //!< processor regs 0 to 31 + int64_t sc_ownedfp; //!< fp has been used + int64_t sc_fpregs[32]; //!< fp regs 0 to 31 + uint64_t sc_fpcr; //!< floating point control reg + uint64_t sc_fp_control; //!< software fpcr + int64_t sc_reserved1; //!< reserved for kernel + uint32_t sc_kreserved1; //!< reserved for kernel + uint32_t sc_kreserved2; //!< reserved for kernel + size_t sc_ssize; //!< stack size + caddr_t sc_sbase; //!< stack start + uint64_t sc_traparg_a0; //!< a0 argument to trap on exc + uint64_t sc_traparg_a1; //!< a1 argument to trap on exc + uint64_t sc_traparg_a2; //!< a2 argument to trap on exc + uint64_t sc_fp_trap_pc; //!< imprecise pc + uint64_t sc_fp_trigger_sum; //!< Exception summary at trigg + uint64_t sc_fp_trigger_inst; //!< Instruction at trigger pc + }; + + + /// For table(). + static const int TBL_SYSINFO = 12; + + /// For table(). + struct tbl_sysinfo { + uint64_t si_user; //!< User time + uint64_t si_nice; //!< Nice time + uint64_t si_sys; //!< System time + uint64_t si_idle; //!< Idle time + uint64_t si_hz; //!< hz + uint64_t si_phz; //!< phz + uint64_t si_boottime; //!< Boot time in seconds + uint64_t wait; //!< Wait time + uint32_t si_max_procs; //!< rpb->rpb_numprocs + uint32_t pad; //!< padding + }; + + + /// For stack_create. + struct vm_stack { + // was void * + Addr address; //!< address hint + size_t rsize; //!< red zone size + size_t ysize; //!< yellow zone size + size_t gsize; //!< green zone size + size_t swap; //!< amount of swap to reserve + size_t incr; //!< growth increment + uint64_t align; //!< address alignment + uint64_t flags; //!< MAP_FIXED etc. + // was struct memalloc_attr * + Addr attr; //!< allocation policy + uint64_t reserved; //!< reserved + }; + + /// Return values for nxm calls. + enum { + KERN_NOT_RECEIVER = 7, + KERN_NOT_IN_SET = 12 + }; + + /// For nxm_task_init. + static const int NXM_TASK_INIT_VP = 2; //!< initial thread is VP + + /// Task attribute structure. + struct nxm_task_attr { + int64_t nxm_callback; //!< nxm_callback + unsigned int nxm_version; //!< nxm_version + unsigned short nxm_uniq_offset; //!< nxm_uniq_offset + unsigned short flags; //!< flags + int nxm_quantum; //!< nxm_quantum + int pad1; //!< pad1 + int64_t pad2; //!< pad2 + }; + + /// Signal set. + typedef uint64_t sigset_t; + + /// Thread state shared between user & kernel. + struct ushared_state { + sigset_t sigmask; //!< thread signal mask + sigset_t sig; //!< thread pending mask + // struct nxm_pth_state * + Addr pth_id; //!< out-of-line state + int flags; //!< shared flags #define US_SIGSTACK 0x1 // thread called sigaltstack #define US_ONSTACK 0x2 // thread is running on altstack #define US_PROFILE 0x4 // thread called profil @@ -370,7 +353,7 @@ struct ushared_state { #define US_YZONE 0x40 // thread has zoned out #define US_FP_OWNED 0x80 // thread used floating point - int cancel_state; // thread's cancelation state + int cancel_state; //!< thread's cancelation state #define US_CANCEL 0x1 // cancel pending #define US_NOCANCEL 0X2 // synch cancel disabled #define US_SYS_NOCANCEL 0x4 // syscall cancel disabled @@ -379,954 +362,951 @@ struct ushared_state { #define US_CANCEL_MASK (US_CANCEL|US_NOCANCEL|US_SYS_NOCANCEL| \ US_ASYNC_NOCANCEL) - // These are semi-shared. They are always visible to - // the kernel but are never context-switched by the library. - - int nxm_ssig; // scheduler's synchronous signals - int reserved1; - int64_t nxm_active; // scheduler active - int64_t reserved2; -}; - -struct nxm_sched_state { - struct ushared_state nxm_u; // state own by user thread - unsigned int nxm_bits; // scheduler state / slot - int nxm_quantum; // quantum count-down value - int nxm_set_quantum; // quantum reset value - int nxm_sysevent; // syscall state - // struct nxm_upcall * - Addr nxm_uc_ret; // stack ptr of null thread - // void * - Addr nxm_tid; // scheduler's thread id - int64_t nxm_va; // page fault address - // struct nxm_pth_state * - Addr nxm_pthid; // id of null thread - uint64_t nxm_bound_pcs_count; // bound PCS thread count - int64_t pad[2]; -}; - -struct nxm_shared { - int64_t nxm_callback; // address of upcall routine - unsigned int nxm_version; // version number - unsigned short nxm_uniq_offset; // correction factor for TEB - unsigned short pad1; - int64_t space[2]; // future growth - struct nxm_sched_state nxm_ss[1]; // array of shared areas -}; - -enum nxm_slot_state_t { - NXM_SLOT_AVAIL, - NXM_SLOT_BOUND, - NXM_SLOT_UNBOUND, - NXM_SLOT_EMPTY -}; - - -struct nxm_config_info { - int nxm_nslots_per_rad; // max number of VP slots per RAD - int nxm_nrads; // max number of RADs - // nxm_slot_state_t * - Addr nxm_slot_state; // per-VP slot state - // struct nxm_shared * - Addr nxm_rad[1]; // per-RAD shared areas -}; - -// -// for nxm_thread_create -// - -enum nxm_thread_type { - NXM_TYPE_SCS = 0, - NXM_TYPE_VP = 1, - NXM_TYPE_MANAGER = 2 -}; - - -struct nxm_thread_attr { - int version; - int type; - int cancel_flags; - int priority; - int policy; - int signal_type; - // void * - Addr pthid; - sigset_t sigmask; - struct { - uint64_t pc; - uint64_t sp; - uint64_t a0; - } registers; - uint64_t pad2[2]; -}; - -static -void -copyOutStatBuf(FunctionalMemory *mem, Addr addr, struct stat *host) -{ - TypedBufferArg tgt(addr); - - tgt->st_dev = host->st_dev; - tgt->st_ino = host->st_ino; - tgt->st_mode = host->st_mode; - tgt->st_nlink = host->st_nlink; - tgt->st_uid = host->st_uid; - tgt->st_gid = host->st_gid; - tgt->st_rdev = host->st_rdev; - tgt->st_size = host->st_size; - tgt->st_atimeX = host->st_atime; - tgt->st_mtimeX = host->st_mtime; - tgt->st_ctimeX = host->st_ctime; - tgt->st_blksize = host->st_blksize; - tgt->st_blocks = host->st_blocks; - - tgt.copyOut(mem); -} - -static const char *hostname; - -static -int -unameFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - TypedBufferArg name(xc->getSyscallArg(0)); - - strcpy(name->sysname, "OSF1"); - strcpy(name->nodename, hostname); - strcpy(name->release, "V5.1"); - strcpy(name->version, "732"); - strcpy(name->machine, "alpha"); - - name.copyOut(xc->mem); - return 0; -} - - -static -int -getsysinfoFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - unsigned op = xc->getSyscallArg(0); - unsigned nbytes = xc->getSyscallArg(2); - - switch (op) { - - case Tru64::GSI_MAX_CPU: { - TypedBufferArg max_cpu(xc->getSyscallArg(1)); - *max_cpu = process->numCpus(); - max_cpu.copyOut(xc->mem); - return 1; - } - - case Tru64::GSI_CPUS_IN_BOX: { - TypedBufferArg cpus_in_box(xc->getSyscallArg(1)); - *cpus_in_box = process->numCpus(); - cpus_in_box.copyOut(xc->mem); - return 1; - } - - case Tru64::GSI_PHYSMEM: { - TypedBufferArg physmem(xc->getSyscallArg(1)); - *physmem = 1024 * 1024; // physical memory in KB - physmem.copyOut(xc->mem); - return 1; - } - - case Tru64::GSI_CPU_INFO: { - TypedBufferArg infop(xc->getSyscallArg(1)); - - infop->current_cpu = 0; - infop->cpus_in_box = process->numCpus(); - infop->cpu_type = 57; - infop->ncpus = process->numCpus(); - int cpumask = (1 << process->numCpus()) - 1; - infop->cpus_present = infop->cpus_running = cpumask; - infop->cpu_binding = 0; - infop->cpu_ex_binding = 0; - infop->mhz = 667; - - infop.copyOut(xc->mem); - return 1; - } - - case Tru64::GSI_PROC_TYPE: { - TypedBufferArg proc_type(xc->getSyscallArg(1)); - *proc_type = 11; - proc_type.copyOut(xc->mem); - return 1; - } - - case Tru64::GSI_PLATFORM_NAME: { - BufferArg bufArg(xc->getSyscallArg(1), nbytes); - strncpy((char *)bufArg.bufferPtr(), - "COMPAQ Professional Workstation XP1000", - nbytes); - bufArg.copyOut(xc->mem); - return 1; - } - - case Tru64::GSI_CLK_TCK: { - TypedBufferArg clk_hz(xc->getSyscallArg(1)); - *clk_hz = 1024; - clk_hz.copyOut(xc->mem); - return 1; - } - - default: - cerr << "getsysinfo: unknown op " << op << endl; - abort(); - break; + // These are semi-shared. They are always visible to + // the kernel but are never context-switched by the library. + + int nxm_ssig; //!< scheduler's synchronous signals + int reserved1; //!< reserved1 + int64_t nxm_active; //!< scheduler active + int64_t reserved2; //!< reserved2 + }; + + struct nxm_sched_state { + struct ushared_state nxm_u; //!< state own by user thread + unsigned int nxm_bits; //!< scheduler state / slot + int nxm_quantum; //!< quantum count-down value + int nxm_set_quantum; //!< quantum reset value + int nxm_sysevent; //!< syscall state + // struct nxm_upcall * + Addr nxm_uc_ret; //!< stack ptr of null thread + // void * + Addr nxm_tid; //!< scheduler's thread id + int64_t nxm_va; //!< page fault address + // struct nxm_pth_state * + Addr nxm_pthid; //!< id of null thread + uint64_t nxm_bound_pcs_count; //!< bound PCS thread count + int64_t pad[2]; //!< pad + }; + + /// nxm_shared. + struct nxm_shared { + int64_t nxm_callback; //!< address of upcall routine + unsigned int nxm_version; //!< version number + unsigned short nxm_uniq_offset; //!< correction factor for TEB + unsigned short pad1; //!< pad1 + int64_t space[2]; //!< future growth + struct nxm_sched_state nxm_ss[1]; //!< array of shared areas + }; + + /// nxm_slot_state_t. + enum nxm_slot_state_t { + NXM_SLOT_AVAIL, + NXM_SLOT_BOUND, + NXM_SLOT_UNBOUND, + NXM_SLOT_EMPTY + }; + + /// nxm_config_info + struct nxm_config_info { + int nxm_nslots_per_rad; //!< max number of VP slots per RAD + int nxm_nrads; //!< max number of RADs + // nxm_slot_state_t * + Addr nxm_slot_state; //!< per-VP slot state + // struct nxm_shared * + Addr nxm_rad[1]; //!< per-RAD shared areas + }; + + /// For nxm_thread_create. + enum nxm_thread_type { + NXM_TYPE_SCS = 0, + NXM_TYPE_VP = 1, + NXM_TYPE_MANAGER = 2 + }; + + /// Thread attributes. + struct nxm_thread_attr { + int version; //!< version + int type; //!< type + int cancel_flags; //!< cancel_flags + int priority; //!< priority + int policy; //!< policy + int signal_type; //!< signal_type + // void * + Addr pthid; //!< pthid + sigset_t sigmask; //!< sigmask + /// Initial register values. + struct { + uint64_t pc; //!< pc + uint64_t sp; //!< sp + uint64_t a0; //!< a0 + } registers; + uint64_t pad2[2]; //!< pad2 + }; + + /// Helper function to convert a host stat buffer to a target stat + /// buffer. Also copies the target buffer out to the simulated + /// memorty space. Used by stat(), fstat(), and lstat(). + static void + copyOutStatBuf(FunctionalMemory *mem, Addr addr, struct stat *host) + { + TypedBufferArg tgt(addr); + + tgt->st_dev = host->st_dev; + tgt->st_ino = host->st_ino; + tgt->st_mode = host->st_mode; + tgt->st_nlink = host->st_nlink; + tgt->st_uid = host->st_uid; + tgt->st_gid = host->st_gid; + tgt->st_rdev = host->st_rdev; + tgt->st_size = host->st_size; + tgt->st_atimeX = host->st_atime; + tgt->st_mtimeX = host->st_mtime; + tgt->st_ctimeX = host->st_ctime; + tgt->st_blksize = host->st_blksize; + tgt->st_blocks = host->st_blocks; + + tgt.copyOut(mem); } - return 0; -} -static -int -fcntlFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - int fd = xc->getSyscallArg(0); + /// The target system's hostname. + static const char *hostname; - if (fd < 0 || process->sim_fd(fd) < 0) - return -EBADF; + /// Target uname() handler. + static int + unameFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) + { + TypedBufferArg name(xc->getSyscallArg(0)); - int cmd = xc->getSyscallArg(1); - switch (cmd) { - case 0: // F_DUPFD - // if we really wanted to support this, we'd need to do it - // in the target fd space. - warn("fcntl(%d, F_DUPFD) not supported, error returned\n", fd); - return -EMFILE; + strcpy(name->sysname, "OSF1"); + strcpy(name->nodename, hostname); + strcpy(name->release, "V5.1"); + strcpy(name->version, "732"); + strcpy(name->machine, "alpha"); - case 1: // F_GETFD (get close-on-exec flag) - case 2: // F_SETFD (set close-on-exec flag) + name.copyOut(xc->mem); return 0; + } - case 3: // F_GETFL (get file flags) - case 4: // F_SETFL (set file flags) - // not sure if this is totally valid, but we'll pass it through - // to the underlying OS - warn("fcntl(%d, %d) passed through to host\n", fd, cmd); - return fcntl(process->sim_fd(fd), cmd); - // return 0; - - case 7: // F_GETLK (get lock) - case 8: // F_SETLK (set lock) - case 9: // F_SETLKW (set lock and wait) - // don't mess with file locking... just act like it's OK - warn("File lock call (fcntl(%d, %d)) ignored.\n", fd, cmd); - return 0; - default: - warn("Unknown fcntl command %d\n", cmd); + /// Target getsysyinfo() handler. + static int + getsysinfoFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) + { + unsigned op = xc->getSyscallArg(0); + unsigned nbytes = xc->getSyscallArg(2); + + switch (op) { + + case Tru64::GSI_MAX_CPU: { + TypedBufferArg max_cpu(xc->getSyscallArg(1)); + *max_cpu = process->numCpus(); + max_cpu.copyOut(xc->mem); + return 1; + } + + case Tru64::GSI_CPUS_IN_BOX: { + TypedBufferArg cpus_in_box(xc->getSyscallArg(1)); + *cpus_in_box = process->numCpus(); + cpus_in_box.copyOut(xc->mem); + return 1; + } + + case Tru64::GSI_PHYSMEM: { + TypedBufferArg physmem(xc->getSyscallArg(1)); + *physmem = 1024 * 1024; // physical memory in KB + physmem.copyOut(xc->mem); + return 1; + } + + case Tru64::GSI_CPU_INFO: { + TypedBufferArg infop(xc->getSyscallArg(1)); + + infop->current_cpu = 0; + infop->cpus_in_box = process->numCpus(); + infop->cpu_type = 57; + infop->ncpus = process->numCpus(); + int cpumask = (1 << process->numCpus()) - 1; + infop->cpus_present = infop->cpus_running = cpumask; + infop->cpu_binding = 0; + infop->cpu_ex_binding = 0; + infop->mhz = 667; + + infop.copyOut(xc->mem); + return 1; + } + + case Tru64::GSI_PROC_TYPE: { + TypedBufferArg proc_type(xc->getSyscallArg(1)); + *proc_type = 11; + proc_type.copyOut(xc->mem); + return 1; + } + + case Tru64::GSI_PLATFORM_NAME: { + BufferArg bufArg(xc->getSyscallArg(1), nbytes); + strncpy((char *)bufArg.bufferPtr(), + "COMPAQ Professional Workstation XP1000", + nbytes); + bufArg.copyOut(xc->mem); + return 1; + } + + case Tru64::GSI_CLK_TCK: { + TypedBufferArg clk_hz(xc->getSyscallArg(1)); + *clk_hz = 1024; + clk_hz.copyOut(xc->mem); + return 1; + } + + default: + cerr << "getsysinfo: unknown op " << op << endl; + abort(); + break; + } + return 0; } -} + /// Target fnctl() handler. + static int + fcntlFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) + { + int fd = xc->getSyscallArg(0); + + if (fd < 0 || process->sim_fd(fd) < 0) + return -EBADF; + + int cmd = xc->getSyscallArg(1); + switch (cmd) { + case 0: // F_DUPFD + // if we really wanted to support this, we'd need to do it + // in the target fd space. + warn("fcntl(%d, F_DUPFD) not supported, error returned\n", fd); + return -EMFILE; + + case 1: // F_GETFD (get close-on-exec flag) + case 2: // F_SETFD (set close-on-exec flag) + return 0; + + case 3: // F_GETFL (get file flags) + case 4: // F_SETFL (set file flags) + // not sure if this is totally valid, but we'll pass it through + // to the underlying OS + warn("fcntl(%d, %d) passed through to host\n", fd, cmd); + return fcntl(process->sim_fd(fd), cmd); + // return 0; + + case 7: // F_GETLK (get lock) + case 8: // F_SETLK (set lock) + case 9: // F_SETLKW (set lock and wait) + // don't mess with file locking... just act like it's OK + warn("File lock call (fcntl(%d, %d)) ignored.\n", fd, cmd); + return 0; + + default: + warn("Unknown fcntl command %d\n", cmd); + return 0; + } + } -static -int -getdirentriesFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - int fd = process->sim_fd(xc->getSyscallArg(0)); - Addr tgt_buf = xc->getSyscallArg(1); - int tgt_nbytes = xc->getSyscallArg(2); - Addr tgt_basep = xc->getSyscallArg(3); - char * const host_buf = new char[tgt_nbytes]; + /// Target getdirentries() handler. + static int + getdirentriesFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) + { + int fd = process->sim_fd(xc->getSyscallArg(0)); + Addr tgt_buf = xc->getSyscallArg(1); + int tgt_nbytes = xc->getSyscallArg(2); + Addr tgt_basep = xc->getSyscallArg(3); + + char * const host_buf = new char[tgt_nbytes]; + + // just pass basep through uninterpreted. + TypedBufferArg basep(tgt_basep); + basep.copyIn(xc->mem); + ::off_t host_basep = (off_t)*basep; + int host_result = getdirentries(fd, host_buf, tgt_nbytes, &host_basep); + + // check for error + if (host_result < 0) { + delete [] host_buf; + return -errno; + } - // just pass basep through uninterpreted. - TypedBufferArg basep(tgt_basep); - basep.copyIn(xc->mem); - ::off_t host_basep = (off_t)*basep; - int host_result = getdirentries(fd, host_buf, tgt_nbytes, &host_basep); + // no error: copy results back to target space + Addr tgt_buf_ptr = tgt_buf; + char *host_buf_ptr = host_buf; + char *host_buf_end = host_buf + host_result; + while (host_buf_ptr < host_buf_end) { + struct dirent *host_dp = (struct dirent *)host_buf_ptr; + int namelen = strlen(host_dp->d_name); + + // Actual size includes padded string rounded up for alignment. + // Subtract 256 for dummy char array in Tru64::dirent definition. + // Add 1 to namelen for terminating null char. + int tgt_bufsize = sizeof(Tru64::dirent) - 256 + RoundUp(namelen+1, 8); + TypedBufferArg tgt_dp(tgt_buf_ptr, tgt_bufsize); + tgt_dp->d_ino = host_dp->d_ino; + tgt_dp->d_reclen = tgt_bufsize; + tgt_dp->d_namlen = namelen; + strcpy(tgt_dp->d_name, host_dp->d_name); + tgt_dp.copyOut(xc->mem); + + tgt_buf_ptr += tgt_bufsize; + host_buf_ptr += host_dp->d_reclen; + } - // check for error - if (host_result < 0) { delete [] host_buf; - return -errno; - } - - // no error: copy results back to target space - Addr tgt_buf_ptr = tgt_buf; - char *host_buf_ptr = host_buf; - char *host_buf_end = host_buf + host_result; - while (host_buf_ptr < host_buf_end) { - struct dirent *host_dp = (struct dirent *)host_buf_ptr; - int namelen = strlen(host_dp->d_name); - - // Actual size includes padded string rounded up for alignment. - // Subtract 256 for dummy char array in Tru64::dirent definition. - // Add 1 to namelen for terminating null char. - int tgt_bufsize = sizeof(Tru64::dirent) - 256 + RoundUp(namelen+1, 8); - TypedBufferArg tgt_dp(tgt_buf_ptr, tgt_bufsize); - tgt_dp->d_ino = host_dp->d_ino; - tgt_dp->d_reclen = tgt_bufsize; - tgt_dp->d_namlen = namelen; - strcpy(tgt_dp->d_name, host_dp->d_name); - tgt_dp.copyOut(xc->mem); - - tgt_buf_ptr += tgt_bufsize; - host_buf_ptr += host_dp->d_reclen; - } - delete [] host_buf; + *basep = host_basep; + basep.copyOut(xc->mem); - *basep = host_basep; - basep.copyOut(xc->mem); + return (tgt_buf_ptr - tgt_buf); + } - return (tgt_buf_ptr - tgt_buf); -} + /// Target sigreturn() handler. + static int + sigreturnFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) + { + RegFile *regs = &xc->regs; + TypedBufferArg sc(xc->getSyscallArg(0)); + sc.copyIn(xc->mem); -static -int -sigreturnFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - RegFile *regs = &xc->regs; - TypedBufferArg sc(xc->getSyscallArg(0)); + // Restore state from sigcontext structure. + // Note that we'll advance PC <- NPC before the end of the cycle, + // so we need to restore the desired PC into NPC. + // The current regs->pc will get clobbered. + regs->npc = sc->sc_pc; - sc.copyIn(xc->mem); + for (int i = 0; i < 31; ++i) { + regs->intRegFile[i] = sc->sc_regs[i]; + regs->floatRegFile.q[i] = sc->sc_fpregs[i]; + } - // Restore state from sigcontext structure. - // Note that we'll advance PC <- NPC before the end of the cycle, - // so we need to restore the desired PC into NPC. - // The current regs->pc will get clobbered. - regs->npc = sc->sc_pc; + regs->miscRegs.fpcr = sc->sc_fpcr; - for (int i = 0; i < 31; ++i) { - regs->intRegFile[i] = sc->sc_regs[i]; - regs->floatRegFile.q[i] = sc->sc_fpregs[i]; + return 0; } - regs->miscRegs.fpcr = sc->sc_fpcr; - - return 0; -} - -static -int -tableFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - int id = xc->getSyscallArg(0); // table ID - int index = xc->getSyscallArg(1); // index into table - // arg 2 is buffer pointer; type depends on table ID - int nel = xc->getSyscallArg(3); // number of elements - int lel = xc->getSyscallArg(4); // expected element size - - switch (id) { - case Tru64::TBL_SYSINFO: { - if (index != 0 || nel != 1 || lel != sizeof(Tru64::tbl_sysinfo)) - return -EINVAL; - TypedBufferArg elp(xc->getSyscallArg(2)); - - const int clk_hz = one_million; - elp->si_user = curTick / (ticksPerSecond / clk_hz); - elp->si_nice = 0; - elp->si_sys = 0; - elp->si_idle = 0; - elp->wait = 0; - elp->si_hz = clk_hz; - elp->si_phz = clk_hz; - elp->si_boottime = seconds_since_epoch; // seconds since epoch? - elp->si_max_procs = process->numCpus(); - elp.copyOut(xc->mem); - return 0; - } - - default: - cerr << "table(): id " << id << " unknown." << endl; - return -EINVAL; + /// Target table() handler. + static int + tableFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) + { + int id = xc->getSyscallArg(0); // table ID + int index = xc->getSyscallArg(1); // index into table + // arg 2 is buffer pointer; type depends on table ID + int nel = xc->getSyscallArg(3); // number of elements + int lel = xc->getSyscallArg(4); // expected element size + + switch (id) { + case Tru64::TBL_SYSINFO: { + if (index != 0 || nel != 1 || lel != sizeof(Tru64::tbl_sysinfo)) + return -EINVAL; + TypedBufferArg elp(xc->getSyscallArg(2)); + + const int clk_hz = one_million; + elp->si_user = curTick / (ticksPerSecond / clk_hz); + elp->si_nice = 0; + elp->si_sys = 0; + elp->si_idle = 0; + elp->wait = 0; + elp->si_hz = clk_hz; + elp->si_phz = clk_hz; + elp->si_boottime = seconds_since_epoch; // seconds since epoch? + elp->si_max_procs = process->numCpus(); + elp.copyOut(xc->mem); + return 0; + } + + default: + cerr << "table(): id " << id << " unknown." << endl; + return -EINVAL; + } } -} -static SyscallDesc syscallDescs[]; + /// Array of syscall descriptors, indexed by call number. + static SyscallDesc syscallDescs[]; -static const int Num_Syscall_Descs; -static const int Max_Syscall_Desc; + /// Number of syscalls in syscallDescs[]. + static const int Num_Syscall_Descs; -// -// Mach syscalls -- identified by negated syscall numbers -// + /// Max supported syscall number. + static const int Max_Syscall_Desc; -// Create a stack region for a thread. -static -int -stack_createFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - TypedBufferArg argp(xc->getSyscallArg(0)); + // + // Mach syscalls -- identified by negated syscall numbers + // - argp.copyIn(xc->mem); + /// Create a stack region for a thread. + static int + stack_createFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) + { + TypedBufferArg argp(xc->getSyscallArg(0)); + + argp.copyIn(xc->mem); + + // if the user chose an address, just let them have it. Otherwise + // pick one for them. + if (argp->address == 0) { + argp->address = process->next_thread_stack_base; + int stack_size = (argp->rsize + argp->ysize + argp->gsize); + process->next_thread_stack_base -= stack_size; + argp.copyOut(xc->mem); + } - // if the user chose an address, just let them have it. Otherwise - // pick one for them. - if (argp->address == 0) { - argp->address = process->next_thread_stack_base; - int stack_size = (argp->rsize + argp->ysize + argp->gsize); - process->next_thread_stack_base -= stack_size; - argp.copyOut(xc->mem); + return 0; } - return 0; -} - -static -const int NXM_LIB_VERSION = 301003; - -// -// This call sets up the interface between the user and kernel -// schedulers by creating a shared-memory region. The shared memory -// region has several structs, some global, some per-RAD, some per-VP. -// -static -int -nxm_task_initFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - TypedBufferArg attrp(xc->getSyscallArg(0)); - TypedBufferArg configptr_ptr(xc->getSyscallArg(1)); + /// NXM library version stamp. + static + const int NXM_LIB_VERSION = 301003; - attrp.copyIn(xc->mem); - - if (attrp->nxm_version != NXM_LIB_VERSION) { - cerr << "nxm_task_init: thread library version mismatch! " - << "got " << attrp->nxm_version - << ", expected " << NXM_LIB_VERSION << endl; - abort(); - } + /// This call sets up the interface between the user and kernel + /// schedulers by creating a shared-memory region. The shared memory + /// region has several structs, some global, some per-RAD, some per-VP. + static int + nxm_task_initFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) + { + TypedBufferArg attrp(xc->getSyscallArg(0)); + TypedBufferArg configptr_ptr(xc->getSyscallArg(1)); - if (attrp->flags != Tru64::NXM_TASK_INIT_VP) { - cerr << "nxm_task_init: bad flag value " << attrp->flags - << " (expected " << Tru64::NXM_TASK_INIT_VP << ")" << endl; - abort(); - } + attrp.copyIn(xc->mem); - const Addr base_addr = 0x12000; // was 0x3f0000000LL; - Addr cur_addr = base_addr; // next addresses to use - // first comes the config_info struct - Addr config_addr = cur_addr; - cur_addr += sizeof(Tru64::nxm_config_info); - // next comes the per-cpu state vector - Addr slot_state_addr = cur_addr; - int slot_state_size = process->numCpus() * sizeof(Tru64::nxm_slot_state_t); - cur_addr += slot_state_size; - // now the per-RAD state struct (we only support one RAD) - cur_addr = 0x14000; // bump up addr for alignment - Addr rad_state_addr = cur_addr; - int rad_state_size = - (sizeof(Tru64::nxm_shared) - + (process->numCpus()-1) * sizeof(Tru64::nxm_sched_state)); - cur_addr += rad_state_size; - - // now initialize a config_info struct and copy it out to user space - TypedBufferArg config(config_addr); - - config->nxm_nslots_per_rad = process->numCpus(); - config->nxm_nrads = 1; // only one RAD in our system! - config->nxm_slot_state = slot_state_addr; - config->nxm_rad[0] = rad_state_addr; - - config.copyOut(xc->mem); - - // initialize the slot_state array and copy it out - TypedBufferArg slot_state(slot_state_addr, - slot_state_size); - for (int i = 0; i < process->numCpus(); ++i) { - // CPU 0 is bound to the calling process; all others are available - slot_state[i] = (i == 0) ? Tru64::NXM_SLOT_BOUND : Tru64::NXM_SLOT_AVAIL; - } + if (attrp->nxm_version != NXM_LIB_VERSION) { + cerr << "nxm_task_init: thread library version mismatch! " + << "got " << attrp->nxm_version + << ", expected " << NXM_LIB_VERSION << endl; + abort(); + } - slot_state.copyOut(xc->mem); - - // same for the per-RAD "shared" struct. Note that we need to - // allocate extra bytes for the per-VP array which is embedded at - // the end. - TypedBufferArg rad_state(rad_state_addr, - rad_state_size); - - rad_state->nxm_callback = attrp->nxm_callback; - rad_state->nxm_version = attrp->nxm_version; - rad_state->nxm_uniq_offset = attrp->nxm_uniq_offset; - for (int i = 0; i < process->numCpus(); ++i) { - Tru64::nxm_sched_state *ssp = &rad_state->nxm_ss[i]; - ssp->nxm_u.sigmask = 0; - ssp->nxm_u.sig = 0; - ssp->nxm_u.flags = 0; - ssp->nxm_u.cancel_state = 0; - ssp->nxm_u.nxm_ssig = 0; - ssp->nxm_bits = 0; - ssp->nxm_quantum = attrp->nxm_quantum; - ssp->nxm_set_quantum = attrp->nxm_quantum; - ssp->nxm_sysevent = 0; - - if (i == 0) { - uint64_t uniq = xc->regs.miscRegs.uniq; - ssp->nxm_u.pth_id = uniq + attrp->nxm_uniq_offset; - ssp->nxm_u.nxm_active = uniq | 1; + if (attrp->flags != Tru64::NXM_TASK_INIT_VP) { + cerr << "nxm_task_init: bad flag value " << attrp->flags + << " (expected " << Tru64::NXM_TASK_INIT_VP << ")" << endl; + abort(); } - else { - ssp->nxm_u.pth_id = 0; - ssp->nxm_u.nxm_active = 0; + + const Addr base_addr = 0x12000; // was 0x3f0000000LL; + Addr cur_addr = base_addr; // next addresses to use + // first comes the config_info struct + Addr config_addr = cur_addr; + cur_addr += sizeof(Tru64::nxm_config_info); + // next comes the per-cpu state vector + Addr slot_state_addr = cur_addr; + int slot_state_size = + process->numCpus() * sizeof(Tru64::nxm_slot_state_t); + cur_addr += slot_state_size; + // now the per-RAD state struct (we only support one RAD) + cur_addr = 0x14000; // bump up addr for alignment + Addr rad_state_addr = cur_addr; + int rad_state_size = + (sizeof(Tru64::nxm_shared) + + (process->numCpus()-1) * sizeof(Tru64::nxm_sched_state)); + cur_addr += rad_state_size; + + // now initialize a config_info struct and copy it out to user space + TypedBufferArg config(config_addr); + + config->nxm_nslots_per_rad = process->numCpus(); + config->nxm_nrads = 1; // only one RAD in our system! + config->nxm_slot_state = slot_state_addr; + config->nxm_rad[0] = rad_state_addr; + + config.copyOut(xc->mem); + + // initialize the slot_state array and copy it out + TypedBufferArg slot_state(slot_state_addr, + slot_state_size); + for (int i = 0; i < process->numCpus(); ++i) { + // CPU 0 is bound to the calling process; all others are available + slot_state[i] = + (i == 0) ? Tru64::NXM_SLOT_BOUND : Tru64::NXM_SLOT_AVAIL; } - } - rad_state.copyOut(xc->mem); + slot_state.copyOut(xc->mem); - // - // copy pointer to shared config area out to user - // - *configptr_ptr = config_addr; - configptr_ptr.copyOut(xc->mem); + // same for the per-RAD "shared" struct. Note that we need to + // allocate extra bytes for the per-VP array which is embedded at + // the end. + TypedBufferArg rad_state(rad_state_addr, + rad_state_size); - return 0; -} + rad_state->nxm_callback = attrp->nxm_callback; + rad_state->nxm_version = attrp->nxm_version; + rad_state->nxm_uniq_offset = attrp->nxm_uniq_offset; + for (int i = 0; i < process->numCpus(); ++i) { + Tru64::nxm_sched_state *ssp = &rad_state->nxm_ss[i]; + ssp->nxm_u.sigmask = 0; + ssp->nxm_u.sig = 0; + ssp->nxm_u.flags = 0; + ssp->nxm_u.cancel_state = 0; + ssp->nxm_u.nxm_ssig = 0; + ssp->nxm_bits = 0; + ssp->nxm_quantum = attrp->nxm_quantum; + ssp->nxm_set_quantum = attrp->nxm_quantum; + ssp->nxm_sysevent = 0; + + if (i == 0) { + uint64_t uniq = xc->regs.miscRegs.uniq; + ssp->nxm_u.pth_id = uniq + attrp->nxm_uniq_offset; + ssp->nxm_u.nxm_active = uniq | 1; + } + else { + ssp->nxm_u.pth_id = 0; + ssp->nxm_u.nxm_active = 0; + } + } + rad_state.copyOut(xc->mem); -static void -init_exec_context(ExecContext *ec, - Tru64::nxm_thread_attr *attrp, uint64_t uniq_val) -{ - memset(&ec->regs, 0, sizeof(ec->regs)); + // + // copy pointer to shared config area out to user + // + *configptr_ptr = config_addr; + configptr_ptr.copyOut(xc->mem); - ec->regs.intRegFile[ArgumentReg0] = attrp->registers.a0; - ec->regs.intRegFile[27/*t12*/] = attrp->registers.pc; - ec->regs.intRegFile[StackPointerReg] = attrp->registers.sp; - ec->regs.miscRegs.uniq = uniq_val; + return 0; + } - ec->regs.pc = attrp->registers.pc; - ec->regs.npc = attrp->registers.pc + sizeof(MachInst); + /// Initialize execution context. + static void + init_exec_context(ExecContext *ec, + Tru64::nxm_thread_attr *attrp, uint64_t uniq_val) + { + memset(&ec->regs, 0, sizeof(ec->regs)); - ec->setStatus(ExecContext::Active); -} + ec->regs.intRegFile[ArgumentReg0] = attrp->registers.a0; + ec->regs.intRegFile[27/*t12*/] = attrp->registers.pc; + ec->regs.intRegFile[StackPointerReg] = attrp->registers.sp; + ec->regs.miscRegs.uniq = uniq_val; -static -int -nxm_thread_createFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - TypedBufferArg attrp(xc->getSyscallArg(0)); - TypedBufferArg kidp(xc->getSyscallArg(1)); - int thread_index = xc->getSyscallArg(2); - - // get attribute args - attrp.copyIn(xc->mem); - - if (attrp->version != NXM_LIB_VERSION) { - cerr << "nxm_thread_create: thread library version mismatch! " - << "got " << attrp->version - << ", expected " << NXM_LIB_VERSION << endl; - abort(); - } + ec->regs.pc = attrp->registers.pc; + ec->regs.npc = attrp->registers.pc + sizeof(MachInst); - if (thread_index < 0 | thread_index > process->numCpus()) { - cerr << "nxm_thread_create: bad thread index " << thread_index - << endl; - abort(); + ec->setStatus(ExecContext::Active); } - // On a real machine, the per-RAD shared structure is in - // shared memory, so both the user and kernel can get at it. - // We don't have that luxury, so we just copy it in and then - // back out again. - int rad_state_size = - (sizeof(Tru64::nxm_shared) + - (process->numCpus()-1) * sizeof(Tru64::nxm_sched_state)); + /// Create thread. + static int + nxm_thread_createFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) + { + TypedBufferArg attrp(xc->getSyscallArg(0)); + TypedBufferArg kidp(xc->getSyscallArg(1)); + int thread_index = xc->getSyscallArg(2); + + // get attribute args + attrp.copyIn(xc->mem); + + if (attrp->version != NXM_LIB_VERSION) { + cerr << "nxm_thread_create: thread library version mismatch! " + << "got " << attrp->version + << ", expected " << NXM_LIB_VERSION << endl; + abort(); + } - TypedBufferArg rad_state(0x14000, - rad_state_size); - rad_state.copyIn(xc->mem); + if (thread_index < 0 | thread_index > process->numCpus()) { + cerr << "nxm_thread_create: bad thread index " << thread_index + << endl; + abort(); + } - uint64_t uniq_val = attrp->pthid - rad_state->nxm_uniq_offset; + // On a real machine, the per-RAD shared structure is in + // shared memory, so both the user and kernel can get at it. + // We don't have that luxury, so we just copy it in and then + // back out again. + int rad_state_size = + (sizeof(Tru64::nxm_shared) + + (process->numCpus()-1) * sizeof(Tru64::nxm_sched_state)); - if (attrp->type == Tru64::NXM_TYPE_MANAGER) { - // DEC pthreads seems to always create one of these (in - // addition to N application threads), but we don't use it, - // so don't bother creating it. + TypedBufferArg rad_state(0x14000, + rad_state_size); + rad_state.copyIn(xc->mem); - // This is supposed to be a port number. Make something up. - *kidp = 99; - kidp.copyOut(xc->mem); + uint64_t uniq_val = attrp->pthid - rad_state->nxm_uniq_offset; - return 0; - } else if (attrp->type == Tru64::NXM_TYPE_VP) { - // A real "virtual processor" kernel thread. Need to fork - // this thread on another CPU. - Tru64::nxm_sched_state *ssp = &rad_state->nxm_ss[thread_index]; + if (attrp->type == Tru64::NXM_TYPE_MANAGER) { + // DEC pthreads seems to always create one of these (in + // addition to N application threads), but we don't use it, + // so don't bother creating it. - if (ssp->nxm_u.nxm_active != 0) - return Tru64::KERN_NOT_RECEIVER; + // This is supposed to be a port number. Make something up. + *kidp = 99; + kidp.copyOut(xc->mem); - ssp->nxm_u.pth_id = attrp->pthid; - ssp->nxm_u.nxm_active = uniq_val | 1; + return 0; + } else if (attrp->type == Tru64::NXM_TYPE_VP) { + // A real "virtual processor" kernel thread. Need to fork + // this thread on another CPU. + Tru64::nxm_sched_state *ssp = &rad_state->nxm_ss[thread_index]; - rad_state.copyOut(xc->mem); + if (ssp->nxm_u.nxm_active != 0) + return Tru64::KERN_NOT_RECEIVER; - Addr slot_state_addr = 0x12000 + sizeof(Tru64::nxm_config_info); - int slot_state_size = process->numCpus() * sizeof(Tru64::nxm_slot_state_t); + ssp->nxm_u.pth_id = attrp->pthid; + ssp->nxm_u.nxm_active = uniq_val | 1; - TypedBufferArg slot_state(slot_state_addr, - slot_state_size); + rad_state.copyOut(xc->mem); - slot_state.copyIn(xc->mem); + Addr slot_state_addr = 0x12000 + sizeof(Tru64::nxm_config_info); + int slot_state_size = + process->numCpus() * sizeof(Tru64::nxm_slot_state_t); - if (slot_state[thread_index] != Tru64::NXM_SLOT_AVAIL) { - cerr << "nxm_thread_createFunc: requested VP slot " - << thread_index << " not available!" << endl; - fatal(""); - } + TypedBufferArg + slot_state(slot_state_addr, + slot_state_size); - slot_state[thread_index] = Tru64::NXM_SLOT_BOUND; + slot_state.copyIn(xc->mem); - slot_state.copyOut(xc->mem); + if (slot_state[thread_index] != Tru64::NXM_SLOT_AVAIL) { + cerr << "nxm_thread_createFunc: requested VP slot " + << thread_index << " not available!" << endl; + fatal(""); + } - // Find a free simulator execution context. - for (int i = 0; i < process->numCpus(); ++i) { - ExecContext *xc = process->execContexts[i]; + slot_state[thread_index] = Tru64::NXM_SLOT_BOUND; - if (xc->status() == ExecContext::Unallocated) { - // inactive context... grab it - init_exec_context(xc, attrp, uniq_val); + slot_state.copyOut(xc->mem); - // This is supposed to be a port number, but we'll try - // and get away with just sticking the thread index - // here. - *kidp = thread_index; - kidp.copyOut(xc->mem); + // Find a free simulator execution context. + for (int i = 0; i < process->numCpus(); ++i) { + ExecContext *xc = process->execContexts[i]; - return 0; + if (xc->status() == ExecContext::Unallocated) { + // inactive context... grab it + init_exec_context(xc, attrp, uniq_val); + + // This is supposed to be a port number, but we'll try + // and get away with just sticking the thread index + // here. + *kidp = thread_index; + kidp.copyOut(xc->mem); + + return 0; + } } + + // fell out of loop... no available inactive context + cerr << "nxm_thread_create: no idle contexts available." << endl; + abort(); + } else { + cerr << "nxm_thread_create: can't handle thread type " + << attrp->type << endl; + abort(); } - // fell out of loop... no available inactive context - cerr << "nxm_thread_create: no idle contexts available." << endl; - abort(); - } else { - cerr << "nxm_thread_create: can't handle thread type " - << attrp->type << endl; - abort(); + return 0; } - return 0; -} - + /// Thread idle call (like yield()). + static int + nxm_idleFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) + { + return 0; + } -static -int -nxm_idleFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - return 0; -} + /// Block thread. + static int + nxm_thread_blockFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) + { + uint64_t tid = xc->getSyscallArg(0); + uint64_t secs = xc->getSyscallArg(1); + uint64_t flags = xc->getSyscallArg(2); + uint64_t action = xc->getSyscallArg(3); + uint64_t usecs = xc->getSyscallArg(4); -static -int -nxm_thread_blockFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - uint64_t tid = xc->getSyscallArg(0); - uint64_t secs = xc->getSyscallArg(1); - uint64_t flags = xc->getSyscallArg(2); - uint64_t action = xc->getSyscallArg(3); - uint64_t usecs = xc->getSyscallArg(4); + cout << xc->cpu->name() << ": nxm_thread_block " << tid << " " << secs + << " " << flags << " " << action << " " << usecs << endl; - cout << xc->cpu->name() << ": nxm_thread_block " << tid << " " << secs - << " " << flags << " " << action << " " << usecs << endl; + return 0; + } - return 0; -} + /// block. + static int + nxm_blockFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) + { + Addr uaddr = xc->getSyscallArg(0); + uint64_t val = xc->getSyscallArg(1); + uint64_t secs = xc->getSyscallArg(2); + uint64_t usecs = xc->getSyscallArg(3); + uint64_t flags = xc->getSyscallArg(4); + BaseCPU *cpu = xc->cpu; -static -int -nxm_blockFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - Addr uaddr = xc->getSyscallArg(0); - uint64_t val = xc->getSyscallArg(1); - uint64_t secs = xc->getSyscallArg(2); - uint64_t usecs = xc->getSyscallArg(3); - uint64_t flags = xc->getSyscallArg(4); + cout << cpu->name() << ": nxm_block " + << hex << uaddr << dec << " " << val + << " " << secs << " " << usecs + << " " << flags << endl; - BaseCPU *cpu = xc->cpu; + return 0; + } - cout << cpu->name() << ": nxm_block " << hex << uaddr << dec << " " << val - << " " << secs << " " << usecs - << " " << flags << endl; + /// Unblock thread. + static int + nxm_unblockFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) + { + Addr uaddr = xc->getSyscallArg(0); - return 0; -} + cout << xc->cpu->name() << ": nxm_unblock " + << hex << uaddr << dec << endl; + return 0; + } -static -int -nxm_unblockFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - Addr uaddr = xc->getSyscallArg(0); + /// Switch thread priority. + static int + swtch_priFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) + { + // Attempts to switch to another runnable thread (if there is + // one). Returns false if there are no other threads to run + // (i.e., the thread can reasonably spin-wait) or true if there + // are other threads. + // + // Since we assume at most one "kernel" thread per CPU, it's + // always safe to return false here. + return false; + } - cout << xc->cpu->name() << ": nxm_unblock " - << hex << uaddr << dec << endl; - return 0; -} + /// Activate exec context waiting on a channel. Just activate one + /// by default. + static int + activate_waiting_context(Addr uaddr, Process *process, + bool activate_all = false) + { + int num_activated = 0; + list::iterator i = process->waitList.begin(); + list::iterator end = process->waitList.end(); -static -int -swtch_priFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - // Attempts to switch to another runnable thread (if there is - // one). Returns false if there are no other threads to run - // (i.e., the thread can reasonably spin-wait) or true if there - // are other threads. - // - // Since we assume at most one "kernel" thread per CPU, it's - // always safe to return false here. - return false; -} + while (i != end && (num_activated == 0 || activate_all)) { + if (i->waitChan == uaddr) { + // found waiting process: make it active + ExecContext *newCtx = i->waitingContext; + assert(newCtx->status() == ExecContext::Suspended); + newCtx->setStatus(ExecContext::Active); + // get rid of this record + i = process->waitList.erase(i); -// just activate one by default -static int -activate_waiting_context(Addr uaddr, Process *process, - bool activate_all = false) -{ - int num_activated = 0; + ++num_activated; + } else { + ++i; + } + } - list::iterator i = process->waitList.begin(); - list::iterator end = process->waitList.end(); + return num_activated; + } - while (i != end && (num_activated == 0 || activate_all)) { - if (i->waitChan == uaddr) { - // found waiting process: make it active - ExecContext *newCtx = i->waitingContext; - assert(newCtx->status() == ExecContext::Suspended); - newCtx->setStatus(ExecContext::Active); + /// M5 hacked-up lock acquire. + static void + m5_lock_mutex(Addr uaddr, Process *process, ExecContext *xc) + { + TypedBufferArg lockp(uaddr); - // get rid of this record - i = process->waitList.erase(i); + lockp.copyIn(xc->mem); - ++num_activated; + if (*lockp == 0) { + // lock is free: grab it + *lockp = 1; + lockp.copyOut(xc->mem); } else { - ++i; + // lock is busy: disable until free + process->waitList.push_back(Process::WaitRec(uaddr, xc)); + xc->setStatus(ExecContext::Suspended); } } - return num_activated; -} - + /// M5 unlock call. + static void + m5_unlock_mutex(Addr uaddr, Process *process, ExecContext *xc) + { + TypedBufferArg lockp(uaddr); -static void -m5_lock_mutex(Addr uaddr, Process *process, ExecContext *xc) -{ - TypedBufferArg lockp(uaddr); + lockp.copyIn(xc->mem); + assert(*lockp != 0); - lockp.copyIn(xc->mem); + // Check for a process waiting on the lock. + int num_waiting = activate_waiting_context(uaddr, process); - if (*lockp == 0) { - // lock is free: grab it - *lockp = 1; - lockp.copyOut(xc->mem); - } else { - // lock is busy: disable until free - process->waitList.push_back(Process::WaitRec(uaddr, xc)); - xc->setStatus(ExecContext::Suspended); + // clear lock field if no waiting context is taking over the lock + if (num_waiting == 0) { + *lockp = 0; + lockp.copyOut(xc->mem); + } } -} -static void -m5_unlock_mutex(Addr uaddr, Process *process, ExecContext *xc) -{ - TypedBufferArg lockp(uaddr); - - lockp.copyIn(xc->mem); - assert(*lockp != 0); + /// Lock acquire syscall handler. + static int + m5_mutex_lockFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) + { + Addr uaddr = xc->getSyscallArg(0); - // Check for a process waiting on the lock. - int num_waiting = activate_waiting_context(uaddr, process); + m5_lock_mutex(uaddr, process, xc); - // clear lock field if no waiting context is taking over the lock - if (num_waiting == 0) { - *lockp = 0; - lockp.copyOut(xc->mem); + // Return 0 since we will always return to the user with the lock + // acquired. We will just keep the context inactive until that is + // true. + return 0; } -} - - -static -int -m5_mutex_lockFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - Addr uaddr = xc->getSyscallArg(0); - - m5_lock_mutex(uaddr, process, xc); - - // Return 0 since we will always return to the user with the lock - // acquired. We will just keep the context inactive until that is - // true. - return 0; -} + /// Try lock (non-blocking). + static int + m5_mutex_trylockFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) + { + Addr uaddr = xc->getSyscallArg(0); + TypedBufferArg lockp(uaddr); + + lockp.copyIn(xc->mem); + + if (*lockp == 0) { + // lock is free: grab it + *lockp = 1; + lockp.copyOut(xc->mem); + return 0; + } else { + return 1; + } + } -static -int -m5_mutex_trylockFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - Addr uaddr = xc->getSyscallArg(0); - TypedBufferArg lockp(uaddr); + /// Unlock syscall handler. + static int + m5_mutex_unlockFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) + { + Addr uaddr = xc->getSyscallArg(0); - lockp.copyIn(xc->mem); + m5_unlock_mutex(uaddr, process, xc); - if (*lockp == 0) { - // lock is free: grab it - *lockp = 1; - lockp.copyOut(xc->mem); return 0; - } else { - return 1; } -} - - -static -int -m5_mutex_unlockFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - Addr uaddr = xc->getSyscallArg(0); - - m5_unlock_mutex(uaddr, process, xc); - - return 0; -} + /// Signal ocndition. + static int + m5_cond_signalFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) + { + Addr cond_addr = xc->getSyscallArg(0); -static -int -m5_cond_signalFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - Addr cond_addr = xc->getSyscallArg(0); - - // Wqake up one process waiting on the condition variable. - activate_waiting_context(cond_addr, process); - - return 0; -} - + // Wake up one process waiting on the condition variable. + activate_waiting_context(cond_addr, process); -static -int -m5_cond_broadcastFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - Addr cond_addr = xc->getSyscallArg(0); - - // Wake up all processes waiting on the condition variable. - activate_waiting_context(cond_addr, process, true); - - return 0; -} - - -static -int -m5_cond_waitFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - Addr cond_addr = xc->getSyscallArg(0); - Addr lock_addr = xc->getSyscallArg(1); - TypedBufferArg condp(cond_addr); - TypedBufferArg lockp(lock_addr); - - // user is supposed to acquire lock before entering - lockp.copyIn(xc->mem); - assert(*lockp != 0); - - m5_unlock_mutex(lock_addr, process, xc); + return 0; + } - process->waitList.push_back(Process::WaitRec(cond_addr, xc)); - xc->setStatus(ExecContext::Suspended); + /// Wake up all processes waiting on the condition variable. + static int + m5_cond_broadcastFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) + { + Addr cond_addr = xc->getSyscallArg(0); - return 0; -} + activate_waiting_context(cond_addr, process, true); + return 0; + } -static -int -m5_thread_exitFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - assert(xc->status() == ExecContext::Active); - xc->setStatus(ExecContext::Unallocated); + /// Wait on a condition. + static int + m5_cond_waitFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) + { + Addr cond_addr = xc->getSyscallArg(0); + Addr lock_addr = xc->getSyscallArg(1); + TypedBufferArg condp(cond_addr); + TypedBufferArg lockp(lock_addr); - return 0; -} + // user is supposed to acquire lock before entering + lockp.copyIn(xc->mem); + assert(*lockp != 0); + m5_unlock_mutex(lock_addr, process, xc); -static SyscallDesc machSyscallDescs[]; + process->waitList.push_back(Process::WaitRec(cond_addr, xc)); + xc->setStatus(ExecContext::Suspended); -static const int Num_Mach_Syscall_Descs; -static const int Max_Mach_Syscall_Desc; + return 0; + } -// Since negated values are used to identify Mach syscalls, the -// minimum (signed) valid syscall number is the negated max Mach -// syscall number. -static const int Min_Syscall_Desc; + /// Thread exit. + static int + m5_thread_exitFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) + { + assert(xc->status() == ExecContext::Active); + xc->setStatus(ExecContext::Unallocated); -// -// helper function for invoking syscalls -// -static -void -doSyscall(int callnum, Process *process, ExecContext *xc) -{ - if (callnum < Min_Syscall_Desc || callnum > Max_Syscall_Desc) { - cerr << "Syscall " << callnum << " out of range" << endl; - abort(); + return 0; } - SyscallDesc *desc = - (callnum < 0) ? &machSyscallDescs[-callnum] : &syscallDescs[callnum]; + /// Array of syscall descriptors for Mach syscalls, indexed by + /// (negated) call number. + static SyscallDesc machSyscallDescs[]; + + /// Number of syscalls in machSyscallDescs[]. + static const int Num_Mach_Syscall_Descs; + + /// Max supported Mach syscall number. + static const int Max_Mach_Syscall_Desc; + + /// Since negated values are used to identify Mach syscalls, the + /// minimum (signed) valid syscall number is the negated max Mach + /// syscall number. + static const int Min_Syscall_Desc; + + /// Do the specified syscall. Just looks the call number up in + /// the table and invokes the appropriate handler. + static void + doSyscall(int callnum, Process *process, ExecContext *xc) + { + if (callnum < Min_Syscall_Desc || callnum > Max_Syscall_Desc) { + cerr << "Syscall " << callnum << " out of range" << endl; + abort(); + } - desc->doSyscall(callnum, process, xc); -} + SyscallDesc *desc = + (callnum < 0) ? + &machSyscallDescs[-callnum] : &syscallDescs[callnum]; -// -// Indirect syscall invocation (call #0) -// -static -int -indirectSyscallFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - int new_callnum = xc->getSyscallArg(0); + desc->doSyscall(callnum, process, xc); + } - for (int i = 0; i < 5; ++i) - xc->setSyscallArg(i, xc->getSyscallArg(i+1)); + /// Indirect syscall invocation (call #0). + static int + indirectSyscallFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) + { + int new_callnum = xc->getSyscallArg(0); - doSyscall(new_callnum, process, xc); + for (int i = 0; i < 5; ++i) + xc->setSyscallArg(i, xc->getSyscallArg(i+1)); - return 0; -} + doSyscall(new_callnum, process, xc); + return 0; + } }; // class Tru64 // open(2) flags translation table OpenFlagTransTable Tru64::openFlagTable[] = { - /* target flag */ /* host flag */ #ifdef _MSC_VER { Tru64::TGT_O_RDONLY, _O_RDONLY }, { Tru64::TGT_O_WRONLY, _O_WRONLY }, diff --git a/arch/alpha/alpha_tru64_process.hh b/arch/alpha/alpha_tru64_process.hh index 2b03d66b2..8e5a64b51 100644 --- a/arch/alpha/alpha_tru64_process.hh +++ b/arch/alpha/alpha_tru64_process.hh @@ -31,15 +31,18 @@ #include "sim/process.hh" +/// A process with emulated Alpha Tru64 syscalls. class AlphaTru64Process : public LiveProcess { public: + /// Constructor. AlphaTru64Process(const std::string &name, ObjectFile *objFile, int stdin_fd, int stdout_fd, int stderr_fd, std::vector &argv, std::vector &envp); + /// Syscall emulation function. virtual void syscall(ExecContext *xc); }; -- cgit v1.2.3