diff options
Diffstat (limited to 'src/sim')
36 files changed, 8442 insertions, 0 deletions
diff --git a/src/sim/async.hh b/src/sim/async.hh new file mode 100644 index 000000000..e0190a133 --- /dev/null +++ b/src/sim/async.hh @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * 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. + */ + +#ifndef __ASYNC_HH__ +#define __ASYNC_HH__ + +/// +/// @file sim/async.hh +/// This file defines flags used to handle asynchronous simulator events. +/// + +/// @name Asynchronous event flags. +/// To avoid races, signal handlers simply set these flags, which are +/// then checked in the main event loop. Defined in main.cc. +/// @note See the PollQueue object (in pollevent.hh) for the use of async_io and async_alarm. +//@{ +extern volatile bool async_event; ///< Some asynchronous event has happened. +extern volatile bool async_dump; ///< Async request to dump stats. +extern volatile bool async_exit; ///< Async request to exit simulator. +extern volatile bool async_io; ///< Async I/O request (SIGIO). +extern volatile bool async_alarm; ///< Async alarm event (SIGALRM). +//@} + +#endif // __ASYNC_HH__ diff --git a/src/sim/builder.cc b/src/sim/builder.cc new file mode 100644 index 000000000..7dc118985 --- /dev/null +++ b/src/sim/builder.cc @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * 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. + */ + +#include <assert.h> + +#include "base/inifile.hh" +#include "base/misc.hh" +#include "sim/builder.hh" +#include "sim/configfile.hh" +#include "sim/config_node.hh" +#include "sim/host.hh" +#include "sim/sim_object.hh" +#include "sim/root.hh" + +using namespace std; + +SimObjectBuilder::SimObjectBuilder(ConfigNode *_configNode) + : ParamContext(_configNode->getPath(), NoAutoInit), + configNode(_configNode) +{ +} + +SimObjectBuilder::~SimObjectBuilder() +{ +} + +/////////////////////////////////////////// +// +// SimObjectBuilder member definitions +// +/////////////////////////////////////////// + +// override ParamContext::parseParams() to check params based on +// instance name first. If not found, then check based on iniSection +// (as in default ParamContext implementation). +void +SimObjectBuilder::parseParams(IniFile &iniFile) +{ + iniFilePtr = &iniFile; // set object member + + ParamList::iterator i; + + for (i = paramList->begin(); i != paramList->end(); ++i) { + string string_value; + if (iniFile.find(iniSection, (*i)->name, string_value)) + (*i)->parse(string_value); + } +} + + +void +SimObjectBuilder::printErrorProlog(ostream &os) +{ + ccprintf(os, "Error creating object '%s' of type '%s':\n", + iniSection, configNode->getType()); +} + + +//////////////////////////////////////////////////////////////////////// +// +// SimObjectClass member definitions +// +//////////////////////////////////////////////////////////////////////// + +// Map of class names to SimObjectBuilder creation functions. Need to +// make this a pointer so we can force initialization on the first +// reference; otherwise, some SimObjectClass constructors may be invoked +// before the classMap constructor. +map<string,SimObjectClass::CreateFunc> *SimObjectClass::classMap = NULL; + +// SimObjectClass constructor: add mapping to classMap +SimObjectClass::SimObjectClass(const string &className, CreateFunc createFunc) +{ + if (classMap == NULL) + classMap = new map<string,SimObjectClass::CreateFunc>(); + + if ((*classMap)[className]) + panic("Error: simulation object class '%s' redefined\n", className); + + // add className --> createFunc to class map + (*classMap)[className] = createFunc; +} + + +// +// +SimObject * +SimObjectClass::createObject(IniFile &configDB, ConfigNode *configNode) +{ + const string &type = configNode->getType(); + + // look up className to get appropriate createFunc + if (classMap->find(type) == classMap->end()) + panic("Simulator object type '%s' not found.\n", type); + + + CreateFunc createFunc = (*classMap)[type]; + + // call createFunc with config hierarchy node to get object + // builder instance (context with parameters for object creation) + SimObjectBuilder *objectBuilder = (*createFunc)(configNode); + + assert(objectBuilder != NULL); + + // parse all parameters in context to generate parameter values + objectBuilder->parseParams(configDB); + + // now create the actual simulation object + SimObject *object = objectBuilder->create(); + + assert(object != NULL); + + // echo object parameters to stats file (for documenting the + // config used to generate the associated stats) + ccprintf(*configStream, "[%s]\n", object->name()); + ccprintf(*configStream, "type=%s\n", type); + objectBuilder->showParams(*configStream); + ccprintf(*configStream, "\n"); + + // done with the SimObjectBuilder now + delete objectBuilder; + + return object; +} + + +// +// static method: +// +void +SimObjectClass::describeAllClasses(ostream &os) +{ + map<string,CreateFunc>::iterator iter; + + for (iter = classMap->begin(); iter != classMap->end(); ++iter) { + const string &className = iter->first; + CreateFunc createFunc = iter->second; + + os << "[" << className << "]\n"; + + // create dummy object builder just to instantiate parameters + SimObjectBuilder *objectBuilder = (*createFunc)(NULL); + + // now get the object builder to describe ite params + objectBuilder->describeParams(os); + + os << endl; + + // done with the object builder now + delete objectBuilder; + } +} diff --git a/src/sim/builder.hh b/src/sim/builder.hh new file mode 100644 index 000000000..b32e00e76 --- /dev/null +++ b/src/sim/builder.hh @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * 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. + */ + +#ifndef __BUILDER_HH__ +#define __BUILDER_HH__ + +#include <iosfwd> +#include <list> +#include <map> +#include <vector> + +#include "sim/param.hh" + +class SimObject; + +// +// A SimObjectBuilder serves as an evaluation context for a set of +// parameters that describe a specific instance of a SimObject. This +// evaluation context corresponds to a section in the .ini file (as +// with the base ParamContext) plus an optional node in the +// configuration hierarchy (the configNode member) for resolving +// SimObject references. SimObjectBuilder is an abstract superclass; +// derived classes specialize the class for particular subclasses of +// SimObject (e.g., BaseCache). +// +// For typical usage, see the definition of +// SimObjectClass::createObject(). +// +class SimObjectBuilder : public ParamContext +{ + private: + // The corresponding node in the configuration hierarchy. + // (optional: may be null if the created object is not in the + // hierarchy) + ConfigNode *configNode; + + public: + SimObjectBuilder(ConfigNode *_configNode); + + virtual ~SimObjectBuilder(); + + // call parse() on all params in this context to convert string + // representations to parameter values + virtual void parseParams(IniFile &iniFile); + + // parameter error prolog (override of ParamContext) + virtual void printErrorProlog(std::ostream &); + + // generate the name for this SimObject instance (derived from the + // configuration hierarchy node label and position) + virtual const std::string &getInstanceName() { return iniSection; } + + // return the configuration hierarchy node for this context. + virtual ConfigNode *getConfigNode() { return configNode; } + + // Create the actual SimObject corresponding to the parameter + // values in this context. This function is overridden in derived + // classes to call a specific constructor for a particular + // subclass of SimObject. + virtual SimObject *create() = 0; +}; + + +// +// Handy macros for initializing parameter members of classes derived +// from SimObjectBuilder. Assumes that the name of the parameter +// member object is the same as the textual parameter name seen by the +// user. (Note that '#p' is expanded by the preprocessor to '"p"'.) +// +#define INIT_PARAM(p, desc) p(this, #p, desc) +#define INIT_PARAM_DFLT(p, desc, dflt) p(this, #p, desc, dflt) + +// +// Initialize an enumeration variable... assumes that 'map' is the +// name of an array of mappings (char * for SimpleEnumParam, or +// EnumParamMap for MappedEnumParam). +// +#define INIT_ENUM_PARAM(p, desc, map) \ + p(this, #p, desc, map, sizeof(map)/sizeof(map[0])) +#define INIT_ENUM_PARAM_DFLT(p, desc, map, dflt) \ + p(this, #p, desc, map, sizeof(map)/sizeof(map[0]), dflt) + +// +// An instance of SimObjectClass corresponds to a class derived from +// SimObject. The SimObjectClass instance serves to bind the string +// name (found in the config file) to a function that creates an +// instance of the appropriate derived class. +// +// This would be much cleaner in Smalltalk or Objective-C, where types +// are first-class objects themselves. +// +class SimObjectClass +{ + public: + // Type CreateFunc is a pointer to a function that creates a new + // simulation object builder based on a .ini-file parameter + // section (specified by the first string argument), a unique name + // for the object (specified by the second string argument), and + // an optional config hierarchy node (specified by the third + // argument). A pointer to the new SimObjectBuilder is returned. + typedef SimObjectBuilder *(*CreateFunc)(ConfigNode *configNode); + + static std::map<std::string,CreateFunc> *classMap; + + // Constructor. For example: + // + // SimObjectClass baseCacheClass("BaseCache", newBaseCacheBuilder); + // + SimObjectClass(const std::string &className, CreateFunc createFunc); + + // create SimObject given name of class and pointer to + // configuration hierarchy node + static SimObject *createObject(IniFile &configDB, ConfigNode *configNode); + + // print descriptions of all parameters registered with all + // SimObject classes + static void describeAllClasses(std::ostream &os); +}; + +// +// Macros to encapsulate the magic of declaring & defining +// SimObjectBuilder and SimObjectClass objects +// + +#define BEGIN_DECLARE_SIM_OBJECT_PARAMS(OBJ_CLASS) \ +class OBJ_CLASS##Builder : public SimObjectBuilder \ +{ \ + public: + +#define END_DECLARE_SIM_OBJECT_PARAMS(OBJ_CLASS) \ + \ + OBJ_CLASS##Builder(ConfigNode *configNode); \ + virtual ~OBJ_CLASS##Builder() {} \ + \ + OBJ_CLASS *create(); \ +}; + +#define BEGIN_INIT_SIM_OBJECT_PARAMS(OBJ_CLASS) \ +OBJ_CLASS##Builder::OBJ_CLASS##Builder(ConfigNode *configNode) \ + : SimObjectBuilder(configNode), + + +#define END_INIT_SIM_OBJECT_PARAMS(OBJ_CLASS) \ +{ \ +} + +#define CREATE_SIM_OBJECT(OBJ_CLASS) \ +OBJ_CLASS *OBJ_CLASS##Builder::create() + +#define REGISTER_SIM_OBJECT(CLASS_NAME, OBJ_CLASS) \ +SimObjectBuilder * \ +new##OBJ_CLASS##Builder(ConfigNode *configNode) \ +{ \ + return new OBJ_CLASS##Builder(configNode); \ +} \ + \ +SimObjectClass the##OBJ_CLASS##Class(CLASS_NAME, \ + new##OBJ_CLASS##Builder); \ + \ +/* see param.hh */ \ +DEFINE_SIM_OBJECT_CLASS_NAME(CLASS_NAME, OBJ_CLASS) + + +#endif // __BUILDER_HH__ diff --git a/src/sim/byteswap.hh b/src/sim/byteswap.hh new file mode 100644 index 000000000..a8c5da9d7 --- /dev/null +++ b/src/sim/byteswap.hh @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2004 The Regents of The University of Michigan + * 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. + */ + +//The purpose of this file is to provide endainness conversion utility +//functions. Depending on the endianness of the guest system, either +//the LittleEndianGuest or BigEndianGuest namespace is used. + +#ifndef __SIM_BYTE_SWAP_HH__ +#define __SIM_BYTE_SWAP_HH__ + +#include "sim/host.hh" + +// This lets us figure out what the byte order of the host system is +#if defined(linux) +#include <endian.h> +// If this is a linux system, lets used the optimized definitions if they exist. +// If one doesn't exist, we pretty much get what is listed below, so it all +// works out +#include <byteswap.h> +#else +#include <machine/endian.h> +#endif + +//These functions actually perform the swapping for parameters +//of various bit lengths +static inline uint64_t +swap_byte64(uint64_t x) +{ +#if defined(linux) + return bswap_64(x); +#else + return (uint64_t)((((uint64_t)(x) & 0xff) << 56) | + ((uint64_t)(x) & 0xff00ULL) << 40 | + ((uint64_t)(x) & 0xff0000ULL) << 24 | + ((uint64_t)(x) & 0xff000000ULL) << 8 | + ((uint64_t)(x) & 0xff00000000ULL) >> 8 | + ((uint64_t)(x) & 0xff0000000000ULL) >> 24 | + ((uint64_t)(x) & 0xff000000000000ULL) >> 40 | + ((uint64_t)(x) & 0xff00000000000000ULL) >> 56) ; +#endif +} + +static inline uint32_t +swap_byte32(uint32_t x) +{ +#if defined(linux) + return bswap_32(x); +#else + return (uint32_t)(((uint32_t)(x) & 0xff) << 24 | + ((uint32_t)(x) & 0xff00) << 8 | ((uint32_t)(x) & 0xff0000) >> 8 | + ((uint32_t)(x) & 0xff000000) >> 24); +#endif +} + +static inline uint16_t +swap_byte16(uint16_t x) +{ +#if defined(linux) + return bswap_16(x); +#else + return (uint16_t)(((uint16_t)(x) & 0xff) << 8 | + ((uint16_t)(x) & 0xff00) >> 8); +#endif +} + +//This lets the compiler figure out how to call the swap_byte functions above +//for different data types. +static inline uint64_t swap_byte(uint64_t x) {return swap_byte64(x);} +static inline int64_t swap_byte(int64_t x) {return swap_byte64((uint64_t)x);} +static inline uint32_t swap_byte(uint32_t x) {return swap_byte32(x);} +static inline int32_t swap_byte(int32_t x) {return swap_byte32((uint32_t)x);} +//This is to prevent the following two functions from compiling on +//64bit machines. It won't detect everything, so it should be changed. +#ifndef __x86_64__ +static inline long swap_byte(long x) {return swap_byte32((long)x);} +static inline unsigned long swap_byte(unsigned long x) + { return swap_byte32((unsigned long)x);} +#endif +static inline uint16_t swap_byte(uint16_t x) {return swap_byte32(x);} +static inline int16_t swap_byte(int16_t x) {return swap_byte16((uint16_t)x);} +static inline uint8_t swap_byte(uint8_t x) {return x;} +static inline int8_t swap_byte(int8_t x) {return x;} +static inline double swap_byte(double x) {return swap_byte64((uint64_t)x);} +static inline float swap_byte(float x) {return swap_byte32((uint32_t)x);} + +//The conversion functions with fixed endianness on both ends don't need to +//be in a namespace +template <typename T> static inline T betole(T value) {return swap_byte(value);} +template <typename T> static inline T letobe(T value) {return swap_byte(value);} + +//For conversions not involving the guest system, we can define the functions +//conditionally based on the BYTE_ORDER macro and outside of the namespaces +#if BYTE_ORDER == BIG_ENDIAN +template <typename T> static inline T htole(T value) {return swap_byte(value);} +template <typename T> static inline T letoh(T value) {return swap_byte(value);} +template <typename T> static inline T htobe(T value) {return value;} +template <typename T> static inline T betoh(T value) {return value;} +#elif BYTE_ORDER == LITTLE_ENDIAN +template <typename T> static inline T htole(T value) {return value;} +template <typename T> static inline T letoh(T value) {return value;} +template <typename T> static inline T htobe(T value) {return swap_byte(value);} +template <typename T> static inline T betoh(T value) {return swap_byte(value);} +#else + #error Invalid Endianess +#endif + +namespace BigEndianGuest +{ + template <typename T> + static inline T gtole(T value) {return betole(value);} + template <typename T> + static inline T letog(T value) {return letobe(value);} + template <typename T> + static inline T gtobe(T value) {return value;} + template <typename T> + static inline T betog(T value) {return value;} + template <typename T> + static inline T htog(T value) {return htobe(value);} + template <typename T> + static inline T gtoh(T value) {return betoh(value);} +} + +namespace LittleEndianGuest +{ + template <typename T> + static inline T gtole(T value) {return value;} + template <typename T> + static inline T letog(T value) {return value;} + template <typename T> + static inline T gtobe(T value) {return letobe(value);} + template <typename T> + static inline T betog(T value) {return betole(value);} + template <typename T> + static inline T htog(T value) {return htole(value);} + template <typename T> + static inline T gtoh(T value) {return letoh(value);} +} +#endif // __SIM_BYTE_SWAP_HH__ diff --git a/src/sim/debug.cc b/src/sim/debug.cc new file mode 100644 index 000000000..09e5346a8 --- /dev/null +++ b/src/sim/debug.cc @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * 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. + */ + +#include <sys/types.h> +#include <signal.h> +#include <unistd.h> + +#include <string> +#include <vector> + +#include "sim/debug.hh" +#include "sim/eventq.hh" +#include "sim/param.hh" +#include "sim/sim_events.hh" + +using namespace std; + +void +debug_break() +{ +#ifndef NDEBUG + kill(getpid(), SIGTRAP); +#else + cprintf("debug_break suppressed, compiled with NDEBUG\n"); +#endif +} + +// +// Debug event: place a breakpoint on the process function and +// schedule the event to break at a particular cycle +// +class DebugBreakEvent : public Event +{ + public: + + DebugBreakEvent(EventQueue *q, Tick _when); + + void process(); // process event + virtual const char *description(); +}; + +// +// constructor: schedule at specified time +// +DebugBreakEvent::DebugBreakEvent(EventQueue *q, Tick _when) + : Event(q, Debug_Break_Pri) +{ + setFlags(AutoDelete); + schedule(_when); +} + +// +// handle debug event: set debugger breakpoint on this function +// +void +DebugBreakEvent::process() +{ + debug_break(); +} + + +const char * +DebugBreakEvent::description() +{ + return "debug break"; +} + +// +// Parameter context for global debug options +// +class DebugContext : public ParamContext +{ + public: + DebugContext(const string &_iniSection) + : ParamContext(_iniSection) {} + void checkParams(); +}; + +DebugContext debugParams("debug"); + +VectorParam<Tick> break_cycles(&debugParams, "break_cycles", + "cycle(s) to create breakpoint events"); + +void +DebugContext::checkParams() +{ + if (break_cycles.isValid()) { + vector<Tick> &cycles = break_cycles; + + vector<Tick>::iterator i = cycles.begin(); + vector<Tick>::iterator end = cycles.end(); + + for (; i < end; ++i) + new DebugBreakEvent(&mainEventQueue, *i); + } +} + +// +// handy function to schedule DebugBreakEvent on main event queue +// (callable from debugger) +// +extern "C" void sched_break_cycle(Tick when) +{ + new DebugBreakEvent(&mainEventQueue, when); +} + +extern "C" void eventq_dump() +{ + mainEventQueue.dump(); +} + diff --git a/src/sim/debug.hh b/src/sim/debug.hh new file mode 100644 index 000000000..75b261d80 --- /dev/null +++ b/src/sim/debug.hh @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * 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. + */ + +#ifndef __DEBUG_HH__ +#define __DEBUG_HH__ + +void debug_break(); + +#endif // __DEBUG_HH__ diff --git a/src/sim/eventq.cc b/src/sim/eventq.cc new file mode 100644 index 000000000..4bfd6face --- /dev/null +++ b/src/sim/eventq.cc @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2000-2005 The Regents of The University of Michigan + * 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. + */ + +#include <assert.h> + +#include <iostream> +#include <string> +#include <vector> + +#include "cpu/smt.hh" +#include "base/misc.hh" + +#include "sim/eventq.hh" +#include "base/trace.hh" +#include "sim/root.hh" + +using namespace std; + +// +// Main Event Queue +// +// Events on this queue are processed at the *beginning* of each +// cycle, before the pipeline simulation is performed. +// +EventQueue mainEventQueue("MainEventQueue"); + +void +EventQueue::insert(Event *event) +{ + if (head == NULL || event->when() < head->when() || + (event->when() == head->when() && + event->priority() <= head->priority())) { + event->next = head; + head = event; + } else { + Event *prev = head; + Event *curr = head->next; + + while (curr) { + if (event->when() <= curr->when() && + (event->when() < curr->when() || + event->priority() <= curr->priority())) + break; + + prev = curr; + curr = curr->next; + } + + event->next = curr; + prev->next = event; + } +} + +void +EventQueue::remove(Event *event) +{ + if (head == NULL) + return; + + if (head == event){ + head = event->next; + return; + } + + Event *prev = head; + Event *curr = head->next; + while (curr && curr != event) { + prev = curr; + curr = curr->next; + } + + if (curr == event) + prev->next = curr->next; +} + +void +EventQueue::serviceOne() +{ + Event *event = head; + event->clearFlags(Event::Scheduled); + head = event->next; + + // handle action + if (!event->squashed()) + event->process(); + else + event->clearFlags(Event::Squashed); + + if (event->getFlags(Event::AutoDelete) && !event->scheduled()) + delete event; +} + + +void +Event::serialize(std::ostream &os) +{ + SERIALIZE_SCALAR(_when); + SERIALIZE_SCALAR(_priority); + SERIALIZE_ENUM(_flags); +} + + +void +Event::unserialize(Checkpoint *cp, const string §ion) +{ + if (scheduled()) + deschedule(); + + UNSERIALIZE_SCALAR(_when); + UNSERIALIZE_SCALAR(_priority); + + // need to see if original event was in a scheduled, unsquashed + // state, but don't want to restore those flags in the current + // object itself (since they aren't immediately true) + UNSERIALIZE_ENUM(_flags); + bool wasScheduled = (_flags & Scheduled) && !(_flags & Squashed); + _flags &= ~(Squashed | Scheduled); + + if (wasScheduled) { + DPRINTF(Config, "rescheduling at %d\n", _when); + schedule(_when); + } +} + +void +EventQueue::serialize(ostream &os) +{ + std::list<Event *> eventPtrs; + + int numEvents = 0; + Event *event = head; + while (event) { + if (event->getFlags(Event::AutoSerialize)) { + eventPtrs.push_back(event); + paramOut(os, csprintf("event%d", numEvents++), event->name()); + } + event = event->next; + } + + SERIALIZE_SCALAR(numEvents); + + for (std::list<Event *>::iterator it=eventPtrs.begin(); + it != eventPtrs.end(); ++it) { + (*it)->nameOut(os); + (*it)->serialize(os); + } +} + +void +EventQueue::unserialize(Checkpoint *cp, const std::string §ion) +{ + int numEvents; + UNSERIALIZE_SCALAR(numEvents); + + std::string eventName; + for (int i = 0; i < numEvents; i++) { + // get the pointer value associated with the event + paramIn(cp, section, csprintf("event%d", i), eventName); + + // create the event based on its pointer value + Serializable::create(cp, eventName); + } +} + +void +EventQueue::dump() +{ + cprintf("============================================================\n"); + cprintf("EventQueue Dump (cycle %d)\n", curTick); + cprintf("------------------------------------------------------------\n"); + + if (empty()) + cprintf("<No Events>\n"); + else { + Event *event = head; + while (event) { + event->dump(); + event = event->next; + } + } + + cprintf("============================================================\n"); +} + +extern "C" +void +dumpMainQueue() +{ + mainEventQueue.dump(); +} + + +const char * +Event::description() +{ + return "generic"; +} + +#if TRACING_ON +void +Event::trace(const char *action) +{ + // This DPRINTF is unconditional because calls to this function + // are protected by an 'if (DTRACE(Event))' in the inlined Event + // methods. + // + // This is just a default implementation for derived classes where + // it's not worth doing anything special. If you want to put a + // more informative message in the trace, override this method on + // the particular subclass where you have the information that + // needs to be printed. + DPRINTFN("%s event %s @ %d\n", description(), action, when()); +} +#endif + +void +Event::dump() +{ + cprintf("Event (%s)\n", description()); + cprintf("Flags: %#x\n", _flags); +#if TRACING_ON + cprintf("Created: %d\n", when_created); +#endif + if (scheduled()) { +#if TRACING_ON + cprintf("Scheduled at %d\n", when_scheduled); +#endif + cprintf("Scheduled for %d, priority %d\n", when(), _priority); + } + else { + cprintf("Not Scheduled\n"); + } +} diff --git a/src/sim/eventq.hh b/src/sim/eventq.hh new file mode 100644 index 000000000..5fc73bb53 --- /dev/null +++ b/src/sim/eventq.hh @@ -0,0 +1,407 @@ +/* + * Copyright (c) 2000-2005 The Regents of The University of Michigan + * 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. + */ + +/* @file + * EventQueue interfaces + */ + +#ifndef __SIM_EVENTQ_HH__ +#define __SIM_EVENTQ_HH__ + +#include <assert.h> + +#include <algorithm> +#include <map> +#include <string> +#include <vector> + +#include "sim/host.hh" // for Tick + +#include "base/fast_alloc.hh" +#include "base/trace.hh" +#include "sim/serialize.hh" + +class EventQueue; // forward declaration + +////////////////////// +// +// Main Event Queue +// +// Events on this queue are processed at the *beginning* of each +// cycle, before the pipeline simulation is performed. +// +// defined in eventq.cc +// +////////////////////// +extern EventQueue mainEventQueue; + + +/* + * An item on an event queue. The action caused by a given + * event is specified by deriving a subclass and overriding the + * process() member function. + */ +class Event : public Serializable, public FastAlloc +{ + friend class EventQueue; + + private: + /// queue to which this event belongs (though it may or may not be + /// scheduled on this queue yet) + EventQueue *queue; + + Event *next; + + Tick _when; //!< timestamp when event should be processed + int _priority; //!< event priority + char _flags; + + protected: + enum Flags { + None = 0x0, + Squashed = 0x1, + Scheduled = 0x2, + AutoDelete = 0x4, + AutoSerialize = 0x8 + }; + + bool getFlags(Flags f) const { return (_flags & f) == f; } + void setFlags(Flags f) { _flags |= f; } + void clearFlags(Flags f) { _flags &= ~f; } + + protected: + EventQueue *theQueue() const { return queue; } + +#if TRACING_ON + Tick when_created; //!< Keep track of creation time For debugging + Tick when_scheduled; //!< Keep track of creation time For debugging + + virtual void trace(const char *action); //!< trace event activity +#else + void trace(const char *) {} +#endif + + unsigned annotated_value; + + public: + + /// Event priorities, to provide tie-breakers for events scheduled + /// at the same cycle. Most events are scheduled at the default + /// priority; these values are used to control events that need to + /// be ordered within a cycle. + enum Priority { + /// Breakpoints should happen before anything else, so we + /// don't miss any action when debugging. + Debug_Break_Pri = -100, + + /// For some reason "delayed" inter-cluster writebacks are + /// scheduled before regular writebacks (which have default + /// priority). Steve? + Delayed_Writeback_Pri = -1, + + /// Default is zero for historical reasons. + Default_Pri = 0, + + /// CPU switches schedule the new CPU's tick event for the + /// same cycle (after unscheduling the old CPU's tick event). + /// The switch needs to come before any tick events to make + /// sure we don't tick both CPUs in the same cycle. + CPU_Switch_Pri = 31, + + /// Serailization needs to occur before tick events also, so + /// that a serialize/unserialize is identical to an on-line + /// CPU switch. + Serialize_Pri = 32, + + /// CPU ticks must come after other associated CPU events + /// (such as writebacks). + CPU_Tick_Pri = 50, + + /// Statistics events (dump, reset, etc.) come after + /// everything else, but before exit. + Stat_Event_Pri = 90, + + /// If we want to exit on this cycle, it's the very last thing + /// we do. + Sim_Exit_Pri = 100 + }; + + /* + * Event constructor + * @param queue that the event gets scheduled on + */ + Event(EventQueue *q, Priority p = Default_Pri) + : queue(q), next(NULL), _priority(p), _flags(None), +#if TRACING_ON + when_created(curTick), when_scheduled(0), +#endif + annotated_value(0) + { + } + + ~Event() {} + + virtual const std::string name() const { + return csprintf("Event_%x", (uintptr_t)this); + } + + /// Determine if the current event is scheduled + bool scheduled() const { return getFlags(Scheduled); } + + /// Schedule the event with the current priority or default priority + void schedule(Tick t); + + /// Reschedule the event with the current priority + void reschedule(Tick t); + + /// Remove the event from the current schedule + void deschedule(); + + /// Return a C string describing the event. This string should + /// *not* be dynamically allocated; just a const char array + /// describing the event class. + virtual const char *description(); + + /// Dump the current event data + void dump(); + + /* + * This member function is invoked when the event is processed + * (occurs). There is no default implementation; each subclass + * must provide its own implementation. The event is not + * automatically deleted after it is processed (to allow for + * statically allocated event objects). + * + * If the AutoDestroy flag is set, the object is deleted once it + * is processed. + */ + virtual void process() = 0; + + void annotate(unsigned value) { annotated_value = value; }; + unsigned annotation() { return annotated_value; } + + /// Squash the current event + void squash() { setFlags(Squashed); } + + /// Check whether the event is squashed + bool squashed() { return getFlags(Squashed); } + + /// Get the time that the event is scheduled + Tick when() const { return _when; } + + /// Get the event priority + int priority() const { return _priority; } + + struct priority_compare : + public std::binary_function<Event *, Event *, bool> + { + bool operator()(const Event *l, const Event *r) const { + return l->when() >= r->when() || l->priority() >= r->priority(); + } + }; + + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); +}; + +template <class T, void (T::* F)()> +void +DelayFunction(Tick when, T *object) +{ + class DelayEvent : public Event + { + private: + T *object; + + public: + DelayEvent(Tick when, T *o) + : Event(&mainEventQueue), object(o) + { setFlags(this->AutoDestroy); schedule(when); } + void process() { (object->*F)(); } + const char *description() { return "delay"; } + }; + + new DelayEvent(when, object); +} + +template <class T, void (T::* F)()> +class EventWrapper : public Event +{ + private: + T *object; + + public: + EventWrapper(T *obj, bool del = false, EventQueue *q = &mainEventQueue, + Priority p = Default_Pri) + : Event(q, p), object(obj) + { + if (del) + setFlags(AutoDelete); + } + void process() { (object->*F)(); } +}; + +/* + * Queue of events sorted in time order + */ +class EventQueue : public Serializable +{ + protected: + std::string objName; + + private: + Event *head; + + void insert(Event *event); + void remove(Event *event); + + public: + + // constructor + EventQueue(const std::string &n) + : objName(n), head(NULL) + {} + + virtual const std::string name() const { return objName; } + + // schedule the given event on this queue + void schedule(Event *ev); + void deschedule(Event *ev); + void reschedule(Event *ev); + + Tick nextTick() { return head->when(); } + void serviceOne(); + + // process all events up to the given timestamp. we inline a + // quick test to see if there are any events to process; if so, + // call the internal out-of-line version to process them all. + void serviceEvents(Tick when) { + while (!empty()) { + if (nextTick() > when) + break; + + /** + * @todo this assert is a good bug catcher. I need to + * make it true again. + */ + //assert(head->when() >= when && "event scheduled in the past"); + serviceOne(); + } + } + + // default: process all events up to 'now' (curTick) + void serviceEvents() { serviceEvents(curTick); } + + // return true if no events are queued + bool empty() { return head == NULL; } + + void dump(); + + Tick nextEventTime() { return empty() ? curTick : head->when(); } + + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); +}; + + +////////////////////// +// +// inline functions +// +// can't put these inside declaration due to circular dependence +// between Event and EventQueue classes. +// +////////////////////// + +// schedule at specified time (place on event queue specified via +// constructor) +inline void +Event::schedule(Tick t) +{ + assert(!scheduled()); + assert(t >= curTick); + + setFlags(Scheduled); +#if TRACING_ON + when_scheduled = curTick; +#endif + _when = t; + queue->schedule(this); +} + +inline void +Event::deschedule() +{ + assert(scheduled()); + + clearFlags(Squashed); + clearFlags(Scheduled); + queue->deschedule(this); +} + +inline void +Event::reschedule(Tick t) +{ + assert(scheduled()); + clearFlags(Squashed); + +#if TRACING_ON + when_scheduled = curTick; +#endif + _when = t; + queue->reschedule(this); +} + +inline void +EventQueue::schedule(Event *event) +{ + insert(event); + if (DTRACE(Event)) + event->trace("scheduled"); +} + +inline void +EventQueue::deschedule(Event *event) +{ + remove(event); + if (DTRACE(Event)) + event->trace("descheduled"); +} + +inline void +EventQueue::reschedule(Event *event) +{ + remove(event); + insert(event); + if (DTRACE(Event)) + event->trace("rescheduled"); +} + + + +#endif // __SIM_EVENTQ_HH__ diff --git a/src/sim/faults.cc b/src/sim/faults.cc new file mode 100644 index 000000000..cb095f852 --- /dev/null +++ b/src/sim/faults.cc @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * 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. + */ + +#include "base/misc.hh" +#include "sim/faults.hh" +#include "cpu/exec_context.hh" +#include "cpu/base.hh" + +#if !FULL_SYSTEM +void FaultBase::invoke(ExecContext * xc) +{ + fatal("fault (%s) detected @ PC 0x%08p", name(), xc->readPC()); +} +#else +void FaultBase::invoke(ExecContext * xc) +{ + DPRINTF(Fault, "Fault %s at PC: %#x\n", name(), xc->readPC()); + xc->getCpuPtr()->recordEvent(csprintf("Fault %s", name())); + + assert(!xc->misspeculating()); +} +#endif + +void UnimpFault::invoke(ExecContext * xc) +{ + panic("Unimpfault: %s\n", panicStr.c_str()); +} diff --git a/src/sim/faults.hh b/src/sim/faults.hh new file mode 100644 index 000000000..9b3bc9103 --- /dev/null +++ b/src/sim/faults.hh @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * 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. + */ + +#ifndef __FAULTS_HH__ +#define __FAULTS_HH__ + +#include "base/refcnt.hh" +#include "sim/stats.hh" +#include "config/full_system.hh" + +class ExecContext; +class FaultBase; +typedef RefCountingPtr<FaultBase> Fault; + +typedef const char * FaultName; +typedef Stats::Scalar<> FaultStat; + +// Each class has it's name statically define in _name, +// and has a virtual function to access it's name. +// The function is necessary because otherwise, all objects +// which are being accessed cast as a FaultBase * (namely +// all faults returned using the Fault type) will use the +// generic FaultBase name. + +class FaultBase : public RefCounted +{ + public: + virtual FaultName name() = 0; +#if FULL_SYSTEM + virtual void invoke(ExecContext * xc); +#else + virtual void invoke(ExecContext * xc); +#endif +// template<typename T> +// bool isA() {return dynamic_cast<T *>(this);} + virtual bool isMachineCheckFault() {return false;} + virtual bool isAlignmentFault() {return false;} +}; + +FaultBase * const NoFault = 0; + +class UnimpFault : public FaultBase +{ + private: + std::string panicStr; + public: + UnimpFault(std::string _str) + : panicStr(_str) + { } + + FaultName name() {return "Unimplemented simulator feature";} + void invoke(ExecContext * xc); +}; + +#endif // __FAULTS_HH__ diff --git a/src/sim/host.hh b/src/sim/host.hh new file mode 100644 index 000000000..48c977331 --- /dev/null +++ b/src/sim/host.hh @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * 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. + */ + +/** + * @file + * Defines host-dependent types: + * Counter, Tick, and (indirectly) {int,uint}{8,16,32,64}_t. + */ + +#ifndef __HOST_HH__ +#define __HOST_HH__ + +#include <inttypes.h> + +/** uint64_t constant */ +#define ULL(N) ((uint64_t)N##ULL) +/** int64_t constant */ +#define LL(N) (((int64_t)N##LL) + +/** Statistics counter type. Not much excuse for not using a 64-bit + * integer here, but if you're desperate and only run short + * simulations you could make this 32 bits. + */ +typedef int64_t Counter; + +/** + * Clock cycle count type. + * @note using an unsigned breaks the cache. + */ +typedef int64_t Tick; + +/** + * Address type + * This will probably be moved somewhere else in the near future. + * This should be at least as big as the biggest address width in use + * in the system, which will probably be 64 bits. + */ +typedef uint64_t Addr; + +const Addr MaxAddr = (Addr)-1; + +#endif // __HOST_H__ diff --git a/src/sim/main.cc b/src/sim/main.cc new file mode 100644 index 000000000..aecc171ed --- /dev/null +++ b/src/sim/main.cc @@ -0,0 +1,433 @@ +/* + * Copyright (c) 2000-2005 The Regents of The University of Michigan + * 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. + */ + +/// +/// @file sim/main.cc +/// +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> +#include <libgen.h> +#include <stdlib.h> +#include <signal.h> + +#include <list> +#include <string> +#include <vector> + +#include "base/copyright.hh" +#include "base/embedfile.hh" +#include "base/inifile.hh" +#include "base/misc.hh" +#include "base/output.hh" +#include "base/pollevent.hh" +#include "base/statistics.hh" +#include "base/str.hh" +#include "base/time.hh" +#include "cpu/base.hh" +#include "cpu/smt.hh" +#include "python/pyconfig.hh" +#include "sim/async.hh" +#include "sim/builder.hh" +#include "sim/configfile.hh" +#include "sim/host.hh" +#include "sim/sim_events.hh" +#include "sim/sim_exit.hh" +#include "sim/sim_object.hh" +#include "sim/stat_control.hh" +#include "sim/stats.hh" +#include "sim/root.hh" + +using namespace std; + +// See async.h. +volatile bool async_event = false; +volatile bool async_dump = false; +volatile bool async_dumpreset = false; +volatile bool async_exit = false; +volatile bool async_io = false; +volatile bool async_alarm = false; + +/// Stats signal handler. +void +dumpStatsHandler(int sigtype) +{ + async_event = true; + async_dump = true; +} + +void +dumprstStatsHandler(int sigtype) +{ + async_event = true; + async_dumpreset = true; +} + +/// Exit signal handler. +void +exitNowHandler(int sigtype) +{ + async_event = true; + async_exit = true; +} + +/// Abort signal handler. +void +abortHandler(int sigtype) +{ + cerr << "Program aborted at cycle " << curTick << endl; + +#if TRACING_ON + // dump trace buffer, if there is one + Trace::theLog.dump(cerr); +#endif +} + +/// Simulator executable name +char *myProgName = ""; + +/// Show brief help message. +void +showBriefHelp(ostream &out) +{ + char *prog = basename(myProgName); + + ccprintf(out, "Usage:\n"); + ccprintf(out, +"%s [-d <dir>] [-E <var>[=<val>]] [-I <dir>] [-P <python>]\n" +" [--<var>=<val>] <config file>\n" +"\n" +" -d set the output directory to <dir>\n" +" -E set the environment variable <var> to <val> (or 'True')\n" +" -I add the directory <dir> to python's path\n" +" -P execute <python> directly in the configuration\n" +" --var=val set the python variable <var> to '<val>'\n" +" <configfile> config file name (ends in .py)\n\n", + prog); + + ccprintf(out, "%s -X\n -X extract embedded files\n\n", prog); + ccprintf(out, "%s -h\n -h print short help\n\n", prog); +} + +/// Print welcome message. +void +sayHello(ostream &out) +{ + extern const char *compileDate; // from date.cc + + ccprintf(out, "M5 Simulator System\n"); + // display copyright + ccprintf(out, "%s\n", briefCopyright); + ccprintf(out, "M5 compiled on %d\n", compileDate); + + char *host = getenv("HOSTNAME"); + if (!host) + host = getenv("HOST"); + + if (host) + ccprintf(out, "M5 executing on %s\n", host); + + ccprintf(out, "M5 simulation started %s\n", Time::start); +} + +/// +/// Echo the command line for posterity in such a way that it can be +/// used to rerun the same simulation (given the same .ini files). +/// +void +echoCommandLine(int argc, char **argv, ostream &out) +{ + out << "command line: " << argv[0]; + for (int i = 1; i < argc; i++) { + string arg(argv[i]); + + out << ' '; + + // If the arg contains spaces, we need to quote it. + // The rest of this is overkill to make it look purty. + + // print dashes first outside quotes + int non_dash_pos = arg.find_first_not_of("-"); + out << arg.substr(0, non_dash_pos); // print dashes + string body = arg.substr(non_dash_pos); // the rest + + // if it's an assignment, handle the lhs & rhs separately + int eq_pos = body.find("="); + if (eq_pos == string::npos) { + out << quote(body); + } + else { + string lhs(body.substr(0, eq_pos)); + string rhs(body.substr(eq_pos + 1)); + + out << quote(lhs) << "=" << quote(rhs); + } + } + out << endl << endl; +} + +char * +getOptionString(int &index, int argc, char **argv) +{ + char *option = argv[index] + 2; + if (*option != '\0') + return option; + + // We didn't find an argument, it must be in the next variable. + if (++index >= argc) + panic("option string for option '%s' not found", argv[index - 1]); + + return argv[index]; +} + +int +main(int argc, char **argv) +{ + // Save off program name + myProgName = argv[0]; + + signal(SIGFPE, SIG_IGN); // may occur on misspeculated paths + signal(SIGTRAP, SIG_IGN); + signal(SIGUSR1, dumpStatsHandler); // dump intermediate stats + signal(SIGUSR2, dumprstStatsHandler); // dump and reset stats + signal(SIGINT, exitNowHandler); // dump final stats and exit + signal(SIGABRT, abortHandler); + + bool configfile_found = false; + PythonConfig pyconfig; + string outdir; + + if (argc < 2) { + showBriefHelp(cerr); + exit(1); + } + + sayHello(cerr); + + // Parse command-line options. + // Since most of the complex options are handled through the + // config database, we don't mess with getopts, and just parse + // manually. + for (int i = 1; i < argc; ++i) { + char *arg_str = argv[i]; + + // if arg starts with '--', parse as a special python option + // of the format --<python var>=<string value>, if the arg + // starts with '-', it should be a simulator option with a + // format similar to getopt. In any other case, treat the + // option as a configuration file name and load it. + if (arg_str[0] == '-' && arg_str[1] == '-') { + string str = &arg_str[2]; + string var, val; + + if (!split_first(str, var, val, '=')) + panic("Could not parse configuration argument '%s'\n" + "Expecting --<variable>=<value>\n", arg_str); + + pyconfig.setVariable(var, val); + } else if (arg_str[0] == '-') { + char *option; + string var, val; + + // switch on second char + switch (arg_str[1]) { + case 'd': + outdir = getOptionString(i, argc, argv); + break; + + case 'h': + showBriefHelp(cerr); + exit(1); + + case 'E': + option = getOptionString(i, argc, argv); + if (!split_first(option, var, val, '=')) + val = "True"; + + if (setenv(var.c_str(), val.c_str(), true) == -1) + panic("setenv: %s\n", strerror(errno)); + break; + + case 'I': + option = getOptionString(i, argc, argv); + pyconfig.addPath(option); + break; + + case 'P': + option = getOptionString(i, argc, argv); + pyconfig.writeLine(option); + break; + + case 'X': { + list<EmbedFile> lst; + EmbedMap::all(lst); + list<EmbedFile>::iterator i = lst.begin(); + list<EmbedFile>::iterator end = lst.end(); + + while (i != end) { + cprintf("Embedded File: %s\n", i->name); + cout.write(i->data, i->length); + ++i; + } + + return 0; + } + + default: + showBriefHelp(cerr); + panic("invalid argument '%s'\n", arg_str); + } + } else { + string file(arg_str); + string base, ext; + + if (!split_last(file, base, ext, '.') || ext != "py") + panic("Config file '%s' must end in '.py'\n", file); + + pyconfig.load(file); + configfile_found = true; + } + } + + if (outdir.empty()) { + char *env = getenv("OUTPUT_DIR"); + outdir = env ? env : "."; + } + + simout.setDirectory(outdir); + + char *env = getenv("CONFIG_OUTPUT"); + if (!env) + env = "config.out"; + configStream = simout.find(env); + + if (!configfile_found) + panic("no configuration file specified!"); + + // The configuration database is now complete; start processing it. + IniFile inifile; + if (!pyconfig.output(inifile)) + panic("Error processing python code"); + + // Initialize statistics database + Stats::InitSimStats(); + + // Now process the configuration hierarchy and create the SimObjects. + ConfigHierarchy configHierarchy(inifile); + configHierarchy.build(); + configHierarchy.createSimObjects(); + + // Parse and check all non-config-hierarchy parameters. + ParamContext::parseAllContexts(inifile); + ParamContext::checkAllContexts(); + + // Print hello message to stats file if it's actually a file. If + // it's not (i.e. it's cout or cerr) then we already did it above. + if (simout.isFile(*outputStream)) + sayHello(*outputStream); + + // Echo command line and all parameter settings to stats file as well. + echoCommandLine(argc, argv, *outputStream); + ParamContext::showAllContexts(*configStream); + + // Any objects that can't connect themselves until after construction should + // do so now + SimObject::connectAll(); + + // Do a second pass to finish initializing the sim objects + SimObject::initAll(); + + // Restore checkpointed state, if any. + configHierarchy.unserializeSimObjects(); + + // Done processing the configuration database. + // Check for unreferenced entries. + if (inifile.printUnreferenced()) + panic("unreferenced sections/entries in the intermediate ini file"); + + SimObject::regAllStats(); + + // uncomment the following to get PC-based execution-time profile +#ifdef DO_PROFILE + init_profile((char *)&_init, (char *)&_fini); +#endif + + // Check to make sure that the stats package is properly initialized + Stats::check(); + + // Reset to put the stats in a consistent state. + Stats::reset(); + + warn("Entering event queue. Starting simulation...\n"); + SimStartup(); + while (!mainEventQueue.empty()) { + assert(curTick <= mainEventQueue.nextTick() && + "event scheduled in the past"); + + // forward current cycle to the time of the first event on the + // queue + curTick = mainEventQueue.nextTick(); + mainEventQueue.serviceOne(); + + if (async_event) { + async_event = false; + if (async_dump) { + async_dump = false; + + using namespace Stats; + SetupEvent(Dump, curTick); + } + + if (async_dumpreset) { + async_dumpreset = false; + + using namespace Stats; + SetupEvent(Dump | Reset, curTick); + } + + if (async_exit) { + async_exit = false; + new SimExitEvent("User requested STOP"); + } + + if (async_io || async_alarm) { + async_io = false; + async_alarm = false; + pollQueue.service(); + } + } + } + + // This should never happen... every conceivable way for the + // simulation to terminate (hit max cycles/insts, signal, + // simulated system halts/exits) generates an exit event, so we + // should never run out of events on the queue. + exitNow("no events on event loop! All CPUs must be idle.", 1); + + return 0; +} diff --git a/src/sim/param.cc b/src/sim/param.cc new file mode 100644 index 000000000..8998d7d77 --- /dev/null +++ b/src/sim/param.cc @@ -0,0 +1,793 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * 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. + */ + +#include <algorithm> +#include <cassert> +#include <list> +#include <string> +#include <vector> + +#include "base/inifile.hh" +#include "base/misc.hh" +#include "base/range.hh" +#include "base/str.hh" +#include "base/trace.hh" +#include "sim/config_node.hh" +#include "sim/configfile.hh" +#include "sim/param.hh" +#include "sim/sim_object.hh" + +using namespace std; + + +//////////////////////////////////////////////////////////////////////// +// +// BaseParam member definitions +// +//////////////////////////////////////////////////////////////////////// + +void +BaseParam::die(const string &err) const +{ + context->printErrorProlog(cerr); + cerr << " parameter '" << name << "': " + << err << endl; + abort(); +} + + +//////////////////////////////////////////////////////////////////////// +// +// Param<T> and VectorParam<T> member definitions +// +// We implement parsing & displaying values for various parameter +// types T using a set of overloaded functions: +// +// - parseParam(string s, T &value) parses s into value +// - showParam(ostream &os, T &value) displays value on os +// +// By making these independent functions, we can reuse the same code +// for type T in both Param<T> and VectorParam<T>. +// +// For enum types, the parseParam function requires additional +// arguments, in which case we must specialize the Param<T>::parse and +// VectorParam<T>::parse calls as well. +// +// Type-specific instances come first, followed by more generic +// templated versions and their instantiations. +// +//////////////////////////////////////////////////////////////////////// + +// +// The base implementations use to_number for parsing and '<<' for +// displaying, suitable for integer types. +// +template <class T> +bool +parseParam(const string &s, T &value) +{ + return to_number(s, value); +} + +template <class T> +void +showParam(ostream &os, T const &value) +{ + os << value; +} + +// +// Template specializations: +// - char (8-bit integer) +// - floating-point types +// - bool +// - string +// + +// Treat 8-bit ints (chars) as ints on output, not as chars +template <> +void +showParam(ostream &os, const char &value) +{ + os << (int)value; +} + + +template <> +void +showParam(ostream &os, const unsigned char &value) +{ + os << (unsigned int)value; +} + + +// Use sscanf() for FP types as to_number() only handles integers +template <> +bool +parseParam(const string &s, float &value) +{ + return (sscanf(s.c_str(), "%f", &value) == 1); +} + +template <> +bool +parseParam(const string &s, double &value) +{ + return (sscanf(s.c_str(), "%lf", &value) == 1); +} + +// Be flexible about what we take for bool +template <> +bool +parseParam(const string &s, bool &value) +{ + const string &ls = to_lower(s); + + if (ls == "true" || ls == "t" || ls == "yes" || ls == "y" || ls == "1") { + value = true; + return true; + } + + if (ls == "false" || ls == "f" || ls == "no" || ls == "n" || ls == "0") { + value = false; + return true; + } + + return false; +} + +// Display bools as strings +template <> +void +showParam(ostream &os, const bool &value) +{ + os << (value ? "true" : "false"); +} + + +// String requires no processing to speak of +template <> +bool +parseParam(const string &s, string &value) +{ + value = s; + return true; +} + +template <> +bool +parseParam(const string &s, Range<uint32_t> &value) +{ + value = s; + return value.valid(); +} + +template <> +bool +parseParam(const string &s, Range<uint64_t> &value) +{ + value = s; + return value.valid(); +} + +// +// End of parseParam/showParam definitions. Now we move on to +// incorporate them into the Param/VectorParam parse() and showValue() +// methods. +// + +// These definitions for Param<T>::parse and VectorParam<T>::parse +// work for any type for which parseParam() takes only two arguments +// (i.e., all the fundamental types like int, bool, etc.), thanks to +// overloading. +template <class T> +void +Param<T>::parse(const string &s) +{ + if (parseParam(s, value)) { + wasSet = true; + } + else { + string err("could not parse \""); + + err += s; + err += "\""; + + die(err); + } +} + +template <class T> +void +VectorParam<T>::parse(const string &s) +{ + if (s.empty()) { + wasSet = true; + return; + } + + vector<string> tokens; + + tokenize(tokens, s, ' '); + + value.resize(tokens.size()); + + for (int i = 0; i < tokens.size(); i++) { + // need to parse into local variable to handle vector<bool>, + // for which operator[] returns a special reference class + // that's not the same as 'bool&', (since it's a packed + // vector) + T scalar_value; + if (!parseParam(tokens[i], scalar_value)) { + string err("could not parse \""); + + err += s; + err += "\""; + + die(err); + } + + // assign parsed value to vector + value[i] = scalar_value; + } + + wasSet = true; +} + +// These definitions for Param<T>::showValue() and +// VectorParam<T>::showValue() work for any type where showParam() +// takes only two arguments (i.e., everything but the SimpleEnum and +// MappedEnum classes). +template <class T> +void +Param<T>::showValue(ostream &os) const +{ + showParam(os, value); +} + +template <class T> +void +VectorParam<T>::showValue(ostream &os) const +{ + for (int i = 0; i < value.size(); i++) { + if (i != 0) { + os << " "; + } + showParam(os, value[i]); + } +} + + +#ifdef INSURE_BUILD +#define INSTANTIATE_PARAM_TEMPLATES(type, typestr) \ +void Param<type>::showType(ostream &os) const { os << typestr; } \ +void VectorParam<type>::showType(ostream &os) const { \ + os << "vector of " << typestr; \ +} \ +template Param<type>; \ +template VectorParam<type>; + +#else +// instantiate all four methods (parse/show, scalar/vector) for basic +// types that can use the above templates +#define INSTANTIATE_PARAM_TEMPLATES(type, typestr) \ +template bool parseParam<type>(const string &s, type &value); \ +template void showParam<type>(ostream &os, type const &value); \ +template void Param<type>::parse(const string &); \ +template void VectorParam<type>::parse(const string &); \ +template void Param<type>::showValue(ostream &) const; \ +template void VectorParam<type>::showValue(ostream &) const; \ +template <> void Param<type>::showType(ostream &os) const { os << typestr; } \ +template <> void VectorParam<type>::showType(ostream &os) const { \ + os << "vector of " << typestr; \ +} +#endif + +INSTANTIATE_PARAM_TEMPLATES(unsigned long long, "ull") +INSTANTIATE_PARAM_TEMPLATES(signed long long, "sll") +INSTANTIATE_PARAM_TEMPLATES(unsigned long, "uns long") +INSTANTIATE_PARAM_TEMPLATES(signed long, "long") +INSTANTIATE_PARAM_TEMPLATES(unsigned int, "uns") +INSTANTIATE_PARAM_TEMPLATES(signed int, "int") +INSTANTIATE_PARAM_TEMPLATES(unsigned short, "uns short") +INSTANTIATE_PARAM_TEMPLATES(signed short, "short") +INSTANTIATE_PARAM_TEMPLATES(unsigned char, "uns char") +INSTANTIATE_PARAM_TEMPLATES(signed char, "char") + +INSTANTIATE_PARAM_TEMPLATES(float, "float") +INSTANTIATE_PARAM_TEMPLATES(double, "double") + +INSTANTIATE_PARAM_TEMPLATES(bool, "bool") +INSTANTIATE_PARAM_TEMPLATES(string, "string") + +INSTANTIATE_PARAM_TEMPLATES(Range<uint64_t>, "uint64 range") +INSTANTIATE_PARAM_TEMPLATES(Range<uint32_t>, "uint32 range") + +#undef INSTANTIATE_PARAM_TEMPLATES + +// +// SimpleEnumParam & MappedEnumParam must specialize their parse(), +// showValue(), and showType() methods. +// + +// +// SimpleEnumParam & SimpleEnumVectorParam +// +bool +parseEnumParam(const char *const *map, const int num_values, + const string &s, int &value) +{ + for (int i = 0; i < num_values; ++i) { + if (s == map[i]) { + value = i; + return true; + } + } + + return false; +} + +void +showEnumParam(ostream &os, + const char *const *map, const int num_values, + int value) +{ + assert(0 <= value && value < num_values); + os << map[value]; +} + +void +showEnumType(ostream &os, + const char *const *map, const int num_values) +{ + os << "{" << map[0]; + for (int i = 1; i < num_values; ++i) + os << "," << map[i]; + + os << "}"; +} + + +// +// MappedEnumParam & MappedEnumVectorParam +// +bool +parseEnumParam(const EnumParamMap *map, const int num_values, + const string &s, int &value) +{ + for (int i = 0; i < num_values; ++i) { + if (s == map[i].name) { + value = map[i].value; + return true; + } + } + + return false; +} + +void +showEnumParam(ostream &os, + const EnumParamMap *map, const int num_values, + int value) +{ + for (int i = 0; i < num_values; ++i) { + if (value == map[i].value) { + os << map[i].name; + return; + } + } + + // if we can't find a reverse mapping just print the int value + os << value; +} + +void +showEnumType(ostream &os, + const EnumParamMap *map, const int num_values) +{ + os << "{" << map[0].name; + for (int i = 1; i < num_values; ++i) + os << "," << map[i].name; + + os << "}"; +} + + +template <class Map> +void +EnumParam<Map>::parse(const string &s) +{ + if (parseEnumParam(map, num_values, s, value)) { + wasSet = true; + } else { + string err("no match for enum string \""); + + err += s; + err += "\""; + + die(err); + } +} + +template <class Map> +void +EnumVectorParam<Map>::parse(const string &s) +{ + vector<string> tokens; + + if (s.empty()) { + wasSet = true; + return; + } + + tokenize(tokens, s, ' '); + + value.resize(tokens.size()); + + for (int i = 0; i < tokens.size(); i++) { + if (!parseEnumParam(map, num_values, tokens[i], value[i])) { + string err("no match for enum string \""); + + err += s; + err += "\""; + + die(err); + } + } + + wasSet = true; +} + +template <class Map> +void +EnumParam<Map>::showValue(ostream &os) const +{ + showEnumParam(os, map, num_values, value); +} + +template <class Map> +void +EnumVectorParam<Map>::showValue(ostream &os) const +{ + for (int i = 0; i < value.size(); i++) { + if (i != 0) { + os << " "; + } + showEnumParam(os, map, num_values, value[i]); + } +} + +template <class Map> +void +EnumParam<Map>::showType(ostream &os) const +{ + showEnumType(os, map, num_values); +} + +template <class Map> +void +EnumVectorParam<Map>::showType(ostream &os) const +{ + os << "vector of"; + showEnumType(os, map, num_values); +} + +template class EnumParam<const char *>; +template class EnumVectorParam<const char *>; + +template class EnumParam<EnumParamMap>; +template class EnumVectorParam<EnumParamMap>; + +//////////////////////////////////////////////////////////////////////// +// +// SimObjectBaseParam methods +// +//////////////////////////////////////////////////////////////////////// + +bool +parseSimObjectParam(ParamContext *context, const string &s, SimObject *&value) +{ + SimObject *obj; + + if (to_lower(s) == "null") { + // explicitly set to null by user; assume that's OK + obj = NULL; + } + else { + obj = context->resolveSimObject(s); + + if (obj == NULL) + return false; + } + + value = obj; + return true; +} + + +void +SimObjectBaseParam::showValue(ostream &os, SimObject *value) const +{ + os << (value ? value->name() : "null"); +} + +void +SimObjectBaseParam::parse(const string &s, SimObject *&value) +{ + if (parseSimObjectParam(context, s, value)) { + wasSet = true; + } + else { + string err("could not resolve object name \""); + + err += s; + err += "\""; + + die(err); + } +} + +void +SimObjectBaseParam::parse(const string &s, vector<SimObject *>&value) +{ + vector<string> tokens; + + tokenize(tokens, s, ' '); + + value.resize(tokens.size()); + + for (int i = 0; i < tokens.size(); i++) { + if (!parseSimObjectParam(context, tokens[i], value[i])) { + string err("could not resolve object name \""); + + err += s; + err += "\""; + + die(err); + } + } + + wasSet = true; +} + +//////////////////////////////////////////////////////////////////////// +// +// ParamContext member definitions +// +//////////////////////////////////////////////////////////////////////// + +list<ParamContext *> *ParamContext::ctxList = NULL; + +ParamContext::ParamContext(const string &_iniSection, InitPhase _initPhase) + : iniFilePtr(NULL), // initialized on call to parseParams() + iniSection(_iniSection), paramList(NULL), + initPhase(_initPhase) +{ + // Put this context on global list for initialization + if (initPhase != NoAutoInit) { + if (ctxList == NULL) + ctxList = new list<ParamContext *>(); + + // keep list sorted by ascending initPhase values + list<ParamContext *>::iterator i = ctxList->begin(); + list<ParamContext *>::iterator end = ctxList->end(); + for (; i != end; ++i) { + if (initPhase <= (*i)->initPhase) { + // found where we want to insert + break; + } + } + // (fall through case: insert at end) + ctxList->insert(i, this); + } +} + + +void +ParamContext::addParam(BaseParam *param) +{ + getParamList()->push_back(param); +} + + +void +ParamContext::parseParams(IniFile &iniFile) +{ + iniFilePtr = &iniFile; // set object member + + ParamList::iterator i; + + for (i = getParamList()->begin(); i != getParamList()->end(); ++i) { + string string_value; + + if (iniFile.find(iniSection, (*i)->name, string_value)) + (*i)->parse(string_value); + } +} + + +// Check parameter values for validity & consistency. Default +// implementation is no-op; derive subclass & override to add +// actual functionality here. +void +ParamContext::checkParams() +{ + // nada +} + + +// Clean up context-related objects at end of execution. Default +// implementation is no-op; derive subclass & override to add actual +// functionality here. +void +ParamContext::cleanup() +{ + // nada +} + + +void +ParamContext::describeParams(ostream &os) +{ + ParamList::iterator i; + + for (i = getParamList()->begin(); i != getParamList()->end(); ++i) { + BaseParam *p = *i; + + os << p->name << " ("; + p->showType(os); + os << "): " << p->description << "\n"; + } +} + + + +void +ParamContext::showParams(ostream &os) +{ + ParamList::iterator i; + + for (i = getParamList()->begin(); i != getParamList()->end(); ++i) { + BaseParam *p = *i; + + if (p->isValid()) { + os << p->name << "="; + p->showValue(os); + os << endl; + } + else { + os << "// "<< p->name << " not specified" << endl; + } + } +} + + +void +ParamContext::printErrorProlog(ostream &os) +{ + os << "Parameter error in section [" << iniSection << "]: " << endl; +} + +// +// Resolve an object name to a SimObject pointer. The object will be +// created as a side-effect if necessary. If the name contains a +// colon (e.g., "iq:IQ"), then the object is local (invisible to +// outside this context). If there is no colon, the name needs to be +// resolved through the configuration hierarchy (only possible for +// SimObjectBuilder objects, which return non-NULL for configNode()). +// +SimObject * +ParamContext::resolveSimObject(const string &name) +{ + ConfigNode *n = getConfigNode(); + return n ? n->resolveSimObject(name) : NULL; +} + + +// +// static method: call parseParams() on all registered contexts +// +void +ParamContext::parseAllContexts(IniFile &iniFile) +{ + list<ParamContext *>::iterator iter; + + for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) { + ParamContext *pc = *iter; + + pc->parseParams(iniFile); + } +} + + +// +// static method: call checkParams() on all registered contexts +// +void +ParamContext::checkAllContexts() +{ + list<ParamContext *>::iterator iter; + + for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) { + ParamContext *pc = *iter; + + pc->checkParams(); + } +} + + +// +// static method: call showParams() on all registered contexts +// +void +ParamContext::showAllContexts(ostream &os) +{ + list<ParamContext *>::iterator iter; + + for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) { + ParamContext *pc = *iter; + + os << "[" << pc->iniSection << "]" << endl; + pc->showParams(os); + os << endl; + } +} + + +// +// static method: call cleanup() on all registered contexts +// +void +ParamContext::cleanupAllContexts() +{ + list<ParamContext *>::iterator iter; + + for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) { + ParamContext *pc = *iter; + + pc->cleanup(); + } +} + + +// +// static method: call describeParams() on all registered contexts +// +void +ParamContext::describeAllContexts(ostream &os) +{ + list<ParamContext *>::iterator iter; + + for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) { + ParamContext *pc = *iter; + + os << "[" << pc->iniSection << "]\n"; + pc->describeParams(os); + os << endl; + } +} diff --git a/src/sim/param.hh b/src/sim/param.hh new file mode 100644 index 000000000..4a1b8bda1 --- /dev/null +++ b/src/sim/param.hh @@ -0,0 +1,788 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * 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. + */ + +#ifndef __SIM_PARAM_HH__ +#define __SIM_PARAM_HH__ + +#include <iostream> +#include <list> +#include <string> +#include <vector> + +#include "sim/configfile.hh" +#include "sim/startup.hh" + +// forward decls +class BaseParam; +class SimObject; + +// +// The context of a parameter definition... usually a subclass of +// SimObjectBuilder (which derives from ParamContext), but abstracted +// here to support more global simulator control parameters as well. +// +class ParamContext : protected StartupCallback +{ + private: + + // static list of all ParamContext objects, built as a side effect + // of the ParamContext constructor + static std::list<ParamContext *> *ctxList; + + protected: + + // .ini file (database) for parameter lookup... initialized on call + // to parseParams() + IniFile *iniFilePtr; + + // .ini file section for parameter lookup + const std::string iniSection; + + typedef std::vector<BaseParam *> ParamList; + + // list of parameters defined in this context + ParamList *paramList; + + ParamList *getParamList() { + if (!paramList) + paramList = new ParamList; + return paramList; + } + + public: + + /// Initialization phases for ParamContext objects. + enum InitPhase { + NoAutoInit = -1, ///< Don't initialize at all... params + /// will be parsed later (used by + /// SimObjectBuilder, which parses + /// params in SimObject::create(). + OutputInitPhase = 0, ///< Output stream initialization + TraceInitPhase = 1, ///< Trace context initialization: + /// depends on output streams, but + /// needs to come before others so we + /// can use tracing in other + /// ParamContext init code + StatsInitPhase = 2, ///< Stats output initialization + DefaultInitPhase = 3 ///< Everything else + }; + + /// Records the initialization phase for this ParamContext. + InitPhase initPhase; + + /// Constructor. + /// @param _iniSection Name of .ini section corresponding to this context. + /// @param _initPhase Initialization phase (see InitPhase). + ParamContext(const std::string &_iniSection, + InitPhase _initPhase = DefaultInitPhase); + + virtual ~ParamContext() {} + + // add a parameter to the context... called from the parameter + // object's constructor (see BaseParam::BaseParam()) + void addParam(BaseParam *); + + // call parse() on all params in this context to convert string + // representations to parameter values + virtual void parseParams(IniFile &iniFile); + + // Check parameter values for validity & consistency. Default + // implementation is no-op; derive subclass & override to add + // actual functionality here + virtual void checkParams(); + + // Clean up at end of execution: close file descriptors, etc. + // Default implementation is no-op; derive subclass & override to + // add actual functionality here + virtual void cleanup(); + + // dump parameter descriptions + void describeParams(std::ostream &); + + // Display the parameters & values used + void showParams(std::ostream &); + + // print context information for parameter error + virtual void printErrorProlog(std::ostream &); + + // resolve a SimObject name in this context to an object pointer. + virtual SimObject *resolveSimObject(const std::string &name); + + // generate the name for this instance of this context (used as a + // prefix to create unique names in resolveSimObject() + virtual const std::string &getInstanceName() { return iniSection; } + + // return the configuration hierarchy node for this context. Bare + // ParamContext objects have no corresponding node, so the default + // implementation returns NULL. + virtual ConfigNode *getConfigNode() { return NULL; } + + // Parse all parameters registered with all ParamContext objects. + static void parseAllContexts(IniFile &iniFile); + + // Check all parameters registered with all ParamContext objects. + // (calls checkParams() on each) + static void checkAllContexts(); + + // Print all parameter values on indicated ostream. + static void showAllContexts(std::ostream &os); + + // Clean up all registered ParamContext objects. (calls cleanup() + // on each) + static void cleanupAllContexts(); + + // print descriptions of all parameters registered with all + // ParamContext objects + static void describeAllContexts(std::ostream &os); +}; + + +// +// Base class for all parameter objects +// +class BaseParam +{ + public: + + ParamContext *context; + std::string name; + std::string description; // text description for help message + bool wasSet; // true if parameter was set by user + bool hasDefault; // true if parameter has default value + + BaseParam(ParamContext *_context, const std::string &_name, + const std::string &_description, bool _hasDefault) + : context(_context), name(_name), description(_description), + wasSet(false), hasDefault(_hasDefault) + { + context->addParam(this); + } + + virtual ~BaseParam() {} + + // a parameter is valid only if its value was set by the user or + // it has a default value + bool isValid() const + { + return (wasSet || hasDefault); + } + + // set value by parsing string + virtual void parse(const std::string &s) = 0; + + // display value to stream + virtual void showValue(std::ostream &) const = 0; + + // display type to stream + virtual void showType(std::ostream &) const = 0; + + // signal parse or usage error + virtual void die(const std::string &err) const; +}; + +// +// Template classes to specialize parameters to specific types. +// +// Param<T> is for single-valued (scalar) parameters of type T. +// VectorParam<T> is for multi-valued (vector) parameters of type T. +// These are specified in the .ini file as a space-delimited list of +// arguments. +// +template <class T> +class Param : public BaseParam +{ + protected: + + T value; + + public: + + // Param with default value: set value to default + Param(ParamContext *context, + const std::string &name, const std::string &description, T dfltValue) + : BaseParam(context, name, description, true), + value(dfltValue) + { + } + + // Param with no default value: leave value uninitialized + Param(ParamContext *context, + const std::string &name, const std::string &description) + : BaseParam(context, name, description, false) + { + } + + virtual ~Param() {} + + operator T&() + { + // if we attempt to reference an invalid parameter (i.e., one + // with no default value that was not set by the user), die. + if (!isValid()) + die("not found"); + return value; + } + + // display value to stream + virtual void showValue(std::ostream &os) const; + + // display type to stream + virtual void showType(std::ostream &) const; + + // set value by parsing string + virtual void parse(const std::string &s); +}; + + +// +// Template class for vector-valued parameters (lists) +// +template <class T> +class VectorParam : public BaseParam +{ + protected: + + std::vector<T> value; + + public: + + typedef typename std::vector<T>::size_type size_type; + + // Param with default value: set value to default + VectorParam(ParamContext *context, const std::string &name, + const std::string &description, + const std::vector<T> &dfltValue) + : BaseParam(context, name, description, true), + value(dfltValue) + { + } + + // Param with no default value: leave value uninitialized + VectorParam(ParamContext *context, + const std::string &name, const std::string &description) + : BaseParam(context, name, description, false) + { + } + + virtual ~VectorParam() {} + + // basic vector access methods + size_type size() const + { + if (!isValid()) + die("not found"); + return value.size(); + } + + const T &operator[](size_type n) const + { + if (!isValid()) + die("not found"); + return value[n]; + } + + // return reference to value vector + operator std::vector<T>&() + { + if (!isValid()) + die("not found"); + return value; + } + + // display value to stream + virtual void showValue(std::ostream &os) const; + + // display type to stream + virtual void showType(std::ostream &) const; + + // set value by parsing string + virtual void parse(const std::string &s); +}; + +// +// Specialization of Param<int> and VectorParam<int> to handle +// enumerated types is done in two ways, using SimpleEnumParam and +// MappedEnumParam (and their vector counterparts, +// SimpleEnumVectorParam and MappedEnumVectorParam). SimpleEnumParam +// takes an array of strings and maps them to integers based on array +// index. MappedEnumParam takes an array of string-to-int mappings, +// allowing for mapping strings to non-contiguous integer values, or +// mapping multiple strings to the same integer value. +// +// Both SimpleEnumParam and MappedEnumParam are implemented using a +// single template class, EnumParam<Map>, which takes the type of the map +// as a parameter (const char * or EnumParamMap). Similarly, +// SimpleEnumVectorParam and MappedEnumVectorParam are both +// implemented using EnumVectorParam<Map>. +// +template <class Map> +class EnumParam : public Param<int> +{ + const int num_values; + const Map *map; + + public: + + // Param with default value: set value to default + EnumParam(ParamContext *context, + const std::string &name, const std::string &description, + const Map *_map, int _num_values, + int dfltValue) + : Param<int>(context, name, description, dfltValue), + num_values(_num_values), map(_map) + { + } + + // Param with no default value: leave value uninitialized + EnumParam(ParamContext *context, + const std::string &name, const std::string &description, + const Map *_map, int _num_values) + : Param<int>(context, name, description), + num_values(_num_values), map(_map) + { + } + + virtual ~EnumParam() {} + + // display value to stream + virtual void showValue(std::ostream &os) const; + + // display type to stream + virtual void showType(std::ostream &) const; + + // set value by parsing string + virtual void parse(const std::string &s); +}; + +// +// Vector counterpart to SimpleEnumParam +// +template <class Map> +class EnumVectorParam : public VectorParam<int> +{ + const int num_values; + const Map *map; + + public: + + // Param with default value: set value to default + EnumVectorParam(ParamContext *context, + const std::string &name, const std::string &description, + const Map *_map, int _num_values, + std::vector<int> &dfltValue) + : VectorParam<int>(context, name, description, dfltValue), + num_values(_num_values), map(_map) + { + } + + // Param with no default value: leave value uninitialized + EnumVectorParam(ParamContext *context, + const std::string &name, const std::string &description, + const Map *_map, int _num_values) + : VectorParam<int>(context, name, description), + num_values(_num_values), map(_map) + { + } + + virtual ~EnumVectorParam() {} + + // display value to stream + virtual void showValue(std::ostream &os) const; + + // display type to stream + virtual void showType(std::ostream &) const; + + // set value by parsing string + virtual void parse(const std::string &s); +}; + +// Specialize EnumParam for a particular enumeration type ENUM +// (automates casting to get value of enum type) + +template <class ENUM> +class SimpleEnumParam : public EnumParam<const char *> +{ + public: + + SimpleEnumParam(ParamContext *context, + const std::string &name, const std::string &description, + const char **_map, int _num_values, + ENUM dfltValue) + : EnumParam<const char *>(context, name, description, + _map, _num_values, (int)dfltValue) + { + } + + SimpleEnumParam(ParamContext *context, + const std::string &name, const std::string &description, + const char **_map, int _num_values) + : EnumParam<const char *>(context, name, description, + _map, _num_values) + { + } + + operator ENUM() const + { + if (!isValid()) + die("not found"); + return (ENUM)value; + } +}; + + +// Specialize EnumParam for a particular enumeration type ENUM +// (automates casting to get value of enum type) + +template <class ENUM> +class SimpleEnumVectorParam : public EnumVectorParam<const char *> +{ + public: + + // skip default value constructor: too much pain to convert + // vector<ENUM> initializer to vector<int> + + + SimpleEnumVectorParam(ParamContext *context, + const std::string &name, + const std::string &description, + const char **_map, int _num_values) + : EnumVectorParam<const char *>(context, name, description, + _map, _num_values) + { + } + + ENUM operator[](size_type n) + { + if (!isValid()) + die("not found"); + return (ENUM)value[n]; + } +}; + + +// +// Handle enums via string-to-int map (see comment above). +// + +// An array of string-to-int mappings must be supplied using the +// following type. +typedef struct { + const char *name; + int value; +} EnumParamMap; + +// Specialize EnumParam for a particular enumeration type ENUM +// (automates casting to get value of enum type) + +template <class ENUM> +class MappedEnumParam : public EnumParam<EnumParamMap> +{ + public: + + MappedEnumParam(ParamContext *context, + const std::string &name, const std::string &description, + const EnumParamMap *_map, int _num_values, + ENUM dfltValue) + : EnumParam<EnumParamMap>(context, name, description, + _map, _num_values, (int)dfltValue) + { + } + + MappedEnumParam(ParamContext *context, + const std::string &name, const std::string &description, + const EnumParamMap *_map, int _num_values) + : EnumParam<EnumParamMap>(context, name, description, + _map, _num_values) + { + } + + operator ENUM() + { + if (!isValid()) + die("not found"); + return (ENUM)value[this->n]; + } +}; + + +// Specialize EnumParam for a particular enumeration type ENUM +// (automates casting to get value of enum type) + +template <class ENUM> +class MappedEnumVectorParam : public EnumVectorParam<EnumParamMap> +{ + public: + + // skip default value constructor: too much pain to convert + // vector<ENUM> initializer to vector<int> + + + MappedEnumVectorParam(ParamContext *context, + const std::string &name, + const std::string &description, + const EnumParamMap *_map, int _num_values) + : EnumVectorParam<EnumParamMap>(context, name, description, + _map, _num_values) + { + } + + ENUM operator[](size_type n) + { + if (!isValid()) + die("not found"); + return (ENUM)value[n]; + } +}; + + +// +// Parameters that point to other simulation objects (e.g. caches, +// busses, etc.) are handled by specializing SimObjectBaseParam to the +// specific subtype. The main purpose of SimObjectBaseParam is to +// provide a place to stick several helper functions common to all +// SimObject-derived parameters. +// +class SimObjectBaseParam : public BaseParam +{ + public: + + SimObjectBaseParam(ParamContext *context, const std::string &name, + const std::string &description, bool hasDefault) + : BaseParam(context, name, description, hasDefault) + { + } + + virtual ~SimObjectBaseParam() {} + + // helper function for SimObjectParam<T>::showValue() + void showValue(std::ostream &os, SimObject *obj) const; + + // helper function for SimObjectParam<T>::parse() + void parse(const std::string &s, SimObject *&value); + + // helper function for SimObjectParam<T>::parse() + void parse(const std::string &s, std::vector<SimObject *>&value_vec); +}; + + +// +// Parameter to a specific type of SimObject. Note that T must be a +// pointer to a class derived from SimObject (e.g., <CPU *>). +// + +template <class T> class SimObjectParam; + +template <class T> +class SimObjectParam<T *> : public SimObjectBaseParam +{ + protected: + + T *value; + + public: + + // initialization w/o default + SimObjectParam(ParamContext *context, + const std::string &name, const std::string &description) + : SimObjectBaseParam(context, name, description, false) + { + } + + // initialization wit=h default + SimObjectParam(ParamContext *context, + const std::string &name, const std::string &description, + T *dfltValue) + : SimObjectBaseParam(context, name, description, true), + value(dfltValue) + { + } + + virtual ~SimObjectParam() {} + + // convert to pointer + operator T*() + { + if (!isValid()) + die("not found"); + return value; + } + + T *operator->() const + { + if (!isValid()) + die("not found"); + return value; + } + + // display value to stream + virtual void showValue(std::ostream &os) const + { + SimObjectBaseParam::showValue(os, value); + } + + // display type to stream: see REGISTER_SIM_OBJECT macro in + // sim_object.hh for declaration + virtual void showType(std::ostream &os) const; + + // set value by parsing string + virtual void parse(const std::string &s) + { + SimObject *so_ptr; + // first parse to generic SimObject * + SimObjectBaseParam::parse(s, so_ptr); + // now dynamic_cast to specific derived type + value = dynamic_cast<T *>(so_ptr); + // check for failure of dynamic_cast + if (value == NULL && so_ptr != NULL) + die("not of appropriate type"); + } +}; + + +// +// Vector counterpart to SimObjectParam<T> +// + +template <class T> class SimObjectVectorParam; + +template <class T> +class SimObjectVectorParam<T *> : public SimObjectBaseParam +{ + protected: + + std::vector<T *> value; + + public: + + typedef typename std::vector<T *>::size_type size_type; + + SimObjectVectorParam(ParamContext *context, + const std::string &name, + const std::string &description) + : SimObjectBaseParam(context, name, description, false) + { + } + + SimObjectVectorParam(ParamContext *context, + const std::string &name, + const std::string &description, + std::vector<T *> dfltValue) + : SimObjectBaseParam(context, name, description, true), + value(dfltValue) + { + } + + virtual ~SimObjectVectorParam() {} + + // basic vector access methods + size_type size() const + { + if (!isValid()) + die("not found"); + return value.size(); + } + + T *&operator[](size_type n) + { + if (!isValid()) + die("not found"); + return value[n]; + } + + // return reference to value vector + operator std::vector<T *>&() + { + if (!isValid()) + die("not found"); + return value; + } + + // display value to stream + virtual void showValue(std::ostream &os) const + { + for (int i = 0; i < value.size(); i++) { + if (i != 0) + os << " "; + SimObjectBaseParam::showValue(os, value[i]); + } + } + + // display type to stream: see + virtual void showType(std::ostream &os) const; + + // set value by parsing string + virtual void parse(const std::string &s) + { + std::vector<SimObject *> so_ptr_vec; + // first parse to generic SimObject * vector (from SimObjectBaseParam) + SimObjectBaseParam::parse(s, so_ptr_vec); + + value.resize(so_ptr_vec.size()); + + for (int i = 0; i < so_ptr_vec.size(); ++i) { + // now dynamic_cast to specific derived type + value[i] = dynamic_cast<T *>(so_ptr_vec[i]); + // check for failure of dynamic_cast + if (value[i] == NULL && so_ptr_vec[i] != NULL) + die("not of appropriate type"); + } + } +}; + +// +// Macro to define showType() methods for SimObjectParam & +// SimObjectVectorParam. Can't do this automatically as it requires a +// string name for the type, which you can't get from a template +// argument. For concrete derived SimObject types, this macro is +// automatically invoked by REGISTER_SIM_OBJECT() (see sim_object.hh). +// +#define DEFINE_SIM_OBJECT_CLASS_NAME(CLASS_NAME, OBJ_CLASS) \ +template<> \ +void \ +SimObjectParam<OBJ_CLASS *>::showType(std::ostream &os) const \ +{ \ + os << CLASS_NAME; \ +} \ + \ +template<> \ +void \ +SimObjectVectorParam<OBJ_CLASS *>::showType(std::ostream &os) const \ +{ \ + os << "vector of " << CLASS_NAME; \ +} + + +// +// Declarations for low-level parsing & displaying functions. These +// are used internally, but should not be used directly by clients of +// the parameter mechanism, but are declared here so they can be +// shared with the serialization code (see sim/serialize.cc). +template <class T> bool parseParam(const std::string &str, T &data); +template <class T> void showParam(std::ostream &os, const T &data); + +#endif // _SIM_PARAM_HH_ diff --git a/src/sim/process.cc b/src/sim/process.cc new file mode 100644 index 000000000..1261b8436 --- /dev/null +++ b/src/sim/process.cc @@ -0,0 +1,361 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * 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. + */ + +#include <unistd.h> +#include <fcntl.h> + +#include <string> + +#include "base/intmath.hh" +#include "base/loader/object_file.hh" +#include "base/loader/symtab.hh" +#include "base/statistics.hh" +#include "config/full_system.hh" +#include "cpu/exec_context.hh" +#include "mem/page_table.hh" +#include "mem/physical.hh" +#include "mem/translating_port.hh" +#include "sim/builder.hh" +#include "sim/process.hh" +#include "sim/stats.hh" +#include "sim/syscall_emul.hh" +#include "sim/system.hh" + +using namespace std; +using namespace TheISA; + +// +// The purpose of this code is to fake the loader & syscall mechanism +// when there's no OS: thus there's no resone to use it in FULL_SYSTEM +// mode when we do have an OS +// +#if FULL_SYSTEM +#error "process.cc not compatible with FULL_SYSTEM" +#endif + +// current number of allocated processes +int num_processes = 0; + +Process::Process(const string &nm, + System *_system, + int stdin_fd, // initial I/O descriptors + int stdout_fd, + int stderr_fd) + : SimObject(nm), system(_system) +{ + // initialize first 3 fds (stdin, stdout, stderr) + fd_map[STDIN_FILENO] = stdin_fd; + fd_map[STDOUT_FILENO] = stdout_fd; + fd_map[STDERR_FILENO] = stderr_fd; + + // mark remaining fds as free + for (int i = 3; i <= MAX_FD; ++i) { + fd_map[i] = -1; + } + + mmap_start = mmap_end = 0; + nxm_start = nxm_end = 0; + pTable = new PageTable(system); + // other parameters will be initialized when the program is loaded +} + + +void +Process::regStats() +{ + using namespace Stats; + + num_syscalls + .name(name() + ".PROG:num_syscalls") + .desc("Number of system calls") + ; +} + +// +// static helper functions +// +int +Process::openInputFile(const string &filename) +{ + int fd = open(filename.c_str(), O_RDONLY); + + if (fd == -1) { + perror(NULL); + cerr << "unable to open \"" << filename << "\" for reading\n"; + fatal("can't open input file"); + } + + return fd; +} + + +int +Process::openOutputFile(const string &filename) +{ + int fd = open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0774); + + if (fd == -1) { + perror(NULL); + cerr << "unable to open \"" << filename << "\" for writing\n"; + fatal("can't open output file"); + } + + return fd; +} + + +int +Process::registerExecContext(ExecContext *xc) +{ + // add to list + int myIndex = execContexts.size(); + execContexts.push_back(xc); + + // return CPU number to caller + return myIndex; +} + +void +Process::startup() +{ + if (execContexts.empty()) + fatal("Process %s is not associated with any CPUs!\n", name()); + + // first exec context for this process... initialize & enable + ExecContext *xc = execContexts[0]; + + // mark this context as active so it will start ticking. + xc->activate(0); + + Port *mem_port; + mem_port = system->physmem->getPort("functional"); + initVirtMem = new TranslatingPort(pTable, true); + mem_port->setPeer(initVirtMem); + initVirtMem->setPeer(mem_port); +} + +void +Process::replaceExecContext(ExecContext *xc, int xcIndex) +{ + if (xcIndex >= execContexts.size()) { + panic("replaceExecContext: bad xcIndex, %d >= %d\n", + xcIndex, execContexts.size()); + } + + execContexts[xcIndex] = xc; +} + +// map simulator fd sim_fd to target fd tgt_fd +void +Process::dup_fd(int sim_fd, int tgt_fd) +{ + if (tgt_fd < 0 || tgt_fd > MAX_FD) + panic("Process::dup_fd tried to dup past MAX_FD (%d)", tgt_fd); + + fd_map[tgt_fd] = sim_fd; +} + + +// generate new target fd for sim_fd +int +Process::alloc_fd(int sim_fd) +{ + // in case open() returns an error, don't allocate a new fd + if (sim_fd == -1) + return -1; + + // find first free target fd + for (int free_fd = 0; free_fd < MAX_FD; ++free_fd) { + if (fd_map[free_fd] == -1) { + fd_map[free_fd] = sim_fd; + return free_fd; + } + } + + panic("Process::alloc_fd: out of file descriptors!"); +} + + +// free target fd (e.g., after close) +void +Process::free_fd(int tgt_fd) +{ + if (fd_map[tgt_fd] == -1) + warn("Process::free_fd: request to free unused fd %d", tgt_fd); + + fd_map[tgt_fd] = -1; +} + + +// look up simulator fd for given target fd +int +Process::sim_fd(int tgt_fd) +{ + if (tgt_fd > MAX_FD) + return -1; + + return fd_map[tgt_fd]; +} + + + +// +// need to declare these here since there is no concrete Process type +// that can be constructed (i.e., no REGISTER_SIM_OBJECT() macro call, +// which is where these get declared for concrete types). +// +DEFINE_SIM_OBJECT_CLASS_NAME("Process", Process) + + +//////////////////////////////////////////////////////////////////////// +// +// LiveProcess member definitions +// +//////////////////////////////////////////////////////////////////////// + + +void +copyStringArray(vector<string> &strings, Addr array_ptr, Addr data_ptr, + TranslatingPort* memPort) +{ + Addr data_ptr_swap; + for (int i = 0; i < strings.size(); ++i) { + data_ptr_swap = htog(data_ptr); + memPort->writeBlob(array_ptr, (uint8_t*)&data_ptr_swap, sizeof(Addr)); + memPort->writeString(data_ptr, strings[i].c_str()); + array_ptr += sizeof(Addr); + data_ptr += strings[i].size() + 1; + } + // add NULL terminator + data_ptr = 0; + + memPort->writeBlob(array_ptr, (uint8_t*)&data_ptr, sizeof(Addr)); +} + +LiveProcess::LiveProcess(const string &nm, ObjectFile *_objFile, + System *_system, + int stdin_fd, int stdout_fd, int stderr_fd, + vector<string> &_argv, vector<string> &_envp) + : Process(nm, _system, stdin_fd, stdout_fd, stderr_fd), + objFile(_objFile), argv(_argv), envp(_envp) +{ + prog_fname = argv[0]; + + // load up symbols, if any... these may be used for debugging or + // profiling. + if (!debugSymbolTable) { + debugSymbolTable = new SymbolTable(); + if (!objFile->loadGlobalSymbols(debugSymbolTable) || + !objFile->loadLocalSymbols(debugSymbolTable)) { + // didn't load any symbols + delete debugSymbolTable; + debugSymbolTable = NULL; + } + } +} + +void +LiveProcess::argsInit(int intSize, int pageSize) +{ + Process::startup(); + + // load object file into target memory + objFile->loadSections(initVirtMem); + + // Calculate how much space we need for arg & env arrays. + int argv_array_size = intSize * (argv.size() + 1); + int envp_array_size = intSize * (envp.size() + 1); + int arg_data_size = 0; + for (int i = 0; i < argv.size(); ++i) { + arg_data_size += argv[i].size() + 1; + } + int env_data_size = 0; + for (int i = 0; i < envp.size(); ++i) { + env_data_size += envp[i].size() + 1; + } + + int space_needed = + argv_array_size + envp_array_size + arg_data_size + env_data_size; + // for SimpleScalar compatibility + if (space_needed < 16384) + space_needed = 16384; + + // set bottom of stack + stack_min = stack_base - space_needed; + // align it + stack_min &= ~(intSize-1); + stack_size = stack_base - stack_min; + // map memory + pTable->allocate(roundDown(stack_min, pageSize), + roundUp(stack_size, pageSize)); + + // map out initial stack contents + Addr argv_array_base = stack_min + intSize; // room for argc + Addr envp_array_base = argv_array_base + argv_array_size; + Addr arg_data_base = envp_array_base + envp_array_size; + Addr env_data_base = arg_data_base + arg_data_size; + + // write contents to stack + uint64_t argc = argv.size(); + if (intSize == 8) + argc = htog((uint64_t)argc); + else if (intSize == 4) + argc = htog((uint32_t)argc); + else + panic("Unknown int size"); + + initVirtMem->writeBlob(stack_min, (uint8_t*)&argc, intSize); + + copyStringArray(argv, argv_array_base, arg_data_base, initVirtMem); + copyStringArray(envp, envp_array_base, env_data_base, initVirtMem); + + execContexts[0]->setIntReg(ArgumentReg0, argc); + execContexts[0]->setIntReg(ArgumentReg1, argv_array_base); + execContexts[0]->setIntReg(StackPointerReg, stack_min); + + Addr prog_entry = objFile->entryPoint(); + execContexts[0]->setPC(prog_entry); + execContexts[0]->setNextPC(prog_entry + sizeof(MachInst)); + execContexts[0]->setNextNPC(prog_entry + (2 * sizeof(MachInst))); + + num_processes++; +} + +void +LiveProcess::syscall(int64_t callnum, ExecContext *xc) +{ + num_syscalls++; + + SyscallDesc *desc = getDesc(callnum); + if (desc == NULL) + fatal("Syscall %d out of range", callnum); + + desc->doSyscall(callnum, this, xc); +} + +DEFINE_SIM_OBJECT_CLASS_NAME("LiveProcess", LiveProcess); diff --git a/src/sim/process.hh b/src/sim/process.hh new file mode 100644 index 000000000..807bf330f --- /dev/null +++ b/src/sim/process.hh @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * 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. + */ + +#ifndef __PROCESS_HH__ +#define __PROCESS_HH__ + +// +// The purpose of this code is to fake the loader & syscall mechanism +// when there's no OS: thus there's no reason to use it in FULL_SYSTEM +// mode when we do have an OS. +// +#include "config/full_system.hh" + +#if !FULL_SYSTEM + +#include <vector> + +#include "base/statistics.hh" +#include "sim/sim_object.hh" + +class CPUExecContext; +class ExecContext; +class SyscallDesc; +class PageTable; +class TranslatingPort; +class System; + +void +copyStringArray(std::vector<std::string> &strings, Addr array_ptr, + Addr data_ptr, TranslatingPort* memPort); + +class Process : public SimObject +{ + public: + + /// Pointer to object representing the system this process is + /// running on. + System *system; + + // have we initialized an execution context from this process? If + // yes, subsequent contexts are assumed to be for dynamically + // created threads and are not initialized. + bool initialContextLoaded; + + // execution contexts associated with this process + std::vector<ExecContext *> execContexts; + + // number of CPUs (esxec contexts, really) assigned to this process. + unsigned int numCpus() { return execContexts.size(); } + + // record of blocked context + struct WaitRec + { + Addr waitChan; + ExecContext *waitingContext; + + WaitRec(Addr chan, ExecContext *ctx) + : waitChan(chan), waitingContext(ctx) + { } + }; + + // list of all blocked contexts + std::list<WaitRec> waitList; + + Addr brk_point; // top of the data segment + + Addr stack_base; // stack segment base (highest address) + unsigned stack_size; // initial stack size + Addr stack_min; // lowest address accessed on the stack + + // addr to use for next stack region (for multithreaded apps) + Addr next_thread_stack_base; + + // Base of region for mmaps (when user doesn't specify an address). + Addr mmap_start; + Addr mmap_end; + + // Base of region for nxm data + Addr nxm_start; + Addr nxm_end; + + std::string prog_fname; // file name + + Stats::Scalar<> num_syscalls; // number of syscalls executed + + + protected: + // constructor + Process(const std::string &nm, + System *_system, + int stdin_fd, // initial I/O descriptors + int stdout_fd, + int stderr_fd); + + // post initialization startup + virtual void startup(); + + protected: + /// Memory object for initialization (image loading) + TranslatingPort *initVirtMem; + + public: + PageTable *pTable; + + private: + // file descriptor remapping support + static const int MAX_FD = 256; // max legal fd value + int fd_map[MAX_FD+1]; + + public: + // static helper functions to generate file descriptors for constructor + static int openInputFile(const std::string &filename); + static int openOutputFile(const std::string &filename); + + // override of virtual SimObject method: register statistics + virtual void regStats(); + + // register an execution context for this process. + // returns xc's cpu number (index into execContexts[]) + int registerExecContext(ExecContext *xc); + + + void replaceExecContext(ExecContext *xc, int xcIndex); + + // map simulator fd sim_fd to target fd tgt_fd + void dup_fd(int sim_fd, int tgt_fd); + + // generate new target fd for sim_fd + int alloc_fd(int sim_fd); + + // free target fd (e.g., after close) + void free_fd(int tgt_fd); + + // look up simulator fd for given target fd + int sim_fd(int tgt_fd); + + virtual void syscall(int64_t callnum, ExecContext *xc) = 0; +}; + +// +// "Live" process with system calls redirected to host system +// +class ObjectFile; +class LiveProcess : public Process +{ + protected: + ObjectFile *objFile; + std::vector<std::string> argv; + std::vector<std::string> envp; + + LiveProcess(const std::string &nm, ObjectFile *objFile, + System *_system, int stdin_fd, int stdout_fd, int stderr_fd, + std::vector<std::string> &argv, + std::vector<std::string> &envp); + + virtual void argsInit(int intSize, int pageSize); + + public: + virtual void syscall(int64_t callnum, ExecContext *xc); + + virtual SyscallDesc* getDesc(int callnum) = 0; +}; + + +#endif // !FULL_SYSTEM + +#endif // __PROCESS_HH__ diff --git a/src/sim/pseudo_inst.cc b/src/sim/pseudo_inst.cc new file mode 100644 index 000000000..7897b5c8b --- /dev/null +++ b/src/sim/pseudo_inst.cc @@ -0,0 +1,284 @@ +/* + * Copyright (c) 2003-2006 The Regents of The University of Michigan + * 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. + */ + +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> + +#include <string> + +#include "sim/pseudo_inst.hh" +#include "arch/vtophys.hh" +#include "cpu/base.hh" +#include "cpu/sampler/sampler.hh" +#include "cpu/exec_context.hh" +#include "kern/kernel_stats.hh" +#include "sim/param.hh" +#include "sim/serialize.hh" +#include "sim/sim_exit.hh" +#include "sim/stat_control.hh" +#include "sim/stats.hh" +#include "sim/system.hh" +#include "sim/debug.hh" +#include "sim/vptr.hh" + +using namespace std; + +extern Sampler *SampCPU; + +using namespace Stats; +using namespace TheISA; + +namespace AlphaPseudo +{ + bool doStatisticsInsts; + bool doCheckpointInsts; + bool doQuiesce; + + void + arm(ExecContext *xc) + { + xc->getCpuPtr()->kernelStats->arm(); + } + + void + quiesce(ExecContext *xc) + { + if (!doQuiesce) + return; + + xc->suspend(); + xc->getCpuPtr()->kernelStats->quiesce(); + } + + void + quiesceNs(ExecContext *xc, uint64_t ns) + { + if (!doQuiesce || ns == 0) + return; + + Event *quiesceEvent = xc->getQuiesceEvent(); + + if (quiesceEvent->scheduled()) + quiesceEvent->reschedule(curTick + Clock::Int::ns * ns); + else + quiesceEvent->schedule(curTick + Clock::Int::ns * ns); + + xc->suspend(); + xc->getCpuPtr()->kernelStats->quiesce(); + } + + void + quiesceCycles(ExecContext *xc, uint64_t cycles) + { + if (!doQuiesce || cycles == 0) + return; + + Event *quiesceEvent = xc->getQuiesceEvent(); + + if (quiesceEvent->scheduled()) + quiesceEvent->reschedule(curTick + + xc->getCpuPtr()->cycles(cycles)); + else + quiesceEvent->schedule(curTick + + xc->getCpuPtr()->cycles(cycles)); + + xc->suspend(); + xc->getCpuPtr()->kernelStats->quiesce(); + } + + uint64_t + quiesceTime(ExecContext *xc) + { + return (xc->readLastActivate() - xc->readLastSuspend()) / Clock::Int::ns; + } + + void + ivlb(ExecContext *xc) + { + xc->getCpuPtr()->kernelStats->ivlb(); + } + + void + ivle(ExecContext *xc) + { + } + + void + m5exit_old(ExecContext *xc) + { + SimExit(curTick, "m5_exit_old instruction encountered"); + } + + void + m5exit(ExecContext *xc, Tick delay) + { + Tick when = curTick + delay * Clock::Int::ns; + SimExit(when, "m5_exit instruction encountered"); + } + + void + resetstats(ExecContext *xc, Tick delay, Tick period) + { + if (!doStatisticsInsts) + return; + + + Tick when = curTick + delay * Clock::Int::ns; + Tick repeat = period * Clock::Int::ns; + + using namespace Stats; + SetupEvent(Reset, when, repeat); + } + + void + dumpstats(ExecContext *xc, Tick delay, Tick period) + { + if (!doStatisticsInsts) + return; + + + Tick when = curTick + delay * Clock::Int::ns; + Tick repeat = period * Clock::Int::ns; + + using namespace Stats; + SetupEvent(Dump, when, repeat); + } + + void + addsymbol(ExecContext *xc, Addr addr, Addr symbolAddr) + { + char symb[100]; + CopyStringOut(xc, symb, symbolAddr, 100); + std::string symbol(symb); + + DPRINTF(Loader, "Loaded symbol: %s @ %#llx\n", symbol, addr); + + xc->getSystemPtr()->kernelSymtab->insert(addr,symbol); + } + + void + dumpresetstats(ExecContext *xc, Tick delay, Tick period) + { + if (!doStatisticsInsts) + return; + + + Tick when = curTick + delay * Clock::Int::ns; + Tick repeat = period * Clock::Int::ns; + + using namespace Stats; + SetupEvent(Dump|Reset, when, repeat); + } + + void + m5checkpoint(ExecContext *xc, Tick delay, Tick period) + { + if (!doCheckpointInsts) + return; + + + Tick when = curTick + delay * Clock::Int::ns; + Tick repeat = period * Clock::Int::ns; + + Checkpoint::setup(when, repeat); + } + + uint64_t + readfile(ExecContext *xc, Addr vaddr, uint64_t len, uint64_t offset) + { + const string &file = xc->getCpuPtr()->system->params()->readfile; + if (file.empty()) { + return ULL(0); + } + + uint64_t result = 0; + + int fd = ::open(file.c_str(), O_RDONLY, 0); + if (fd < 0) + panic("could not open file %s\n", file); + + if (::lseek(fd, offset, SEEK_SET) < 0) + panic("could not seek: %s", strerror(errno)); + + char *buf = new char[len]; + char *p = buf; + while (len > 0) { + int bytes = ::read(fd, p, len); + if (bytes <= 0) + break; + + p += bytes; + result += bytes; + len -= bytes; + } + + close(fd); + CopyIn(xc, vaddr, buf, result); + delete [] buf; + return result; + } + + class Context : public ParamContext + { + public: + Context(const string §ion) : ParamContext(section) {} + void checkParams(); + }; + + Context context("pseudo_inst"); + + Param<bool> __quiesce(&context, "quiesce", + "enable quiesce instructions", + true); + Param<bool> __statistics(&context, "statistics", + "enable statistics pseudo instructions", + true); + Param<bool> __checkpoint(&context, "checkpoint", + "enable checkpoint pseudo instructions", + true); + + void + Context::checkParams() + { + doQuiesce = __quiesce; + doStatisticsInsts = __statistics; + doCheckpointInsts = __checkpoint; + } + + void debugbreak(ExecContext *xc) + { + debug_break(); + } + + void switchcpu(ExecContext *xc) + { + if (SampCPU) + SampCPU->switchCPUs(); + } +} diff --git a/src/sim/pseudo_inst.hh b/src/sim/pseudo_inst.hh new file mode 100644 index 000000000..4dd427c99 --- /dev/null +++ b/src/sim/pseudo_inst.hh @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2003-2006 The Regents of The University of Michigan + * 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. + */ + +class ExecContext; + +//We need the "Tick" data type from here +#include "sim/host.hh" +//We need the "Addr" data type from here +#include "arch/isa_traits.hh" + +namespace AlphaPseudo +{ + /** + * @todo these externs are only here for a hack in fullCPU::takeOver... + */ + extern bool doStatisticsInsts; + extern bool doCheckpointInsts; + extern bool doQuiesce; + + void arm(ExecContext *xc); + void quiesce(ExecContext *xc); + void quiesceNs(ExecContext *xc, uint64_t ns); + void quiesceCycles(ExecContext *xc, uint64_t cycles); + uint64_t quiesceTime(ExecContext *xc); + void ivlb(ExecContext *xc); + void ivle(ExecContext *xc); + void m5exit(ExecContext *xc, Tick delay); + void m5exit_old(ExecContext *xc); + void resetstats(ExecContext *xc, Tick delay, Tick period); + void dumpstats(ExecContext *xc, Tick delay, Tick period); + void dumpresetstats(ExecContext *xc, Tick delay, Tick period); + void m5checkpoint(ExecContext *xc, Tick delay, Tick period); + uint64_t readfile(ExecContext *xc, Addr vaddr, uint64_t len, uint64_t offset); + void debugbreak(ExecContext *xc); + void switchcpu(ExecContext *xc); + void addsymbol(ExecContext *xc, Addr addr, Addr symbolAddr); +} diff --git a/src/sim/root.cc b/src/sim/root.cc new file mode 100644 index 000000000..6348ec104 --- /dev/null +++ b/src/sim/root.cc @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * 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. + */ + +#include <cstring> +#include <fstream> +#include <list> +#include <string> +#include <vector> + +#include "base/misc.hh" +#include "base/output.hh" +#include "sim/builder.hh" +#include "sim/host.hh" +#include "sim/sim_events.hh" +#include "sim/sim_object.hh" +#include "sim/root.hh" + +using namespace std; + +Tick curTick = 0; +ostream *outputStream; +ostream *configStream; + +/// The simulated frequency of curTick. (This is only here for a short time) +Tick ticksPerSecond; + +namespace Clock { +/// The simulated frequency of curTick. (In ticks per second) +Tick Frequency; + +namespace Float { +double s; +double ms; +double us; +double ns; +double ps; + +double Hz; +double kHz; +double MHz; +double GHZ; +/* namespace Float */ } + +namespace Int { +Tick s; +Tick ms; +Tick us; +Tick ns; +Tick ps; +/* namespace Float */ } + +/* namespace Clock */ } + + +// Dummy Object +class Root : public SimObject +{ + private: + Tick max_tick; + Tick progress_interval; + + public: + Root(const std::string &name, Tick maxtick, Tick pi) + : SimObject(name), max_tick(maxtick), progress_interval(pi) + {} + + virtual void startup(); +}; + +void +Root::startup() +{ + if (max_tick != 0) + new SimExitEvent(curTick + max_tick, "reached maximum cycle count"); + + if (progress_interval != 0) + new ProgressEvent(&mainEventQueue, progress_interval); +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(Root) + + Param<Tick> clock; + Param<Tick> max_tick; + Param<Tick> progress_interval; + Param<string> output_file; + +END_DECLARE_SIM_OBJECT_PARAMS(Root) + +BEGIN_INIT_SIM_OBJECT_PARAMS(Root) + + INIT_PARAM(clock, "tick frequency"), + INIT_PARAM(max_tick, "maximum simulation time"), + INIT_PARAM(progress_interval, "print a progress message"), + INIT_PARAM(output_file, "file to dump simulator output to") + +END_INIT_SIM_OBJECT_PARAMS(Root) + +CREATE_SIM_OBJECT(Root) +{ + static bool created = false; + if (created) + panic("only one root object allowed!"); + + created = true; + + outputStream = simout.find(output_file); + Root *root = new Root(getInstanceName(), max_tick, progress_interval); + + using namespace Clock; + Frequency = clock; + Float::s = static_cast<double>(Frequency); + Float::ms = Float::s / 1.0e3; + Float::us = Float::s / 1.0e6; + Float::ns = Float::s / 1.0e9; + Float::ps = Float::s / 1.0e12; + + Float::Hz = 1.0 / Float::s; + Float::kHz = 1.0 / Float::ms; + Float::MHz = 1.0 / Float::us; + Float::GHZ = 1.0 / Float::ns; + + Int::s = Frequency; + Int::ms = Int::s / 1000; + Int::us = Int::ms / 1000; + Int::ns = Int::us / 1000; + Int::ps = Int::ns / 1000; + + return root; +} + +REGISTER_SIM_OBJECT("Root", Root) diff --git a/src/sim/serialize.cc b/src/sim/serialize.cc new file mode 100644 index 000000000..c4ef124bb --- /dev/null +++ b/src/sim/serialize.cc @@ -0,0 +1,484 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * 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. + */ + +#include <sys/time.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> + +#include <fstream> +#include <list> +#include <string> +#include <vector> + +#include "base/inifile.hh" +#include "base/misc.hh" +#include "base/output.hh" +#include "base/str.hh" +#include "base/trace.hh" +#include "sim/config_node.hh" +#include "sim/eventq.hh" +#include "sim/param.hh" +#include "sim/serialize.hh" +#include "sim/sim_events.hh" +#include "sim/sim_exit.hh" +#include "sim/sim_object.hh" + +using namespace std; + +int Serializable::ckptMaxCount = 0; +int Serializable::ckptCount = 0; +int Serializable::ckptPrevCount = -1; + +void +Serializable::nameOut(ostream &os) +{ + os << "\n[" << name() << "]\n"; +} + +void +Serializable::nameOut(ostream &os, const string &_name) +{ + os << "\n[" << _name << "]\n"; +} + +template <class T> +void +paramOut(ostream &os, const std::string &name, const T ¶m) +{ + os << name << "="; + showParam(os, param); + os << "\n"; +} + + +template <class T> +void +paramIn(Checkpoint *cp, const std::string §ion, + const std::string &name, T ¶m) +{ + std::string str; + if (!cp->find(section, name, str) || !parseParam(str, param)) { + fatal("Can't unserialize '%s:%s'\n", section, name); + } +} + + +template <class T> +void +arrayParamOut(ostream &os, const std::string &name, + const T *param, int size) +{ + os << name << "="; + if (size > 0) + showParam(os, param[0]); + for (int i = 1; i < size; ++i) { + os << " "; + showParam(os, param[i]); + } + os << "\n"; +} + + +template <class T> +void +arrayParamIn(Checkpoint *cp, const std::string §ion, + const std::string &name, T *param, int size) +{ + std::string str; + if (!cp->find(section, name, str)) { + fatal("Can't unserialize '%s:%s'\n", section, name); + } + + // code below stolen from VectorParam<T>::parse(). + // it would be nice to unify these somehow... + + vector<string> tokens; + + tokenize(tokens, str, ' '); + + // Need this if we were doing a vector + // value.resize(tokens.size()); + + if (tokens.size() != size) { + fatal("Array size mismatch on %s:%s'\n", section, name); + } + + for (int i = 0; i < tokens.size(); i++) { + // need to parse into local variable to handle vector<bool>, + // for which operator[] returns a special reference class + // that's not the same as 'bool&', (since it's a packed + // vector) + T scalar_value; + if (!parseParam(tokens[i], scalar_value)) { + string err("could not parse \""); + + err += str; + err += "\""; + + fatal(err); + } + + // assign parsed value to vector + param[i] = scalar_value; + } +} + + +void +objParamIn(Checkpoint *cp, const std::string §ion, + const std::string &name, Serializable * ¶m) +{ + if (!cp->findObj(section, name, param)) { + fatal("Can't unserialize '%s:%s'\n", section, name); + } +} + + +#define INSTANTIATE_PARAM_TEMPLATES(type) \ +template void \ +paramOut(ostream &os, const std::string &name, type const ¶m); \ +template void \ +paramIn(Checkpoint *cp, const std::string §ion, \ + const std::string &name, type & param); \ +template void \ +arrayParamOut(ostream &os, const std::string &name, \ + type const *param, int size); \ +template void \ +arrayParamIn(Checkpoint *cp, const std::string §ion, \ + const std::string &name, type *param, int size); + +INSTANTIATE_PARAM_TEMPLATES(signed char) +INSTANTIATE_PARAM_TEMPLATES(unsigned char) +INSTANTIATE_PARAM_TEMPLATES(signed short) +INSTANTIATE_PARAM_TEMPLATES(unsigned short) +INSTANTIATE_PARAM_TEMPLATES(signed int) +INSTANTIATE_PARAM_TEMPLATES(unsigned int) +INSTANTIATE_PARAM_TEMPLATES(signed long) +INSTANTIATE_PARAM_TEMPLATES(unsigned long) +INSTANTIATE_PARAM_TEMPLATES(signed long long) +INSTANTIATE_PARAM_TEMPLATES(unsigned long long) +INSTANTIATE_PARAM_TEMPLATES(bool) +INSTANTIATE_PARAM_TEMPLATES(string) + + +///////////////////////////// + +/// Container for serializing global variables (not associated with +/// any serialized object). +class Globals : public Serializable +{ + public: + const string name() const; + void serialize(ostream &os); + void unserialize(Checkpoint *cp); +}; + +/// The one and only instance of the Globals class. +Globals globals; + +const string +Globals::name() const +{ + return "Globals"; +} + +void +Globals::serialize(ostream &os) +{ + nameOut(os); + SERIALIZE_SCALAR(curTick); + + nameOut(os, "MainEventQueue"); + mainEventQueue.serialize(os); +} + +void +Globals::unserialize(Checkpoint *cp) +{ + const string §ion = name(); + UNSERIALIZE_SCALAR(curTick); + + mainEventQueue.unserialize(cp, "MainEventQueue"); +} + +void +Serializable::serializeAll() +{ + string dir = Checkpoint::dir(); + if (mkdir(dir.c_str(), 0775) == -1 && errno != EEXIST) + fatal("couldn't mkdir %s\n", dir); + + string cpt_file = dir + Checkpoint::baseFilename; + ofstream outstream(cpt_file.c_str()); + time_t t = time(NULL); + outstream << "// checkpoint generated: " << ctime(&t); + + globals.serialize(outstream); + SimObject::serializeAll(outstream); + + assert(Serializable::ckptPrevCount + 1 == Serializable::ckptCount); + Serializable::ckptPrevCount++; + if (ckptMaxCount && ++ckptCount >= ckptMaxCount) + SimExit(curTick + 1, "Maximum number of checkpoints dropped"); + +} + + +void +Serializable::unserializeGlobals(Checkpoint *cp) +{ + globals.unserialize(cp); +} + + +class SerializeEvent : public Event +{ + protected: + Tick repeat; + + public: + SerializeEvent(Tick _when, Tick _repeat); + virtual void process(); + virtual void serialize(std::ostream &os) + { + panic("Cannot serialize the SerializeEvent"); + } + +}; + +SerializeEvent::SerializeEvent(Tick _when, Tick _repeat) + : Event(&mainEventQueue, Serialize_Pri), repeat(_repeat) +{ + setFlags(AutoDelete); + schedule(_when); +} + +void +SerializeEvent::process() +{ + Serializable::serializeAll(); + if (repeat) + schedule(curTick + repeat); +} + +const char *Checkpoint::baseFilename = "m5.cpt"; + +static string checkpointDirBase; + +string +Checkpoint::dir() +{ + // use csprintf to insert curTick into directory name if it + // appears to have a format placeholder in it. + return (checkpointDirBase.find("%") != string::npos) ? + csprintf(checkpointDirBase, curTick) : checkpointDirBase; +} + +void +Checkpoint::setup(Tick when, Tick period) +{ + new SerializeEvent(when, period); +} + +class SerializeParamContext : public ParamContext +{ + private: + SerializeEvent *event; + + public: + SerializeParamContext(const string §ion); + ~SerializeParamContext(); + void checkParams(); +}; + +SerializeParamContext serialParams("serialize"); + +Param<string> serialize_dir(&serialParams, "dir", + "dir to stick checkpoint in " + "(sprintf format with cycle #)"); + +Param<Counter> serialize_cycle(&serialParams, + "cycle", + "cycle to serialize", + 0); + +Param<Counter> serialize_period(&serialParams, + "period", + "period to repeat serializations", + 0); + +Param<int> serialize_count(&serialParams, "count", + "maximum number of checkpoints to drop"); + +SerializeParamContext::SerializeParamContext(const string §ion) + : ParamContext(section), event(NULL) +{ } + +SerializeParamContext::~SerializeParamContext() +{ +} + +void +SerializeParamContext::checkParams() +{ + checkpointDirBase = simout.resolve(serialize_dir); + + // guarantee that directory ends with a '/' + if (checkpointDirBase[checkpointDirBase.size() - 1] != '/') + checkpointDirBase += "/"; + + if (serialize_cycle > 0) + Checkpoint::setup(serialize_cycle, serialize_period); + + Serializable::ckptMaxCount = serialize_count; +} + +void +debug_serialize() +{ + Serializable::serializeAll(); +} + +void +debug_serialize(Tick when) +{ + new SerializeEvent(when, 0); +} + +//////////////////////////////////////////////////////////////////////// +// +// SerializableClass member definitions +// +//////////////////////////////////////////////////////////////////////// + +// Map of class names to SerializableBuilder creation functions. +// Need to make this a pointer so we can force initialization on the +// first reference; otherwise, some SerializableClass constructors +// may be invoked before the classMap constructor. +map<string,SerializableClass::CreateFunc> *SerializableClass::classMap = 0; + +// SerializableClass constructor: add mapping to classMap +SerializableClass::SerializableClass(const string &className, + CreateFunc createFunc) +{ + if (classMap == NULL) + classMap = new map<string,SerializableClass::CreateFunc>(); + + if ((*classMap)[className]) + { + cerr << "Error: simulation object class " << className << " redefined" + << endl; + fatal(""); + } + + // add className --> createFunc to class map + (*classMap)[className] = createFunc; +} + + +// +// +Serializable * +SerializableClass::createObject(Checkpoint *cp, + const std::string §ion) +{ + string className; + + if (!cp->find(section, "type", className)) { + fatal("Serializable::create: no 'type' entry in section '%s'.\n", + section); + } + + CreateFunc createFunc = (*classMap)[className]; + + if (createFunc == NULL) { + fatal("Serializable::create: no create function for class '%s'.\n", + className); + } + + Serializable *object = createFunc(cp, section); + + assert(object != NULL); + + return object; +} + + +Serializable * +Serializable::create(Checkpoint *cp, const std::string §ion) +{ + Serializable *object = SerializableClass::createObject(cp, section); + object->unserialize(cp, section); + return object; +} + + +Checkpoint::Checkpoint(const std::string &cpt_dir, const std::string &path, + const ConfigNode *_configNode) + : db(new IniFile), basePath(path), configNode(_configNode), cptDir(cpt_dir) +{ + string filename = cpt_dir + "/" + Checkpoint::baseFilename; + if (!db->load(filename)) { + fatal("Can't load checkpoint file '%s'\n", filename); + } +} + + +bool +Checkpoint::find(const std::string §ion, const std::string &entry, + std::string &value) +{ + return db->find(section, entry, value); +} + + +bool +Checkpoint::findObj(const std::string §ion, const std::string &entry, + Serializable *&value) +{ + string path; + + if (!db->find(section, entry, path)) + return false; + + if ((value = configNode->resolveSimObject(path)) != NULL) + return true; + + if ((value = objMap[path]) != NULL) + return true; + + return false; +} + + +bool +Checkpoint::sectionExists(const std::string §ion) +{ + return db->sectionExists(section); +} diff --git a/src/sim/serialize.hh b/src/sim/serialize.hh new file mode 100644 index 000000000..d8f5f8fc5 --- /dev/null +++ b/src/sim/serialize.hh @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * 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. + */ + +/* @file + * Serialization Interface Declarations + */ + +#ifndef __SERIALIZE_HH__ +#define __SERIALIZE_HH__ + + +#include <list> +#include <iostream> +#include <map> + +#include "sim/host.hh" +#include "sim/configfile.hh" + +class Serializable; +class Checkpoint; + +template <class T> +void paramOut(std::ostream &os, const std::string &name, const T ¶m); + +template <class T> +void paramIn(Checkpoint *cp, const std::string §ion, + const std::string &name, T ¶m); + +template <class T> +void arrayParamOut(std::ostream &os, const std::string &name, + const T *param, int size); + +template <class T> +void arrayParamIn(Checkpoint *cp, const std::string §ion, + const std::string &name, T *param, int size); + +void +objParamIn(Checkpoint *cp, const std::string §ion, + const std::string &name, Serializable * ¶m); + + +// +// These macros are streamlined to use in serialize/unserialize +// functions. It's assumed that serialize() has a parameter 'os' for +// the ostream, and unserialize() has parameters 'cp' and 'section'. +#define SERIALIZE_SCALAR(scalar) paramOut(os, #scalar, scalar) + +#define UNSERIALIZE_SCALAR(scalar) paramIn(cp, section, #scalar, scalar) + +// ENUMs are like SCALARs, but we cast them to ints on the way out +#define SERIALIZE_ENUM(scalar) paramOut(os, #scalar, (int)scalar) + +#define UNSERIALIZE_ENUM(scalar) \ + do { \ + int tmp; \ + paramIn(cp, section, #scalar, tmp); \ + scalar = (typeof(scalar))tmp; \ + } while (0) + +#define SERIALIZE_ARRAY(member, size) \ + arrayParamOut(os, #member, member, size) + +#define UNSERIALIZE_ARRAY(member, size) \ + arrayParamIn(cp, section, #member, member, size) + +#define SERIALIZE_OBJPTR(objptr) paramOut(os, #objptr, (objptr)->name()) + +#define UNSERIALIZE_OBJPTR(objptr) \ + do { \ + Serializable *sptr; \ + objParamIn(cp, section, #objptr, sptr); \ + objptr = dynamic_cast<typeof(objptr)>(sptr); \ + } while (0) + +/* + * Basic support for object serialization. + */ +class Serializable +{ + protected: + void nameOut(std::ostream &os); + void nameOut(std::ostream &os, const std::string &_name); + + public: + Serializable() {} + virtual ~Serializable() {} + + // manditory virtual function, so objects must provide names + virtual const std::string name() const = 0; + + virtual void serialize(std::ostream &os) {} + virtual void unserialize(Checkpoint *cp, const std::string §ion) {} + + static Serializable *create(Checkpoint *cp, + const std::string §ion); + + static int ckptCount; + static int ckptMaxCount; + static int ckptPrevCount; + static void serializeAll(); + static void unserializeGlobals(Checkpoint *cp); +}; + +// +// A SerializableBuilder serves as an evaluation context for a set of +// parameters that describe a specific instance of a Serializable. This +// evaluation context corresponds to a section in the .ini file (as +// with the base ParamContext) plus an optional node in the +// configuration hierarchy (the configNode member) for resolving +// Serializable references. SerializableBuilder is an abstract superclass; +// derived classes specialize the class for particular subclasses of +// Serializable (e.g., BaseCache). +// +// For typical usage, see the definition of +// SerializableClass::createObject(). +// +class SerializableBuilder +{ + public: + + SerializableBuilder() {} + + virtual ~SerializableBuilder() {} + + // Create the actual Serializable corresponding to the parameter + // values in this context. This function is overridden in derived + // classes to call a specific constructor for a particular + // subclass of Serializable. + virtual Serializable *create() = 0; +}; + +// +// An instance of SerializableClass corresponds to a class derived from +// Serializable. The SerializableClass instance serves to bind the string +// name (found in the config file) to a function that creates an +// instance of the appropriate derived class. +// +// This would be much cleaner in Smalltalk or Objective-C, where types +// are first-class objects themselves. +// +class SerializableClass +{ + public: + + // Type CreateFunc is a pointer to a function that creates a new + // simulation object builder based on a .ini-file parameter + // section (specified by the first string argument), a unique name + // for the object (specified by the second string argument), and + // an optional config hierarchy node (specified by the third + // argument). A pointer to the new SerializableBuilder is returned. + typedef Serializable *(*CreateFunc)(Checkpoint *cp, + const std::string §ion); + + static std::map<std::string,CreateFunc> *classMap; + + // Constructor. For example: + // + // SerializableClass baseCacheSerializableClass("BaseCacheSerializable", + // newBaseCacheSerializableBuilder); + // + SerializableClass(const std::string &className, CreateFunc createFunc); + + // create Serializable given name of class and pointer to + // configuration hierarchy node + static Serializable *createObject(Checkpoint *cp, + const std::string §ion); +}; + +// +// Macros to encapsulate the magic of declaring & defining +// SerializableBuilder and SerializableClass objects +// + +#define REGISTER_SERIALIZEABLE(CLASS_NAME, OBJ_CLASS) \ +SerializableClass the##OBJ_CLASS##Class(CLASS_NAME, \ + OBJ_CLASS::createForUnserialize); + +class Checkpoint +{ + private: + + IniFile *db; + const std::string basePath; + const ConfigNode *configNode; + std::map<std::string, Serializable*> objMap; + + public: + Checkpoint(const std::string &cpt_dir, const std::string &path, + const ConfigNode *_configNode); + + const std::string cptDir; + + bool find(const std::string §ion, const std::string &entry, + std::string &value); + + bool findObj(const std::string §ion, const std::string &entry, + Serializable *&value); + + bool sectionExists(const std::string §ion); + + // The following static functions have to do with checkpoint + // creation rather than restoration. This class makes a handy + // namespace for them though. + + // Export current checkpoint directory name so other objects can + // derive filenames from it (e.g., memory). The return value is + // guaranteed to end in '/' so filenames can be directly appended. + // This function is only valid while a checkpoint is being created. + static std::string dir(); + + // Filename for base checkpoint file within directory. + static const char *baseFilename; + + // Set up a checkpoint creation event or series of events. + static void setup(Tick when, Tick period = 0); +}; + +#endif // __SERIALIZE_HH__ diff --git a/src/sim/sim_events.cc b/src/sim/sim_events.cc new file mode 100644 index 000000000..c2bdca9df --- /dev/null +++ b/src/sim/sim_events.cc @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * 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. + */ + +#include <string> + +#include "base/callback.hh" +#include "base/hostinfo.hh" +#include "sim/eventq.hh" +#include "sim/param.hh" +#include "sim/sim_events.hh" +#include "sim/sim_exit.hh" +#include "sim/startup.hh" +#include "sim/stats.hh" + +using namespace std; + +// +// handle termination event +// +void +SimExitEvent::process() +{ + // This event does not autodelete because exitNow may be called, + // and the function will never be allowed to finish. + if (theQueue() == &mainEventQueue) { + string _cause = cause; + int _code = code; + delete this; + exitNow(_cause, _code); + } else { + new SimExitEvent(cause, code); + delete this; + } +} + + +const char * +SimExitEvent::description() +{ + return "simulation termination"; +} + +// +// constructor: automatically schedules at specified time +// +CountedExitEvent::CountedExitEvent(EventQueue *q, const std::string &_cause, + Tick _when, int &_downCounter) + : Event(q, Sim_Exit_Pri), + cause(_cause), + downCounter(_downCounter) +{ + // catch stupid mistakes + assert(downCounter > 0); + + schedule(_when); +} + + +// +// handle termination event +// +void +CountedExitEvent::process() +{ + if (--downCounter == 0) { + new SimExitEvent(cause, 0); + } +} + + +const char * +CountedExitEvent::description() +{ + return "counted exit"; +} + +#ifdef CHECK_SWAP_CYCLES +new CheckSwapEvent(&mainEventQueue, CHECK_SWAP_CYCLES); +#endif + +void +CheckSwapEvent::process() +{ + /* Check the amount of free swap space */ + long swap; + + /* returns free swap in KBytes */ + swap = procInfo("/proc/meminfo", "SwapFree:"); + + if (swap < 1000) + ccprintf(cerr, "\a\a\aWarning! Swap space is low (%d)\n", swap); + + if (swap < 100) { + cerr << "\a\aAborting Simulation! Inadequate swap space!\n\n"; + new SimExitEvent("Lack of swap space"); + } + + schedule(curTick + interval); +} + +const char * +CheckSwapEvent::description() +{ + return "check swap"; +} + +// +// handle progress event: print message and reschedule +// +void +ProgressEvent::process() +{ + DPRINTFN("ProgressEvent\n"); + // reschedule for next interval + schedule(curTick + interval); +} + + +const char * +ProgressEvent::description() +{ + return "progress message"; +} diff --git a/src/sim/sim_events.hh b/src/sim/sim_events.hh new file mode 100644 index 000000000..c93914457 --- /dev/null +++ b/src/sim/sim_events.hh @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * 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. + */ + +#ifndef __SIM_SIM_EVENTS_HH__ +#define __SIM_SIM_EVENTS_HH__ + +#include "sim/eventq.hh" + +// +// Event to terminate simulation at a particular cycle/instruction +// +class SimExitEvent : public Event +{ + private: + // string explaining why we're terminating + std::string cause; + int code; + + public: + SimExitEvent(const std::string &_cause, int c = 0) + : Event(&mainEventQueue, Sim_Exit_Pri), cause(_cause), + code(c) + { schedule(curTick); } + + SimExitEvent(Tick _when, const std::string &_cause, int c = 0) + : Event(&mainEventQueue, Sim_Exit_Pri), cause(_cause), + code(c) + { schedule(_when); } + + SimExitEvent(EventQueue *q, const std::string &_cause, int c = 0) + : Event(q, Sim_Exit_Pri), cause(_cause), code(c) + { schedule(curTick); } + + SimExitEvent(EventQueue *q, Tick _when, const std::string &_cause, + int c = 0) + : Event(q, Sim_Exit_Pri), cause(_cause), code(c) + { schedule(_when); } + + void process(); // process event + + virtual const char *description(); +}; + +// +// Event class to terminate simulation after 'n' related events have +// occurred using a shared counter: used to terminate when *all* +// threads have reached a particular instruction count +// +class CountedExitEvent : public Event +{ + private: + std::string cause; // string explaining why we're terminating + int &downCounter; // decrement & terminate if zero + + public: + CountedExitEvent(EventQueue *q, const std::string &_cause, + Tick _when, int &_downCounter); + + void process(); // process event + + virtual const char *description(); +}; + +// +// Event to check swap usage +// +class CheckSwapEvent : public Event +{ + private: + int interval; + + public: + CheckSwapEvent(EventQueue *q, int ival) + : Event(q), interval(ival) + { schedule(curTick + interval); } + + void process(); // process event + + virtual const char *description(); +}; + +// +// Progress event: print out cycle every so often so we know we're +// making forward progress. +// +class ProgressEvent : public Event +{ + protected: + Tick interval; + + public: + ProgressEvent(EventQueue *q, Tick ival) + : Event(q), interval(ival) + { schedule(curTick + interval); } + + void process(); // process event + + virtual const char *description(); +}; + +#endif // __SIM_SIM_EVENTS_HH__ diff --git a/src/sim/sim_exit.hh b/src/sim/sim_exit.hh new file mode 100644 index 000000000..f14256933 --- /dev/null +++ b/src/sim/sim_exit.hh @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * 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. + */ + +#ifndef __SIM_EXIT_HH__ +#define __SIM_EXIT_HH__ + +#include <string> + +#include "sim/host.hh" + +class Callback; + +void registerExitCallback(Callback *); + +void exitNow(const std::string &cause, int exit_code); +void exitNow(const char *cause, int exit_code); +void SimExit(Tick when, const char *message); + +#endif // __SIM_EXIT_HH__ diff --git a/src/sim/sim_object.cc b/src/sim/sim_object.cc new file mode 100644 index 000000000..17d58ba4f --- /dev/null +++ b/src/sim/sim_object.cc @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * 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. + */ + +#include <assert.h> + +#include "base/callback.hh" +#include "base/inifile.hh" +#include "base/match.hh" +#include "base/misc.hh" +#include "base/trace.hh" +#include "base/stats/events.hh" +#include "base/serializer.hh" +#include "sim/configfile.hh" +#include "sim/host.hh" +#include "sim/sim_object.hh" +#include "sim/stats.hh" +#include "sim/param.hh" + +using namespace std; + + +//////////////////////////////////////////////////////////////////////// +// +// SimObject member definitions +// +//////////////////////////////////////////////////////////////////////// + +// +// static list of all SimObjects, used for initialization etc. +// +SimObject::SimObjectList SimObject::simObjectList; + +namespace Stats { + extern ObjectMatch event_ignore; +} + +// +// SimObject constructor: used to maintain static simObjectList +// +SimObject::SimObject(Params *p) + : _params(p) +{ +#ifdef DEBUG + doDebugBreak = false; +#endif + + doRecordEvent = !Stats::event_ignore.match(name()); + simObjectList.push_back(this); +} + +// +// SimObject constructor: used to maintain static simObjectList +// +SimObject::SimObject(const string &_name) + : _params(new Params) +{ + _params->name = _name; +#ifdef DEBUG + doDebugBreak = false; +#endif + + doRecordEvent = !Stats::event_ignore.match(name()); + simObjectList.push_back(this); +} + +void +SimObject::connect() +{ +} + +void +SimObject::init() +{ +} + +// +// no default statistics, so nothing to do in base implementation +// +void +SimObject::regStats() +{ +} + +void +SimObject::regFormulas() +{ +} + +void +SimObject::resetStats() +{ +} + +// +// static function: +// call regStats() on all SimObjects and then regFormulas() on all +// SimObjects. +// +struct SimObjectResetCB : public Callback +{ + virtual void process() { SimObject::resetAllStats(); } +}; + +namespace { + static SimObjectResetCB StatResetCB; +} + +void +SimObject::regAllStats() +{ + SimObjectList::iterator i; + SimObjectList::iterator end = simObjectList.end(); + + /** + * @todo change cprintfs to DPRINTFs + */ + for (i = simObjectList.begin(); i != end; ++i) { +#ifdef STAT_DEBUG + cprintf("registering stats for %s\n", (*i)->name()); +#endif + (*i)->regStats(); + } + + for (i = simObjectList.begin(); i != end; ++i) { +#ifdef STAT_DEBUG + cprintf("registering formulas for %s\n", (*i)->name()); +#endif + (*i)->regFormulas(); + } + + Stats::registerResetCallback(&StatResetCB); +} + +// +// static function: call connect() on all SimObjects. +// +void +SimObject::connectAll() +{ + SimObjectList::iterator i = simObjectList.begin(); + SimObjectList::iterator end = simObjectList.end(); + + for (; i != end; ++i) { + SimObject *obj = *i; + obj->connect(); + } +} + +// +// static function: call init() on all SimObjects. +// +void +SimObject::initAll() +{ + SimObjectList::iterator i = simObjectList.begin(); + SimObjectList::iterator end = simObjectList.end(); + + for (; i != end; ++i) { + SimObject *obj = *i; + obj->init(); + } +} + +// +// static function: call resetStats() on all SimObjects. +// +void +SimObject::resetAllStats() +{ + SimObjectList::iterator i = simObjectList.begin(); + SimObjectList::iterator end = simObjectList.end(); + + for (; i != end; ++i) { + SimObject *obj = *i; + obj->resetStats(); + } +} + +// +// static function: serialize all SimObjects. +// +void +SimObject::serializeAll(ostream &os) +{ + SimObjectList::reverse_iterator ri = simObjectList.rbegin(); + SimObjectList::reverse_iterator rend = simObjectList.rend(); + + for (; ri != rend; ++ri) { + SimObject *obj = *ri; + obj->nameOut(os); + obj->serialize(os); + } +} + +#ifdef DEBUG +// +// static function: flag which objects should have the debugger break +// +void +SimObject::debugObjectBreak(const string &objs) +{ + SimObjectList::const_iterator i = simObjectList.begin(); + SimObjectList::const_iterator end = simObjectList.end(); + + ObjectMatch match(objs); + for (; i != end; ++i) { + SimObject *obj = *i; + obj->doDebugBreak = match.match(obj->name()); + } +} + +extern "C" +void +debugObjectBreak(const char *objs) +{ + SimObject::debugObjectBreak(string(objs)); +} +#endif + +void +SimObject::recordEvent(const std::string &stat) +{ + if (doRecordEvent) + Stats::recordEvent(stat); +} + +void +SimObject::drain(Serializer *serializer) +{ + serializer->signalDrained(); +} + +DEFINE_SIM_OBJECT_CLASS_NAME("SimObject", SimObject) diff --git a/src/sim/sim_object.hh b/src/sim/sim_object.hh new file mode 100644 index 000000000..76aba7ea1 --- /dev/null +++ b/src/sim/sim_object.hh @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * 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. + */ + +/* @file + * User Console Definitions + */ + +#ifndef __SIM_OBJECT_HH__ +#define __SIM_OBJECT_HH__ + +#include <map> +#include <list> +#include <vector> +#include <iostream> + +#include "sim/serialize.hh" +#include "sim/startup.hh" + +class Serializer; + +/* + * Abstract superclass for simulation objects. Represents things that + * correspond to physical components and can be specified via the + * config file (CPUs, caches, etc.). + */ +class SimObject : public Serializable, protected StartupCallback +{ + public: + struct Params { + std::string name; + }; + + protected: + Params *_params; + + public: + const Params *params() const { return _params; } + + private: + friend class Serializer; + + typedef std::vector<SimObject *> SimObjectList; + + // list of all instantiated simulation objects + static SimObjectList simObjectList; + + public: + SimObject(Params *_params); + SimObject(const std::string &_name); + + virtual ~SimObject() {} + + virtual const std::string name() const { return params()->name; } + + // initialization pass of all objects. + // Gets invoked after construction, before unserialize. + virtual void init(); + virtual void connect(); + static void initAll(); + static void connectAll(); + + // register statistics for this object + virtual void regStats(); + virtual void regFormulas(); + virtual void resetStats(); + + // static: call reg_stats on all SimObjects + static void regAllStats(); + + // static: call resetStats on all SimObjects + static void resetAllStats(); + + // static: call nameOut() & serialize() on all SimObjects + static void serializeAll(std::ostream &); + + // Methods to drain objects in order to take checkpoints + // Or switch from timing -> atomic memory model + virtual void drain(Serializer *serializer); + virtual void resume() { return;} ; + virtual void serializationComplete() + { assert(0 && "Unimplemented"); }; + +#ifdef DEBUG + public: + bool doDebugBreak; + static void debugObjectBreak(const std::string &objs); +#endif + + public: + bool doRecordEvent; + void recordEvent(const std::string &stat); +}; + +#endif // __SIM_OBJECT_HH__ diff --git a/src/sim/startup.cc b/src/sim/startup.cc new file mode 100644 index 000000000..683e6c746 --- /dev/null +++ b/src/sim/startup.cc @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * 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. + */ + +#include <list> + +#include "base/misc.hh" +#include "sim/debug.hh" +#include "sim/startup.hh" + +typedef std::list<StartupCallback *> startupq_t; + +startupq_t *startupq = NULL; + +StartupCallback::StartupCallback() +{ + if (startupq == NULL) + startupq = new startupq_t; + startupq->push_back(this); +} + +StartupCallback::~StartupCallback() +{ + startupq->remove(this); +} + +void StartupCallback::startup() { } + +void +SimStartup() +{ + startupq_t::iterator i = startupq->begin(); + startupq_t::iterator end = startupq->end(); + + while (i != end) { + (*i)->startup(); + ++i; + } +} diff --git a/src/sim/startup.hh b/src/sim/startup.hh new file mode 100644 index 000000000..3c9b654f1 --- /dev/null +++ b/src/sim/startup.hh @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * 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. + */ + +#ifndef __SIM_STARTUP_HH__ +#define __SIM_STARTUP_HH__ + +struct StartupCallback +{ + StartupCallback(); + virtual ~StartupCallback(); + virtual void startup(); +}; + +void SimStartup(); + +#endif // __SIM_STARTUP_HH__ diff --git a/src/sim/stat_control.cc b/src/sim/stat_control.cc new file mode 100644 index 000000000..85c405b7f --- /dev/null +++ b/src/sim/stat_control.cc @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * 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. + */ + +// This file will contain default statistics for the simulator that +// don't really belong to a specific simulator object + +#include <fstream> +#include <iostream> +#include <list> + +#include "base/callback.hh" +#include "base/hostinfo.hh" +#include "base/statistics.hh" +#include "base/str.hh" +#include "base/time.hh" +#include "base/stats/output.hh" +#include "cpu/base.hh" +#include "sim/eventq.hh" +#include "sim/sim_object.hh" +#include "sim/stat_control.hh" +#include "sim/root.hh" + +using namespace std; + +Stats::Formula hostInstRate; +Stats::Formula hostTickRate; +Stats::Value hostMemory; +Stats::Value hostSeconds; + +Stats::Value simTicks; +Stats::Value simInsts; +Stats::Value simFreq; +Stats::Formula simSeconds; + +namespace Stats { + +Time statTime(true); +Tick startTick; +Tick lastDump(0); + +class SimTicksReset : public Callback +{ + public: + void process() + { + statTime.set(); + startTick = curTick; + } +}; + +double +statElapsedTime() +{ + Time now(true); + Time elapsed = now - statTime; + return elapsed(); +} + +Tick +statElapsedTicks() +{ + return curTick - startTick; +} + +SimTicksReset simTicksReset; + +void +InitSimStats() +{ + simInsts + .functor(BaseCPU::numSimulatedInstructions) + .name("sim_insts") + .desc("Number of instructions simulated") + .precision(0) + .prereq(simInsts) + ; + + simSeconds + .name("sim_seconds") + .desc("Number of seconds simulated") + ; + + simFreq + .scalar(Clock::Frequency) + .name("sim_freq") + .desc("Frequency of simulated ticks") + ; + + simTicks + .functor(statElapsedTicks) + .name("sim_ticks") + .desc("Number of ticks simulated") + ; + + hostInstRate + .name("host_inst_rate") + .desc("Simulator instruction rate (inst/s)") + .precision(0) + .prereq(simInsts) + ; + + hostMemory + .functor(memUsage) + .name("host_mem_usage") + .desc("Number of bytes of host memory used") + .prereq(hostMemory) + ; + + hostSeconds + .functor(statElapsedTime) + .name("host_seconds") + .desc("Real time elapsed on the host") + .precision(2) + ; + + hostTickRate + .name("host_tick_rate") + .desc("Simulator tick rate (ticks/s)") + .precision(0) + ; + + simSeconds = simTicks / simFreq; + hostInstRate = simInsts / hostSeconds; + hostTickRate = simTicks / hostSeconds; + + registerResetCallback(&simTicksReset); +} + +class StatEvent : public Event +{ + protected: + int flags; + Tick repeat; + + public: + StatEvent(int _flags, Tick _when, Tick _repeat); + virtual void process(); + virtual const char *description(); +}; + +StatEvent::StatEvent(int _flags, Tick _when, Tick _repeat) + : Event(&mainEventQueue, Stat_Event_Pri), + flags(_flags), repeat(_repeat) +{ + setFlags(AutoDelete); + schedule(_when); +} + +const char * +StatEvent::description() +{ + return "Statistics dump and/or reset"; +} + +void +StatEvent::process() +{ + if (flags & Stats::Dump) + DumpNow(); + + if (flags & Stats::Reset) + reset(); + + if (repeat) + schedule(curTick + repeat); +} + +list<Output *> OutputList; + +void +DumpNow() +{ + assert(lastDump <= curTick); + if (lastDump == curTick) + return; + lastDump = curTick; + + list<Output *>::iterator i = OutputList.begin(); + list<Output *>::iterator end = OutputList.end(); + for (; i != end; ++i) { + Output *output = *i; + if (!output->valid()) + continue; + + output->output(); + } +} + +void +SetupEvent(int flags, Tick when, Tick repeat) +{ + new StatEvent(flags, when, repeat); +} + +/* namespace Stats */ } + +extern "C" void +debugDumpStats() +{ + Stats::DumpNow(); +} + diff --git a/src/sim/stat_control.hh b/src/sim/stat_control.hh new file mode 100644 index 000000000..a22ce76af --- /dev/null +++ b/src/sim/stat_control.hh @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * 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. + */ + +#ifndef __SIM_STAT_CONTROL_HH__ +#define __SIM_STAT_CONTROL_HH__ + +#include <fstream> +#include <list> + +namespace Stats { + +enum { + Reset = 0x1, + Dump = 0x2 +}; + +class Output; +extern std::list<Output *> OutputList; + +void DumpNow(); +void SetupEvent(int flags, Tick when, Tick repeat = 0); + +void InitSimStats(); + +/* namespace Stats */ } + +#endif // __SIM_STAT_CONTROL_HH__ diff --git a/src/sim/stats.hh b/src/sim/stats.hh new file mode 100644 index 000000000..8e97d041f --- /dev/null +++ b/src/sim/stats.hh @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * 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. + */ + +#ifndef __SIM_STATS_HH__ +#define __SIM_STATS_HH__ + +#include "base/statistics.hh" + +extern Stats::Formula simSeconds; +extern Stats::Value simTicks; + +#endif // __SIM_SIM_STATS_HH__ diff --git a/src/sim/syscall_emul.cc b/src/sim/syscall_emul.cc new file mode 100644 index 000000000..ed0da628e --- /dev/null +++ b/src/sim/syscall_emul.cc @@ -0,0 +1,454 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * 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. + */ + +#include <fcntl.h> +#include <unistd.h> + +#include <string> +#include <iostream> + +#include "sim/syscall_emul.hh" +#include "base/chunk_generator.hh" +#include "base/trace.hh" +#include "cpu/exec_context.hh" +#include "cpu/base.hh" +#include "mem/page_table.hh" +#include "sim/process.hh" + +#include "sim/sim_events.hh" + +using namespace std; +using namespace TheISA; + +void +SyscallDesc::doSyscall(int callnum, Process *process, ExecContext *xc) +{ + DPRINTFR(SyscallVerbose, "%d: %s: syscall %s called w/arguments %d,%d,%d,%d\n", + curTick,xc->getCpuPtr()->name(), name, + xc->getSyscallArg(0),xc->getSyscallArg(1), + xc->getSyscallArg(2),xc->getSyscallArg(3)); + + SyscallReturn retval = (*funcPtr)(this, callnum, process, xc); + + DPRINTFR(SyscallVerbose, "%d: %s: syscall %s returns %d\n", + curTick,xc->getCpuPtr()->name(), name, retval.value()); + + if (!(flags & SyscallDesc::SuppressReturnValue)) + xc->setSyscallReturn(retval); +} + + +SyscallReturn +unimplementedFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + fatal("syscall %s (#%d) unimplemented.", desc->name, callnum); + + return 1; +} + + +SyscallReturn +ignoreFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + warn("ignoring syscall %s(%d, %d, ...)", desc->name, + xc->getSyscallArg(0), xc->getSyscallArg(1)); + + return 0; +} + + +SyscallReturn +exitFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + new SimExitEvent("target called exit()", xc->getSyscallArg(0) & 0xff); + + return 1; +} + + +SyscallReturn +getpagesizeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) +{ + return (int)VMPageSize; +} + + +SyscallReturn +obreakFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) +{ + Addr junk; + + // change brk addr to first arg + Addr new_brk = xc->getSyscallArg(0); + if (new_brk != 0) { + for (ChunkGenerator gen(p->brk_point, new_brk - p->brk_point, + VMPageSize); !gen.done(); gen.next()) { + if (!p->pTable->translate(gen.addr(), junk)) + p->pTable->allocate(roundDown(gen.addr(), VMPageSize), + VMPageSize); + } + p->brk_point = new_brk; + } + DPRINTF(SyscallVerbose, "Break Point changed to: %#X\n", p->brk_point); + return p->brk_point; +} + + +SyscallReturn +closeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) +{ + int target_fd = xc->getSyscallArg(0); + int status = close(p->sim_fd(target_fd)); + if (status >= 0) + p->free_fd(target_fd); + return status; +} + + +SyscallReturn +readFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) +{ + int fd = p->sim_fd(xc->getSyscallArg(0)); + int nbytes = xc->getSyscallArg(2); + BufferArg bufArg(xc->getSyscallArg(1), nbytes); + + int bytes_read = read(fd, bufArg.bufferPtr(), nbytes); + + if (bytes_read != -1) + bufArg.copyOut(xc->getMemPort()); + + return bytes_read; +} + +SyscallReturn +writeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) +{ + int fd = p->sim_fd(xc->getSyscallArg(0)); + int nbytes = xc->getSyscallArg(2); + BufferArg bufArg(xc->getSyscallArg(1), nbytes); + + bufArg.copyIn(xc->getMemPort()); + + int bytes_written = write(fd, bufArg.bufferPtr(), nbytes); + + fsync(fd); + + return bytes_written; +} + + +SyscallReturn +lseekFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) +{ + int fd = p->sim_fd(xc->getSyscallArg(0)); + uint64_t offs = xc->getSyscallArg(1); + int whence = xc->getSyscallArg(2); + + off_t result = lseek(fd, offs, whence); + + return (result == (off_t)-1) ? -errno : result; +} + + +SyscallReturn +munmapFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) +{ + // given that we don't really implement mmap, munmap is really easy + return 0; +} + + +const char *hostname = "m5.eecs.umich.edu"; + +SyscallReturn +gethostnameFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) +{ + int name_len = xc->getSyscallArg(1); + BufferArg name(xc->getSyscallArg(0), name_len); + + strncpy((char *)name.bufferPtr(), hostname, name_len); + + name.copyOut(xc->getMemPort()); + + return 0; +} + +SyscallReturn +unlinkFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) +{ + string path; + + if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0))) + return (TheISA::IntReg)-EFAULT; + + int result = unlink(path.c_str()); + return (result == -1) ? -errno : result; +} + +SyscallReturn +renameFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) +{ + string old_name; + + if (!xc->getMemPort()->tryReadString(old_name, xc->getSyscallArg(0))) + return -EFAULT; + + string new_name; + + if (!xc->getMemPort()->tryReadString(new_name, xc->getSyscallArg(1))) + return -EFAULT; + + int64_t result = rename(old_name.c_str(), new_name.c_str()); + return (result == -1) ? -errno : result; +} + +SyscallReturn +truncateFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) +{ + string path; + + if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0))) + return -EFAULT; + + off_t length = xc->getSyscallArg(1); + + int result = truncate(path.c_str(), length); + return (result == -1) ? -errno : result; +} + +SyscallReturn +ftruncateFunc(SyscallDesc *desc, int num, Process *process, ExecContext *xc) +{ + int fd = process->sim_fd(xc->getSyscallArg(0)); + + if (fd < 0) + return -EBADF; + + off_t length = xc->getSyscallArg(1); + + int result = ftruncate(fd, length); + return (result == -1) ? -errno : result; +} + +SyscallReturn +chownFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) +{ + string path; + + if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0))) + return -EFAULT; + + /* XXX endianess */ + uint32_t owner = xc->getSyscallArg(1); + uid_t hostOwner = owner; + uint32_t group = xc->getSyscallArg(2); + gid_t hostGroup = group; + + int result = chown(path.c_str(), hostOwner, hostGroup); + return (result == -1) ? -errno : result; +} + +SyscallReturn +fchownFunc(SyscallDesc *desc, int num, Process *process, ExecContext *xc) +{ + int fd = process->sim_fd(xc->getSyscallArg(0)); + + if (fd < 0) + return -EBADF; + + /* XXX endianess */ + uint32_t owner = xc->getSyscallArg(1); + uid_t hostOwner = owner; + uint32_t group = xc->getSyscallArg(2); + gid_t hostGroup = group; + + int result = fchown(fd, hostOwner, hostGroup); + return (result == -1) ? -errno : result; +} + + +SyscallReturn +fcntlFunc(SyscallDesc *desc, int num, Process *process, + ExecContext *xc) +{ + int fd = xc->getSyscallArg(0); + + if (fd < 0 || process->sim_fd(fd) < 0) + return -EBADF; + + int cmd = xc->getSyscallArg(1); + switch (cmd) { + case 0: // F_DUPFD + // if we really wanted to support this, we'd need to do it + // in the target fd space. + warn("fcntl(%d, F_DUPFD) not supported, error returned\n", fd); + return -EMFILE; + + case 1: // F_GETFD (get close-on-exec flag) + case 2: // F_SETFD (set close-on-exec flag) + return 0; + + case 3: // F_GETFL (get file flags) + case 4: // F_SETFL (set file flags) + // not sure if this is totally valid, but we'll pass it through + // to the underlying OS + warn("fcntl(%d, %d) passed through to host\n", fd, cmd); + return fcntl(process->sim_fd(fd), cmd); + // return 0; + + case 7: // F_GETLK (get lock) + case 8: // F_SETLK (set lock) + case 9: // F_SETLKW (set lock and wait) + // don't mess with file locking... just act like it's OK + warn("File lock call (fcntl(%d, %d)) ignored.\n", fd, cmd); + return 0; + + default: + warn("Unknown fcntl command %d\n", cmd); + return 0; + } +} + +SyscallReturn +pipePseudoFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + int fds[2], sim_fds[2]; + int pipe_retval = pipe(fds); + + if (pipe_retval < 0) { + // error + return pipe_retval; + } + + sim_fds[0] = process->alloc_fd(fds[0]); + sim_fds[1] = process->alloc_fd(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. + xc->setIntReg(SyscallPseudoReturnReg, sim_fds[1]); + return sim_fds[0]; +} + + +SyscallReturn +getpidPseudoFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + // Make up a PID. There's no interprocess communication in + // fake_syscall mode, so there's no way for a process to know it's + // not getting a unique value. + + xc->setIntReg(SyscallPseudoReturnReg, 99); + return 100; +} + + +SyscallReturn +getuidPseudoFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + // Make up a UID and EUID... it shouldn't matter, and we want the + // simulation to be deterministic. + + // EUID goes in r20. + xc->setIntReg(SyscallPseudoReturnReg, 100); //EUID + return 100; // UID +} + + +SyscallReturn +getgidPseudoFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + // Get current group ID. EGID goes in r20. + xc->setIntReg(SyscallPseudoReturnReg, 100); //EGID + return 100; +} + + +SyscallReturn +setuidFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + // can't fathom why a benchmark would call this. + warn("Ignoring call to setuid(%d)\n", xc->getSyscallArg(0)); + return 0; +} + +SyscallReturn +getpidFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + // Make up a PID. There's no interprocess communication in + // fake_syscall mode, so there's no way for a process to know it's + // not getting a unique value. + + xc->setIntReg(SyscallPseudoReturnReg, 99); //PID + return 100; +} + +SyscallReturn +getppidFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + return 99; +} + +SyscallReturn +getuidFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + return 100; // UID +} + +SyscallReturn +geteuidFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + return 100; // UID +} + +SyscallReturn +getgidFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + return 100; +} + +SyscallReturn +getegidFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + return 100; +} + + diff --git a/src/sim/syscall_emul.hh b/src/sim/syscall_emul.hh new file mode 100644 index 000000000..00f016410 --- /dev/null +++ b/src/sim/syscall_emul.hh @@ -0,0 +1,849 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * 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. + */ + +#ifndef __SIM_SYSCALL_EMUL_HH__ +#define __SIM_SYSCALL_EMUL_HH__ + +#define BSD_HOST (defined(__APPLE__) || defined(__OpenBSD__) || \ + defined(__FreeBSD__)) + +/// +/// @file syscall_emul.hh +/// +/// This file defines objects used to emulate syscalls from the target +/// application on the host machine. + +#include <errno.h> +#include <string> +#ifdef __CYGWIN32__ +#include <sys/fcntl.h> // for O_BINARY +#endif +#include <sys/uio.h> + +#include "arch/isa_traits.hh" // for Addr +#include "base/chunk_generator.hh" +#include "base/intmath.hh" // for RoundUp +#include "base/misc.hh" +#include "base/trace.hh" +#include "cpu/base.hh" +#include "cpu/exec_context.hh" +#include "mem/translating_port.hh" +#include "mem/page_table.hh" +#include "sim/process.hh" + +/// +/// System call descriptor. +/// +class SyscallDesc { + + public: + + /// Typedef for target syscall handler functions. + typedef SyscallReturn (*FuncPtr)(SyscallDesc *, int num, + Process *, ExecContext *); + + const char *name; //!< Syscall name (e.g., "open"). + FuncPtr funcPtr; //!< Pointer to emulation function. + int flags; //!< Flags (see Flags enum). + + /// Flag values for controlling syscall behavior. + enum Flags { + /// Don't set return regs according to funcPtr return value. + /// Used for syscalls with non-standard return conventions + /// that explicitly set the ExecContext regs (e.g., + /// sigreturn). + SuppressReturnValue = 1 + }; + + /// Constructor. + SyscallDesc(const char *_name, FuncPtr _funcPtr, int _flags = 0) + : name(_name), funcPtr(_funcPtr), flags(_flags) + { + } + + /// Emulate the syscall. Public interface for calling through funcPtr. + void doSyscall(int callnum, Process *proc, ExecContext *xc); +}; + + +class BaseBufferArg { + + public: + + BaseBufferArg(Addr _addr, int _size) : addr(_addr), size(_size) + { + bufPtr = new uint8_t[size]; + // clear out buffer: in case we only partially populate this, + // and then do a copyOut(), we want to make sure we don't + // introduce any random junk into the simulated address space + memset(bufPtr, 0, size); + } + + virtual ~BaseBufferArg() { delete [] bufPtr; } + + // + // copy data into simulator space (read from target memory) + // + virtual bool copyIn(TranslatingPort *memport) + { + memport->readBlob(addr, bufPtr, size); + return true; // no EFAULT detection for now + } + + // + // copy data out of simulator space (write to target memory) + // + virtual bool copyOut(TranslatingPort *memport) + { + memport->writeBlob(addr, bufPtr, size); + return true; // no EFAULT detection for now + } + + protected: + Addr addr; + int size; + uint8_t *bufPtr; +}; + + +class BufferArg : public BaseBufferArg +{ + public: + BufferArg(Addr _addr, int _size) : BaseBufferArg(_addr, _size) { } + void *bufferPtr() { return bufPtr; } +}; + +template <class T> +class TypedBufferArg : public BaseBufferArg +{ + public: + // user can optionally specify a specific number of bytes to + // allocate to deal with those structs that have variable-size + // arrays at the end + TypedBufferArg(Addr _addr, int _size = sizeof(T)) + : BaseBufferArg(_addr, _size) + { } + + // type case + operator T*() { return (T *)bufPtr; } + + // dereference operators + T &operator*() { return *((T *)bufPtr); } + T* operator->() { return (T *)bufPtr; } + T &operator[](int i) { return ((T *)bufPtr)[i]; } +}; + +////////////////////////////////////////////////////////////////////// +// +// The following emulation functions are generic enough that they +// don't need to be recompiled for different emulated OS's. They are +// defined in sim/syscall_emul.cc. +// +////////////////////////////////////////////////////////////////////// + + +/// Handler for unimplemented syscalls that we haven't thought about. +SyscallReturn unimplementedFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + +/// Handler for unimplemented syscalls that we never intend to +/// implement (signal handling, etc.) and should not affect the correct +/// behavior of the program. Print a warning only if the appropriate +/// trace flag is enabled. Return success to the target program. +SyscallReturn ignoreFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + +/// Target exit() handler: terminate simulation. +SyscallReturn exitFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + +/// Target getpagesize() handler. +SyscallReturn getpagesizeFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + +/// Target obreak() handler: set brk address. +SyscallReturn obreakFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + +/// Target close() handler. +SyscallReturn closeFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + +/// Target read() handler. +SyscallReturn readFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + +/// Target write() handler. +SyscallReturn writeFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + +/// Target lseek() handler. +SyscallReturn lseekFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + +/// Target munmap() handler. +SyscallReturn munmapFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + +/// Target gethostname() handler. +SyscallReturn gethostnameFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + +/// Target unlink() handler. +SyscallReturn unlinkFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + +/// Target rename() handler. +SyscallReturn renameFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + + +/// Target truncate() handler. +SyscallReturn truncateFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + + +/// Target ftruncate() handler. +SyscallReturn ftruncateFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + + +/// Target chown() handler. +SyscallReturn chownFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + + +/// Target fchown() handler. +SyscallReturn fchownFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + +/// Target fnctl() handler. +SyscallReturn fcntlFunc(SyscallDesc *desc, int num, + Process *process, ExecContext *xc); + +/// Target setuid() handler. +SyscallReturn setuidFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + +/// Target getpid() handler. +SyscallReturn getpidFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + +/// Target getuid() handler. +SyscallReturn getuidFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + +/// Target getgid() handler. +SyscallReturn getgidFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + +/// Target getppid() handler. +SyscallReturn getppidFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + +/// Target geteuid() handler. +SyscallReturn geteuidFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + +/// Target getegid() handler. +SyscallReturn getegidFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + + + +/// Pseudo Funcs - These functions use a different return convension, +/// returning a second value in a register other than the normal return register +SyscallReturn pipePseudoFunc(SyscallDesc *desc, int num, + Process *process, ExecContext *xc); + +/// Target getpidPseudo() handler. +SyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + +/// Target getuidPseudo() handler. +SyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + +/// Target getgidPseudo() handler. +SyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num, + Process *p, ExecContext *xc); + + +/// This struct is used to build an target-OS-dependent table that +/// maps the target's open() flags to the host open() flags. +struct OpenFlagTransTable { + int tgtFlag; //!< Target system flag value. + int hostFlag; //!< Corresponding host system flag value. +}; + + + +/// A readable name for 1,000,000, for converting microseconds to seconds. +const int one_million = 1000000; + +/// Approximate seconds since the epoch (1/1/1970). About a billion, +/// by my reckoning. We want to keep this a constant (not use the +/// real-world time) to keep simulations repeatable. +const unsigned seconds_since_epoch = 1000000000; + +/// Helper function to convert current elapsed time to seconds and +/// microseconds. +template <class T1, class T2> +void +getElapsedTime(T1 &sec, T2 &usec) +{ + int elapsed_usecs = curTick / Clock::Int::us; + sec = elapsed_usecs / one_million; + usec = elapsed_usecs % one_million; +} + +////////////////////////////////////////////////////////////////////// +// +// The following emulation functions are generic, but need to be +// templated to account for differences in types, constants, etc. +// +////////////////////////////////////////////////////////////////////// + +/// Target ioctl() handler. For the most part, programs call ioctl() +/// only to find out if their stdout is a tty, to determine whether to +/// do line or block buffering. +template <class OS> +SyscallReturn +ioctlFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + int fd = xc->getSyscallArg(0); + unsigned req = xc->getSyscallArg(1); + + DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", fd, req); + + if (fd < 0 || process->sim_fd(fd) < 0) { + // doesn't map to any simulator fd: not a valid target fd + return -EBADF; + } + + switch (req) { + case OS::TIOCISATTY: + case OS::TIOCGETP: + case OS::TIOCSETP: + case OS::TIOCSETN: + case OS::TIOCSETC: + case OS::TIOCGETC: + case OS::TIOCGETS: + case OS::TIOCGETA: + return -ENOTTY; + + default: + fatal("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ 0x%llx\n", + fd, req, xc->readPC()); + } +} + +/// Target open() handler. +template <class OS> +SyscallReturn +openFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + std::string path; + + if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0))) + 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 = xc->getSyscallArg(1); + int mode = xc->getSyscallArg(2); + int hostFlags = 0; + + // translate open flags + 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; + } + } + + // any target flags left? + if (tgtFlags != 0) + warn("Syscall: open: cannot decode flags 0x%x", tgtFlags); + +#ifdef __CYGWIN32__ + hostFlags |= O_BINARY; +#endif + + DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str()); + + // open the file + int fd = open(path.c_str(), hostFlags, mode); + + return (fd == -1) ? -errno : process->alloc_fd(fd); +} + + +/// Target chmod() handler. +template <class OS> +SyscallReturn +chmodFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + std::string path; + + if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0))) + return -EFAULT; + + uint32_t mode = xc->getSyscallArg(1); + mode_t hostMode = 0; + + // XXX translate mode flags via OS::something??? + hostMode = mode; + + // do the chmod + int result = chmod(path.c_str(), hostMode); + if (result < 0) + return -errno; + + return 0; +} + + +/// Target fchmod() handler. +template <class OS> +SyscallReturn +fchmodFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + int fd = xc->getSyscallArg(0); + if (fd < 0 || process->sim_fd(fd) < 0) { + // doesn't map to any simulator fd: not a valid target fd + return -EBADF; + } + + uint32_t mode = xc->getSyscallArg(1); + mode_t hostMode = 0; + + // XXX translate mode flags via OS::someting??? + hostMode = mode; + + // do the fchmod + int result = fchmod(process->sim_fd(fd), hostMode); + if (result < 0) + return -errno; + + return 0; +} + + +/// Target stat() handler. +template <class OS> +SyscallReturn +statFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + std::string path; + + if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0))) + return -EFAULT; + + struct stat hostBuf; + int result = stat(path.c_str(), &hostBuf); + + if (result < 0) + return -errno; + + OS::copyOutStatBuf(xc->getMemPort(), xc->getSyscallArg(1), &hostBuf); + + return 0; +} + + +/// Target fstat64() handler. +template <class OS> +SyscallReturn +fstat64Func(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + int fd = xc->getSyscallArg(0); + if (fd < 0 || process->sim_fd(fd) < 0) { + // doesn't map to any simulator fd: not a valid target fd + return -EBADF; + } + +#if BSD_HOST + struct stat hostBuf; + int result = fstat(process->sim_fd(fd), &hostBuf); +#else + struct stat64 hostBuf; + int result = fstat64(process->sim_fd(fd), &hostBuf); +#endif + + if (result < 0) + return -errno; + + OS::copyOutStat64Buf(xc->getMemPort(), fd, xc->getSyscallArg(1), &hostBuf); + + return 0; +} + + +/// Target lstat() handler. +template <class OS> +SyscallReturn +lstatFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + std::string path; + + if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0))) + return -EFAULT; + + struct stat hostBuf; + int result = lstat(path.c_str(), &hostBuf); + + if (result < 0) + return -errno; + + OS::copyOutStatBuf(xc->getMemPort(), xc->getSyscallArg(1), &hostBuf); + + return 0; +} + +/// Target lstat64() handler. +template <class OS> +SyscallReturn +lstat64Func(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + std::string path; + + if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0))) + return -EFAULT; + +#if BSD_HOST + struct stat hostBuf; + int result = lstat(path.c_str(), &hostBuf); +#else + struct stat64 hostBuf; + int result = lstat64(path.c_str(), &hostBuf); +#endif + + if (result < 0) + return -errno; + + OS::copyOutStat64Buf(xc->getMemPort(), -1, xc->getSyscallArg(1), &hostBuf); + + return 0; +} + +/// Target fstat() handler. +template <class OS> +SyscallReturn +fstatFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + int fd = process->sim_fd(xc->getSyscallArg(0)); + + DPRINTF(SyscallVerbose, "fstat(%d, ...)\n", fd); + + if (fd < 0) + return -EBADF; + + struct stat hostBuf; + int result = fstat(fd, &hostBuf); + + if (result < 0) + return -errno; + + OS::copyOutStatBuf(xc->getMemPort(), xc->getSyscallArg(1), &hostBuf); + + return 0; +} + + +/// Target statfs() handler. +template <class OS> +SyscallReturn +statfsFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + std::string path; + + if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0))) + return -EFAULT; + + struct statfs hostBuf; + int result = statfs(path.c_str(), &hostBuf); + + if (result < 0) + return -errno; + + OS::copyOutStatfsBuf(xc->getMemPort(), xc->getSyscallArg(1), &hostBuf); + + return 0; +} + + +/// Target fstatfs() handler. +template <class OS> +SyscallReturn +fstatfsFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + int fd = process->sim_fd(xc->getSyscallArg(0)); + + if (fd < 0) + return -EBADF; + + struct statfs hostBuf; + int result = fstatfs(fd, &hostBuf); + + if (result < 0) + return -errno; + + OS::copyOutStatfsBuf(xc->getMemPort(), xc->getSyscallArg(1), &hostBuf); + + return 0; +} + + +/// Target writev() handler. +template <class OS> +SyscallReturn +writevFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + int fd = xc->getSyscallArg(0); + if (fd < 0 || process->sim_fd(fd) < 0) { + // doesn't map to any simulator fd: not a valid target fd + return -EBADF; + } + + TranslatingPort *p = xc->getMemPort(); + uint64_t tiov_base = xc->getSyscallArg(1); + size_t count = xc->getSyscallArg(2); + struct iovec hiov[count]; + for (int 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)); + hiov[i].iov_len = gtoh(tiov.iov_len); + hiov[i].iov_base = new char [hiov[i].iov_len]; + p->readBlob(gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base, + hiov[i].iov_len); + } + + int result = writev(process->sim_fd(fd), hiov, count); + + for (int i = 0; i < count; ++i) + { + delete [] (char *)hiov[i].iov_base; + } + + if (result < 0) + return -errno; + + return 0; +} + + +/// Target mmap() handler. +/// +/// We don't really handle mmap(). If the target is mmaping an +/// anonymous region or /dev/zero, we can get away with doing basically +/// nothing (since memory is initialized to zero and the simulator +/// doesn't really check addresses anyway). Always print a warning, +/// since this could be seriously broken if we're not mapping +/// /dev/zero. +// +/// Someday we should explicitly check for /dev/zero in open, flag the +/// file descriptor, and fail (or implement!) a non-anonymous mmap to +/// anything else. +template <class OS> +SyscallReturn +mmapFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) +{ + Addr start = xc->getSyscallArg(0); + uint64_t length = xc->getSyscallArg(1); + // int prot = xc->getSyscallArg(2); + int flags = xc->getSyscallArg(3); + // int fd = p->sim_fd(xc->getSyscallArg(4)); + // int offset = xc->getSyscallArg(5); + + if ((start % TheISA::VMPageSize) != 0 || + (length % TheISA::VMPageSize) != 0) { + warn("mmap failing: arguments not page-aligned: " + "start 0x%x length 0x%x", + start, length); + return -EINVAL; + } + + if (start != 0) { + warn("mmap: ignoring suggested map address 0x%x, using 0x%x", + start, p->mmap_end); + } + + // pick next address from our "mmap region" + start = p->mmap_end; + p->pTable->allocate(start, length); + p->mmap_end += length; + + if (!(flags & OS::TGT_MAP_ANONYMOUS)) { + warn("allowing mmap of file @ fd %d. " + "This will break if not /dev/zero.", xc->getSyscallArg(4)); + } + + return start; +} + +/// Target getrlimit() handler. +template <class OS> +SyscallReturn +getrlimitFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + unsigned resource = xc->getSyscallArg(0); + TypedBufferArg<typename OS::rlimit> rlp(xc->getSyscallArg(1)); + + switch (resource) { + case OS::TGT_RLIMIT_STACK: + // max stack size in bytes: make up a number (2MB for now) + rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; + rlp->rlim_cur = htog(rlp->rlim_cur); + rlp->rlim_max = htog(rlp->rlim_max); + break; + + default: + std::cerr << "getrlimitFunc: unimplemented resource " << resource + << std::endl; + abort(); + break; + } + + rlp.copyOut(xc->getMemPort()); + return 0; +} + +/// Target gettimeofday() handler. +template <class OS> +SyscallReturn +gettimeofdayFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + TypedBufferArg<typename OS::timeval> tp(xc->getSyscallArg(0)); + + getElapsedTime(tp->tv_sec, tp->tv_usec); + tp->tv_sec += seconds_since_epoch; + tp->tv_sec = htog(tp->tv_sec); + tp->tv_usec = htog(tp->tv_usec); + + tp.copyOut(xc->getMemPort()); + + return 0; +} + + +/// Target utimes() handler. +template <class OS> +SyscallReturn +utimesFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + std::string path; + + if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0))) + return -EFAULT; + + TypedBufferArg<typename OS::timeval [2]> tp(xc->getSyscallArg(1)); + tp.copyIn(xc->getMemPort()); + + struct timeval hostTimeval[2]; + for (int i = 0; i < 2; ++i) + { + hostTimeval[i].tv_sec = gtoh((*tp)[i].tv_sec); + hostTimeval[i].tv_usec = gtoh((*tp)[i].tv_usec); + } + int result = utimes(path.c_str(), hostTimeval); + + if (result < 0) + return -errno; + + return 0; +} +/// Target getrusage() function. +template <class OS> +SyscallReturn +getrusageFunc(SyscallDesc *desc, int callnum, Process *process, + ExecContext *xc) +{ + int who = xc->getSyscallArg(0); // THREAD, SELF, or CHILDREN + TypedBufferArg<typename OS::rusage> rup(xc->getSyscallArg(1)); + + if (who != OS::TGT_RUSAGE_SELF) { + // don't really handle THREAD or CHILDREN, but just warn and + // plow ahead + warn("getrusage() only supports RUSAGE_SELF. Parameter %d ignored.", + who); + } + + getElapsedTime(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec); + rup->ru_utime.tv_sec = htog(rup->ru_utime.tv_sec); + rup->ru_utime.tv_usec = htog(rup->ru_utime.tv_usec); + + rup->ru_stime.tv_sec = 0; + rup->ru_stime.tv_usec = 0; + rup->ru_maxrss = 0; + rup->ru_ixrss = 0; + rup->ru_idrss = 0; + rup->ru_isrss = 0; + rup->ru_minflt = 0; + rup->ru_majflt = 0; + rup->ru_nswap = 0; + rup->ru_inblock = 0; + rup->ru_oublock = 0; + rup->ru_msgsnd = 0; + rup->ru_msgrcv = 0; + rup->ru_nsignals = 0; + rup->ru_nvcsw = 0; + rup->ru_nivcsw = 0; + + rup.copyOut(xc->getMemPort()); + + return 0; +} + + + + +#endif // __SIM_SYSCALL_EMUL_HH__ diff --git a/src/sim/system.cc b/src/sim/system.cc new file mode 100644 index 000000000..ca9d68d77 --- /dev/null +++ b/src/sim/system.cc @@ -0,0 +1,265 @@ +#include "arch/isa_traits.hh" +#include "base/loader/object_file.hh" +#include "base/loader/symtab.hh" +#include "base/trace.hh" +#include "cpu/exec_context.hh" +#include "mem/mem_object.hh" +#include "mem/physical.hh" +#include "sim/builder.hh" +#include "sim/byteswap.hh" +#include "sim/system.hh" +#if FULL_SYSTEM +#include "arch/vtophys.hh" +#include "base/remote_gdb.hh" +#include "kern/kernel_stats.hh" +#endif + +using namespace std; +using namespace TheISA; + +vector<System *> System::systemList; + +int System::numSystemsRunning = 0; + +System::System(Params *p) + : SimObject(p->name), physmem(p->physmem), numcpus(0), +#if FULL_SYSTEM + init_param(p->init_param), +#else + page_ptr(0), +#endif + _params(p) +{ + // add self to global system list + systemList.push_back(this); + +#if FULL_SYSTEM + kernelSymtab = new SymbolTable; + debugSymbolTable = new SymbolTable; + + + /** + * Get a functional port to memory + */ + Port *mem_port; + mem_port = physmem->getPort("functional"); + functionalPort.setPeer(mem_port); + mem_port->setPeer(&functionalPort); + + mem_port = physmem->getPort("functional"); + virtPort.setPeer(mem_port); + mem_port->setPeer(&virtPort); + + + /** + * Load the kernel code into memory + */ + // Load kernel code + kernel = createObjectFile(params()->kernel_path); + if (kernel == NULL) + fatal("Could not load kernel file %s", params()->kernel_path); + + // Load program sections into memory + kernel->loadSections(&functionalPort, LoadAddrMask); + + // setup entry points + kernelStart = kernel->textBase(); + kernelEnd = kernel->bssBase() + kernel->bssSize(); + kernelEntry = kernel->entryPoint(); + + // load symbols + if (!kernel->loadGlobalSymbols(kernelSymtab)) + panic("could not load kernel symbols\n"); + + if (!kernel->loadLocalSymbols(kernelSymtab)) + panic("could not load kernel local symbols\n"); + + if (!kernel->loadGlobalSymbols(debugSymbolTable)) + panic("could not load kernel symbols\n"); + + if (!kernel->loadLocalSymbols(debugSymbolTable)) + panic("could not load kernel local symbols\n"); + + DPRINTF(Loader, "Kernel start = %#x\n", kernelStart); + DPRINTF(Loader, "Kernel end = %#x\n", kernelEnd); + DPRINTF(Loader, "Kernel entry = %#x\n", kernelEntry); + DPRINTF(Loader, "Kernel loaded...\n"); + + kernelBinning = new Kernel::Binning(this); +#endif // FULL_SYSTEM + + // increment the number of running systms + numSystemsRunning++; +} + +System::~System() +{ +#if FULL_SYSTEM + delete kernelSymtab; + delete kernel; + + delete kernelBinning; +#else + panic("System::fixFuncEventAddr needs to be rewritten " + "to work with syscall emulation"); +#endif // FULL_SYSTEM} +} + +#if FULL_SYSTEM + + +int rgdb_wait = -1; + +#endif // FULL_SYSTEM + +int +System::registerExecContext(ExecContext *xc, int id) +{ + if (id == -1) { + for (id = 0; id < execContexts.size(); id++) { + if (!execContexts[id]) + break; + } + } + + if (execContexts.size() <= id) + execContexts.resize(id + 1); + + if (execContexts[id]) + panic("Cannot have two CPUs with the same id (%d)\n", id); + + execContexts[id] = xc; + numcpus++; + +#if FULL_SYSTEM + RemoteGDB *rgdb = new RemoteGDB(this, xc); + GDBListener *gdbl = new GDBListener(rgdb, 7000 + id); + gdbl->listen(); + /** + * Uncommenting this line waits for a remote debugger to connect + * to the simulator before continuing. + */ + if (rgdb_wait != -1 && rgdb_wait == id) + gdbl->accept(); + + if (remoteGDB.size() <= id) { + remoteGDB.resize(id + 1); + } + + remoteGDB[id] = rgdb; +#endif // FULL_SYSTEM + + return id; +} + +void +System::startup() +{ + int i; + for (i = 0; i < execContexts.size(); i++) + execContexts[i]->activate(0); +} + +void +System::replaceExecContext(ExecContext *xc, int id) +{ + if (id >= execContexts.size()) { + panic("replaceExecContext: bad id, %d >= %d\n", + id, execContexts.size()); + } + + execContexts[id] = xc; +#if FULL_SYSTEM + remoteGDB[id]->replaceExecContext(xc); +#endif // FULL_SYSTEM +} + +#if !FULL_SYSTEM +Addr +System::new_page() +{ + Addr return_addr = page_ptr << LogVMPageSize; + ++page_ptr; + return return_addr; +} +#endif + +void +System::regStats() +{ +#if FULL_SYSTEM + kernelBinning->regStats(name() + ".kern"); +#endif // FULL_SYSTEM +} + +void +System::serialize(ostream &os) +{ +#if FULL_SYSTEM + kernelBinning->serialize(os); + + kernelSymtab->serialize("kernel_symtab", os); +#endif // FULL_SYSTEM +} + + +void +System::unserialize(Checkpoint *cp, const string §ion) +{ +#if FULL_SYSTEM + kernelBinning->unserialize(cp, section); + + kernelSymtab->unserialize("kernel_symtab", cp, section); +#endif // FULL_SYSTEM +} + +void +System::printSystems() +{ + vector<System *>::iterator i = systemList.begin(); + vector<System *>::iterator end = systemList.end(); + for (; i != end; ++i) { + System *sys = *i; + cerr << "System " << sys->name() << ": " << hex << sys << endl; + } +} + +extern "C" +void +printSystems() +{ + System::printSystems(); +} + +#if FULL_SYSTEM + +// In full system mode, only derived classes (e.g. AlphaLinuxSystem) +// can be created directly. + +DEFINE_SIM_OBJECT_CLASS_NAME("System", System) + +#else + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(System) + + SimObjectParam<PhysicalMemory *> physmem; + +END_DECLARE_SIM_OBJECT_PARAMS(System) + +BEGIN_INIT_SIM_OBJECT_PARAMS(System) + + INIT_PARAM(physmem, "physical memory") + +END_INIT_SIM_OBJECT_PARAMS(System) + +CREATE_SIM_OBJECT(System) +{ + System::Params *p = new System::Params; + p->name = getInstanceName(); + p->physmem = physmem; + return new System(p); +} + +REGISTER_SIM_OBJECT("System", System) + +#endif diff --git a/src/sim/system.hh b/src/sim/system.hh new file mode 100644 index 000000000..7e21bd587 --- /dev/null +++ b/src/sim/system.hh @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * 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. + */ + +#ifndef __SYSTEM_HH__ +#define __SYSTEM_HH__ + +#include <string> +#include <vector> + +#include "base/loader/symtab.hh" +#include "base/misc.hh" +#include "base/statistics.hh" +#include "cpu/pc_event.hh" +#include "mem/port.hh" +#include "sim/sim_object.hh" +#if FULL_SYSTEM +#include "kern/system_events.hh" +#include "mem/vport.hh" +#endif + +class BaseCPU; +class ExecContext; +class ObjectFile; +class PhysicalMemory; + +#if FULL_SYSTEM +class Platform; +class GDBListener; +class RemoteGDB; +namespace Kernel { class Binning; } +#endif + +class System : public SimObject +{ + public: + PhysicalMemory *physmem; + PCEventQueue pcEventQueue; + + std::vector<ExecContext *> execContexts; + int numcpus; + + int getNumCPUs() + { + if (numcpus != execContexts.size()) + panic("cpu array not fully populated!"); + + return numcpus; + } + +#if FULL_SYSTEM + Platform *platform; + uint64_t init_param; + + /** Port to physical memory used for writing object files into ram at + * boot.*/ + FunctionalPort functionalPort; + VirtualPort virtPort; + + /** kernel symbol table */ + SymbolTable *kernelSymtab; + + /** Object pointer for the kernel code */ + ObjectFile *kernel; + + /** Begining of kernel code */ + Addr kernelStart; + + /** End of kernel code */ + Addr kernelEnd; + + /** Entry point in the kernel to start at */ + Addr kernelEntry; + + Kernel::Binning *kernelBinning; + +#else + + int page_ptr; + + +#endif // FULL_SYSTEM + + protected: + +#if FULL_SYSTEM + /** + * Fix up an address used to match PCs for hooking simulator + * events on to target function executions. See comment in + * system.cc for details. + */ + virtual Addr fixFuncEventAddr(Addr addr) = 0; + + /** + * Add a function-based event to the given function, to be looked + * up in the specified symbol table. + */ + template <class T> + T *System::addFuncEvent(SymbolTable *symtab, const char *lbl) + { + Addr addr = 0; // initialize only to avoid compiler warning + + if (symtab->findAddress(lbl, addr)) { + T *ev = new T(&pcEventQueue, lbl, fixFuncEventAddr(addr)); + return ev; + } + + return NULL; + } + + /** Add a function-based event to kernel code. */ + template <class T> + T *System::addKernelFuncEvent(const char *lbl) + { + return addFuncEvent<T>(kernelSymtab, lbl); + } + +#endif + public: +#if FULL_SYSTEM + std::vector<RemoteGDB *> remoteGDB; + std::vector<GDBListener *> gdbListen; + virtual bool breakpoint() = 0; +#endif // FULL_SYSTEM + + public: + struct Params + { + std::string name; + PhysicalMemory *physmem; + +#if FULL_SYSTEM + Tick boot_cpu_frequency; + std::string boot_osflags; + uint64_t init_param; + bool bin; + std::vector<std::string> binned_fns; + bool bin_int; + + std::string kernel_path; + std::string readfile; +#endif + }; + + protected: + Params *_params; + + public: + System(Params *p); + ~System(); + + void startup(); + + const Params *params() const { return (const Params *)_params; } + + public: + +#if FULL_SYSTEM + /** + * Returns the addess the kernel starts at. + * @return address the kernel starts at + */ + Addr getKernelStart() const { return kernelStart; } + + /** + * Returns the addess the kernel ends at. + * @return address the kernel ends at + */ + Addr getKernelEnd() const { return kernelEnd; } + + /** + * Returns the addess the entry point to the kernel code. + * @return entry point of the kernel code + */ + Addr getKernelEntry() const { return kernelEntry; } + +#else + + Addr new_page(); + +#endif // FULL_SYSTEM + + int registerExecContext(ExecContext *xc, int xcIndex); + void replaceExecContext(ExecContext *xc, int xcIndex); + + void regStats(); + void serialize(std::ostream &os); + void unserialize(Checkpoint *cp, const std::string §ion); + + public: + //////////////////////////////////////////// + // + // STATIC GLOBAL SYSTEM LIST + // + //////////////////////////////////////////// + + static std::vector<System *> systemList; + static int numSystemsRunning; + + static void printSystems(); + + +}; + +#endif // __SYSTEM_HH__ diff --git a/src/sim/vptr.hh b/src/sim/vptr.hh new file mode 100644 index 000000000..cc57e63f0 --- /dev/null +++ b/src/sim/vptr.hh @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * 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. + */ + +#ifndef __ARCH_ALPHA_VPTR_HH__ +#define __ARCH_ALPHA_VPTR_HH__ + +#include "arch/vtophys.hh" +#include "arch/isa_traits.hh" + +class ExecContext; + +template <class T> +class VPtr +{ + public: + typedef T Type; + + private: + ExecContext *xc; + Addr ptr; + + public: + ExecContext *GetXC() const { return xc; } + Addr GetPointer() const { return ptr; } + + public: + explicit VPtr(ExecContext *_xc, Addr p = 0) : xc(_xc), ptr(p) { } + template <class U> + VPtr(const VPtr<U> &vp) : xc(vp.GetXC()), ptr(vp.GetPointer()) {} + ~VPtr() {} + + bool operator!() const + { + return ptr == 0; + } + + VPtr<T> operator+(int offset) + { + VPtr<T> ptr(*this); + ptr += offset; + + return ptr; + } + + const VPtr<T> &operator+=(int offset) + { + ptr += offset; + assert((ptr & (TheISA::PageBytes - 1)) + sizeof(T) + < TheISA::PageBytes); + + return *this; + } + + const VPtr<T> &operator=(Addr p) + { + assert((p & (TheISA::PageBytes - 1)) + sizeof(T) + < TheISA::PageBytes); + ptr = p; + + return *this; + } + + template <class U> + const VPtr<T> &operator=(const VPtr<U> &vp) + { + xc = vp.GetXC(); + ptr = vp.GetPointer(); + + return *this; + } + + operator T *() + { + panic("Needs to be rewritten\n"); +/* void *addr = vtomem(xc, ptr, sizeof(T)); + return (T *)addr; + */ + } + + T *operator->() + { + panic("Needs to be rewritten\n"); +/* void *addr = vtomem(xc, ptr, sizeof(T)); + return (T *)addr; + */ + } + + T &operator*() + { + panic("Needs to be rewritten\n"); +/* void *addr = vtomem(xc, ptr, sizeof(T)); + return *(T *)addr; + */ + } +}; + +#endif // __ARCH_ALPHA_VPTR_HH__ |