summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteve Reinhardt <stever@eecs.umich.edu>2003-12-01 22:39:27 -0800
committerSteve Reinhardt <stever@eecs.umich.edu>2003-12-01 22:39:27 -0800
commit9984b2bd6ccee7e24843236315c19f0f0c83f685 (patch)
treed7891068695af2a23b313efc61df092d44f21774
parent745f0044cd65d476b3b190377989eb0af3738df5 (diff)
downloadgem5-9984b2bd6ccee7e24843236315c19f0f0c83f685.tar.xz
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
-rw-r--r--arch/alpha/alpha_linux_process.cc588
-rw-r--r--arch/alpha/alpha_linux_process.hh4
-rw-r--r--arch/alpha/alpha_tru64_process.cc2202
-rw-r--r--arch/alpha/alpha_tru64_process.hh3
-rw-r--r--sim/syscall_emul.cc9
-rw-r--r--sim/syscall_emul.hh80
6 files changed, 1449 insertions, 1437 deletions
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<Linux::tgt_stat> 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<Linux::utsname> 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<uint64_t> 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<Linux::tgt_stat> 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<Linux::utsname> 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<uint64_t> 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<uint64_t> 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<uint64_t> 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<std::string> &argv,
std::vector<std::string> &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<Tru64::F64_stat> 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<Tru64::utsname> 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<uint32_t> max_cpu(xc->getSyscallArg(1));
- *max_cpu = process->numCpus();
- max_cpu.copyOut(xc->mem);
- return 1;
- }
-
- case Tru64::GSI_CPUS_IN_BOX: {
- TypedBufferArg<uint32_t> cpus_in_box(xc->getSyscallArg(1));
- *cpus_in_box = process->numCpus();
- cpus_in_box.copyOut(xc->mem);
- return 1;
- }
-
- case Tru64::GSI_PHYSMEM: {
- TypedBufferArg<uint64_t> physmem(xc->getSyscallArg(1));
- *physmem = 1024 * 1024; // physical memory in KB
- physmem.copyOut(xc->mem);
- return 1;
- }
-
- case Tru64::GSI_CPU_INFO: {
- TypedBufferArg<Tru64::cpu_info> 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<uint64_t> 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<uint64_t> 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<Tru64::F64_stat> 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<Tru64::utsname> 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<uint32_t> max_cpu(xc->getSyscallArg(1));
+ *max_cpu = process->numCpus();
+ max_cpu.copyOut(xc->mem);
+ return 1;
+ }
+
+ case Tru64::GSI_CPUS_IN_BOX: {
+ TypedBufferArg<uint32_t> cpus_in_box(xc->getSyscallArg(1));
+ *cpus_in_box = process->numCpus();
+ cpus_in_box.copyOut(xc->mem);
+ return 1;
+ }
+
+ case Tru64::GSI_PHYSMEM: {
+ TypedBufferArg<uint64_t> physmem(xc->getSyscallArg(1));
+ *physmem = 1024 * 1024; // physical memory in KB
+ physmem.copyOut(xc->mem);
+ return 1;
+ }
+
+ case Tru64::GSI_CPU_INFO: {
+ TypedBufferArg<Tru64::cpu_info> 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<uint64_t> 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<uint64_t> 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<int64_t> 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<int64_t> 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<Tru64::dirent> 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<Tru64::dirent> 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<Tru64::sigcontext> sc(xc->getSyscallArg(0));
+ sc.copyIn(xc->mem);
-static
-int
-sigreturnFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
-{
- RegFile *regs = &xc->regs;
- TypedBufferArg<Tru64::sigcontext> 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<Tru64::tbl_sysinfo> 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<Tru64::tbl_sysinfo> 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<Tru64::vm_stack> 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<Tru64::vm_stack> 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<Tru64::nxm_task_attr> attrp(xc->getSyscallArg(0));
- TypedBufferArg<Addr> 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<Tru64::nxm_task_attr> attrp(xc->getSyscallArg(0));
+ TypedBufferArg<Addr> 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<Tru64::nxm_config_info> 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<Tru64::nxm_slot_state_t> 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<Tru64::nxm_shared> 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<Tru64::nxm_config_info> 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<Tru64::nxm_slot_state_t> 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<Tru64::nxm_shared> 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<Tru64::nxm_thread_attr> attrp(xc->getSyscallArg(0));
- TypedBufferArg<uint64_t> 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<Tru64::nxm_thread_attr> attrp(xc->getSyscallArg(0));
+ TypedBufferArg<uint64_t> 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<Tru64::nxm_shared> 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<Tru64::nxm_shared> 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<Tru64::nxm_slot_state_t> 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<Tru64::nxm_slot_state_t>
+ 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<Process::WaitRec>::iterator i = process->waitList.begin();
+ list<Process::WaitRec>::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<Process::WaitRec>::iterator i = process->waitList.begin();
- list<Process::WaitRec>::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<uint64_t> 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<uint64_t> lockp(uaddr);
-static void
-m5_lock_mutex(Addr uaddr, Process *process, ExecContext *xc)
-{
- TypedBufferArg<uint64_t> 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<uint64_t> 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<uint64_t> 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<uint64_t> 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<uint64_t> condp(cond_addr);
- TypedBufferArg<uint64_t> 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<uint64_t> condp(cond_addr);
+ TypedBufferArg<uint64_t> 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<std::string> &argv,
std::vector<std::string> &envp);
+ /// Syscall emulation function.
virtual void syscall(ExecContext *xc);
};
diff --git a/sim/syscall_emul.cc b/sim/syscall_emul.cc
index 0e4e78612..9955d4421 100644
--- a/sim/syscall_emul.cc
+++ b/sim/syscall_emul.cc
@@ -57,9 +57,6 @@ SyscallDesc::doSyscall(int callnum, Process *process, ExecContext *xc)
}
-//
-// Handler for unimplemented syscalls that we haven't thought about.
-//
int
unimplementedFunc(SyscallDesc *desc, int callnum, Process *process,
ExecContext *xc)
@@ -73,12 +70,6 @@ unimplementedFunc(SyscallDesc *desc, int callnum, Process *process,
}
-//
-// Handler for unimplemented syscalls that we never intend to
-// implement (signal handling, etc.) and should not affect the correct
-// behavior of the program. Print a warning only if the appropriate
-// trace flag is enabled. Return success to the target program.
-//
int
ignoreFunc(SyscallDesc *desc, int callnum, Process *process,
ExecContext *xc)
diff --git a/sim/syscall_emul.hh b/sim/syscall_emul.hh
index a02b4a608..1031b0823 100644
--- a/sim/syscall_emul.hh
+++ b/sim/syscall_emul.hh
@@ -51,6 +51,7 @@ class SyscallDesc {
public:
+ /// Typedef for target syscall handler functions.
typedef int (*FuncPtr)(SyscallDesc *, int num,
Process *, ExecContext *);
@@ -58,7 +59,6 @@ class SyscallDesc {
FuncPtr funcPtr; //!< Pointer to emulation function.
int flags; //!< Flags (see Flags enum).
-
/// Flag values for controlling syscall behavior.
enum Flags {
/// Don't set return regs according to funcPtr return value.
@@ -155,17 +155,40 @@ class TypedBufferArg : public BaseBufferArg
//////////////////////////////////////////////////////////////////////
+/// Handler for unimplemented syscalls that we haven't thought about.
int unimplementedFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
+
+/// Handler for unimplemented syscalls that we never intend to
+/// implement (signal handling, etc.) and should not affect the correct
+/// behavior of the program. Print a warning only if the appropriate
+/// trace flag is enabled. Return success to the target program.
int ignoreFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
+/// Target exit() handler: terminate simulation.
int exitFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
+
+/// Target getpagesize() handler.
int getpagesizeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
+
+/// Target obreak() handler: set brk address.
int obreakFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
+
+/// Target close() handler.
int closeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
+
+/// Target read() handler.
int readFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
+
+/// Target write() handler.
int writeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
+
+/// Target lseek() handler.
int lseekFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
+
+/// Target munmap() handler.
int munmapFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
+
+/// Target gethostname() handler.
int gethostnameFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
//////////////////////////////////////////////////////////////////////
@@ -175,6 +198,9 @@ int gethostnameFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
//
//////////////////////////////////////////////////////////////////////
+/// Target ioctl() handler. For the most part, programs call ioctl()
+/// only to find out if their stdout is a tty, to determine whether to
+/// do line or block buffering.
template <class OS>
int
ioctlFunc(SyscallDesc *desc, int callnum, Process *process,
@@ -204,12 +230,15 @@ ioctlFunc(SyscallDesc *desc, int callnum, Process *process,
}
}
+/// This struct is used to build an target-OS-dependent table that
+/// maps the target's open() flags to the host open() flags.
struct OpenFlagTransTable {
- int tgtFlag;
- int hostFlag;
+ int tgtFlag; //!< Target system flag value.
+ int hostFlag; //!< Corresponding host system flag value.
};
+/// Target open() handler.
template <class OS>
int
openFunc(SyscallDesc *desc, int callnum, Process *process,
@@ -254,6 +283,7 @@ openFunc(SyscallDesc *desc, int callnum, Process *process,
}
+/// Target stat() handler.
template <class OS>
int
statFunc(SyscallDesc *desc, int callnum, Process *process,
@@ -276,6 +306,7 @@ statFunc(SyscallDesc *desc, int callnum, Process *process,
}
+/// Target lstat() handler.
template <class OS>
int
lstatFunc(SyscallDesc *desc, int callnum, Process *process,
@@ -297,6 +328,7 @@ lstatFunc(SyscallDesc *desc, int callnum, Process *process,
return 0;
}
+/// Target fstat() handler.
template <class OS>
int
fstatFunc(SyscallDesc *desc, int callnum, Process *process,
@@ -321,18 +353,18 @@ fstatFunc(SyscallDesc *desc, int callnum, Process *process,
}
+/// Target mmap() handler.
+///
+/// We don't really handle mmap(). If the target is mmaping an
+/// anonymous region or /dev/zero, we can get away with doing basically
+/// nothing (since memory is initialized to zero and the simulator
+/// doesn't really check addresses anyway). Always print a warning,
+/// since this could be seriously broken if we're not mapping
+/// /dev/zero.
//
-// We don't really handle mmap(). If the target is mmaping an
-// anonymous region or /dev/zero, we can get away with doing basically
-// nothing (since memory is initialized to zero and the simulator
-// doesn't really check addresses anyway). Always print a warning,
-// since this could be seriously broken if we're not mapping
-// /dev/zero.
-//
-// Someday we should explicitly check for /dev/zero in open, flag the
-// file descriptor, and fail (or implement!) a non-anonymous mmap to
-// anything else.
-//
+/// Someday we should explicitly check for /dev/zero in open, flag the
+/// file descriptor, and fail (or implement!) a non-anonymous mmap to
+/// anything else.
template <class OS>
int
mmapFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
@@ -341,7 +373,7 @@ mmapFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
uint64_t length = xc->getSyscallArg(1);
// int prot = xc->getSyscallArg(2);
int flags = xc->getSyscallArg(3);
- int fd = p->sim_fd(xc->getSyscallArg(4));
+ // int fd = p->sim_fd(xc->getSyscallArg(4));
// int offset = xc->getSyscallArg(5);
if (start == 0) {
@@ -352,13 +384,13 @@ mmapFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
if (!(flags & OS::TGT_MAP_ANONYMOUS)) {
DPRINTF(SyscallWarnings, "Warning: allowing mmap of file @ fd %d. "
- "This will break if not /dev/zero.", fd);
+ "This will break if not /dev/zero.", xc->getSyscallArg(4));
}
return start;
}
-
+/// Target getrlimit() handler.
template <class OS>
int
getrlimitFunc(SyscallDesc *desc, int callnum, Process *process,
@@ -383,16 +415,16 @@ getrlimitFunc(SyscallDesc *desc, int callnum, Process *process,
return 0;
}
-// 1M usecs in 1 sec, for readability
+/// A readable name for 1,000,000, for converting microseconds to seconds.
const int one_million = 1000000;
-// seconds since the epoch (1/1/1970)... about a billion, by my reckoning
+/// Approximate seconds since the epoch (1/1/1970). About a billion,
+/// by my reckoning. We want to keep this a constant (not use the
+/// real-world time) to keep simulations repeatable.
const unsigned seconds_since_epoch = 1000000000;
-//
-// helper function: populate struct timeval with approximation of
-// current elapsed time
-//
+/// Helper function to convert current elapsed time to seconds and
+/// microseconds.
template <class T1, class T2>
void
getElapsedTime(T1 &sec, T2 &usec)
@@ -405,6 +437,7 @@ getElapsedTime(T1 &sec, T2 &usec)
}
+/// Target gettimeofday() handler.
template <class OS>
int
gettimeofdayFunc(SyscallDesc *desc, int callnum, Process *process,
@@ -421,6 +454,7 @@ gettimeofdayFunc(SyscallDesc *desc, int callnum, Process *process,
}
+/// Target getrusage() function.
template <class OS>
int
getrusageFunc(SyscallDesc *desc, int callnum, Process *process,