summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBrandon Potter <Brandon.Potter@amd.com>2017-03-01 13:24:16 -0600
committerBrandon Potter <Brandon.Potter@amd.com>2017-03-09 22:42:45 +0000
commitacce7b0dc0edf85b99c75d1800df99bd9e288b01 (patch)
tree1737ac1d3885f083f3c568c41870ff97caa9fe66 /src
parente5fe2b82b7cf8842a5a202da69c003d2a2c6af3f (diff)
downloadgem5-acce7b0dc0edf85b99c75d1800df99bd9e288b01.tar.xz
syscall-emul: Add functionality to open syscalls
This changeset adds refactors the existing open system call, adds the openat variant (enabled for x86 builds), and adds additional "special file" test cases for /proc/meminfo and /etc/passwd. Change-Id: I6f429db65bbf2a28ffa3fd12df518c2d0de49663 Reviewed-on: https://gem5-review.googlesource.com/2265 Maintainer: Jason Lowe-Power <jason@lowepower.com> Reviewed-by: Tony Gutierrez <anthony.gutierrez@amd.com> Reviewed-by: Michael LeBeane <Michael.Lebeane@amd.com>
Diffstat (limited to 'src')
-rw-r--r--src/arch/x86/linux/process.cc4
-rw-r--r--src/kern/linux/linux.cc35
-rw-r--r--src/kern/linux/linux.hh1
-rw-r--r--src/kern/solaris/solaris.hh3
-rw-r--r--src/sim/syscall_emul.cc1
-rw-r--r--src/sim/syscall_emul.hh174
6 files changed, 147 insertions, 71 deletions
diff --git a/src/arch/x86/linux/process.cc b/src/arch/x86/linux/process.cc
index 806d8605b..f90022bdd 100644
--- a/src/arch/x86/linux/process.cc
+++ b/src/arch/x86/linux/process.cc
@@ -477,7 +477,7 @@ static SyscallDesc syscallDescs64[] = {
/* 254 */ SyscallDesc("inotify_add_watch", unimplementedFunc),
/* 255 */ SyscallDesc("inotify_rm_watch", unimplementedFunc),
/* 256 */ SyscallDesc("migrate_pages", unimplementedFunc),
- /* 257 */ SyscallDesc("openat", unimplementedFunc),
+ /* 257 */ SyscallDesc("openat", openatFunc<X86Linux64>),
/* 258 */ SyscallDesc("mkdirat", unimplementedFunc),
/* 259 */ SyscallDesc("mknodat", unimplementedFunc),
/* 260 */ SyscallDesc("fchownat", unimplementedFunc),
@@ -844,7 +844,7 @@ static SyscallDesc syscallDescs32[] = {
/* 292 */ SyscallDesc("inotify_add_watch", unimplementedFunc),
/* 293 */ SyscallDesc("inotify_rm_watch", unimplementedFunc),
/* 294 */ SyscallDesc("migrate_pages", unimplementedFunc),
- /* 295 */ SyscallDesc("openat", unimplementedFunc),
+ /* 295 */ SyscallDesc("openat", openatFunc<X86Linux32>),
/* 296 */ SyscallDesc("mkdirat", unimplementedFunc),
/* 297 */ SyscallDesc("mknodat", unimplementedFunc),
/* 298 */ SyscallDesc("fchownat", unimplementedFunc),
diff --git a/src/kern/linux/linux.cc b/src/kern/linux/linux.cc
index 493be9611..bd0b4d09a 100644
--- a/src/kern/linux/linux.cc
+++ b/src/kern/linux/linux.cc
@@ -33,6 +33,7 @@
#include <cstdio>
#include <string>
+#include "cpu/base.hh"
#include "debug/SyscallVerbose.hh"
#include "sim/process.hh"
#include "sim/system.hh"
@@ -41,21 +42,35 @@ int
Linux::openSpecialFile(std::string path, Process *process,
ThreadContext *tc)
{
- DPRINTF(SyscallVerbose, "Opening special file: %s\n", path.c_str());
+ DPRINTFR(SyscallVerbose,
+ "%d: %s: generic-open: opening special file: %s\n",
+ curTick(), tc->getCpuPtr()->name(), path.c_str());
+
+ bool matched = false;
+ std::string data;
+
if (path.compare(0, 13, "/proc/meminfo") == 0) {
- std::string data = Linux::procMeminfo(process, tc);
+ data = Linux::procMeminfo(process, tc);
+ matched = true;
+ } else if (path.compare(0, 11, "/etc/passwd") == 0) {
+ data = Linux::etcPasswd(process, tc);
+ matched = true;
+ }
+
+ if (matched) {
FILE *f = tmpfile();
int fd = fileno(f);
size_t ret M5_VAR_USED = fwrite(data.c_str(), 1, data.size(), f);
assert(ret == data.size());
rewind(f);
return fd;
+ } else {
+ warn("Attempting to open special file: %s. Ignoring. Simulation may "
+ "take un-expected code path or be non-deterministic until proper "
+ "handling is implemented.\n", path.c_str());
+ errno = EACCES;
+ return -1;
}
-
- warn("Attempting to open special file: %s. Ignoring. Simulation may"
- " take un-expected code path or be non-deterministic until proper"
- " handling is implemented.\n", path.c_str());
- return -1;
}
std::string
@@ -66,3 +81,9 @@ Linux::procMeminfo(Process *process, ThreadContext *tc)
process->system->freeMemSize() >> 10);
}
+std::string
+Linux::etcPasswd(Process *process, ThreadContext *tc)
+{
+ return csprintf("gem5-user:x:1000:1000:gem5-user,,,:%s:/bin/bash\n",
+ process->getcwd());
+}
diff --git a/src/kern/linux/linux.hh b/src/kern/linux/linux.hh
index e6899a9ca..b24ee3895 100644
--- a/src/kern/linux/linux.hh
+++ b/src/kern/linux/linux.hh
@@ -226,6 +226,7 @@ class Linux : public OperatingSystem
static int openSpecialFile(std::string path, Process *process,
ThreadContext *tc);
static std::string procMeminfo(Process *process, ThreadContext *tc);
+ static std::string etcPasswd(Process *process, ThreadContext *tc);
// For futex system call
static const unsigned TGT_FUTEX_WAIT = 0;
diff --git a/src/kern/solaris/solaris.hh b/src/kern/solaris/solaris.hh
index 9cd5af16f..d875f4402 100644
--- a/src/kern/solaris/solaris.hh
+++ b/src/kern/solaris/solaris.hh
@@ -114,6 +114,9 @@ class Solaris : public OperatingSystem
char machine[_SYS_NMLN]; //!< Machine type.
} utsname;
+ // for *at syscalls
+ static const int TGT_AT_FDCWD = -100;
+
}; // class Solaris
#endif // __SOLARIS_HH__
diff --git a/src/sim/syscall_emul.cc b/src/sim/syscall_emul.cc
index 2459c801f..968019323 100644
--- a/src/sim/syscall_emul.cc
+++ b/src/sim/syscall_emul.cc
@@ -365,7 +365,6 @@ getcwdFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
return (result == -1) ? -errno : result;
}
-/// Target open() handler.
SyscallReturn
readlinkFunc(SyscallDesc *desc, int callnum, Process *process,
ThreadContext *tc)
diff --git a/src/sim/syscall_emul.hh b/src/sim/syscall_emul.hh
index 099ff58d9..d379bbe85 100644
--- a/src/sim/syscall_emul.hh
+++ b/src/sim/syscall_emul.hh
@@ -613,80 +613,136 @@ ioctlFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
}
template <class OS>
-static SyscallReturn
-openFunc(SyscallDesc *desc, int callnum, Process *process,
- ThreadContext *tc, int index)
+SyscallReturn
+openImpl(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc,
+ bool isopenat)
{
- std::string path;
+ int index = 0;
+ int tgt_dirfd = -1;
- if (!tc->getMemProxy().tryReadString(path,
- process->getSyscallArg(tc, index)))
- return -EFAULT;
+ /**
+ * If using the openat variant, read in the target directory file
+ * descriptor from the simulated process.
+ */
+ if (isopenat)
+ tgt_dirfd = p->getSyscallArg(tc, index);
- int tgtFlags = process->getSyscallArg(tc, index);
- int mode = process->getSyscallArg(tc, index);
- int hostFlags = 0;
+ /**
+ * Retrieve the simulated process' memory proxy and then read in the path
+ * string from that memory space into the host's working memory space.
+ */
+ std::string path;
+ if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
+ return -EFAULT;
- // translate open flags
+#ifdef __CYGWIN32__
+ int host_flags = O_BINARY;
+#else
+ int host_flags = 0;
+#endif
+ /**
+ * Translate target flags into host flags. Flags exist which are not
+ * ported between architectures which can cause check failures.
+ */
+ int tgt_flags = p->getSyscallArg(tc, index);
for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) {
- if (tgtFlags & OS::openFlagTable[i].tgtFlag) {
- tgtFlags &= ~OS::openFlagTable[i].tgtFlag;
- hostFlags |= OS::openFlagTable[i].hostFlag;
+ if (tgt_flags & OS::openFlagTable[i].tgtFlag) {
+ tgt_flags &= ~OS::openFlagTable[i].tgtFlag;
+ host_flags |= OS::openFlagTable[i].hostFlag;
}
}
-
- // any target flags left?
- if (tgtFlags != 0)
- warn("Syscall: open: cannot decode flags 0x%x", tgtFlags);
-
+ if (tgt_flags) {
+ warn("open%s: cannot decode flags 0x%x",
+ isopenat ? "at" : "", tgt_flags);
+ }
#ifdef __CYGWIN32__
- hostFlags |= O_BINARY;
+ host_flags |= O_BINARY;
#endif
- // Adjust path for current working directory
- path = process->fullPath(path);
+ int mode = p->getSyscallArg(tc, index);
- DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str());
+ /**
+ * If the simulated process called open or openat with AT_FDCWD specified,
+ * take the current working directory value which was passed into the
+ * process class as a Python parameter and append the current path to
+ * create a full path.
+ * Otherwise, openat with a valid target directory file descriptor has
+ * been called. If the path option, which was passed in as a parameter,
+ * is not absolute, retrieve the directory file descriptor's path and
+ * prepend it to the path passed in as a parameter.
+ * In every case, we should have a full path (which is relevant to the
+ * host) to work with after this block has been passed.
+ */
+ if (!isopenat || (isopenat && tgt_dirfd == OS::TGT_AT_FDCWD)) {
+ path = p->fullPath(path);
+ } else if (!startswith(path, "/")) {
+ std::shared_ptr<FDEntry> fdep = ((*p->fds)[tgt_dirfd]);
+ auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep);
+ if (!ffdp)
+ return -EBADF;
+ path.insert(0, ffdp->getFileName());
+ }
+ /**
+ * Since this is an emulated environment, we create pseudo file
+ * descriptors for device requests that have been registered with
+ * the process class through Python; this allows us to create a file
+ * descriptor for subsequent ioctl or mmap calls.
+ */
if (startswith(path, "/dev/")) {
std::string filename = path.substr(strlen("/dev/"));
- if (filename == "sysdev0") {
- // This is a memory-mapped high-resolution timer device on Alpha.
- // We don't support it, so just punt.
- warn("Ignoring open(%s, ...)\n", path);
- return -ENOENT;
- }
-
- EmulatedDriver *drv = process->findDriver(filename);
+ EmulatedDriver *drv = p->findDriver(filename);
if (drv) {
- // the driver's open method will allocate a fd from the
- // process if necessary.
- return drv->open(process, tc, mode, hostFlags);
+ DPRINTF_SYSCALL(Verbose, "open%s: passing call to "
+ "driver open with path[%s]\n",
+ isopenat ? "at" : "", path.c_str());
+ return drv->open(p, tc, mode, host_flags);
}
+ /**
+ * Fall through here for pass through to host devices, such
+ * as /dev/zero
+ */
+ }
- // fall through here for pass through to host devices, such as
- // /dev/zero
+ /**
+ * Some special paths and files cannot be called on the host and need
+ * to be handled as special cases inside the simulator.
+ * If the full path that was created above does not match any of the
+ * special cases, pass it through to the open call on the host to let
+ * the host open the file on our behalf.
+ * If the host cannot open the file, return the host's error code back
+ * through the system call to the simulated process.
+ */
+ int sim_fd = -1;
+ std::vector<std::string> special_paths =
+ { "/proc/", "/system/", "/sys/", "/platform/", "/etc/passwd" };
+ for (auto entry : special_paths) {
+ if (startswith(path, entry))
+ sim_fd = OS::openSpecialFile(path, p, tc);
+ }
+ if (sim_fd == -1) {
+ sim_fd = open(path.c_str(), host_flags, mode);
+ }
+ if (sim_fd == -1) {
+ int local = -errno;
+ DPRINTF_SYSCALL(Verbose, "open%s: failed -> path:%s\n",
+ isopenat ? "at" : "", path.c_str());
+ return local;
}
- int fd;
- int local_errno;
- if (startswith(path, "/proc/") || startswith(path, "/system/") ||
- startswith(path, "/platform/") || startswith(path, "/sys/")) {
- // It's a proc/sys entry and requires special handling
- fd = OS::openSpecialFile(path, process, tc);
- local_errno = ENOENT;
- } else {
- // open the file
- fd = open(path.c_str(), hostFlags, mode);
- local_errno = errno;
- }
-
- if (fd == -1)
- return -local_errno;
-
- std::shared_ptr<FileFDEntry> ffdp =
- std::make_shared<FileFDEntry>(fd, hostFlags, path.c_str(), false);
- return process->fds->allocFD(ffdp);
+ /**
+ * The file was opened successfully and needs to be recorded in the
+ * process' file descriptor array so that it can be retrieved later.
+ * The target file descriptor that is chosen will be the lowest unused
+ * file descriptor.
+ * Return the indirect target file descriptor back to the simulated
+ * process to act as a handle for the opened file.
+ */
+ auto ffdp = std::make_shared<FileFDEntry>(sim_fd, host_flags, path, 0);
+ int tgt_fd = p->fds->allocFD(ffdp);
+ DPRINTF_SYSCALL(Verbose, "open%s: sim_fd[%d], target_fd[%d] -> path:%s\n",
+ isopenat ? "at" : "", sim_fd, tgt_fd, path.c_str());
+ return tgt_fd;
}
/// Target open() handler.
@@ -695,7 +751,7 @@ SyscallReturn
openFunc(SyscallDesc *desc, int callnum, Process *process,
ThreadContext *tc)
{
- return openFunc<OS>(desc, callnum, process, tc, 0);
+ return openImpl<OS>(desc, callnum, process, tc, false);
}
/// Target openat() handler.
@@ -704,11 +760,7 @@ SyscallReturn
openatFunc(SyscallDesc *desc, int callnum, Process *process,
ThreadContext *tc)
{
- int index = 0;
- int dirfd = process->getSyscallArg(tc, index);
- if (dirfd != OS::TGT_AT_FDCWD)
- warn("openat: first argument not AT_FDCWD; unlikely to work");
- return openFunc<OS>(desc, callnum, process, tc, 1);
+ return openImpl<OS>(desc, callnum, process, tc, true);
}
/// Target unlinkat() handler.