2006-02-03 20:54:37 +01:00
|
|
|
/*
|
2010-11-08 20:58:25 +01:00
|
|
|
* Copyright (c) 2010 ARM Limited
|
|
|
|
* All rights reserved
|
|
|
|
*
|
|
|
|
* The license below extends only to copyright in the software and shall
|
|
|
|
* not be construed as granting a license to any other intellectual
|
|
|
|
* property including but not limited to intellectual property relating
|
|
|
|
* to a hardware implementation of the functionality of the software
|
|
|
|
* licensed hereunder. You may use the software subject to the license
|
|
|
|
* terms below provided that you ensure that this notice is replicated
|
|
|
|
* unmodified and in its entirety in all distributions of the software,
|
|
|
|
* modified or unmodified, in source code or in binary form.
|
|
|
|
*
|
2006-02-03 20:54:37 +01:00
|
|
|
* 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.
|
2006-06-01 01:26:56 +02:00
|
|
|
*
|
|
|
|
* Authors: Ron Dreslinski
|
2006-07-21 01:03:47 +02:00
|
|
|
* Ali Saidi
|
2006-02-03 20:54:37 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sys/mman.h>
|
2011-04-15 19:44:06 +02:00
|
|
|
#include <sys/types.h>
|
2010-11-08 20:58:24 +01:00
|
|
|
#include <sys/user.h>
|
2006-02-03 20:54:37 +01:00
|
|
|
#include <fcntl.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <zlib.h>
|
|
|
|
|
2011-04-15 19:44:06 +02:00
|
|
|
#include <cerrno>
|
2009-11-05 01:57:01 +01:00
|
|
|
#include <cstdio>
|
2006-02-03 20:54:37 +01:00
|
|
|
#include <iostream>
|
|
|
|
#include <string>
|
|
|
|
|
2011-02-23 22:10:49 +01:00
|
|
|
#include "arch/isa_traits.hh"
|
2009-07-09 08:02:21 +02:00
|
|
|
#include "arch/registers.hh"
|
2010-11-08 20:58:24 +01:00
|
|
|
#include "base/intmath.hh"
|
2006-02-03 20:54:37 +01:00
|
|
|
#include "base/misc.hh"
|
2008-04-10 20:44:52 +02:00
|
|
|
#include "base/random.hh"
|
2009-05-17 23:34:52 +02:00
|
|
|
#include "base/types.hh"
|
2006-02-03 20:54:37 +01:00
|
|
|
#include "config/full_system.hh"
|
2009-09-23 17:34:21 +02:00
|
|
|
#include "config/the_isa.hh"
|
2011-04-15 19:44:32 +02:00
|
|
|
#include "debug/LLSC.hh"
|
|
|
|
#include "debug/MemoryAccess.hh"
|
2006-12-27 20:32:26 +01:00
|
|
|
#include "mem/packet_access.hh"
|
2006-02-15 20:21:09 +01:00
|
|
|
#include "mem/physical.hh"
|
2006-02-23 19:51:54 +01:00
|
|
|
#include "sim/eventq.hh"
|
2006-02-15 20:21:09 +01:00
|
|
|
|
2006-02-03 20:54:37 +01:00
|
|
|
using namespace std;
|
2006-03-10 01:21:35 +01:00
|
|
|
using namespace TheISA;
|
2006-02-03 20:54:37 +01:00
|
|
|
|
2007-07-24 06:51:38 +02:00
|
|
|
PhysicalMemory::PhysicalMemory(const Params *p)
|
2010-11-20 01:01:01 +01:00
|
|
|
: MemObject(p), pmemAddr(NULL), lat(p->latency), lat_var(p->latency_var),
|
2010-11-08 20:58:24 +01:00
|
|
|
_size(params()->range.size()), _start(params()->range.start)
|
2006-02-03 20:54:37 +01:00
|
|
|
{
|
2010-11-08 20:58:24 +01:00
|
|
|
if (size() % TheISA::PageBytes != 0)
|
2006-02-03 20:54:37 +01:00
|
|
|
panic("Memory Size not divisible by page size\n");
|
|
|
|
|
2008-06-16 06:39:29 +02:00
|
|
|
if (params()->null)
|
|
|
|
return;
|
|
|
|
|
2010-11-08 20:58:24 +01:00
|
|
|
|
|
|
|
if (params()->file == "") {
|
|
|
|
int map_flags = MAP_ANON | MAP_PRIVATE;
|
|
|
|
pmemAddr = (uint8_t *)mmap(NULL, size(),
|
|
|
|
PROT_READ | PROT_WRITE, map_flags, -1, 0);
|
|
|
|
} else {
|
|
|
|
int map_flags = MAP_PRIVATE;
|
|
|
|
int fd = open(params()->file.c_str(), O_RDONLY);
|
|
|
|
_size = lseek(fd, 0, SEEK_END);
|
|
|
|
lseek(fd, 0, SEEK_SET);
|
|
|
|
pmemAddr = (uint8_t *)mmap(NULL, roundUp(size(), PAGE_SIZE),
|
|
|
|
PROT_READ | PROT_WRITE, map_flags, fd, 0);
|
|
|
|
}
|
2006-02-03 20:54:37 +01:00
|
|
|
|
2006-08-17 01:01:11 +02:00
|
|
|
if (pmemAddr == (void *)MAP_FAILED) {
|
2006-02-03 20:54:37 +01:00
|
|
|
perror("mmap");
|
2010-11-08 20:58:24 +01:00
|
|
|
if (params()->file == "")
|
|
|
|
fatal("Could not mmap!\n");
|
|
|
|
else
|
|
|
|
fatal("Could not find file: %s\n", params()->file);
|
2006-02-03 20:54:37 +01:00
|
|
|
}
|
|
|
|
|
2006-11-23 05:09:27 +01:00
|
|
|
//If requested, initialize all the memory to 0
|
2007-07-24 06:51:38 +02:00
|
|
|
if (p->zero)
|
2010-11-08 20:58:24 +01:00
|
|
|
memset(pmemAddr, 0, size());
|
2006-02-03 20:54:37 +01:00
|
|
|
}
|
|
|
|
|
2006-04-10 20:40:22 +02:00
|
|
|
void
|
|
|
|
PhysicalMemory::init()
|
|
|
|
{
|
2007-05-21 03:23:05 +02:00
|
|
|
if (ports.size() == 0) {
|
|
|
|
fatal("PhysicalMemory object %s is unconnected!", name());
|
|
|
|
}
|
|
|
|
|
2007-05-19 06:24:34 +02:00
|
|
|
for (PortIterator pi = ports.begin(); pi != ports.end(); ++pi) {
|
|
|
|
if (*pi)
|
|
|
|
(*pi)->sendStatusChange(Port::RangeChange);
|
|
|
|
}
|
2006-04-10 20:40:22 +02:00
|
|
|
}
|
|
|
|
|
2006-02-03 20:54:37 +01:00
|
|
|
PhysicalMemory::~PhysicalMemory()
|
|
|
|
{
|
2006-08-17 01:01:11 +02:00
|
|
|
if (pmemAddr)
|
2010-11-08 20:58:24 +01:00
|
|
|
munmap((char*)pmemAddr, size());
|
2006-02-03 20:54:37 +01:00
|
|
|
}
|
|
|
|
|
2009-06-05 08:21:12 +02:00
|
|
|
unsigned
|
|
|
|
PhysicalMemory::deviceBlockSize() const
|
2006-02-21 19:39:01 +01:00
|
|
|
{
|
2006-02-22 02:04:23 +01:00
|
|
|
//Can accept anysize request
|
|
|
|
return 0;
|
2006-02-21 19:39:01 +01:00
|
|
|
}
|
|
|
|
|
2006-08-17 01:01:11 +02:00
|
|
|
Tick
|
2006-10-20 09:10:12 +02:00
|
|
|
PhysicalMemory::calculateLatency(PacketPtr pkt)
|
2006-08-17 01:01:11 +02:00
|
|
|
{
|
2008-04-10 20:44:52 +02:00
|
|
|
Tick latency = lat;
|
|
|
|
if (lat_var != 0)
|
|
|
|
latency += random_mt.random<Tick>(0, lat_var);
|
|
|
|
return latency;
|
2006-08-17 01:01:11 +02:00
|
|
|
}
|
2006-02-22 23:29:04 +01:00
|
|
|
|
2006-10-08 19:53:24 +02:00
|
|
|
|
|
|
|
|
|
|
|
// Add load-locked to tracking list. Should only be called if the
|
2009-04-19 13:25:01 +02:00
|
|
|
// operation is a load and the LLSC flag is set.
|
2006-10-08 19:53:24 +02:00
|
|
|
void
|
2007-06-18 02:27:53 +02:00
|
|
|
PhysicalMemory::trackLoadLocked(PacketPtr pkt)
|
2006-10-08 19:53:24 +02:00
|
|
|
{
|
2007-06-18 02:27:53 +02:00
|
|
|
Request *req = pkt->req;
|
2006-10-08 19:53:24 +02:00
|
|
|
Addr paddr = LockedAddr::mask(req->getPaddr());
|
|
|
|
|
|
|
|
// first we check if we already have a locked addr for this
|
|
|
|
// xc. Since each xc only gets one, we just update the
|
|
|
|
// existing record with the new address.
|
|
|
|
list<LockedAddr>::iterator i;
|
|
|
|
|
|
|
|
for (i = lockedAddrList.begin(); i != lockedAddrList.end(); ++i) {
|
|
|
|
if (i->matchesContext(req)) {
|
2008-11-03 03:57:07 +01:00
|
|
|
DPRINTF(LLSC, "Modifying lock record: context %d addr %#x\n",
|
|
|
|
req->contextId(), paddr);
|
2006-10-08 19:53:24 +02:00
|
|
|
i->addr = paddr;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// no record for this xc: need to allocate a new one
|
2008-11-03 03:57:07 +01:00
|
|
|
DPRINTF(LLSC, "Adding lock record: context %d addr %#x\n",
|
|
|
|
req->contextId(), paddr);
|
2006-10-08 19:53:24 +02:00
|
|
|
lockedAddrList.push_front(LockedAddr(req));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Called on *writes* only... both regular stores and
|
|
|
|
// store-conditional operations. Check for conventional stores which
|
|
|
|
// conflict with locked addresses, and for success/failure of store
|
|
|
|
// conditionals.
|
|
|
|
bool
|
2007-06-18 02:27:53 +02:00
|
|
|
PhysicalMemory::checkLockedAddrList(PacketPtr pkt)
|
2006-10-08 19:53:24 +02:00
|
|
|
{
|
2007-06-18 02:27:53 +02:00
|
|
|
Request *req = pkt->req;
|
2006-10-08 19:53:24 +02:00
|
|
|
Addr paddr = LockedAddr::mask(req->getPaddr());
|
2009-04-20 06:44:15 +02:00
|
|
|
bool isLLSC = pkt->isLLSC();
|
2006-10-08 19:53:24 +02:00
|
|
|
|
|
|
|
// Initialize return value. Non-conditional stores always
|
|
|
|
// succeed. Assume conditional stores will fail until proven
|
|
|
|
// otherwise.
|
2009-04-20 06:44:15 +02:00
|
|
|
bool success = !isLLSC;
|
2006-10-08 19:53:24 +02:00
|
|
|
|
|
|
|
// Iterate over list. Note that there could be multiple matching
|
|
|
|
// records, as more than one context could have done a load locked
|
|
|
|
// to this location.
|
|
|
|
list<LockedAddr>::iterator i = lockedAddrList.begin();
|
|
|
|
|
|
|
|
while (i != lockedAddrList.end()) {
|
|
|
|
|
|
|
|
if (i->addr == paddr) {
|
|
|
|
// we have a matching address
|
|
|
|
|
2009-04-20 06:44:15 +02:00
|
|
|
if (isLLSC && i->matchesContext(req)) {
|
2006-10-08 19:53:24 +02:00
|
|
|
// it's a store conditional, and as far as the memory
|
|
|
|
// system can tell, the requesting context's lock is
|
|
|
|
// still valid.
|
2008-11-03 03:57:07 +01:00
|
|
|
DPRINTF(LLSC, "StCond success: context %d addr %#x\n",
|
|
|
|
req->contextId(), paddr);
|
2006-10-08 19:53:24 +02:00
|
|
|
success = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get rid of our record of this lock and advance to next
|
2008-11-03 03:57:07 +01:00
|
|
|
DPRINTF(LLSC, "Erasing lock record: context %d addr %#x\n",
|
|
|
|
i->contextId, paddr);
|
2006-10-08 19:53:24 +02:00
|
|
|
i = lockedAddrList.erase(i);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// no match: advance to next record
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-04-20 06:44:15 +02:00
|
|
|
if (isLLSC) {
|
2007-02-12 19:06:30 +01:00
|
|
|
req->setExtraData(success ? 1 : 0);
|
2006-10-08 19:53:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return success;
|
|
|
|
}
|
|
|
|
|
2007-06-18 02:27:53 +02:00
|
|
|
|
|
|
|
#if TRACING_ON
|
|
|
|
|
|
|
|
#define CASE(A, T) \
|
|
|
|
case sizeof(T): \
|
2009-08-02 07:50:14 +02:00
|
|
|
DPRINTF(MemoryAccess,"%s of size %i on address 0x%x data 0x%x\n", \
|
|
|
|
A, pkt->getSize(), pkt->getAddr(), pkt->get<T>()); \
|
2007-06-18 02:27:53 +02:00
|
|
|
break
|
|
|
|
|
|
|
|
|
|
|
|
#define TRACE_PACKET(A) \
|
|
|
|
do { \
|
|
|
|
switch (pkt->getSize()) { \
|
|
|
|
CASE(A, uint64_t); \
|
|
|
|
CASE(A, uint32_t); \
|
|
|
|
CASE(A, uint16_t); \
|
|
|
|
CASE(A, uint8_t); \
|
|
|
|
default: \
|
2009-08-02 07:50:14 +02:00
|
|
|
DPRINTF(MemoryAccess, "%s of size %i on address 0x%x\n", \
|
|
|
|
A, pkt->getSize(), pkt->getAddr()); \
|
2011-02-23 22:10:50 +01:00
|
|
|
DDUMP(MemoryAccess, pkt->getPtr<uint8_t>(), pkt->getSize());\
|
2007-06-18 02:27:53 +02:00
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
#define TRACE_PACKET(A)
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
Tick
|
|
|
|
PhysicalMemory::doAtomicAccess(PacketPtr pkt)
|
2006-02-22 23:29:04 +01:00
|
|
|
{
|
2007-02-12 19:06:30 +01:00
|
|
|
assert(pkt->getAddr() >= start() &&
|
|
|
|
pkt->getAddr() + pkt->getSize() <= start() + size());
|
2006-02-22 23:43:08 +01:00
|
|
|
|
2007-06-18 02:27:53 +02:00
|
|
|
if (pkt->memInhibitAsserted()) {
|
|
|
|
DPRINTF(MemoryAccess, "mem inhibited on 0x%x: not responding\n",
|
|
|
|
pkt->getAddr());
|
|
|
|
return 0;
|
2006-10-09 01:05:48 +02:00
|
|
|
}
|
2007-06-18 02:27:53 +02:00
|
|
|
|
|
|
|
uint8_t *hostAddr = pmemAddr + pkt->getAddr() - start();
|
|
|
|
|
|
|
|
if (pkt->cmd == MemCmd::SwapReq) {
|
2007-02-12 19:06:30 +01:00
|
|
|
IntReg overwrite_val;
|
|
|
|
bool overwrite_mem;
|
|
|
|
uint64_t condition_val64;
|
|
|
|
uint32_t condition_val32;
|
|
|
|
|
2008-06-16 06:39:29 +02:00
|
|
|
if (!pmemAddr)
|
|
|
|
panic("Swap only works if there is real memory (i.e. null=False)");
|
2007-02-12 19:06:30 +01:00
|
|
|
assert(sizeof(IntReg) >= pkt->getSize());
|
|
|
|
|
|
|
|
overwrite_mem = true;
|
|
|
|
// keep a copy of our possible write value, and copy what is at the
|
|
|
|
// memory address into the packet
|
2007-02-13 00:40:08 +01:00
|
|
|
std::memcpy(&overwrite_val, pkt->getPtr<uint8_t>(), pkt->getSize());
|
2007-06-18 02:27:53 +02:00
|
|
|
std::memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize());
|
2007-02-12 19:06:30 +01:00
|
|
|
|
|
|
|
if (pkt->req->isCondSwap()) {
|
|
|
|
if (pkt->getSize() == sizeof(uint64_t)) {
|
2007-02-13 00:40:08 +01:00
|
|
|
condition_val64 = pkt->req->getExtraData();
|
2007-06-18 02:27:53 +02:00
|
|
|
overwrite_mem = !std::memcmp(&condition_val64, hostAddr,
|
|
|
|
sizeof(uint64_t));
|
2007-02-12 19:06:30 +01:00
|
|
|
} else if (pkt->getSize() == sizeof(uint32_t)) {
|
2007-02-13 00:40:08 +01:00
|
|
|
condition_val32 = (uint32_t)pkt->req->getExtraData();
|
2007-06-18 02:27:53 +02:00
|
|
|
overwrite_mem = !std::memcmp(&condition_val32, hostAddr,
|
|
|
|
sizeof(uint32_t));
|
2007-02-12 19:06:30 +01:00
|
|
|
} else
|
|
|
|
panic("Invalid size for conditional read/write\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (overwrite_mem)
|
2007-06-18 02:27:53 +02:00
|
|
|
std::memcpy(hostAddr, &overwrite_val, pkt->getSize());
|
2007-02-12 19:06:30 +01:00
|
|
|
|
2009-08-02 07:50:14 +02:00
|
|
|
assert(!pkt->req->isInstFetch());
|
2007-06-18 02:27:53 +02:00
|
|
|
TRACE_PACKET("Read/Write");
|
|
|
|
} else if (pkt->isRead()) {
|
|
|
|
assert(!pkt->isWrite());
|
2009-04-20 06:44:15 +02:00
|
|
|
if (pkt->isLLSC()) {
|
2007-06-18 02:27:53 +02:00
|
|
|
trackLoadLocked(pkt);
|
|
|
|
}
|
2008-06-16 06:39:29 +02:00
|
|
|
if (pmemAddr)
|
|
|
|
memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize());
|
2009-08-02 07:50:14 +02:00
|
|
|
TRACE_PACKET(pkt->req->isInstFetch() ? "IFetch" : "Read");
|
2007-06-18 02:27:53 +02:00
|
|
|
} else if (pkt->isWrite()) {
|
|
|
|
if (writeOK(pkt)) {
|
2008-06-16 06:39:29 +02:00
|
|
|
if (pmemAddr)
|
|
|
|
memcpy(hostAddr, pkt->getPtr<uint8_t>(), pkt->getSize());
|
2009-08-02 07:50:14 +02:00
|
|
|
assert(!pkt->req->isInstFetch());
|
2007-06-18 02:27:53 +02:00
|
|
|
TRACE_PACKET("Write");
|
|
|
|
}
|
|
|
|
} else if (pkt->isInvalidate()) {
|
|
|
|
//upgrade or invalidate
|
|
|
|
if (pkt->needsResponse()) {
|
|
|
|
pkt->makeAtomicResponse();
|
2007-02-12 19:06:30 +01:00
|
|
|
}
|
|
|
|
} else {
|
2006-02-22 23:29:04 +01:00
|
|
|
panic("unimplemented");
|
|
|
|
}
|
2006-03-02 16:31:48 +01:00
|
|
|
|
2007-06-18 02:27:53 +02:00
|
|
|
if (pkt->needsResponse()) {
|
|
|
|
pkt->makeAtomicResponse();
|
|
|
|
}
|
|
|
|
return calculateLatency(pkt);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
PhysicalMemory::doFunctionalAccess(PacketPtr pkt)
|
|
|
|
{
|
|
|
|
assert(pkt->getAddr() >= start() &&
|
|
|
|
pkt->getAddr() + pkt->getSize() <= start() + size());
|
|
|
|
|
2007-11-13 22:58:16 +01:00
|
|
|
|
2007-06-18 02:27:53 +02:00
|
|
|
uint8_t *hostAddr = pmemAddr + pkt->getAddr() - start();
|
|
|
|
|
2008-01-02 21:20:15 +01:00
|
|
|
if (pkt->isRead()) {
|
2008-06-16 06:39:29 +02:00
|
|
|
if (pmemAddr)
|
|
|
|
memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize());
|
2007-06-18 02:27:53 +02:00
|
|
|
TRACE_PACKET("Read");
|
2008-01-02 21:20:15 +01:00
|
|
|
pkt->makeAtomicResponse();
|
|
|
|
} else if (pkt->isWrite()) {
|
2008-06-16 06:39:29 +02:00
|
|
|
if (pmemAddr)
|
|
|
|
memcpy(hostAddr, pkt->getPtr<uint8_t>(), pkt->getSize());
|
2007-06-18 02:27:53 +02:00
|
|
|
TRACE_PACKET("Write");
|
2008-01-02 21:20:15 +01:00
|
|
|
pkt->makeAtomicResponse();
|
|
|
|
} else if (pkt->isPrint()) {
|
2008-01-02 22:46:22 +01:00
|
|
|
Packet::PrintReqState *prs =
|
|
|
|
dynamic_cast<Packet::PrintReqState*>(pkt->senderState);
|
|
|
|
// Need to call printLabels() explicitly since we're not going
|
|
|
|
// through printObj().
|
2008-01-02 21:20:15 +01:00
|
|
|
prs->printLabels();
|
2008-01-02 22:46:22 +01:00
|
|
|
// Right now we just print the single byte at the specified address.
|
2008-01-02 21:20:15 +01:00
|
|
|
ccprintf(prs->os, "%s%#x\n", prs->curPrefix(), *hostAddr);
|
2007-06-18 02:27:53 +02:00
|
|
|
} else {
|
|
|
|
panic("PhysicalMemory: unimplemented functional command %s",
|
|
|
|
pkt->cmdString());
|
|
|
|
}
|
2006-02-22 23:29:04 +01:00
|
|
|
}
|
|
|
|
|
2007-06-18 02:27:53 +02:00
|
|
|
|
2006-02-22 23:29:04 +01:00
|
|
|
Port *
|
2006-06-14 05:19:28 +02:00
|
|
|
PhysicalMemory::getPort(const std::string &if_name, int idx)
|
2006-02-22 23:29:04 +01:00
|
|
|
{
|
2007-05-19 07:20:58 +02:00
|
|
|
// Accept request for "functional" port for backwards compatibility
|
|
|
|
// with places where this function is called from C++. I'd prefer
|
|
|
|
// to move all these into Python someday.
|
|
|
|
if (if_name == "functional") {
|
|
|
|
return new MemoryPort(csprintf("%s-functional", name()), this);
|
|
|
|
}
|
|
|
|
|
2007-05-19 06:24:34 +02:00
|
|
|
if (if_name != "port") {
|
2006-03-12 23:21:59 +01:00
|
|
|
panic("PhysicalMemory::getPort: unknown port %s requested", if_name);
|
|
|
|
}
|
2007-05-19 06:24:34 +02:00
|
|
|
|
2009-06-05 08:21:12 +02:00
|
|
|
if (idx >= (int)ports.size()) {
|
|
|
|
ports.resize(idx + 1);
|
2007-05-19 06:24:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ports[idx] != NULL) {
|
|
|
|
panic("PhysicalMemory::getPort: port %d already assigned", idx);
|
|
|
|
}
|
|
|
|
|
|
|
|
MemoryPort *port =
|
|
|
|
new MemoryPort(csprintf("%s-port%d", name(), idx), this);
|
|
|
|
|
|
|
|
ports[idx] = port;
|
|
|
|
return port;
|
2006-02-22 23:29:04 +01:00
|
|
|
}
|
|
|
|
|
2007-05-19 06:24:34 +02:00
|
|
|
|
2006-02-22 23:29:04 +01:00
|
|
|
void
|
|
|
|
PhysicalMemory::recvStatusChange(Port::Status status)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2006-05-26 19:48:35 +02:00
|
|
|
PhysicalMemory::MemoryPort::MemoryPort(const std::string &_name,
|
|
|
|
PhysicalMemory *_memory)
|
2008-10-09 13:58:24 +02:00
|
|
|
: SimpleTimingPort(_name, _memory), memory(_memory)
|
2006-02-22 23:29:04 +01:00
|
|
|
{ }
|
|
|
|
|
|
|
|
void
|
|
|
|
PhysicalMemory::MemoryPort::recvStatusChange(Port::Status status)
|
|
|
|
{
|
|
|
|
memory->recvStatusChange(status);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2006-04-06 20:57:51 +02:00
|
|
|
PhysicalMemory::MemoryPort::getDeviceAddressRanges(AddrRangeList &resp,
|
2007-05-22 08:36:09 +02:00
|
|
|
bool &snoop)
|
2006-02-22 23:29:04 +01:00
|
|
|
{
|
2006-04-06 20:57:51 +02:00
|
|
|
memory->getAddressRanges(resp, snoop);
|
2006-03-26 00:31:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2007-05-22 08:36:09 +02:00
|
|
|
PhysicalMemory::getAddressRanges(AddrRangeList &resp, bool &snoop)
|
2006-03-26 00:31:20 +01:00
|
|
|
{
|
2007-05-22 08:36:09 +02:00
|
|
|
snoop = false;
|
2006-04-06 20:57:51 +02:00
|
|
|
resp.clear();
|
2010-11-08 20:58:24 +01:00
|
|
|
resp.push_back(RangeSize(start(), size()));
|
2006-02-22 23:29:04 +01:00
|
|
|
}
|
|
|
|
|
2009-06-05 08:21:12 +02:00
|
|
|
unsigned
|
|
|
|
PhysicalMemory::MemoryPort::deviceBlockSize() const
|
2006-02-23 19:51:54 +01:00
|
|
|
{
|
|
|
|
return memory->deviceBlockSize();
|
|
|
|
}
|
2006-02-22 23:29:04 +01:00
|
|
|
|
|
|
|
Tick
|
2006-10-20 09:10:12 +02:00
|
|
|
PhysicalMemory::MemoryPort::recvAtomic(PacketPtr pkt)
|
2006-02-22 23:29:04 +01:00
|
|
|
{
|
2007-06-18 02:27:53 +02:00
|
|
|
return memory->doAtomicAccess(pkt);
|
2006-02-22 23:29:04 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2006-10-20 09:10:12 +02:00
|
|
|
PhysicalMemory::MemoryPort::recvFunctional(PacketPtr pkt)
|
2006-02-22 23:29:04 +01:00
|
|
|
{
|
2008-01-02 21:20:15 +01:00
|
|
|
pkt->pushLabel(memory->name());
|
|
|
|
|
2007-07-30 05:17:03 +02:00
|
|
|
if (!checkFunctional(pkt)) {
|
|
|
|
// Default implementation of SimpleTimingPort::recvFunctional()
|
|
|
|
// calls recvAtomic() and throws away the latency; we can save a
|
|
|
|
// little here by just not calculating the latency.
|
|
|
|
memory->doFunctionalAccess(pkt);
|
|
|
|
}
|
2008-01-02 21:20:15 +01:00
|
|
|
|
|
|
|
pkt->popLabel();
|
2006-02-22 23:29:04 +01:00
|
|
|
}
|
|
|
|
|
2006-07-21 01:03:47 +02:00
|
|
|
unsigned int
|
|
|
|
PhysicalMemory::drain(Event *de)
|
|
|
|
{
|
2007-05-19 06:24:34 +02:00
|
|
|
int count = 0;
|
|
|
|
for (PortIterator pi = ports.begin(); pi != ports.end(); ++pi) {
|
|
|
|
count += (*pi)->drain(de);
|
|
|
|
}
|
|
|
|
|
2006-07-21 01:03:47 +02:00
|
|
|
if (count)
|
|
|
|
changeState(Draining);
|
|
|
|
else
|
|
|
|
changeState(Drained);
|
|
|
|
return count;
|
|
|
|
}
|
2006-02-22 23:29:04 +01:00
|
|
|
|
2006-02-03 20:54:37 +01:00
|
|
|
void
|
|
|
|
PhysicalMemory::serialize(ostream &os)
|
|
|
|
{
|
2008-06-16 06:39:29 +02:00
|
|
|
if (!pmemAddr)
|
|
|
|
return;
|
|
|
|
|
2006-02-03 20:54:37 +01:00
|
|
|
gzFile compressedMem;
|
|
|
|
string filename = name() + ".physmem";
|
|
|
|
|
|
|
|
SERIALIZE_SCALAR(filename);
|
2010-11-08 20:58:24 +01:00
|
|
|
SERIALIZE_SCALAR(_size);
|
2006-02-03 20:54:37 +01:00
|
|
|
|
|
|
|
// write memory file
|
|
|
|
string thefile = Checkpoint::dir() + "/" + filename.c_str();
|
|
|
|
int fd = creat(thefile.c_str(), 0664);
|
|
|
|
if (fd < 0) {
|
|
|
|
perror("creat");
|
|
|
|
fatal("Can't open physical memory checkpoint file '%s'\n", filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
compressedMem = gzdopen(fd, "wb");
|
|
|
|
if (compressedMem == NULL)
|
|
|
|
fatal("Insufficient memory to allocate compression state for %s\n",
|
|
|
|
filename);
|
|
|
|
|
2010-11-08 20:58:24 +01:00
|
|
|
if (gzwrite(compressedMem, pmemAddr, size()) != (int)size()) {
|
2006-02-03 20:54:37 +01:00
|
|
|
fatal("Write failed on physical memory checkpoint file '%s'\n",
|
|
|
|
filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (gzclose(compressedMem))
|
|
|
|
fatal("Close failed on physical memory checkpoint file '%s'\n",
|
|
|
|
filename);
|
2010-11-08 20:58:25 +01:00
|
|
|
|
|
|
|
list<LockedAddr>::iterator i = lockedAddrList.begin();
|
|
|
|
|
|
|
|
vector<Addr> lal_addr;
|
|
|
|
vector<int> lal_cid;
|
|
|
|
while (i != lockedAddrList.end()) {
|
|
|
|
lal_addr.push_back(i->addr);
|
|
|
|
lal_cid.push_back(i->contextId);
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
arrayParamOut(os, "lal_addr", lal_addr);
|
|
|
|
arrayParamOut(os, "lal_cid", lal_cid);
|
2006-02-03 20:54:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
PhysicalMemory::unserialize(Checkpoint *cp, const string §ion)
|
|
|
|
{
|
2008-06-16 06:39:29 +02:00
|
|
|
if (!pmemAddr)
|
|
|
|
return;
|
|
|
|
|
2006-02-03 20:54:37 +01:00
|
|
|
gzFile compressedMem;
|
|
|
|
long *tempPage;
|
|
|
|
long *pmem_current;
|
|
|
|
uint64_t curSize;
|
|
|
|
uint32_t bytesRead;
|
2009-06-05 08:21:12 +02:00
|
|
|
const uint32_t chunkSize = 16384;
|
2006-02-03 20:54:37 +01:00
|
|
|
|
|
|
|
string filename;
|
|
|
|
|
|
|
|
UNSERIALIZE_SCALAR(filename);
|
|
|
|
|
|
|
|
filename = cp->cptDir + "/" + filename;
|
|
|
|
|
|
|
|
// mmap memoryfile
|
|
|
|
int fd = open(filename.c_str(), O_RDONLY);
|
|
|
|
if (fd < 0) {
|
|
|
|
perror("open");
|
|
|
|
fatal("Can't open physical memory checkpoint file '%s'", filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
compressedMem = gzdopen(fd, "rb");
|
|
|
|
if (compressedMem == NULL)
|
|
|
|
fatal("Insufficient memory to allocate compression state for %s\n",
|
|
|
|
filename);
|
|
|
|
|
2011-03-02 08:18:47 +01:00
|
|
|
// unmap file that was mmapped in the constructor
|
2006-08-17 01:01:11 +02:00
|
|
|
// This is done here to make sure that gzip and open don't muck with our
|
|
|
|
// nice large space of memory before we reallocate it
|
2010-11-08 20:58:24 +01:00
|
|
|
munmap((char*)pmemAddr, size());
|
|
|
|
|
|
|
|
UNSERIALIZE_SCALAR(_size);
|
|
|
|
if (size() > params()->range.size())
|
|
|
|
fatal("Memory size has changed!\n");
|
2006-02-03 20:54:37 +01:00
|
|
|
|
2010-11-08 20:58:24 +01:00
|
|
|
pmemAddr = (uint8_t *)mmap(NULL, size(),
|
2007-07-24 06:51:38 +02:00
|
|
|
PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
|
2006-02-03 20:54:37 +01:00
|
|
|
|
2006-08-17 01:01:11 +02:00
|
|
|
if (pmemAddr == (void *)MAP_FAILED) {
|
2006-02-03 20:54:37 +01:00
|
|
|
perror("mmap");
|
|
|
|
fatal("Could not mmap physical memory!\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
curSize = 0;
|
|
|
|
tempPage = (long*)malloc(chunkSize);
|
|
|
|
if (tempPage == NULL)
|
|
|
|
fatal("Unable to malloc memory to read file %s\n", filename);
|
|
|
|
|
|
|
|
/* Only copy bytes that are non-zero, so we don't give the VM system hell */
|
2010-11-08 20:58:24 +01:00
|
|
|
while (curSize < size()) {
|
2006-02-03 20:54:37 +01:00
|
|
|
bytesRead = gzread(compressedMem, tempPage, chunkSize);
|
2010-01-20 07:03:44 +01:00
|
|
|
if (bytesRead == 0)
|
|
|
|
break;
|
2006-02-03 20:54:37 +01:00
|
|
|
|
|
|
|
assert(bytesRead % sizeof(long) == 0);
|
|
|
|
|
2009-06-05 08:21:12 +02:00
|
|
|
for (uint32_t x = 0; x < bytesRead / sizeof(long); x++)
|
2006-02-03 20:54:37 +01:00
|
|
|
{
|
|
|
|
if (*(tempPage+x) != 0) {
|
2006-08-17 01:01:11 +02:00
|
|
|
pmem_current = (long*)(pmemAddr + curSize + x * sizeof(long));
|
2006-02-03 20:54:37 +01:00
|
|
|
*pmem_current = *(tempPage+x);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
curSize += bytesRead;
|
|
|
|
}
|
|
|
|
|
|
|
|
free(tempPage);
|
|
|
|
|
|
|
|
if (gzclose(compressedMem))
|
|
|
|
fatal("Close failed on physical memory checkpoint file '%s'\n",
|
|
|
|
filename);
|
|
|
|
|
2010-11-08 20:58:25 +01:00
|
|
|
vector<Addr> lal_addr;
|
|
|
|
vector<int> lal_cid;
|
|
|
|
arrayParamIn(cp, section, "lal_addr", lal_addr);
|
|
|
|
arrayParamIn(cp, section, "lal_cid", lal_cid);
|
|
|
|
for(int i = 0; i < lal_addr.size(); i++)
|
|
|
|
lockedAddrList.push_front(LockedAddr(lal_addr[i], lal_cid[i]));
|
2006-02-03 20:54:37 +01:00
|
|
|
}
|
|
|
|
|
2007-07-24 06:51:38 +02:00
|
|
|
PhysicalMemory *
|
|
|
|
PhysicalMemoryParams::create()
|
2006-02-03 20:54:37 +01:00
|
|
|
{
|
2007-07-24 06:51:38 +02:00
|
|
|
return new PhysicalMemory(this);
|
2006-02-03 20:54:37 +01:00
|
|
|
}
|