syscall_emul: add EmulatedDriver object
authorSteve Reinhardt <steve.reinhardt@amd.com>
Wed, 22 Oct 2014 22:53:34 +0000 (15:53 -0700)
committerSteve Reinhardt <steve.reinhardt@amd.com>
Wed, 22 Oct 2014 22:53:34 +0000 (15:53 -0700)
Fake SE-mode device drivers can now be added by
deriving from this abstract object.

src/sim/Process.py
src/sim/emul_driver.hh [new file with mode: 0644]
src/sim/process.cc
src/sim/process.hh
src/sim/syscall_emul.hh

index 6f2322805c32ac6afeaf94a4ee41a01a5095f9e5..7e5f753634134f0ab56905ef4d733e7854c4f170 100644 (file)
@@ -46,6 +46,12 @@ class Process(SimObject):
     def export_methods(cls, code):
         code('bool map(Addr vaddr, Addr paddr, int size);')
 
+class EmulatedDriver(SimObject):
+    type = 'EmulatedDriver'
+    cxx_header = "sim/emul_driver.hh"
+    abstract = True
+    filename = Param.String("device file name (under /dev)")
+
 class LiveProcess(Process):
     type = 'LiveProcess'
     cxx_header = "sim/process.hh"
@@ -60,3 +66,5 @@ class LiveProcess(Process):
     pid = Param.Int(100, 'process id')
     ppid = Param.Int(99, 'parent process id')
     simpoint = Param.UInt64(0, 'simulation point at which to start simulation')
+    drivers = VectorParam.EmulatedDriver([], 'Available emulated drivers')
+
diff --git a/src/sim/emul_driver.hh b/src/sim/emul_driver.hh
new file mode 100644 (file)
index 0000000..778fc64
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2014 Advanced Micro Devices, Inc.
+ * All rights reserved
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Steve Reinhardt
+ */
+
+#ifndef __SIM_EMUL_DRIVER_HH
+#define __SIM_EMUL_DRIVER_HH
+
+#include <string>
+
+#include "params/EmulatedDriver.hh"
+#include "sim/sim_object.hh"
+
+class LiveProcess;
+class ThreadContext;
+
+/**
+ * EmulatedDriver is an abstract base class for fake SE-mode device drivers.
+ *
+ * Specific drivers that allow applications to communicate with simulated
+ * hardware inside gem5 can be created by deriving from this class and
+ * overriding the abstract virtual methods.
+ *
+ * Currently only open() and ioctl() calls are supported, but other calls
+ * (e.g., read(), write(), mmap()) could be added as needed.
+ */
+class EmulatedDriver : public SimObject
+{
+  protected:
+    /**
+     * filename for opening this driver (under /dev)
+     */
+    const std::string &filename;
+
+  public:
+    EmulatedDriver(EmulatedDriverParams *p)
+        : SimObject(p), filename(p->filename)
+    {
+    }
+
+    /**
+     * Check for a match with this driver's filename.
+     */
+    bool match(const std::string &s) const { return (s == filename); }
+
+    /**
+     * Abstract method, invoked when the user program calls open() on
+     * the device driver.  The parameters are the same as those passed
+     * to openFunc() (q.v.).
+     * @return A newly allocated target fd, or -1 on error.
+     */
+    virtual int open(LiveProcess *p, ThreadContext *tc,
+                     int mode, int flags) = 0;
+
+    /**
+     * Abstract method, invoked when the user program calls ioctl() on
+     * the file descriptor returned by a previous open().  The parameters
+     * are the same as those passed in to ioctlFunc() (q.v.).
+     * @return The return code for the ioctl, or the negation of the errno
+     * (see the SyscallReturn class).
+     */
+    virtual int ioctl(LiveProcess *p, ThreadContext *tc, unsigned req) = 0;
+};
+
+#endif // __SIM_EMUL_DRIVER_HH
index 913e9298deb9a8e8b37b70cac922560c9b912118..15dc8c3e8ff9e7963e1b21d66f6f23315f74fdea 100644 (file)
@@ -278,7 +278,7 @@ Process::alloc_fd(int sim_fd, string filename, int flags, int mode, bool pipe)
     // find first free target fd
     for (int free_fd = 0; free_fd <= MAX_FD; ++free_fd) {
         Process::FdMap *fdo = &fd_map[free_fd];
-        if (fdo->fd == -1) {
+        if (fdo->fd == -1 && fdo->driver == NULL) {
             fdo->fd = sim_fd;
             fdo->filename = filename;
             fdo->mode = mode;
@@ -309,6 +309,7 @@ Process::free_fd(int tgt_fd)
     fdo->flags = 0;
     fdo->isPipe = false;
     fdo->readPipeSource = 0;
+    fdo->driver = NULL;
 }
 
 
@@ -567,7 +568,8 @@ Process::map(Addr vaddr, Addr paddr, int size)
 
 LiveProcess::LiveProcess(LiveProcessParams * params, ObjectFile *_objFile)
     : Process(params), objFile(_objFile),
-      argv(params->cmd), envp(params->env), cwd(params->cwd)
+      argv(params->cmd), envp(params->env), cwd(params->cwd),
+      drivers(params->drivers)
 {
     __uid = params->uid;
     __euid = params->euid;
@@ -608,6 +610,19 @@ LiveProcess::getSyscallArg(ThreadContext *tc, int &i, int width)
     return getSyscallArg(tc, i);
 }
 
+
+EmulatedDriver *
+LiveProcess::findDriver(std::string filename)
+{
+    for (EmulatedDriver *d : drivers) {
+        if (d->match(filename))
+            return d;
+    }
+
+    return NULL;
+}
+
+
 LiveProcess *
 LiveProcess::create(LiveProcessParams * params)
 {
index 03380acf74f02ffb0e6b0f6ffec24c00f1ea12e9..6e26bb8bd913cef12a285be29813376ab466f488 100644 (file)
@@ -50,6 +50,7 @@ struct LiveProcessParams;
 class SyscallDesc;
 class System;
 class ThreadContext;
+class EmulatedDriver;
 
 template<class IntType>
 struct AuxVector
@@ -139,10 +140,11 @@ class Process : public SimObject
         bool isPipe;
         int readPipeSource;
         uint64_t fileOffset;
+        EmulatedDriver *driver;
 
         FdMap()
             : fd(-1), filename("NULL"), mode(0), flags(0),
-              isPipe(false), readPipeSource(0), fileOffset(0)
+              isPipe(false), readPipeSource(0), fileOffset(0), driver(NULL)
         { }
 
         void serialize(std::ostream &os);
@@ -256,6 +258,9 @@ class LiveProcess : public Process
     uint64_t __pid;
     uint64_t __ppid;
 
+    // Emulated drivers available to this process
+    std::vector<EmulatedDriver *> drivers;
+
   public:
 
     enum AuxiliaryVectorType {
@@ -325,6 +330,14 @@ class LiveProcess : public Process
 
     virtual SyscallDesc *getDesc(int callnum) = 0;
 
+    /**
+     * Find an emulated device driver.
+     *
+     * @param filename Name of the device (under /dev)
+     * @return Pointer to driver object if found, else NULL
+     */
+    EmulatedDriver *findDriver(std::string filename);
+
     // this function is used to create the LiveProcess object, since
     // we can't tell which subclass of LiveProcess to use until we
     // open and look at the object file.
index dff34982d75f56ee2fb75aa27f4e8f5a2ad3017e..1c84e9f48cf98271d99ab6e8b4c85894990a9458 100644 (file)
@@ -77,6 +77,7 @@
 #include "mem/page_table.hh"
 #include "mem/se_translating_port_proxy.hh"
 #include "sim/byteswap.hh"
+#include "sim/emul_driver.hh"
 #include "sim/process.hh"
 #include "sim/syscallreturn.hh"
 #include "sim/system.hh"
@@ -604,11 +605,17 @@ ioctlFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
 
     DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", fd, req);
 
-    if (fd < 0 || process->sim_fd(fd) < 0) {
+    Process::FdMap *fdObj = process->sim_fd_obj(fd);
+
+    if (fdObj == NULL) {
         // doesn't map to any simulator fd: not a valid target fd
         return -EBADF;
     }
 
+    if (fdObj->driver != NULL) {
+        return fdObj->driver->ioctl(process, tc, req);
+    }
+
     if (OS::isTtyReq(req)) {
         return -ENOTTY;
     }
@@ -629,13 +636,6 @@ openFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
                 process->getSyscallArg(tc, index)))
         return -EFAULT;
 
-    if (path == "/dev/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;
-    }
-
     int tgtFlags = process->getSyscallArg(tc, index);
     int mode = process->getSyscallArg(tc, index);
     int hostFlags = 0;
@@ -661,6 +661,26 @@ openFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
 
     DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str());
 
+    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);
+        if (drv != NULL) {
+            // the driver's open method will allocate a fd from the
+            // process if necessary.
+            return drv->open(process, tc, mode, hostFlags);
+        }
+
+        // fall through here for pass through to host devices, such as
+        // /dev/zero
+    }
+
     int fd;
     int local_errno;
     if (startswith(path, "/proc/") || startswith(path, "/system/") ||