syscall_emul: add EmulatedDriver object
Fake SE-mode device drivers can now be added by deriving from this abstract object.
This commit is contained in:
parent
6523aad25c
commit
44ec1d2124
5 changed files with 157 additions and 11 deletions
|
@ -46,6 +46,12 @@ class Process(SimObject):
|
||||||
def export_methods(cls, code):
|
def export_methods(cls, code):
|
||||||
code('bool map(Addr vaddr, Addr paddr, int size);')
|
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):
|
class LiveProcess(Process):
|
||||||
type = 'LiveProcess'
|
type = 'LiveProcess'
|
||||||
cxx_header = "sim/process.hh"
|
cxx_header = "sim/process.hh"
|
||||||
|
@ -60,3 +66,5 @@ class LiveProcess(Process):
|
||||||
pid = Param.Int(100, 'process id')
|
pid = Param.Int(100, 'process id')
|
||||||
ppid = Param.Int(99, 'parent process id')
|
ppid = Param.Int(99, 'parent process id')
|
||||||
simpoint = Param.UInt64(0, 'simulation point at which to start simulation')
|
simpoint = Param.UInt64(0, 'simulation point at which to start simulation')
|
||||||
|
drivers = VectorParam.EmulatedDriver([], 'Available emulated drivers')
|
||||||
|
|
||||||
|
|
90
src/sim/emul_driver.hh
Normal file
90
src/sim/emul_driver.hh
Normal file
|
@ -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
|
|
@ -278,7 +278,7 @@ Process::alloc_fd(int sim_fd, string filename, int flags, int mode, bool pipe)
|
||||||
// find first free target fd
|
// find first free target fd
|
||||||
for (int free_fd = 0; free_fd <= MAX_FD; ++free_fd) {
|
for (int free_fd = 0; free_fd <= MAX_FD; ++free_fd) {
|
||||||
Process::FdMap *fdo = &fd_map[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->fd = sim_fd;
|
||||||
fdo->filename = filename;
|
fdo->filename = filename;
|
||||||
fdo->mode = mode;
|
fdo->mode = mode;
|
||||||
|
@ -309,6 +309,7 @@ Process::free_fd(int tgt_fd)
|
||||||
fdo->flags = 0;
|
fdo->flags = 0;
|
||||||
fdo->isPipe = false;
|
fdo->isPipe = false;
|
||||||
fdo->readPipeSource = 0;
|
fdo->readPipeSource = 0;
|
||||||
|
fdo->driver = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -567,7 +568,8 @@ Process::map(Addr vaddr, Addr paddr, int size)
|
||||||
|
|
||||||
LiveProcess::LiveProcess(LiveProcessParams * params, ObjectFile *_objFile)
|
LiveProcess::LiveProcess(LiveProcessParams * params, ObjectFile *_objFile)
|
||||||
: Process(params), objFile(_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;
|
__uid = params->uid;
|
||||||
__euid = params->euid;
|
__euid = params->euid;
|
||||||
|
@ -608,6 +610,19 @@ LiveProcess::getSyscallArg(ThreadContext *tc, int &i, int width)
|
||||||
return getSyscallArg(tc, i);
|
return getSyscallArg(tc, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
EmulatedDriver *
|
||||||
|
LiveProcess::findDriver(std::string filename)
|
||||||
|
{
|
||||||
|
for (EmulatedDriver *d : drivers) {
|
||||||
|
if (d->match(filename))
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
LiveProcess *
|
LiveProcess *
|
||||||
LiveProcess::create(LiveProcessParams * params)
|
LiveProcess::create(LiveProcessParams * params)
|
||||||
{
|
{
|
||||||
|
|
|
@ -50,6 +50,7 @@ struct LiveProcessParams;
|
||||||
class SyscallDesc;
|
class SyscallDesc;
|
||||||
class System;
|
class System;
|
||||||
class ThreadContext;
|
class ThreadContext;
|
||||||
|
class EmulatedDriver;
|
||||||
|
|
||||||
template<class IntType>
|
template<class IntType>
|
||||||
struct AuxVector
|
struct AuxVector
|
||||||
|
@ -139,10 +140,11 @@ class Process : public SimObject
|
||||||
bool isPipe;
|
bool isPipe;
|
||||||
int readPipeSource;
|
int readPipeSource;
|
||||||
uint64_t fileOffset;
|
uint64_t fileOffset;
|
||||||
|
EmulatedDriver *driver;
|
||||||
|
|
||||||
FdMap()
|
FdMap()
|
||||||
: fd(-1), filename("NULL"), mode(0), flags(0),
|
: 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);
|
void serialize(std::ostream &os);
|
||||||
|
@ -256,6 +258,9 @@ class LiveProcess : public Process
|
||||||
uint64_t __pid;
|
uint64_t __pid;
|
||||||
uint64_t __ppid;
|
uint64_t __ppid;
|
||||||
|
|
||||||
|
// Emulated drivers available to this process
|
||||||
|
std::vector<EmulatedDriver *> drivers;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
enum AuxiliaryVectorType {
|
enum AuxiliaryVectorType {
|
||||||
|
@ -325,6 +330,14 @@ class LiveProcess : public Process
|
||||||
|
|
||||||
virtual SyscallDesc *getDesc(int callnum) = 0;
|
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
|
// this function is used to create the LiveProcess object, since
|
||||||
// we can't tell which subclass of LiveProcess to use until we
|
// we can't tell which subclass of LiveProcess to use until we
|
||||||
// open and look at the object file.
|
// open and look at the object file.
|
||||||
|
|
|
@ -77,6 +77,7 @@
|
||||||
#include "mem/page_table.hh"
|
#include "mem/page_table.hh"
|
||||||
#include "mem/se_translating_port_proxy.hh"
|
#include "mem/se_translating_port_proxy.hh"
|
||||||
#include "sim/byteswap.hh"
|
#include "sim/byteswap.hh"
|
||||||
|
#include "sim/emul_driver.hh"
|
||||||
#include "sim/process.hh"
|
#include "sim/process.hh"
|
||||||
#include "sim/syscallreturn.hh"
|
#include "sim/syscallreturn.hh"
|
||||||
#include "sim/system.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);
|
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
|
// doesn't map to any simulator fd: not a valid target fd
|
||||||
return -EBADF;
|
return -EBADF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fdObj->driver != NULL) {
|
||||||
|
return fdObj->driver->ioctl(process, tc, req);
|
||||||
|
}
|
||||||
|
|
||||||
if (OS::isTtyReq(req)) {
|
if (OS::isTtyReq(req)) {
|
||||||
return -ENOTTY;
|
return -ENOTTY;
|
||||||
}
|
}
|
||||||
|
@ -629,13 +636,6 @@ openFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
|
||||||
process->getSyscallArg(tc, index)))
|
process->getSyscallArg(tc, index)))
|
||||||
return -EFAULT;
|
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 tgtFlags = process->getSyscallArg(tc, index);
|
||||||
int mode = process->getSyscallArg(tc, index);
|
int mode = process->getSyscallArg(tc, index);
|
||||||
int hostFlags = 0;
|
int hostFlags = 0;
|
||||||
|
@ -661,6 +661,26 @@ openFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
|
||||||
|
|
||||||
DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str());
|
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 fd;
|
||||||
int local_errno;
|
int local_errno;
|
||||||
if (startswith(path, "/proc/") || startswith(path, "/system/") ||
|
if (startswith(path, "/proc/") || startswith(path, "/system/") ||
|
||||||
|
|
Loading…
Reference in a new issue