gem5/src/arch/generic/types.hh
Brandon Potter 2367198921 syscall_emul: [PATCH 15/22] add clone/execve for threading and multiprocess simulations
Modifies the clone system call and adds execve system call. Requires allowing
processes to steal thread contexts from other processes in the same system
object and the ability to detach pieces of process state (such as MemState)
to allow dynamic sharing.
2017-02-27 14:10:15 -05:00

463 lines
9.8 KiB
C++

/*
* Copyright (c) 2010 Gabe Black
* 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.
*
* Authors: Gabe Black
*/
#ifndef __ARCH_GENERIC_TYPES_HH__
#define __ARCH_GENERIC_TYPES_HH__
#include <iostream>
#include "base/trace.hh"
#include "base/types.hh"
#include "sim/serialize.hh"
namespace GenericISA
{
// The guaranteed interface.
class PCStateBase : public Serializable
{
protected:
Addr _pc;
Addr _npc;
PCStateBase() : _pc(0), _npc(0) {}
PCStateBase(Addr val) : _pc(0), _npc(0) { set(val); }
public:
/**
* Returns the memory address the bytes of this instruction came from.
*
* @return Memory address of the current instruction's encoding.
*/
Addr
instAddr() const
{
return _pc;
}
/**
* Returns the memory address the bytes of the next instruction came from.
*
* @return Memory address of the next instruction's encoding.
*/
Addr
nextInstAddr() const
{
return _npc;
}
/**
* Returns the current micropc.
*
* @return The current micropc.
*/
MicroPC
microPC() const
{
return 0;
}
/**
* Force this PC to reflect a particular value, resetting all its other
* fields around it. This is useful for in place (re)initialization.
*
* @param val The value to set the PC to.
*/
void set(Addr val);
bool
operator == (const PCStateBase &opc) const
{
return _pc == opc._pc && _npc == opc._npc;
}
bool
operator != (const PCStateBase &opc) const
{
return !(*this == opc);
}
void
serialize(CheckpointOut &cp) const override
{
SERIALIZE_SCALAR(_pc);
SERIALIZE_SCALAR(_npc);
}
void
unserialize(CheckpointIn &cp) override
{
UNSERIALIZE_SCALAR(_pc);
UNSERIALIZE_SCALAR(_npc);
}
};
/*
* Different flavors of PC state. Only ISA specific code should rely on
* any particular type of PC state being available. All other code should
* use the interface above.
*/
// The most basic type of PC.
template <class MachInst>
class SimplePCState : public PCStateBase
{
protected:
typedef PCStateBase Base;
public:
Addr pc() const { return _pc; }
void pc(Addr val) { _pc = val; }
Addr npc() const { return _npc; }
void npc(Addr val) { _npc = val; }
void
set(Addr val)
{
pc(val);
npc(val + sizeof(MachInst));
};
void
setNPC(Addr val)
{
npc(val);
}
SimplePCState() {}
SimplePCState(Addr val) { set(val); }
bool
branching() const
{
return this->npc() != this->pc() + sizeof(MachInst);
}
// Advance the PC.
void
advance()
{
_pc = _npc;
_npc += sizeof(MachInst);
}
};
template <class MachInst>
std::ostream &
operator<<(std::ostream & os, const SimplePCState<MachInst> &pc)
{
ccprintf(os, "(%#x=>%#x)", pc.pc(), pc.npc());
return os;
}
// A PC and microcode PC.
template <class MachInst>
class UPCState : public SimplePCState<MachInst>
{
protected:
typedef SimplePCState<MachInst> Base;
MicroPC _upc;
MicroPC _nupc;
public:
MicroPC upc() const { return _upc; }
void upc(MicroPC val) { _upc = val; }
MicroPC nupc() const { return _nupc; }
void nupc(MicroPC val) { _nupc = val; }
MicroPC
microPC() const
{
return _upc;
}
void
set(Addr val)
{
Base::set(val);
upc(0);
nupc(1);
}
UPCState() : _upc(0), _nupc(0) {}
UPCState(Addr val) : _upc(0), _nupc(0) { set(val); }
bool
branching() const
{
return this->npc() != this->pc() + sizeof(MachInst) ||
this->nupc() != this->upc() + 1;
}
// Advance the upc within the instruction.
void
uAdvance()
{
_upc = _nupc;
_nupc++;
}
// End the macroop by resetting the upc and advancing the regular pc.
void
uEnd()
{
this->advance();
_upc = 0;
_nupc = 1;
}
bool
operator == (const UPCState<MachInst> &opc) const
{
return Base::_pc == opc._pc &&
Base::_npc == opc._npc &&
_upc == opc._upc && _nupc == opc._nupc;
}
bool
operator != (const UPCState<MachInst> &opc) const
{
return !(*this == opc);
}
void
serialize(CheckpointOut &cp) const override
{
Base::serialize(cp);
SERIALIZE_SCALAR(_upc);
SERIALIZE_SCALAR(_nupc);
}
void
unserialize(CheckpointIn &cp) override
{
Base::unserialize(cp);
UNSERIALIZE_SCALAR(_upc);
UNSERIALIZE_SCALAR(_nupc);
}
};
template <class MachInst>
std::ostream &
operator<<(std::ostream & os, const UPCState<MachInst> &pc)
{
ccprintf(os, "(%#x=>%#x).(%d=>%d)",
pc.pc(), pc.npc(), pc.upc(), pc.nupc());
return os;
}
// A PC with a delay slot.
template <class MachInst>
class DelaySlotPCState : public SimplePCState<MachInst>
{
protected:
typedef SimplePCState<MachInst> Base;
Addr _nnpc;
public:
Addr nnpc() const { return _nnpc; }
void nnpc(Addr val) { _nnpc = val; }
void
set(Addr val)
{
Base::set(val);
nnpc(val + 2 * sizeof(MachInst));
}
DelaySlotPCState() {}
DelaySlotPCState(Addr val) { set(val); }
bool
branching() const
{
return !(this->nnpc() == this->npc() + sizeof(MachInst) &&
(this->npc() == this->pc() + sizeof(MachInst) ||
this->npc() == this->pc() + 2 * sizeof(MachInst)));
}
// Advance the PC.
void
advance()
{
Base::_pc = Base::_npc;
Base::_npc = _nnpc;
_nnpc += sizeof(MachInst);
}
bool
operator == (const DelaySlotPCState<MachInst> &opc) const
{
return Base::_pc == opc._pc &&
Base::_npc == opc._npc &&
_nnpc == opc._nnpc;
}
bool
operator != (const DelaySlotPCState<MachInst> &opc) const
{
return !(*this == opc);
}
void
serialize(CheckpointOut &cp) const override
{
Base::serialize(cp);
SERIALIZE_SCALAR(_nnpc);
}
void
unserialize(CheckpointIn &cp) override
{
Base::unserialize(cp);
UNSERIALIZE_SCALAR(_nnpc);
}
};
template <class MachInst>
std::ostream &
operator<<(std::ostream & os, const DelaySlotPCState<MachInst> &pc)
{
ccprintf(os, "(%#x=>%#x=>%#x)",
pc.pc(), pc.npc(), pc.nnpc());
return os;
}
// A PC with a delay slot and a microcode PC.
template <class MachInst>
class DelaySlotUPCState : public DelaySlotPCState<MachInst>
{
protected:
typedef DelaySlotPCState<MachInst> Base;
MicroPC _upc;
MicroPC _nupc;
public:
MicroPC upc() const { return _upc; }
void upc(MicroPC val) { _upc = val; }
MicroPC nupc() const { return _nupc; }
void nupc(MicroPC val) { _nupc = val; }
MicroPC
microPC() const
{
return _upc;
}
void
set(Addr val)
{
Base::set(val);
upc(0);
nupc(1);
}
DelaySlotUPCState() {}
DelaySlotUPCState(Addr val) { set(val); }
bool
branching() const
{
return Base::branching() || this->nupc() != this->upc() + 1;
}
// Advance the upc within the instruction.
void
uAdvance()
{
_upc = _nupc;
_nupc++;
}
// End the macroop by resetting the upc and advancing the regular pc.
void
uEnd()
{
this->advance();
_upc = 0;
_nupc = 1;
}
bool
operator == (const DelaySlotUPCState<MachInst> &opc) const
{
return Base::_pc == opc._pc &&
Base::_npc == opc._npc &&
Base::_nnpc == opc._nnpc &&
_upc == opc._upc && _nupc == opc._nupc;
}
bool
operator != (const DelaySlotUPCState<MachInst> &opc) const
{
return !(*this == opc);
}
void
serialize(CheckpointOut &cp) const override
{
Base::serialize(cp);
SERIALIZE_SCALAR(_upc);
SERIALIZE_SCALAR(_nupc);
}
void
unserialize(CheckpointIn &cp) override
{
Base::unserialize(cp);
UNSERIALIZE_SCALAR(_upc);
UNSERIALIZE_SCALAR(_nupc);
}
};
template <class MachInst>
std::ostream &
operator<<(std::ostream & os, const DelaySlotUPCState<MachInst> &pc)
{
ccprintf(os, "(%#x=>%#x=>%#x).(%d=>%d)",
pc.pc(), pc.npc(), pc.nnpc(), pc.upc(), pc.nupc());
return os;
}
}
#endif