diff --git a/src/gpu-compute/cl_driver.cc b/src/gpu-compute/cl_driver.cc index 41ae3ab9a..119091fc5 100644 --- a/src/gpu-compute/cl_driver.cc +++ b/src/gpu-compute/cl_driver.cc @@ -35,6 +35,8 @@ #include "gpu-compute/cl_driver.hh" +#include + #include "base/intmath.hh" #include "cpu/thread_context.hh" #include "gpu-compute/dispatcher.hh" @@ -93,11 +95,10 @@ ClDriver::handshake(GpuDispatcher *_dispatcher) int ClDriver::open(Process *p, ThreadContext *tc, int mode, int flags) { - int fd = p->allocFD(-1, filename, 0, 0, false); - FDEntry *fde = p->getFDEntry(fd); - fde->driver = this; - - return fd; + std::shared_ptr fdp; + fdp = std::make_shared(this, filename); + int tgt_fd = p->fds->allocFD(fdp); + return tgt_fd; } int diff --git a/src/sim/SConscript b/src/sim/SConscript index 6b0b8430b..c36b33b51 100644 --- a/src/sim/SConscript +++ b/src/sim/SConscript @@ -78,6 +78,7 @@ if env['TARGET_ISA'] != 'null': Source('aux_vector.cc') Source('faults.cc') Source('process.cc') + Source('fd_array.cc') Source('fd_entry.cc') Source('pseudo_inst.cc') Source('syscall_emul.cc') diff --git a/src/sim/fd_array.cc b/src/sim/fd_array.cc new file mode 100644 index 000000000..d73707054 --- /dev/null +++ b/src/sim/fd_array.cc @@ -0,0 +1,344 @@ +/* + * Copyright (c) 2016 Advanced Micro Devices, Inc. + * All rights reserved. + * + * For use for simulation and test purposes only + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. 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. + * + * 3. Neither the name of the copyright holder 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 HOLDER 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: Brandon Potter + */ + +#include "sim/fd_array.hh" + +#include +#include + +#include +#include +#include + +#include "base/misc.hh" +#include "params/Process.hh" +#include "sim/fd_entry.hh" + +FDArray::FDArray(std::string const& input, std::string const& output, + std::string const& errout) + : _input(input), _output(output), _errout(errout), _fdArray(), + imap {{"", -1}, + {"cin", STDIN_FILENO}, + {"stdin", STDIN_FILENO}}, + oemap{{"", -1}, + {"cout", STDOUT_FILENO}, + {"stdout", STDOUT_FILENO}, + {"cerr", STDERR_FILENO}, + {"stderr", STDERR_FILENO}} +{ + int sim_fd; + std::map::iterator it; + + /** + * Search through the input options and setup the default fd if match is + * found; otherwise, open an input file and seek to location. + */ + if ((it = imap.find(input)) != imap.end()) + sim_fd = it->second; + else + sim_fd = openInputFile(input); + + auto ffd = std::make_shared(sim_fd, O_RDONLY, input, false); + _fdArray[STDIN_FILENO] = ffd; + + /** + * Search through the output/error options and setup the default fd if + * match is found; otherwise, open an output file and seek to location. + */ + if ((it = oemap.find(output)) != oemap.end()) + sim_fd = it->second; + else + sim_fd = openOutputFile(output); + + ffd = std::make_shared(sim_fd, O_WRONLY | O_CREAT | O_TRUNC, + output, false); + _fdArray[STDOUT_FILENO] = ffd; + + if (output == errout) + ; /* Reuse the same file descriptor if these match. */ + else if ((it = oemap.find(errout)) != oemap.end()) + sim_fd = it->second; + else + sim_fd = openOutputFile(errout); + + ffd = std::make_shared(sim_fd, O_WRONLY | O_CREAT | O_TRUNC, + errout, false); + _fdArray[STDERR_FILENO] = ffd; +} + +void +FDArray::updateFileOffsets() +{ + for (auto& fdp : _fdArray) { + /** + * It only makes sense to check the offsets if the file descriptor + * type is 'File' (which indicates that this file is backed by a + * file on the host). If the type is File, then record the offset. + */ + auto ffd = std::dynamic_pointer_cast(fdp); + + if (!ffd) + continue; + + /** + * Use lseek with SEEK_CUR with offset 0 to figure out where the + * offset currently resides and pass that back to our setter. + */ + int sim_fd = ffd->getSimFD(); + ffd->setFileOffset(lseek(sim_fd, 0, SEEK_CUR)); + } +} + +void +FDArray::restoreFileOffsets() +{ + /** + * Use this lambda to highlight what we mean to do with the seek. + * Notice that this either seeks correctly (sets the file location on the + * host) or it fails with a fatal. The error is fatal because it's not + * possible to guarantee that the simulation will proceed as it should + * have in the same way that it would have proceeded sans checkpoints. + */ + void (*seek)(std::shared_ptr) + = [] (std::shared_ptr ffd) + { + if (lseek(ffd->getSimFD(), ffd->getFileOffset(), SEEK_SET) < 0) + fatal("Unable to seek to location in %s", ffd->getFileName()); + }; + + std::map::iterator it; + + /** + * Search through the input options and set fd if match is found; + * otherwise, open an input file and seek to location. + * Check if user has specified a different input file, and if so, use it + * instead of the file specified in the checkpoint. This also resets the + * file offset from the checkpointed value + */ + std::shared_ptr stdin_fde = _fdArray[STDIN_FILENO]; + auto stdin_ffd = std::dynamic_pointer_cast(stdin_fde); + + if (_input != stdin_ffd->getFileName()) { + warn("Using new input file (%s) rather than checkpointed (%s)\n", + _input, stdin_ffd->getFileName()); + stdin_ffd->setFileName(_input); + stdin_ffd->setFileOffset(0); + } + + if ((it = imap.find(stdin_ffd->getFileName())) != imap.end()) { + stdin_ffd->setSimFD(it->second); + } else { + stdin_ffd->setSimFD(openInputFile(stdin_ffd->getFileName())); + seek(stdin_ffd); + } + + /** + * Search through the output options and set fd if match is found; + * otherwise, open an output file and seek to location. + * Check if user has specified a different output file, and if so, use it + * instead of the file specified in the checkpoint. This also resets the + * file offset from the checkpointed value + */ + std::shared_ptr stdout_fde = _fdArray[STDOUT_FILENO]; + auto stdout_ffd = std::dynamic_pointer_cast(stdout_fde); + + if (_output != stdout_ffd->getFileName()) { + warn("Using new output file (%s) rather than checkpointed (%s)\n", + _output, stdout_ffd->getFileName()); + stdout_ffd->setFileName(_output); + stdout_ffd->setFileOffset(0); + } + + if ((it = oemap.find(stdout_ffd->getFileName())) != oemap.end()) { + stdout_ffd->setSimFD(it->second); + } else { + stdout_ffd->setSimFD(openOutputFile(stdout_ffd->getFileName())); + seek(stdout_ffd); + } + + /** + * Search through the error options and set fd if match is found; + * otherwise, open an error file and seek to location. + * Check if user has specified a different error file, and if so, use it + * instead of the file specified in the checkpoint. This also resets the + * file offset from the checkpointed value + */ + std::shared_ptr stderr_fde = _fdArray[STDERR_FILENO]; + auto stderr_ffd = std::dynamic_pointer_cast(stderr_fde); + + if (_errout != stderr_ffd->getFileName()) { + warn("Using new error file (%s) rather than checkpointed (%s)\n", + _errout, stderr_ffd->getFileName()); + stderr_ffd->setFileName(_errout); + stderr_ffd->setFileOffset(0); + } + + if (stdout_ffd->getFileName() == stderr_ffd->getFileName()) { + /* Reuse the same sim_fd file descriptor if these match. */ + stderr_ffd->setSimFD(stdout_ffd->getSimFD()); + } else if ((it = oemap.find(stderr_ffd->getFileName())) != oemap.end()) { + stderr_ffd->setSimFD(it->second); + } else { + stderr_ffd->setSimFD(openOutputFile(stderr_ffd->getFileName())); + seek(stderr_ffd); + } + + for (int tgt_fd = 3; tgt_fd < _fdArray.size(); tgt_fd++) { + std::shared_ptr fdp = _fdArray[tgt_fd]; + if (!fdp) + continue; + + /* Need to reconnect pipe ends. */ + if (auto pfd = std::dynamic_pointer_cast(fdp)) { + /** + * Check which end of the pipe we are looking at; we only want + * to setup the pipe once so we arbitrarily choose the read + * end to be the end that sets up the pipe. + */ + if (pfd->getEndType() == PipeFDEntry::EndType::write) + continue; + + /* Setup the pipe or fatal out of the simulation. */ + int fd_pair[2]; + if (pipe(fd_pair) < 0) + fatal("Unable to create new pipe"); + + /** + * Reconstruct the ends of the pipe by reassigning the pipe + * that we created on the host. This one is the read end. + */ + pfd->setSimFD(fd_pair[0]); + + /** + * Grab the write end by referencing the read ends source and + * using that tgt_fd to index the array. + */ + int prs = pfd->getPipeReadSource(); + std::shared_ptr write_fdp = _fdArray[prs]; + + /* Now cast it and make sure that we are still sane. */ + auto write_pfd = std::dynamic_pointer_cast(write_fdp); + + /* Hook up the write end back to the right side of the pipe. */ + write_pfd->setSimFD(fd_pair[1]); + } + + /* Need to reassign 'driver'. */ + if (auto dfd = std::dynamic_pointer_cast(fdp)) { + /** + * Yeah, how does one retain the entire driver state from this + * particular set of code? If you figure it out, add some code + * here to rectify the issue. + */ + fatal("Unable to restore checkpoints with emulated drivers"); + } + + /* Need to open files and seek. */ + if (auto ffd = std::dynamic_pointer_cast(fdp)) { + /** + * Assume that this has the mode of an output file so there's no + * need to worry about properly recording the mode. If you're + * reading this and this happens to be your issue, at least be + * happy that you've discovered the issue (and not mad at me). + * Onward ho! + */ + int sim_fd = openFile(ffd->getFileName(), ffd->getFlags(), 0664); + ffd->setSimFD(sim_fd); + seek(ffd); + } + } +} + +int +FDArray::allocFD(std::shared_ptr in) +{ + for (int i = 0; i < _fdArray.size(); i++) { + std::shared_ptr fdp = _fdArray[i]; + if (!fdp) { + _fdArray[i] = in; + return i; + } + } + fatal("Out of target file descriptors"); +} + +int +FDArray::openFile(std::string const& filename, int flags, mode_t mode) const +{ + int sim_fd = open(filename.c_str(), flags, mode); + if (sim_fd != -1) + return sim_fd; + fatal("Unable to open %s with mode %O", filename, mode); +} + +int +FDArray::openInputFile(std::string const& filename) const +{ + return openFile(filename, O_RDONLY, 00); +} + +int +FDArray::openOutputFile(std::string const& filename) const +{ + return openFile(filename, O_WRONLY | O_CREAT | O_TRUNC, 0664); +} + +std::shared_ptr +FDArray::getFDEntry(int tgt_fd) +{ + assert(0 <= tgt_fd && tgt_fd < _fdArray.size()); + return _fdArray[tgt_fd]; +} + +int +FDArray::closeFDEntry(int tgt_fd) +{ + if (tgt_fd >= _fdArray.size() || tgt_fd < 0) + return -EBADF; + + int sim_fd = -1; + auto hbfdp = std::dynamic_pointer_cast(_fdArray[tgt_fd]); + if (hbfdp) + sim_fd = hbfdp->getSimFD(); + + int status = 0; + if (sim_fd > 2) + status = close(sim_fd); + + if (status == 0) + _fdArray[tgt_fd] = nullptr; + + return status; +} diff --git a/src/sim/fd_array.hh b/src/sim/fd_array.hh new file mode 100644 index 000000000..1d57c4654 --- /dev/null +++ b/src/sim/fd_array.hh @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2016 Advanced Micro Devices, Inc. + * All rights reserved. + * + * For use for simulation and test purposes only + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. 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. + * + * 3. Neither the name of the copyright holder 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 HOLDER 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: Brandon Potter + */ + +#ifndef __FD_ARRAY_HH__ +#define __FD_ARRAY_HH__ + +#include +#include +#include + +#include "sim/fd_entry.hh" + +class FDArray +{ + private: + static const int NUM_FDS = 1024; + + public: + /** + * Initialize the file descriptor array and set the standard file + * descriptors to defaults or values passed in with the process + * params. + * @param input Used to initialize the stdin file descriptor + * @param output Used to initialize the stdout file descriptor + * @param errout Used to initialize the stderr file descriptor + */ + FDArray(std::string const& input, std::string const& output, + std::string const& errout); + + std::string _input; + std::string _output; + std::string _errout; + + /** + * Figure out the file offsets for all currently open files and save them + * the offsets during the calls to drain by the owning process. + */ + void updateFileOffsets(); + + /** + * Restore all offsets for currently open files during the unserialize + * phase for the owning process class. + */ + void restoreFileOffsets(); + + /** + * Treat this object like a normal array in using the subscript operator + * to pull entries out of it. + * @param tgt_fd Use target file descriptors to index the array. + */ + inline std::shared_ptr + operator[](int tgt_fd) + { + return getFDEntry(tgt_fd); + } + + /** + * Step through the file descriptor array and find the first available + * entry which is denoted as being free by being a 'nullptr'. That file + * descriptor entry is the new target file descriptor entry that we + * return as the return parameter. + * @param fdp Allocated beforehand and passed into this method; + * the fdp is meant to be a generic pointer capable of pointing to + * different types of file descriptors. Must cast the pointer to the + * correct type before dereferencing to access the needed fields. + */ + int allocFD(std::shared_ptr fdp); + + /** + * Return the size of the _fdArray field + */ + int getSize() const { return _fdArray.size(); } + + /** + * Try to close the host file descriptor. If successful, set the + * specified file descriptor entry object pointer to nullptr. + * Used to "close" the target file descriptor. + * @param tgt_fd Use target file descriptors to index the array. + */ + int closeFDEntry(int tgt_fd); + + private: + /** + * Help clarify our intention when opening files in the init and + * restoration code. These are helper functions which are not meant to + * be exposed to other objects or files. + */ + int openFile(std::string const& file_name, int flags, mode_t mode) const; + int openInputFile(std::string const& file_name) const; + int openOutputFile(std::string const& file_name) const; + + /** + * Return the file descriptor entry object associated with the index + * provided. (The index is protected with bounds checking on the array + * size without the use of the array's at operator.) + * @param tgt_fd Use target file descriptors to index the array. + */ + std::shared_ptr getFDEntry(int tgt_fd); + + /** + * Hold pointers to the file descriptor entries. The array size is + * statically defined by the operating system. + */ + std::array, NUM_FDS> _fdArray; + + /** + * Hold strings which represent the default values which are checked + * against to initialize the standard file descriptors. If the string + * provided doesn't hit against these maps, then a file is opened on the + * host instead of using the host's standard file descriptors. + */ + std::map imap; + std::map oemap; +}; + +#endif // __FD_ARRAY_HH__ diff --git a/src/sim/fd_entry.cc b/src/sim/fd_entry.cc index 72975a7a6..65bf7a81c 100644 --- a/src/sim/fd_entry.cc +++ b/src/sim/fd_entry.cc @@ -1,91 +1,100 @@ /* - * Copyright (c) 2015 Advanced Micro Devices, Inc. - * Copyright (c) 2001-2005 The Regents of The University of Michigan + * Copyright (c) 2016 Advanced Micro Devices, Inc. + * All rights reserved. + * + * For use for simulation and test purposes only * * 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. + * modification, are permitted provided that the following conditions are met: * - * 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. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. * - * Authors: Nathan Binkert - * Steve Reinhardt + * 2. 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. + * + * 3. Neither the name of the copyright holder 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 HOLDER 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: Brandon Potter */ -#include "base/misc.hh" -#include "fd_entry.hh" +#include "sim/fd_entry.hh" -using namespace std; +#include "sim/serialize.hh" void FDEntry::serialize(CheckpointOut &cp) const { - SERIALIZE_SCALAR(fd); - if (fd != -1) { - SERIALIZE_SCALAR(mode); - SERIALIZE_SCALAR(flags); - SERIALIZE_SCALAR(isPipe); - SERIALIZE_SCALAR(readPipeSource); - SERIALIZE_SCALAR(fileOffset); - SERIALIZE_SCALAR(filename); - } - if (driver) - warn("EmulatedDriver objects do not currently support checkpoints"); + SERIALIZE_SCALAR(_closeOnExec); } void FDEntry::unserialize(CheckpointIn &cp) { - UNSERIALIZE_SCALAR(fd); - if (fd != -1) { - UNSERIALIZE_SCALAR(mode); - UNSERIALIZE_SCALAR(flags); - UNSERIALIZE_SCALAR(isPipe); - UNSERIALIZE_SCALAR(readPipeSource); - UNSERIALIZE_SCALAR(fileOffset); - UNSERIALIZE_SCALAR(filename); - } - driver = NULL; -} - -bool -FDEntry::isFree() -{ - return (fd == -1 && driver == NULL); + UNSERIALIZE_SCALAR(_closeOnExec); } void -FDEntry::set(int sim_fd, const string name, int flags, int mode, bool pipe) +FileFDEntry::serialize(CheckpointOut &cp) const { - fd = sim_fd; - filename = name; - this->flags = flags; - this->mode = mode; - isPipe = pipe; - fileOffset = 0; - readPipeSource = 0; - driver = NULL; + SERIALIZE_SCALAR(_closeOnExec); + SERIALIZE_SCALAR(_flags); + SERIALIZE_SCALAR(_fileName); + SERIALIZE_SCALAR(_fileOffset); } void -FDEntry::reset() +FileFDEntry::unserialize(CheckpointIn &cp) { - set(-1, "", 0, 0, false); + UNSERIALIZE_SCALAR(_closeOnExec); + UNSERIALIZE_SCALAR(_flags); + UNSERIALIZE_SCALAR(_fileName); + UNSERIALIZE_SCALAR(_fileOffset); +} + +void +PipeFDEntry::serialize(CheckpointOut &cp) const +{ + SERIALIZE_SCALAR(_closeOnExec); + SERIALIZE_SCALAR(_flags); + //SERIALIZE_SCALAR(_pipeEndType); +} + +void +PipeFDEntry::unserialize(CheckpointIn &cp) +{ + UNSERIALIZE_SCALAR(_closeOnExec); + UNSERIALIZE_SCALAR(_flags); + //UNSERIALIZE_SCALAR(_pipeEndType); +} + +void +DeviceFDEntry::serialize(CheckpointOut &cp) const +{ + SERIALIZE_SCALAR(_closeOnExec); + //SERIALIZE_SCALAR(_driver); + SERIALIZE_SCALAR(_fileName); +} + +void +DeviceFDEntry::unserialize(CheckpointIn &cp) +{ + UNSERIALIZE_SCALAR(_closeOnExec); + //UNSERIALIZE_SCALAR(_driver); + UNSERIALIZE_SCALAR(_fileName); } diff --git a/src/sim/fd_entry.hh b/src/sim/fd_entry.hh index fd68ba50b..950d1b740 100644 --- a/src/sim/fd_entry.hh +++ b/src/sim/fd_entry.hh @@ -1,37 +1,42 @@ /* - * Copyright (c) 2015 Advanced Micro Devices, Inc. - * Copyright (c) 2001-2005 The Regents of The University of Michigan + * Copyright (c) 2016 Advanced Micro Devices, Inc. + * All rights reserved. + * + * For use for simulation and test purposes only * * 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. + * modification, are permitted provided that the following conditions are met: * - * 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. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. * - * Authors: Nathan Binkert - * Steve Reinhardt + * 2. 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. + * + * 3. Neither the name of the copyright holder 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 HOLDER 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: Brandon Potter */ #ifndef __FD_ENTRY_HH__ #define __FD_ENTRY_HH__ +#include #include #include @@ -40,55 +45,170 @@ class EmulatedDriver; /** - * FDEntry is used to manage a single file descriptor mapping and metadata - * for processes. - * Note that the fields are all declared publicly since system calls have a - * habit of only needing to access a single field at a time and accessor - * methods seem like overkill. + * Holds a single file descriptor mapping and that mapping's data for + * processes running in syscall emulation mode. */ class FDEntry : public Serializable { public: - /** - * Constructor contains default values - * The file descriptor is free. - */ - FDEntry() - : fd(-1), mode(0), flags(0), isPipe(false), readPipeSource(0), - fileOffset(0), filename(""), driver(NULL) + FDEntry(bool close_on_exec = false) + : _closeOnExec(close_on_exec) { } + virtual std::shared_ptr clone() const = 0; + + inline bool getCOE() const { return _closeOnExec; } + + inline void setCOE(bool close_on_exec) { _closeOnExec = close_on_exec; } + + virtual void serialize(CheckpointOut &cp) const; + virtual void unserialize(CheckpointIn &cp); + + protected: + bool _closeOnExec; +}; + +/** + * Extends the base class to include a host-backed file descriptor field + * that records the integer used to represent the file descriptor on the host + * and the file's flags. + */ +class HBFDEntry: public FDEntry +{ + public: + HBFDEntry(int flags, int sim_fd, bool close_on_exec = false) + : FDEntry(close_on_exec), _flags(flags), _simFD(sim_fd) + { } + + inline int getFlags() const { return _flags; } + inline int getSimFD() const { return _simFD; } + + inline void setFlags(int flags) { _flags = flags; } + inline void setSimFD(int sim_fd) { _simFD = sim_fd; } + + protected: + int _flags; + int _simFD; +}; + +/** + * Holds file descriptors for host-backed files; host-backed files are + * files which were opened on the physical machine where the simulation + * is running (probably the thing on/under your desk). All regular files + * are redirected to make it appear that the file descriptor assignment + * starts at file descriptor '3' (not including stdin, stdout, stderr) and + * then grows upward. + */ +class FileFDEntry: public HBFDEntry +{ + public: + FileFDEntry(int sim_fd, int flags, std::string const& file_name, + uint64_t file_offset, bool close_on_exec = false) + : HBFDEntry(flags, sim_fd, close_on_exec), + _fileName(file_name), _fileOffset(file_offset) + { } + + FileFDEntry(FileFDEntry const& reg, bool close_on_exec = false) + : HBFDEntry(reg._flags, reg._simFD, close_on_exec), + _fileName(reg._fileName), _fileOffset(reg._fileOffset) + { } + + inline std::shared_ptr + clone() const override + { + return std::make_shared(*this); + } + + inline std::string getFileName() const { return _fileName; } + inline uint64_t getFileOffset() const { return _fileOffset; } + + inline void setFileName(std::string file_name) { _fileName = file_name; } + inline void setFileOffset (uint64_t f_off) { _fileOffset = f_off; } + void serialize(CheckpointOut &cp) const override; void unserialize(CheckpointIn &cp) override; - /** - * Check if the target file descriptor is in use. - * @return value denoting if target file descriptor already used - */ - bool isFree(); + private: + std::string _fileName; + uint64_t _fileOffset; +}; - /** - * Fill in members for this file descriptor entry. - * @param sim_fd host file descriptor - * @param name filename string - * @param flags current flags of the file descriptor - * @param mode current mode of the file descriptor - * @param pipe denotes whether the file descriptor belongs to a pipe - */ - void set(int sim_fd, const std::string name, int flags, int mode, - bool pipe); +/** + * Holds the metadata needed to maintain the mappings for file descriptors + * allocated with the pipe() system calls and its variants. + */ +class PipeFDEntry: public HBFDEntry +{ + public: + enum EndType { + read = 0, + write = 1 + }; - /** Reset members to their default values. */ - void reset(); + PipeFDEntry(int sim_fd, int flags, EndType pipe_end_type, + bool close_on_exec = false) + : HBFDEntry(flags, sim_fd, close_on_exec), _pipeReadSource(-1), + _pipeEndType(pipe_end_type) + { } - int fd; - int mode; - int flags; - bool isPipe; - int readPipeSource; - uint64_t fileOffset; - std::string filename; - EmulatedDriver *driver; + PipeFDEntry(PipeFDEntry const& pipe, bool close_on_exec = false) + : HBFDEntry(pipe._flags, pipe._simFD, close_on_exec), + _pipeReadSource(pipe._pipeReadSource), + _pipeEndType(pipe._pipeEndType) + { } + + inline std::shared_ptr + clone() const override + { + return std::make_shared(*this); + } + + inline EndType getEndType() const { return _pipeEndType; } + inline int getPipeReadSource() const { return _pipeReadSource; } + + inline void setPipeReadSource(int tgt_fd) { _pipeReadSource = tgt_fd; } + inline void setEndType(EndType type) { _pipeEndType = type; } + + void serialize(CheckpointOut &cp) const override; + void unserialize(CheckpointIn &cp) override; + + private: + int _pipeReadSource; + EndType _pipeEndType; +}; + +/** + * Holds file descriptors needed to simulate devices opened with pseudo + * files (commonly with calls to ioctls). + */ +class DeviceFDEntry : public FDEntry +{ + public: + DeviceFDEntry(EmulatedDriver *driver, std::string const& file_name, + bool close_on_exec = false) + : FDEntry(close_on_exec), _driver(driver), _fileName(file_name) + { } + + DeviceFDEntry(DeviceFDEntry const& dev, bool close_on_exec = false) + : FDEntry(close_on_exec), _driver(dev._driver), + _fileName(dev._fileName) + { } + + std::shared_ptr + clone() const override + { + return std::make_shared(*this); + } + + inline EmulatedDriver *getDriver() const { return _driver; } + inline std::string getFileName() const { return _fileName; } + + void serialize(CheckpointOut &cp) const override; + void unserialize(CheckpointIn &cp) override; + + private: + EmulatedDriver *_driver; + std::string _fileName; }; #endif // __FD_ENTRY_HH__ diff --git a/src/sim/process.cc b/src/sim/process.cc index 9510fd71d..4c44f4086 100644 --- a/src/sim/process.cc +++ b/src/sim/process.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Advanced Micro Devices, Inc. + * Copyright (c) 2014-2016 Advanced Micro Devices, Inc. * Copyright (c) 2012 ARM Limited * All rights reserved * @@ -41,6 +41,7 @@ * Authors: Nathan Binkert * Steve Reinhardt * Ali Saidi + * Brandon Potter */ #include "sim/process.hh" @@ -63,6 +64,8 @@ #include "mem/se_translating_port_proxy.hh" #include "params/Process.hh" #include "sim/emul_driver.hh" +#include "sim/fd_array.hh" +#include "sim/fd_entry.hh" #include "sim/syscall_desc.hh" #include "sim/system.hh" @@ -90,27 +93,6 @@ using namespace std; using namespace TheISA; -static int -openFile(const string& filename, int flags, mode_t mode) -{ - int sim_fd = open(filename.c_str(), flags, mode); - if (sim_fd != -1) - return sim_fd; - fatal("Unable to open %s with mode %O", filename, mode); -} - -static int -openInputFile(const string &filename) -{ - return openFile(filename, O_RDONLY, 0); -} - -static int -openOutputFile(const string &filename) -{ - return openFile(filename, O_WRONLY | O_CREAT | O_TRUNC, 0664); -} - Process::Process(ProcessParams * params, ObjectFile * obj_file) : SimObject(params), system(params->system), brk_point(0), stack_base(0), stack_size(0), stack_min(0), @@ -124,58 +106,16 @@ Process::Process(ProcessParams * params, ObjectFile * obj_file) static_cast(new FuncPageTable(name(), params->pid))), initVirtMem(system->getSystemPort(), this, SETranslatingPortProxy::Always), - fd_array(make_shared>()), - imap {{"", -1}, - {"cin", STDIN_FILENO}, - {"stdin", STDIN_FILENO}}, - oemap{{"", -1}, - {"cout", STDOUT_FILENO}, - {"stdout", STDOUT_FILENO}, - {"cerr", STDERR_FILENO}, - {"stderr", STDERR_FILENO}}, objFile(obj_file), argv(params->cmd), envp(params->env), cwd(params->cwd), executable(params->executable), _uid(params->uid), _euid(params->euid), _gid(params->gid), _egid(params->egid), _pid(params->pid), _ppid(params->ppid), - drivers(params->drivers) + drivers(params->drivers), + fds(make_shared(params->input, params->output, params->errout)) { - int sim_fd; - std::map::iterator it; - - // Search through the input options and set fd if match is found; - // otherwise, open an input file and seek to location. - FDEntry *fde_stdin = getFDEntry(STDIN_FILENO); - if ((it = imap.find(params->input)) != imap.end()) - sim_fd = it->second; - else - sim_fd = openInputFile(params->input); - fde_stdin->set(sim_fd, params->input, O_RDONLY, -1, false); - - // Search through the output/error options and set fd if match is found; - // otherwise, open an output file and seek to location. - FDEntry *fde_stdout = getFDEntry(STDOUT_FILENO); - if ((it = oemap.find(params->output)) != oemap.end()) - sim_fd = it->second; - else - sim_fd = openOutputFile(params->output); - fde_stdout->set(sim_fd, params->output, O_WRONLY | O_CREAT | O_TRUNC, - 0664, false); - - FDEntry *fde_stderr = getFDEntry(STDERR_FILENO); - if (params->output == params->errout) - // Reuse the same file descriptor if these match. - sim_fd = fde_stdout->fd; - else if ((it = oemap.find(params->errout)) != oemap.end()) - sim_fd = it->second; - else - sim_fd = openOutputFile(params->errout); - fde_stderr->set(sim_fd, params->errout, O_WRONLY | O_CREAT | O_TRUNC, - 0664, false); - mmap_end = 0; - // other parameters will be initialized when the program is loaded // load up symbols, if any... these may be used for debugging or // profiling. @@ -204,12 +144,6 @@ Process::regStats() ; } -void -Process::inheritFDArray(Process *p) -{ - fd_array = p->fd_array; -} - ThreadContext * Process::findFreeContext() { @@ -239,57 +173,10 @@ Process::initState() DrainState Process::drain() { - findFileOffsets(); + fds->updateFileOffsets(); return DrainState::Drained; } -int -Process::allocFD(int sim_fd, const string& filename, int flags, int mode, - bool pipe) -{ - for (int free_fd = 0; free_fd < fd_array->size(); free_fd++) { - FDEntry *fde = getFDEntry(free_fd); - if (fde->isFree()) { - fde->set(sim_fd, filename, flags, mode, pipe); - return free_fd; - } - } - - fatal("Out of target file descriptors"); -} - -void -Process::resetFDEntry(int tgt_fd) -{ - FDEntry *fde = getFDEntry(tgt_fd); - assert(fde->fd > -1); - - fde->reset(); -} - -int -Process::getSimFD(int tgt_fd) -{ - FDEntry *entry = getFDEntry(tgt_fd); - return entry ? entry->fd : -1; -} - -FDEntry * -Process::getFDEntry(int tgt_fd) -{ - assert(0 <= tgt_fd && tgt_fd < fd_array->size()); - return &(*fd_array)[tgt_fd]; -} - -int -Process::getTgtFD(int sim_fd) -{ - for (int index = 0; index < fd_array->size(); index++) - if ((*fd_array)[index].fd == sim_fd) - return index; - return -1; -} - void Process::allocateMem(Addr vaddr, int64_t size, bool clobber) { @@ -324,127 +211,6 @@ Process::fixupStackFault(Addr vaddr) return false; } -void -Process::fixFileOffsets() -{ - auto seek = [] (FDEntry *fde) - { - if (lseek(fde->fd, fde->fileOffset, SEEK_SET) < 0) - fatal("Unable to see to location in %s", fde->filename); - }; - - std::map::iterator it; - - // Search through the input options and set fd if match is found; - // otherwise, open an input file and seek to location. - FDEntry *fde_stdin = getFDEntry(STDIN_FILENO); - - // Check if user has specified a different input file, and if so, use it - // instead of the file specified in the checkpoint. This also resets the - // file offset from the checkpointed value - string new_in = ((ProcessParams*)params())->input; - if (new_in != fde_stdin->filename) { - warn("Using new input file (%s) rather than checkpointed (%s)\n", - new_in, fde_stdin->filename); - fde_stdin->filename = new_in; - fde_stdin->fileOffset = 0; - } - - if ((it = imap.find(fde_stdin->filename)) != imap.end()) { - fde_stdin->fd = it->second; - } else { - fde_stdin->fd = openInputFile(fde_stdin->filename); - seek(fde_stdin); - } - - // Search through the output/error options and set fd if match is found; - // otherwise, open an output file and seek to location. - FDEntry *fde_stdout = getFDEntry(STDOUT_FILENO); - - // Check if user has specified a different output file, and if so, use it - // instead of the file specified in the checkpoint. This also resets the - // file offset from the checkpointed value - string new_out = ((ProcessParams*)params())->output; - if (new_out != fde_stdout->filename) { - warn("Using new output file (%s) rather than checkpointed (%s)\n", - new_out, fde_stdout->filename); - fde_stdout->filename = new_out; - fde_stdout->fileOffset = 0; - } - - if ((it = oemap.find(fde_stdout->filename)) != oemap.end()) { - fde_stdout->fd = it->second; - } else { - fde_stdout->fd = openOutputFile(fde_stdout->filename); - seek(fde_stdout); - } - - FDEntry *fde_stderr = getFDEntry(STDERR_FILENO); - - // Check if user has specified a different error file, and if so, use it - // instead of the file specified in the checkpoint. This also resets the - // file offset from the checkpointed value - string new_err = ((ProcessParams*)params())->errout; - if (new_err != fde_stderr->filename) { - warn("Using new error file (%s) rather than checkpointed (%s)\n", - new_err, fde_stderr->filename); - fde_stderr->filename = new_err; - fde_stderr->fileOffset = 0; - } - - if (fde_stdout->filename == fde_stderr->filename) { - // Reuse the same file descriptor if these match. - fde_stderr->fd = fde_stdout->fd; - } else if ((it = oemap.find(fde_stderr->filename)) != oemap.end()) { - fde_stderr->fd = it->second; - } else { - fde_stderr->fd = openOutputFile(fde_stderr->filename); - seek(fde_stderr); - } - - for (int tgt_fd = 3; tgt_fd < fd_array->size(); tgt_fd++) { - FDEntry *fde = getFDEntry(tgt_fd); - if (fde->fd == -1) - continue; - - if (fde->isPipe) { - if (fde->filename == "PIPE-WRITE") - continue; - assert(fde->filename == "PIPE-READ"); - - int fds[2]; - if (pipe(fds) < 0) - fatal("Unable to create new pipe"); - - fde->fd = fds[0]; - - FDEntry *fde_write = getFDEntry(fde->readPipeSource); - assert(fde_write->filename == "PIPE-WRITE"); - fde_write->fd = fds[1]; - } else { - fde->fd = openFile(fde->filename.c_str(), fde->flags, fde->mode); - seek(fde); - } - } -} - -void -Process::findFileOffsets() -{ - for (auto& fde : *fd_array) { - if (fde.fd != -1) - fde.fileOffset = lseek(fde.fd, 0, SEEK_CUR); - } -} - -void -Process::setReadPipeSource(int read_pipe_fd, int source_fd) -{ - FDEntry *fde = getFDEntry(read_pipe_fd); - assert(source_fd >= -1); - fde->readPipeSource = source_fd; -} - void Process::serialize(CheckpointOut &cp) const { @@ -455,9 +221,16 @@ Process::serialize(CheckpointOut &cp) const SERIALIZE_SCALAR(next_thread_stack_base); SERIALIZE_SCALAR(mmap_end); pTable->serialize(cp); - for (int x = 0; x < fd_array->size(); x++) { - (*fd_array)[x].serializeSection(cp, csprintf("FDEntry%d", x)); - } + /** + * Checkpoints for file descriptors currently do not work. Need to + * come back and fix them at a later date. + */ + + warn("Checkpoints for file descriptors currently do not work."); +#if 0 + for (int x = 0; x < fds->getSize(); x++) + (*fds)[x].serializeSection(cp, csprintf("FDEntry%d", x)); +#endif } @@ -471,11 +244,16 @@ Process::unserialize(CheckpointIn &cp) UNSERIALIZE_SCALAR(next_thread_stack_base); UNSERIALIZE_SCALAR(mmap_end); pTable->unserialize(cp); - for (int x = 0; x < fd_array->size(); x++) { - FDEntry *fde = getFDEntry(x); - fde->unserializeSection(cp, csprintf("FDEntry%d", x)); - } - fixFileOffsets(); + /** + * Checkpoints for file descriptors currently do not work. Need to + * come back and fix them at a later date. + */ + warn("Checkpoints for file descriptors currently do not work."); +#if 0 + for (int x = 0; x < fds->getSize(); x++) + (*fds)[x]->unserializeSection(cp, csprintf("FDEntry%d", x)); + fds->restoreFileOffsets(); +#endif // The above returns a bool so that you could do something if you don't // find the param in the checkpoint if you wanted to, like set a default // but in this case we'll just stick with the instantiated value if not diff --git a/src/sim/process.hh b/src/sim/process.hh index dde131628..2191c3cd0 100644 --- a/src/sim/process.hh +++ b/src/sim/process.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Advanced Micro Devices, Inc. + * Copyright (c) 2014-2016 Advanced Micro Devices, Inc. * Copyright (c) 2001-2005 The Regents of The University of Michigan * All rights reserved. * @@ -28,6 +28,7 @@ * * Authors: Nathan Binkert * Steve Reinhardt + * Brandon Potter */ #ifndef __PROCESS_HH__ @@ -35,7 +36,6 @@ #include -#include #include #include #include @@ -45,6 +45,7 @@ #include "base/types.hh" #include "config/the_isa.hh" #include "mem/se_translating_port_proxy.hh" +#include "sim/fd_array.hh" #include "sim/fd_entry.hh" #include "sim/sim_object.hh" @@ -115,42 +116,9 @@ class Process : public SimObject Addr getStartPC(); ObjectFile *getInterpreter(); - // inherit file descriptor map from another process (necessary for clone) - void inheritFDArray(Process *p); - // override of virtual SimObject method: register statistics void regStats() override; - // generate new target fd for sim_fd - int allocFD(int sim_fd, const std::string& filename, int flags, int mode, - bool pipe); - - // disassociate target fd with simulator fd and cleanup subsidiary fields - void resetFDEntry(int tgt_fd); - - // look up simulator fd for given target fd - int getSimFD(int tgt_fd); - - // look up fd entry for a given target fd - FDEntry *getFDEntry(int tgt_fd); - - // look up target fd for given host fd - // Assumes a 1:1 mapping between target file descriptor and host file - // descriptor. Given the current API, this must be true given that it's - // not possible to map multiple target file descriptors to the same host - // file descriptor - int getTgtFD(int sim_fd); - - // fix all offsets for currently open files and save them - void fixFileOffsets(); - - // find all offsets for currently open files and save them - void findFileOffsets(); - - // set the source of this read pipe for a checkpoint resume - void setReadPipeSource(int read_pipe_fd, int source_fd); - - void allocateMem(Addr vaddr, int64_t size, bool clobber = false); /// Attempt to fix up a fault at vaddr by allocating a page on the stack. @@ -216,15 +184,6 @@ class Process : public SimObject SETranslatingPortProxy initVirtMem; // memory proxy for initial image load - static const int NUM_FDS = 1024; - - // File descriptor remapping support. - std::shared_ptr> fd_array; - - // Standard file descriptor options for initialization and checkpoints. - std::map imap; - std::map oemap; - ObjectFile *objFile; std::vector argv; std::vector envp; @@ -243,6 +202,8 @@ class Process : public SimObject // Emulated drivers available to this process std::vector drivers; + + std::shared_ptr fds; }; #endif // __PROCESS_HH__ diff --git a/src/sim/syscall_emul.cc b/src/sim/syscall_emul.cc index d77901fa7..f4bfca6c2 100644 --- a/src/sim/syscall_emul.cc +++ b/src/sim/syscall_emul.cc @@ -172,16 +172,7 @@ closeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) int index = 0; int tgt_fd = p->getSyscallArg(tc, index); - int sim_fd = p->getSimFD(tgt_fd); - if (sim_fd < 0) - return -EBADF; - - int status = 0; - if (sim_fd > 2) - status = close(sim_fd); - if (status >= 0) - p->resetFDEntry(tgt_fd); - return status; + return p->fds->closeFDEntry(tgt_fd); } @@ -192,12 +183,13 @@ readFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) int tgt_fd = p->getSyscallArg(tc, index); Addr bufPtr = p->getSyscallArg(tc, index); int nbytes = p->getSyscallArg(tc, index); - BufferArg bufArg(bufPtr, nbytes); - int sim_fd = p->getSimFD(tgt_fd); - if (sim_fd < 0) + auto hbfdp = std::dynamic_pointer_cast((*p->fds)[tgt_fd]); + if (!hbfdp) return -EBADF; + int sim_fd = hbfdp->getSimFD(); + BufferArg bufArg(bufPtr, nbytes); int bytes_read = read(sim_fd, bufArg.bufferPtr(), nbytes); if (bytes_read > 0) @@ -213,12 +205,13 @@ writeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) int tgt_fd = p->getSyscallArg(tc, index); Addr bufPtr = p->getSyscallArg(tc, index); int nbytes = p->getSyscallArg(tc, index); - BufferArg bufArg(bufPtr, nbytes); - int sim_fd = p->getSimFD(tgt_fd); - if (sim_fd < 0) + auto hbfdp = std::dynamic_pointer_cast((*p->fds)[tgt_fd]); + if (!hbfdp) return -EBADF; + int sim_fd = hbfdp->getSimFD(); + BufferArg bufArg(bufPtr, nbytes); bufArg.copyIn(tc->getMemProxy()); int bytes_written = write(sim_fd, bufArg.bufferPtr(), nbytes); @@ -237,9 +230,10 @@ lseekFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) uint64_t offs = p->getSyscallArg(tc, index); int whence = p->getSyscallArg(tc, index); - int sim_fd = p->getSimFD(tgt_fd); - if (sim_fd < 0) + auto ffdp = std::dynamic_pointer_cast((*p->fds)[tgt_fd]); + if (!ffdp) return -EBADF; + int sim_fd = ffdp->getSimFD(); off_t result = lseek(sim_fd, offs, whence); @@ -257,9 +251,10 @@ _llseekFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) Addr result_ptr = p->getSyscallArg(tc, index); int whence = p->getSyscallArg(tc, index); - int sim_fd = p->getSimFD(tgt_fd); - if (sim_fd < 0) + auto ffdp = std::dynamic_pointer_cast((*p->fds)[tgt_fd]); + if (!ffdp) return -EBADF; + int sim_fd = ffdp->getSimFD(); uint64_t offset = (offset_high << 32) | offset_low; @@ -322,7 +317,7 @@ getcwdFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) strncpy((char *)buf.bufferPtr(), cwd.c_str(), size); result = cwd.length(); } else { - if (getcwd((char *)buf.bufferPtr(), size) != NULL) { + if (getcwd((char *)buf.bufferPtr(), size)) { result = strlen((char *)buf.bufferPtr()); } else { result = -1; @@ -484,16 +479,16 @@ truncateFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) } SyscallReturn -ftruncateFunc(SyscallDesc *desc, int num, - Process *process, ThreadContext *tc) +ftruncateFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) { int index = 0; - int tgt_fd = process->getSyscallArg(tc, index); - off_t length = process->getSyscallArg(tc, index); + int tgt_fd = p->getSyscallArg(tc, index); + off_t length = p->getSyscallArg(tc, index); - int sim_fd = process->getSimFD(tgt_fd); - if (sim_fd < 0) + auto ffdp = std::dynamic_pointer_cast((*p->fds)[tgt_fd]); + if (!ffdp) return -EBADF; + int sim_fd = ffdp->getSimFD(); int result = ftruncate(sim_fd, length); return (result == -1) ? -errno : result; @@ -523,16 +518,16 @@ truncate64Func(SyscallDesc *desc, int num, } SyscallReturn -ftruncate64Func(SyscallDesc *desc, int num, - Process *process, ThreadContext *tc) +ftruncate64Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) { int index = 0; - int tgt_fd = process->getSyscallArg(tc, index); - int64_t length = process->getSyscallArg(tc, index, 64); + int tgt_fd = p->getSyscallArg(tc, index); + int64_t length = p->getSyscallArg(tc, index, 64); - int sim_fd = process->getSimFD(tgt_fd); - if (sim_fd < 0) + auto ffdp = std::dynamic_pointer_cast((*p->fds)[tgt_fd]); + if (!ffdp) return -EBADF; + int sim_fd = ffdp->getSimFD(); #if NO_STAT64 int result = ftruncate(sim_fd, length); @@ -576,19 +571,20 @@ chownFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) } SyscallReturn -fchownFunc(SyscallDesc *desc, int num, Process *process, ThreadContext *tc) +fchownFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) { int index = 0; - int tgt_fd = process->getSyscallArg(tc, index); + int tgt_fd = p->getSyscallArg(tc, index); - int sim_fd = process->getSimFD(tgt_fd); - if (sim_fd < 0) + auto ffdp = std::dynamic_pointer_cast((*p->fds)[tgt_fd]); + if (!ffdp) return -EBADF; + int sim_fd = ffdp->getSimFD(); /* XXX endianess */ - uint32_t owner = process->getSyscallArg(tc, index); + uint32_t owner = p->getSyscallArg(tc, index); uid_t hostOwner = owner; - uint32_t group = process->getSyscallArg(tc, index); + uint32_t group = p->getSyscallArg(tc, index); gid_t hostGroup = group; int result = fchown(sim_fd, hostOwner, hostGroup); @@ -596,36 +592,47 @@ fchownFunc(SyscallDesc *desc, int num, Process *process, ThreadContext *tc) } +/** + * TODO: there's a bit more involved here since file descriptors created with + * dup are supposed to share a file description. So, there is a problem with + * maintaining fields like file offset or flags since an update to such a + * field won't be reflected in the metadata for the fd entries that we + * maintain to hold metadata for checkpoint restoration. + */ SyscallReturn -dupFunc(SyscallDesc *desc, int num, Process *process, ThreadContext *tc) +dupFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) { int index = 0; - int tgt_fd = process->getSyscallArg(tc, index); + int tgt_fd = p->getSyscallArg(tc, index); - int sim_fd = process->getSimFD(tgt_fd); - if (sim_fd < 0) + auto old_hbfdp = std::dynamic_pointer_cast((*p->fds)[tgt_fd]); + if (!old_hbfdp) return -EBADF; - - FDEntry *fde = process->getFDEntry(tgt_fd); + int sim_fd = old_hbfdp->getSimFD(); int result = dup(sim_fd); - return (result == -1) ? -errno : - process->allocFD(result, fde->filename, fde->flags, fde->mode, false); + int local_errno = errno; + + std::shared_ptr new_fdep = old_hbfdp->clone(); + auto new_hbfdp = std::dynamic_pointer_cast(new_fdep); + new_hbfdp->setSimFD(result); + + return (result == -1) ? -local_errno : p->fds->allocFD(new_fdep); } SyscallReturn -fcntlFunc(SyscallDesc *desc, int num, Process *process, - ThreadContext *tc) +fcntlFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) { int index = 0; - int tgt_fd = process->getSyscallArg(tc, index); + int tgt_fd = p->getSyscallArg(tc, index); - int sim_fd = process->getSimFD(tgt_fd); - if (sim_fd < 0) + auto hbfdp = std::dynamic_pointer_cast((*p->fds)[tgt_fd]); + if (!hbfdp) return -EBADF; + int sim_fd = hbfdp->getSimFD(); - int cmd = process->getSyscallArg(tc, index); + int cmd = p->getSyscallArg(tc, index); switch (cmd) { case 0: // F_DUPFD // if we really wanted to support this, we'd need to do it @@ -659,17 +666,17 @@ fcntlFunc(SyscallDesc *desc, int num, Process *process, } SyscallReturn -fcntl64Func(SyscallDesc *desc, int num, Process *process, - ThreadContext *tc) +fcntl64Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) { int index = 0; - int tgt_fd = process->getSyscallArg(tc, index); + int tgt_fd = p->getSyscallArg(tc, index); - int sim_fd = process->getSimFD(tgt_fd); - if (sim_fd < 0) + auto hbfdp = std::dynamic_pointer_cast((*p->fds)[tgt_fd]); + if (!hbfdp) return -EBADF; + int sim_fd = hbfdp->getSimFD(); - int cmd = process->getSyscallArg(tc, index); + int cmd = p->getSyscallArg(tc, index); switch (cmd) { case 33: //F_GETLK64 warn("fcntl64(%d, F_GETLK64) not supported, error returned\n", tgt_fd); @@ -694,21 +701,32 @@ SyscallReturn pipePseudoFunc(SyscallDesc *desc, int callnum, Process *process, ThreadContext *tc) { - int fds[2], sim_fds[2]; - int pipe_retval = pipe(fds); + int sim_fds[2], tgt_fds[2]; - if (pipe_retval < 0) { - // error + int pipe_retval = pipe(sim_fds); + if (pipe_retval < 0) return pipe_retval; - } - sim_fds[0] = process->allocFD(fds[0], "PIPE-READ", O_WRONLY, -1, true); - sim_fds[1] = process->allocFD(fds[1], "PIPE-WRITE", O_RDONLY, -1, true); + auto rend = PipeFDEntry::EndType::read; + auto rpfd = std::make_shared(sim_fds[0], O_WRONLY, rend); - process->setReadPipeSource(sim_fds[0], sim_fds[1]); - // Alpha Linux convention for pipe() is that fd[0] is returned as - // the return value of the function, and fd[1] is returned in r20. - tc->setIntReg(SyscallPseudoReturnReg, sim_fds[1]); + auto wend = PipeFDEntry::EndType::write; + auto wpfd = std::make_shared(sim_fds[1], O_RDONLY, wend); + + tgt_fds[0] = process->fds->allocFD(rpfd); + tgt_fds[1] = process->fds->allocFD(wpfd); + + /** + * Now patch the read object to record the target file descriptor chosen + * as the write end of the pipe. + */ + rpfd->setPipeReadSource(tgt_fds[1]); + + /** + * Alpha Linux convention for pipe() is that fd[0] is returned as + * the return value of the function, and fd[1] is returned in r20. + */ + tc->setIntReg(SyscallPseudoReturnReg, tgt_fds[1]); return sim_fds[0]; } @@ -828,7 +846,7 @@ cloneFunc(SyscallDesc *desc, int callnum, Process *process, } ThreadContext* ctc; // child thread context - if ( ( ctc = process->findFreeContext() ) != NULL ) { + if ((ctc = process->findFreeContext())) { DPRINTF(SyscallVerbose, " Found unallocated thread context\n"); ctc->clearArchRegs(); @@ -890,21 +908,21 @@ cloneFunc(SyscallDesc *desc, int callnum, Process *process, } SyscallReturn -fallocateFunc(SyscallDesc *desc, int callnum, Process *process, - ThreadContext *tc) +fallocateFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) { #if NO_FALLOCATE warn("Host OS cannot support calls to fallocate. Ignoring syscall"); #else int index = 0; - int tgt_fd = process->getSyscallArg(tc, index); - int mode = process->getSyscallArg(tc, index); - off_t offset = process->getSyscallArg(tc, index); - off_t len = process->getSyscallArg(tc, index); + int tgt_fd = p->getSyscallArg(tc, index); + int mode = p->getSyscallArg(tc, index); + off_t offset = p->getSyscallArg(tc, index); + off_t len = p->getSyscallArg(tc, index); - int sim_fd = process->getSimFD(tgt_fd); - if (sim_fd < 0) + auto ffdp = std::dynamic_pointer_cast((*p->fds)[tgt_fd]); + if (!ffdp) return -EBADF; + int sim_fd = ffdp->getSimFD(); int result = fallocate(sim_fd, mode, offset, len); if (result < 0) diff --git a/src/sim/syscall_emul.hh b/src/sim/syscall_emul.hh index c75784f79..376ae6f32 100644 --- a/src/sim/syscall_emul.hh +++ b/src/sim/syscall_emul.hh @@ -78,6 +78,7 @@ #include #include +#include #include #include "base/intmath.hh" @@ -570,31 +571,35 @@ copyOutStatfsBuf(SETranslatingPortProxy &mem, Addr addr, /// not TTYs to provide repeatable results. template SyscallReturn -ioctlFunc(SyscallDesc *desc, int callnum, Process *process, - ThreadContext *tc) +ioctlFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) { int index = 0; - int tgt_fd = process->getSyscallArg(tc, index); - unsigned req = process->getSyscallArg(tc, index); + int tgt_fd = p->getSyscallArg(tc, index); + unsigned req = p->getSyscallArg(tc, index); DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", tgt_fd, req); - FDEntry *fde = process->getFDEntry(tgt_fd); - - if (fde == NULL) { - // doesn't map to any simulator fd: not a valid target fd - return -EBADF; - } - - if (fde->driver != NULL) { - return fde->driver->ioctl(process, tc, req); - } - - if (OS::isTtyReq(req)) { + if (OS::isTtyReq(req)) return -ENOTTY; - } - warn("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ \n", + auto dfdp = std::dynamic_pointer_cast((*p->fds)[tgt_fd]); + if (!dfdp) + return -EBADF; + + /** + * If the driver is valid, issue the ioctl through it. Otherwise, + * there's an implicit assumption that the device is a TTY type and we + * return that we do not have a valid TTY. + */ + EmulatedDriver *emul_driver = dfdp->getDriver(); + if (emul_driver) + return emul_driver->ioctl(p, tc, req); + + /** + * For lack of a better return code, return ENOTTY. Ideally, we should + * return something better here, but at least we issue the warning. + */ + warn("Unsupported ioctl call (return ENOTTY): ioctl(%d, 0x%x, ...) @ \n", tgt_fd, req, tc->pcState()); return -ENOTTY; } @@ -645,7 +650,7 @@ openFunc(SyscallDesc *desc, int callnum, Process *process, } EmulatedDriver *drv = process->findDriver(filename); - if (drv != NULL) { + if (drv) { // the driver's open method will allocate a fd from the // process if necessary. return drv->open(process, tc, mode, hostFlags); @@ -671,7 +676,9 @@ openFunc(SyscallDesc *desc, int callnum, Process *process, if (fd == -1) return -local_errno; - return process->allocFD(fd, path.c_str(), hostFlags, mode, false); + std::shared_ptr ffdp = + std::make_shared(fd, hostFlags, path.c_str(), false); + return process->fds->allocFD(ffdp); } /// Target open() handler. @@ -827,28 +834,22 @@ chmodFunc(SyscallDesc *desc, int callnum, Process *process, /// Target fchmod() handler. template SyscallReturn -fchmodFunc(SyscallDesc *desc, int callnum, Process *process, - ThreadContext *tc) +fchmodFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) { int index = 0; - int tgt_fd = process->getSyscallArg(tc, index); - uint32_t mode = process->getSyscallArg(tc, index); + int tgt_fd = p->getSyscallArg(tc, index); + uint32_t mode = p->getSyscallArg(tc, index); - int sim_fd = process->getSimFD(tgt_fd); - if (sim_fd < 0) + auto ffdp = std::dynamic_pointer_cast((*p->fds)[tgt_fd]); + if (!ffdp) return -EBADF; + int sim_fd = ffdp->getSimFD(); - mode_t hostMode = 0; + mode_t hostMode = mode; - // XXX translate mode flags via OS::someting??? - hostMode = mode; - - // do the fchmod int result = fchmod(sim_fd, hostMode); - if (result < 0) - return -errno; - return 0; + return (result < 0) ? -errno : 0; } /// Target mremap() handler. @@ -1021,16 +1022,16 @@ fstatat64Func(SyscallDesc *desc, int callnum, Process *process, /// Target fstat64() handler. template SyscallReturn -fstat64Func(SyscallDesc *desc, int callnum, Process *process, - ThreadContext *tc) +fstat64Func(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) { int index = 0; - int tgt_fd = process->getSyscallArg(tc, index); - Addr bufPtr = process->getSyscallArg(tc, index); + int tgt_fd = p->getSyscallArg(tc, index); + Addr bufPtr = p->getSyscallArg(tc, index); - int sim_fd = process->getSimFD(tgt_fd); - if (sim_fd < 0) + auto ffdp = std::dynamic_pointer_cast((*p->fds)[tgt_fd]); + if (!ffdp) return -EBADF; + int sim_fd = ffdp->getSimFD(); #if NO_STAT64 struct stat hostBuf; @@ -1115,18 +1116,18 @@ lstat64Func(SyscallDesc *desc, int callnum, Process *process, /// Target fstat() handler. template SyscallReturn -fstatFunc(SyscallDesc *desc, int callnum, Process *process, - ThreadContext *tc) +fstatFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) { int index = 0; - int tgt_fd = process->getSyscallArg(tc, index); - Addr bufPtr = process->getSyscallArg(tc, index); + int tgt_fd = p->getSyscallArg(tc, index); + Addr bufPtr = p->getSyscallArg(tc, index); DPRINTF_SYSCALL(Verbose, "fstat(%d, ...)\n", tgt_fd); - int sim_fd = process->getSimFD(tgt_fd); - if (sim_fd < 0) + auto ffdp = std::dynamic_pointer_cast((*p->fds)[tgt_fd]); + if (!ffdp) return -EBADF; + int sim_fd = ffdp->getSimFD(); struct stat hostBuf; int result = fstat(sim_fd, &hostBuf); @@ -1176,16 +1177,16 @@ statfsFunc(SyscallDesc *desc, int callnum, Process *process, /// Target fstatfs() handler. template SyscallReturn -fstatfsFunc(SyscallDesc *desc, int callnum, Process *process, - ThreadContext *tc) +fstatfsFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) { int index = 0; - int tgt_fd = process->getSyscallArg(tc, index); - Addr bufPtr = process->getSyscallArg(tc, index); + int tgt_fd = p->getSyscallArg(tc, index); + Addr bufPtr = p->getSyscallArg(tc, index); - int sim_fd = process->getSimFD(tgt_fd); - if (sim_fd < 0) + auto ffdp = std::dynamic_pointer_cast((*p->fds)[tgt_fd]); + if (!ffdp) return -EBADF; + int sim_fd = ffdp->getSimFD(); struct statfs hostBuf; int result = fstatfs(sim_fd, &hostBuf); @@ -1202,29 +1203,29 @@ fstatfsFunc(SyscallDesc *desc, int callnum, Process *process, /// Target writev() handler. template SyscallReturn -writevFunc(SyscallDesc *desc, int callnum, Process *process, - ThreadContext *tc) +writevFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) { int index = 0; - int tgt_fd = process->getSyscallArg(tc, index); + int tgt_fd = p->getSyscallArg(tc, index); - int sim_fd = process->getSimFD(tgt_fd); - if (sim_fd < 0) + auto hbfdp = std::dynamic_pointer_cast((*p->fds)[tgt_fd]); + if (!hbfdp) return -EBADF; + int sim_fd = hbfdp->getSimFD(); - SETranslatingPortProxy &p = tc->getMemProxy(); - uint64_t tiov_base = process->getSyscallArg(tc, index); - size_t count = process->getSyscallArg(tc, index); + SETranslatingPortProxy &prox = tc->getMemProxy(); + uint64_t tiov_base = p->getSyscallArg(tc, index); + size_t count = p->getSyscallArg(tc, index); struct iovec hiov[count]; for (size_t i = 0; i < count; ++i) { typename OS::tgt_iovec tiov; - p.readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec), - (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec)); + prox.readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec), + (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec)); hiov[i].iov_len = TheISA::gtoh(tiov.iov_len); hiov[i].iov_base = new char [hiov[i].iov_len]; - p.readBlob(TheISA::gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base, - hiov[i].iov_len); + prox.readBlob(TheISA::gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base, + hiov[i].iov_len); } int result = writev(sim_fd, hiov, count); @@ -1296,19 +1297,19 @@ mmapImpl(SyscallDesc *desc, int num, Process *p, ThreadContext *tc, int sim_fd = -1; uint8_t *pmap = nullptr; if (!(tgt_flags & OS::TGT_MAP_ANONYMOUS)) { - // Check for EmulatedDriver mmap - FDEntry *fde = p->getFDEntry(tgt_fd); - if (fde == NULL) - return -EBADF; + std::shared_ptr fdep = (*p->fds)[tgt_fd]; - if (fde->driver != NULL) { - return fde->driver->mmap(p, tc, start, length, prot, + auto dfdp = std::dynamic_pointer_cast(fdep); + if (dfdp) { + EmulatedDriver *emul_driver = dfdp->getDriver(); + return emul_driver->mmap(p, tc, start, length, prot, tgt_flags, tgt_fd, offset); } - sim_fd = fde->fd; - if (sim_fd < 0) + auto ffdp = std::dynamic_pointer_cast(fdep); + if (!ffdp) return -EBADF; + sim_fd = ffdp->getSimFD(); pmap = (decltype(pmap))mmap(NULL, length, PROT_READ, MAP_PRIVATE, sim_fd, offset); @@ -1393,9 +1394,9 @@ mmapImpl(SyscallDesc *desc, int num, Process *p, ThreadContext *tc, Addr pc = tc->pcState().pc(); if (pc >= text_start && pc < text_end) { - FDEntry *fde = p->getFDEntry(tgt_fd); - - ObjectFile *lib = createObjectFile(fde->filename); + std::shared_ptr fdep = (*p->fds)[tgt_fd]; + auto ffdp = std::dynamic_pointer_cast(fdep); + ObjectFile *lib = createObjectFile(ffdp->getFileName()); if (lib) { lib->loadAllSymbols(debugSymbolTable, @@ -1422,9 +1423,10 @@ pwrite64Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) int nbytes = p->getSyscallArg(tc, index); int offset = p->getSyscallArg(tc, index); - int sim_fd = p->getSimFD(tgt_fd); - if (sim_fd < 0) + auto ffdp = std::dynamic_pointer_cast((*p->fds)[tgt_fd]); + if (!ffdp) return -EBADF; + int sim_fd = ffdp->getSimFD(); BufferArg bufArg(bufPtr, nbytes); bufArg.copyIn(tc->getMemProxy());