/*
- * Copyright (c) 2010-2012,2017 ARM Limited
+ * Copyright (c) 2010-2012,2017-2019 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* 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: Ron Dreslinski
- * Ali Saidi
- * Andreas Hansson
*/
#include "mem/abstract_mem.hh"
#include <vector>
#include "arch/locked_mem.hh"
-#include "cpu/base.hh"
+#include "base/loader/memory_image.hh"
+#include "base/loader/object_file.hh"
#include "cpu/thread_context.hh"
#include "debug/LLSC.hh"
#include "debug/MemoryAccess.hh"
using namespace std;
-AbstractMemory::AbstractMemory(const Params *p) :
- MemObject(p), range(params()->range), pmemAddr(NULL),
- confTableReported(p->conf_table_reported), inAddrMap(p->in_addr_map),
- kvmMap(p->kvm_map), _system(NULL)
+AbstractMemory::AbstractMemory(const Params &p) :
+ ClockedObject(p), range(p.range), pmemAddr(NULL),
+ backdoor(params().range, nullptr,
+ (MemBackdoor::Flags)(MemBackdoor::Readable |
+ MemBackdoor::Writeable)),
+ confTableReported(p.conf_table_reported), inAddrMap(p.in_addr_map),
+ kvmMap(p.kvm_map), _system(NULL),
+ stats(*this)
{
+ panic_if(!range.valid() || !range.size(),
+ "Memory range %s must be valid with non-zero size.",
+ range.to_string());
}
void
-AbstractMemory::init()
+AbstractMemory::initState()
{
- assert(system());
+ ClockedObject::initState();
+
+ const auto &file = params().image_file;
+ if (file == "")
+ return;
+
+ auto *object = Loader::createObjectFile(file, true);
+ fatal_if(!object, "%s: Could not load %s.", name(), file);
+
+ Loader::debugSymbolTable.insert(*object->symtab().globals());
+ Loader::MemoryImage image = object->buildImage();
+
+ AddrRange image_range(image.minAddr(), image.maxAddr());
+ if (!range.contains(image_range.start())) {
+ warn("%s: Moving image from %s to memory address range %s.",
+ name(), image_range.to_string(), range.to_string());
+ image = image.offset(range.start());
+ image_range = AddrRange(image.minAddr(), image.maxAddr());
+ }
+ panic_if(!image_range.isSubset(range), "%s: memory image %s doesn't fit.",
+ name(), file);
+
+ PortProxy proxy([this](PacketPtr pkt) { functionalAccess(pkt); },
+ system()->cacheLineSize());
- if (size() % _system->getPageBytes() != 0)
- panic("Memory Size not divisible by page size\n");
+ panic_if(!image.write(proxy), "%s: Unable to write image.");
}
void
AbstractMemory::setBackingStore(uint8_t* pmem_addr)
{
+ // If there was an existing backdoor, let everybody know it's going away.
+ if (backdoor.ptr())
+ backdoor.invalidate();
+
+ // The back door can't handle interleaved memory.
+ backdoor.ptr(range.interleaved() ? nullptr : pmem_addr);
+
pmemAddr = pmem_addr;
}
-void
-AbstractMemory::regStats()
+AbstractMemory::MemStats::MemStats(AbstractMemory &_mem)
+ : Stats::Group(&_mem), mem(_mem),
+ bytesRead(this, "bytes_read",
+ "Number of bytes read from this memory"),
+ bytesInstRead(this, "bytes_inst_read",
+ "Number of instructions bytes read from this memory"),
+ bytesWritten(this, "bytes_written",
+ "Number of bytes written to this memory"),
+ numReads(this, "num_reads",
+ "Number of read requests responded to by this memory"),
+ numWrites(this, "num_writes",
+ "Number of write requests responded to by this memory"),
+ numOther(this, "num_other",
+ "Number of other requests responded to by this memory"),
+ bwRead(this, "bw_read",
+ "Total read bandwidth from this memory (bytes/s)"),
+ bwInstRead(this, "bw_inst_read",
+ "Instruction read bandwidth from this memory (bytes/s)"),
+ bwWrite(this, "bw_write",
+ "Write bandwidth from this memory (bytes/s)"),
+ bwTotal(this, "bw_total",
+ "Total bandwidth to/from this memory (bytes/s)")
{
- MemObject::regStats();
+}
+void
+AbstractMemory::MemStats::regStats()
+{
using namespace Stats;
- assert(system());
+ Stats::Group::regStats();
+
+ System *sys = mem.system();
+ assert(sys);
+ const auto max_requestors = sys->maxRequestors();
bytesRead
- .init(system()->maxMasters())
- .name(name() + ".bytes_read")
- .desc("Number of bytes read from this memory")
+ .init(max_requestors)
.flags(total | nozero | nonan)
;
- for (int i = 0; i < system()->maxMasters(); i++) {
- bytesRead.subname(i, system()->getMasterName(i));
+ for (int i = 0; i < max_requestors; i++) {
+ bytesRead.subname(i, sys->getRequestorName(i));
}
+
bytesInstRead
- .init(system()->maxMasters())
- .name(name() + ".bytes_inst_read")
- .desc("Number of instructions bytes read from this memory")
+ .init(max_requestors)
.flags(total | nozero | nonan)
;
- for (int i = 0; i < system()->maxMasters(); i++) {
- bytesInstRead.subname(i, system()->getMasterName(i));
+ for (int i = 0; i < max_requestors; i++) {
+ bytesInstRead.subname(i, sys->getRequestorName(i));
}
+
bytesWritten
- .init(system()->maxMasters())
- .name(name() + ".bytes_written")
- .desc("Number of bytes written to this memory")
+ .init(max_requestors)
.flags(total | nozero | nonan)
;
- for (int i = 0; i < system()->maxMasters(); i++) {
- bytesWritten.subname(i, system()->getMasterName(i));
+ for (int i = 0; i < max_requestors; i++) {
+ bytesWritten.subname(i, sys->getRequestorName(i));
}
+
numReads
- .init(system()->maxMasters())
- .name(name() + ".num_reads")
- .desc("Number of read requests responded to by this memory")
+ .init(max_requestors)
.flags(total | nozero | nonan)
;
- for (int i = 0; i < system()->maxMasters(); i++) {
- numReads.subname(i, system()->getMasterName(i));
+ for (int i = 0; i < max_requestors; i++) {
+ numReads.subname(i, sys->getRequestorName(i));
}
+
numWrites
- .init(system()->maxMasters())
- .name(name() + ".num_writes")
- .desc("Number of write requests responded to by this memory")
+ .init(max_requestors)
.flags(total | nozero | nonan)
;
- for (int i = 0; i < system()->maxMasters(); i++) {
- numWrites.subname(i, system()->getMasterName(i));
+ for (int i = 0; i < max_requestors; i++) {
+ numWrites.subname(i, sys->getRequestorName(i));
}
+
numOther
- .init(system()->maxMasters())
- .name(name() + ".num_other")
- .desc("Number of other requests responded to by this memory")
+ .init(max_requestors)
.flags(total | nozero | nonan)
;
- for (int i = 0; i < system()->maxMasters(); i++) {
- numOther.subname(i, system()->getMasterName(i));
+ for (int i = 0; i < max_requestors; i++) {
+ numOther.subname(i, sys->getRequestorName(i));
}
+
bwRead
- .name(name() + ".bw_read")
- .desc("Total read bandwidth from this memory (bytes/s)")
.precision(0)
.prereq(bytesRead)
.flags(total | nozero | nonan)
;
- for (int i = 0; i < system()->maxMasters(); i++) {
- bwRead.subname(i, system()->getMasterName(i));
+ for (int i = 0; i < max_requestors; i++) {
+ bwRead.subname(i, sys->getRequestorName(i));
}
bwInstRead
- .name(name() + ".bw_inst_read")
- .desc("Instruction read bandwidth from this memory (bytes/s)")
.precision(0)
.prereq(bytesInstRead)
.flags(total | nozero | nonan)
;
- for (int i = 0; i < system()->maxMasters(); i++) {
- bwInstRead.subname(i, system()->getMasterName(i));
+ for (int i = 0; i < max_requestors; i++) {
+ bwInstRead.subname(i, sys->getRequestorName(i));
}
+
bwWrite
- .name(name() + ".bw_write")
- .desc("Write bandwidth from this memory (bytes/s)")
.precision(0)
.prereq(bytesWritten)
.flags(total | nozero | nonan)
;
- for (int i = 0; i < system()->maxMasters(); i++) {
- bwWrite.subname(i, system()->getMasterName(i));
+ for (int i = 0; i < max_requestors; i++) {
+ bwWrite.subname(i, sys->getRequestorName(i));
}
+
bwTotal
- .name(name() + ".bw_total")
- .desc("Total bandwidth to/from this memory (bytes/s)")
.precision(0)
.prereq(bwTotal)
.flags(total | nozero | nonan)
;
- for (int i = 0; i < system()->maxMasters(); i++) {
- bwTotal.subname(i, system()->getMasterName(i));
+ for (int i = 0; i < max_requestors; i++) {
+ bwTotal.subname(i, sys->getRequestorName(i));
}
+
bwRead = bytesRead / simSeconds;
bwInstRead = bytesInstRead / simSeconds;
bwWrite = bytesWritten / simSeconds;
DPRINTF(LLSC, "Adding lock record: context %d addr %#x\n",
req->contextId(), paddr);
lockedAddrList.push_front(LockedAddr(req));
+ backdoor.invalidate();
}
DPRINTF(LLSC, "Erasing lock record: context %d addr %#x\n",
i->contextId, paddr);
ContextID owner_cid = i->contextId;
- ContextID requester_cid = pkt->req->contextId();
- if (owner_cid != requester_cid) {
- ThreadContext* ctx = system()->getThreadContext(owner_cid);
+ assert(owner_cid != InvalidContextID);
+ ContextID requestor_cid = req->hasContextId() ?
+ req->contextId() :
+ InvalidContextID;
+ if (owner_cid != requestor_cid) {
+ ThreadContext* ctx = system()->threads[owner_cid];
TheISA::globalClearExclusive(ctx);
}
i = lockedAddrList.erase(i);
return allowStore;
}
+#if TRACING_ON
static inline void
tracePacket(System *sys, const char *label, PacketPtr pkt)
{
int size = pkt->getSize();
-#if THE_ISA != NULL_ISA
if (size == 1 || size == 2 || size == 4 || size == 8) {
- DPRINTF(MemoryAccess,"%s from %s of size %i on address %#x data "
- "%#x %c\n", label, sys->getMasterName(pkt->req->masterId()),
- size, pkt->getAddr(), pkt->getUintX(TheISA::GuestByteOrder),
+ ByteOrder byte_order = sys->getGuestByteOrder();
+ DPRINTF(MemoryAccess, "%s from %s of size %i on address %#x data "
+ "%#x %c\n", label, sys->getRequestorName(pkt->req->
+ requestorId()), size, pkt->getAddr(),
+ size, pkt->getAddr(), pkt->getUintX(byte_order),
pkt->req->isUncacheable() ? 'U' : 'C');
return;
}
-#endif
DPRINTF(MemoryAccess, "%s from %s of size %i on address %#x %c\n",
- label, sys->getMasterName(pkt->req->masterId()),
+ label, sys->getRequestorName(pkt->req->requestorId()),
size, pkt->getAddr(), pkt->req->isUncacheable() ? 'U' : 'C');
DDUMP(MemoryAccess, pkt->getConstPtr<uint8_t>(), pkt->getSize());
}
-#if TRACING_ON
# define TRACE_PACKET(A) tracePacket(system(), A, pkt)
#else
# define TRACE_PACKET(A)
return;
}
- assert(AddrRange(pkt->getAddr(),
- pkt->getAddr() + (pkt->getSize() - 1)).isSubset(range));
+ assert(pkt->getAddrRange().isSubset(range));
- uint8_t *hostAddr = pmemAddr + pkt->getAddr() - range.start();
+ uint8_t *host_addr = toHostAddr(pkt->getAddr());
if (pkt->cmd == MemCmd::SwapReq) {
if (pkt->isAtomicOp()) {
if (pmemAddr) {
- memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize());
- (*(pkt->getAtomicOp()))(hostAddr);
+ pkt->setData(host_addr);
+ (*(pkt->getAtomicOp()))(host_addr);
}
} else {
std::vector<uint8_t> overwrite_val(pkt->getSize());
uint64_t condition_val64;
uint32_t condition_val32;
- if (!pmemAddr)
- panic("Swap only works if there is real memory (i.e. null=False)");
+ panic_if(!pmemAddr, "Swap only works if there is real memory " \
+ "(i.e. null=False)");
bool overwrite_mem = true;
// keep a copy of our possible write value, and copy what is at the
// memory address into the packet
- std::memcpy(&overwrite_val[0], pkt->getConstPtr<uint8_t>(),
- pkt->getSize());
- std::memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize());
+ pkt->writeData(&overwrite_val[0]);
+ pkt->setData(host_addr);
if (pkt->req->isCondSwap()) {
if (pkt->getSize() == sizeof(uint64_t)) {
condition_val64 = pkt->req->getExtraData();
- overwrite_mem = !std::memcmp(&condition_val64, hostAddr,
+ overwrite_mem = !std::memcmp(&condition_val64, host_addr,
sizeof(uint64_t));
} else if (pkt->getSize() == sizeof(uint32_t)) {
condition_val32 = (uint32_t)pkt->req->getExtraData();
- overwrite_mem = !std::memcmp(&condition_val32, hostAddr,
+ overwrite_mem = !std::memcmp(&condition_val32, host_addr,
sizeof(uint32_t));
} else
panic("Invalid size for conditional read/write\n");
}
if (overwrite_mem)
- std::memcpy(hostAddr, &overwrite_val[0], pkt->getSize());
+ std::memcpy(host_addr, &overwrite_val[0], pkt->getSize());
assert(!pkt->req->isInstFetch());
TRACE_PACKET("Read/Write");
- numOther[pkt->req->masterId()]++;
+ stats.numOther[pkt->req->requestorId()]++;
}
} else if (pkt->isRead()) {
assert(!pkt->isWrite());
// to do the LL/SC tracking here
trackLoadLocked(pkt);
}
- if (pmemAddr)
- memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize());
+ if (pmemAddr) {
+ pkt->setData(host_addr);
+ }
TRACE_PACKET(pkt->req->isInstFetch() ? "IFetch" : "Read");
- numReads[pkt->req->masterId()]++;
- bytesRead[pkt->req->masterId()] += pkt->getSize();
+ stats.numReads[pkt->req->requestorId()]++;
+ stats.bytesRead[pkt->req->requestorId()] += pkt->getSize();
if (pkt->req->isInstFetch())
- bytesInstRead[pkt->req->masterId()] += pkt->getSize();
+ stats.bytesInstRead[pkt->req->requestorId()] += pkt->getSize();
} else if (pkt->isInvalidate() || pkt->isClean()) {
assert(!pkt->isWrite());
// in a fastmem system invalidating and/or cleaning packets
} else if (pkt->isWrite()) {
if (writeOK(pkt)) {
if (pmemAddr) {
- memcpy(hostAddr, pkt->getConstPtr<uint8_t>(), pkt->getSize());
- DPRINTF(MemoryAccess, "%s wrote %i bytes to address %x\n",
- __func__, pkt->getSize(), pkt->getAddr());
+ pkt->writeData(host_addr);
+ DPRINTF(MemoryAccess, "%s write due to %s\n",
+ __func__, pkt->print());
}
assert(!pkt->req->isInstFetch());
TRACE_PACKET("Write");
- numWrites[pkt->req->masterId()]++;
- bytesWritten[pkt->req->masterId()] += pkt->getSize();
+ stats.numWrites[pkt->req->requestorId()]++;
+ stats.bytesWritten[pkt->req->requestorId()] += pkt->getSize();
}
} else {
panic("Unexpected packet %s", pkt->print());
void
AbstractMemory::functionalAccess(PacketPtr pkt)
{
- assert(AddrRange(pkt->getAddr(),
- pkt->getAddr() + pkt->getSize() - 1).isSubset(range));
+ assert(pkt->getAddrRange().isSubset(range));
- uint8_t *hostAddr = pmemAddr + pkt->getAddr() - range.start();
+ uint8_t *host_addr = toHostAddr(pkt->getAddr());
if (pkt->isRead()) {
- if (pmemAddr)
- memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize());
+ if (pmemAddr) {
+ pkt->setData(host_addr);
+ }
TRACE_PACKET("Read");
pkt->makeResponse();
} else if (pkt->isWrite()) {
- if (pmemAddr)
- memcpy(hostAddr, pkt->getConstPtr<uint8_t>(), pkt->getSize());
+ if (pmemAddr) {
+ pkt->writeData(host_addr);
+ }
TRACE_PACKET("Write");
pkt->makeResponse();
} else if (pkt->isPrint()) {
// through printObj().
prs->printLabels();
// Right now we just print the single byte at the specified address.
- ccprintf(prs->os, "%s%#x\n", prs->curPrefix(), *hostAddr);
+ ccprintf(prs->os, "%s%#x\n", prs->curPrefix(), *host_addr);
} else {
panic("AbstractMemory: unimplemented functional command %s",
pkt->cmdString());