}
 
 void
-AlphaLiveProcess::startup()
+AlphaLiveProcess::setupASNReg()
 {
     ThreadContext *tc = system->getThreadContext(contextIds[0]);
     tc->setMiscRegNoEffect(IPR_DTB_ASN, M5_pid << 57);
+}
 
-    if (checkpointRestored) {
-        return;
-    }
 
-    Process::startup();
+void
+AlphaLiveProcess::loadState(Checkpoint *cp)
+{
+    LiveProcess::loadState(cp);
+    // need to set up ASN after unserialization since M5_pid value may
+    // come from checkpoint
+    setupASNReg();
+}
+
+
+void
+AlphaLiveProcess::initState()
+{
+    // need to set up ASN before further initialization since init
+    // will involve writing to virtual memory addresses
+    setupASNReg();
+
+    LiveProcess::initState();
 
     argsInit(MachineBytes, VMPageSize);
 
+    ThreadContext *tc = system->getThreadContext(contextIds[0]);
     tc->setIntReg(GlobalPointerReg, objFile->globalPointer());
     //Operate in user mode
     tc->setMiscRegNoEffect(IPR_ICM, 0x18);
 
 
 class AlphaLiveProcess : public LiveProcess
 {
+  private:
+    void setupASNReg();
+
   protected:
     AlphaLiveProcess(LiveProcessParams *params, ObjectFile *objFile);
 
-    void startup();
+    void loadState(Checkpoint *cp);
+    void initState();
 
     void argsInit(int intSize, int pageSize);
 
 
 void
 ArmLiveProcess::startup()
 {
+    LiveProcess::startup();
     argsInit(MachineBytes, VMPageSize);
 }
 
     //We want 16 byte alignment
     uint64_t align = 16;
 
-    // Overloaded argsInit so that we can fine-tune for ARM architecture
-    Process::startup();
-
     // load object file into target memory
     objFile->loadSections(initVirtMem);
 
 
 }
 
 void
-MipsLiveProcess::startup()
+MipsLiveProcess::initState()
 {
-    Process::startup();
+    LiveProcess::initState();
 
     argsInit<uint32_t>(VMPageSize);
 }
 MipsLiveProcess::argsInit(int pageSize)
 {
     int intSize = sizeof(IntType);
-    Process::startup();
 
     // load object file into target memory
     objFile->loadSections(initVirtMem);
 
   protected:
     MipsLiveProcess(LiveProcessParams * params, ObjectFile *objFile);
 
-    void startup();
+    void initState();
 
     template<class IntType>
     void argsInit(int pageSize);
 
 }
 
 void
-PowerLinuxProcess::startup()
+PowerLinuxProcess::initState()
 {
-    PowerLiveProcess::startup();
+    PowerLiveProcess::initState();
 }
 
 PowerISA::IntReg
 
 
     virtual SyscallDesc* getDesc(int callnum);
 
-    void startup();
+    void initState();
 
     PowerISA::IntReg getSyscallArg(ThreadContext *tc, int &i);
     void setSyscallArg(ThreadContext *tc, int i, PowerISA::IntReg val);
 
 }
 
 void
-PowerLiveProcess::startup()
+PowerLiveProcess::initState()
 {
+    Process::initState();
+
     argsInit(MachineBytes, VMPageSize);
 }
 
     //We want 16 byte alignment
     uint64_t align = 16;
 
-    // Overloaded argsInit so that we can fine-tune for POWER architecture
-    Process::startup();
-
     // load object file into target memory
     objFile->loadSections(initVirtMem);
 
 
   protected:
     PowerLiveProcess(LiveProcessParams * params, ObjectFile *objFile);
 
-    void startup();
+    void initState();
 
   public:
     void argsInit(int intSize, int pageSize);
 
 }
 
 void
-SparcLiveProcess::startup()
+SparcLiveProcess::initState()
 {
-    Process::startup();
+    LiveProcess::initState();
 
     ThreadContext *tc = system->getThreadContext(contextIds[0]);
     //From the SPARC ABI
 }
 
 void
-Sparc32LiveProcess::startup()
+Sparc32LiveProcess::initState()
 {
-    if (checkpointRestored)
-        return;
-
-    SparcLiveProcess::startup();
+    SparcLiveProcess::initState();
 
     ThreadContext *tc = system->getThreadContext(contextIds[0]);
     //The process runs in user mode with 32 bit addresses
 }
 
 void
-Sparc64LiveProcess::startup()
+Sparc64LiveProcess::initState()
 {
-    if (checkpointRestored)
-        return;
-
-    SparcLiveProcess::startup();
+    SparcLiveProcess::initState();
 
     ThreadContext *tc = system->getThreadContext(contextIds[0]);
     //The process runs in user mode
 
     SparcLiveProcess(LiveProcessParams * params,
             ObjectFile *objFile, Addr _StackBias);
 
-    void startup();
+    void initState();
 
     template<class IntType>
     void argsInit(int pageSize);
         mmap_start = mmap_end = 0x70000000;
     }
 
-    void startup();
+    void initState();
 
   public:
 
         mmap_start = mmap_end = 0xfffff80000000000ULL;
     }
 
-    void startup();
+    void initState();
 
   public:
 
 
 }
 
 void
-LinuxX86System::startup()
+LinuxX86System::initState()
 {
-    X86System::startup();
+    X86System::initState();
 
     // The location of the real mode data structure.
     const Addr realModeData = 0x90200;
 
     LinuxX86System(Params *p);
     ~LinuxX86System();
 
-    void startup();
+    void initState();
 };
 
 #endif
 
 }
 
 void
-X86_64LiveProcess::startup()
+X86_64LiveProcess::initState()
 {
-    LiveProcess::startup();
-
-    if (checkpointRestored)
-        return;
+    X86LiveProcess::initState();
 
     argsInit(sizeof(uint64_t), VMPageSize);
 
 }
 
 void
-I386LiveProcess::startup()
+I386LiveProcess::initState()
 {
-    LiveProcess::startup();
-
-    if (checkpointRestored)
-        return;
+    X86LiveProcess::initState();
 
     argsInit(sizeof(uint32_t), VMPageSize);
 
 
 
       public:
         void argsInit(int intSize, int pageSize);
-        void startup();
+        void initState();
 
         X86ISA::IntReg getSyscallArg(ThreadContext *tc, int &i);
         void setSyscallArg(ThreadContext *tc, int i, X86ISA::IntReg val);
 
       public:
         void argsInit(int intSize, int pageSize);
-        void startup();
+        void initState();
 
         void syscall(int64_t callnum, ThreadContext *tc);
         X86ISA::IntReg getSyscallArg(ThreadContext *tc, int &i);
 
 }
 
 void
-X86System::startup()
+X86System::initState()
 {
-    System::startup();
+    System::initState();
+
     ThreadContext *tc = threadContexts[0];
     // This is the boot strap processor (BSP). Initialize it to look like
     // the boot loader has just turned control over to the 64 bit OS. We
 
     void serialize(std::ostream &os);
     void unserialize(Checkpoint *cp, const std::string §ion);
 
-    void startup();
+    void initState();
 
   protected:
 
 
 
     # Restore checkpoint (if any)
     if ckpt_dir:
-        internal.core.unserializeAll(ckpt_dir)
+        ckpt = internal.core.getCheckpoint(ckpt_dir)
+        internal.core.unserializeGlobals(ckpt);
+        for obj in root.descendants(): obj.loadState(ckpt)
         need_resume.append(root)
+    else:
+        for obj in root.descendants(): obj.initState()
 
     # Reset to put the stats in a consistent state.
     stats.reset()
 
 %immutable curTick;
 Tick curTick;
 
+class Checkpoint;
+
 void serializeAll(const std::string &cpt_dir);
-void unserializeAll(const std::string &cpt_dir);
+Checkpoint *getCheckpoint(const std::string &cpt_dir);
+void unserializeGlobals(Checkpoint *cp);
 
 bool want_warn, warn_verbose;
 bool want_info, info_verbose;
 
     Serializable::serializeAll(cpt_dir);
 }
 
+inline Checkpoint *
+getCheckpoint(const std::string &cpt_dir)
+{
+    return new Checkpoint(cpt_dir);
+}
+
 inline void
-unserializeAll(const std::string &cpt_dir)
+unserializeGlobals(Checkpoint *cp)
 {
-    Serializable::unserializeAll(cpt_dir);
+    Serializable::unserializeGlobals(cp);
 }
 
     };
 
     void init();
+    void loadState(Checkpoint *cp);
+    void initState();
     void regStats();
     void regFormulas();
     void resetStats();
 
 template class AuxVector<uint64_t>;
 
 Process::Process(ProcessParams * params)
-    : SimObject(params), system(params->system), checkpointRestored(false),
-    max_stack_size(params->max_stack_size)
+    : SimObject(params), system(params->system),
+      max_stack_size(params->max_stack_size)
 {
     string in = params->input;
     string out = params->output;
 }
 
 void
-Process::startup()
+Process::initState()
 {
     if (contextIds.empty())
         fatal("Process %s is not associated with any HW contexts!\n", name());
     // find the param in the checkpoint if you wanted to, like set a default
     // but in this case we'll just stick with the instantianted value if not
     // found.   
-
-    checkpointRestored = true;
-
 }
 
 
 
     /// running on.
     System *system;
 
-    bool checkpointRestored;
-
     // thread contexts associated with this process
     std::vector<int> contextIds;
 
     // constructor
     Process(ProcessParams * params);
 
-    // post initialization startup
-    virtual void startup();
+    virtual void initState();
 
   protected:
     /// Memory object for initialization (image loading)
 
     SimObject::serializeAll(outstream);
 }
 
-void
-Serializable::unserializeAll(const string &cpt_dir)
-{
-    string dir = Checkpoint::setDir(cpt_dir);
-
-    DPRINTFR(Config, "Loading checkpoint dir '%s'\n", dir);
-    Checkpoint *cp = new Checkpoint(dir);
-    unserializeGlobals(cp);
-    SimObject::unserializeAll(cp);
-}
-
 void
 Serializable::unserializeGlobals(Checkpoint *cp)
 {
 
 
 Checkpoint::Checkpoint(const string &cpt_dir)
-    : db(new IniFile), cptDir(cpt_dir)
+    : db(new IniFile), cptDir(setDir(cpt_dir))
 {
-    string filename = cpt_dir + "/" + Checkpoint::baseFilename;
+    string filename = cptDir + "/" + Checkpoint::baseFilename;
     if (!db->load(filename)) {
         fatal("Can't load checkpoint file '%s'\n", filename);
     }
 
     static int ckptMaxCount;
     static int ckptPrevCount;
     static void serializeAll(const std::string &cpt_dir);
-    static void unserializeAll(const std::string &cpt_dir);
     static void unserializeGlobals(Checkpoint *cp);
 };
 
 
 {
 }
 
+void
+SimObject::loadState(Checkpoint *cp)
+{
+    if (cp->sectionExists(name()))
+        unserialize(cp, name());
+}
+
+void
+SimObject::initState()
+{
+}
+
 void
 SimObject::startup()
 {
 
 
     virtual const std::string name() const { return params()->name; }
 
-    // initialization pass of all objects.
-    // Gets invoked after construction, before unserialize.
+    // The following SimObject initialization methods are called from
+    // the instantiate() method in src/python/m5/simulate.py.  See
+    // that function for details on how/when these methods are
+    // invoked.
+
+    /**
+     * init() is called after all C++ SimObjects have been created and
+     * all ports are connected.  Initializations that are independent
+     * of unserialization but rely on a fully instantiated and
+     * connected SimObject graph should be done here.
+     */
     virtual void init();
 
+    /**
+     * loadState() is called on each SimObject when restoring from a
+     * checkpoint.  The default implementation simply calls
+     * unserialize() if there is a corresponding section in the
+     * checkpoint.  However, objects can override loadState() to get
+     * other behaviors, e.g., doing other programmed initializations
+     * after unserialize(), or complaining if no checkpoint section is
+     * found.
+     */
+    virtual void loadState(Checkpoint *cp);
+
+    /**
+     * initState() is called on each SimObject when *not* restoring
+     * from a checkpoint.  This provides a hook for state
+     * initializations that are only required for a "cold start".
+     */
+    virtual void initState();
+
     // register statistics for this object
     virtual void regStats();
     virtual void regFormulas();
     virtual void resetStats();
 
-    // final initialization before simulation
-    // all state is unserialized so 
+    /**
+     * startup() is the final initialization call before simulation.
+     * All state is initialized (including unserialized state, if any,
+     * such as the curTick value), so this is the appropriate place to
+     * schedule initial event(s) for objects that need them.
+     */
     virtual void startup();
 
     // static: call nameOut() & serialize() on all SimObjects