diff options
Diffstat (limited to 'src/mem/physical.cc')
-rw-r--r-- | src/mem/physical.cc | 642 |
1 files changed, 57 insertions, 585 deletions
diff --git a/src/mem/physical.cc b/src/mem/physical.cc index 78181b7df..5f92976f9 100644 --- a/src/mem/physical.cc +++ b/src/mem/physical.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2011 ARM Limited + * Copyright (c) 2012 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -11,9 +11,6 @@ * unmodified and in its entirety in all distributions of the software, * modified or unmodified, in source code or in binary form. * - * 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 @@ -37,618 +34,93 @@ * (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 + * Authors: Andreas Hansson */ -#include <sys/mman.h> -#include <sys/types.h> -#include <sys/user.h> -#include <fcntl.h> -#include <unistd.h> -#include <zlib.h> - -#include <cerrno> -#include <cstdio> -#include <iostream> -#include <string> - -#include "arch/isa_traits.hh" -#include "arch/registers.hh" -#include "base/intmath.hh" -#include "base/misc.hh" -#include "base/random.hh" -#include "base/types.hh" -#include "config/the_isa.hh" -#include "debug/LLSC.hh" -#include "debug/MemoryAccess.hh" -#include "mem/packet_access.hh" +#include "debug/BusAddrRanges.hh" #include "mem/physical.hh" -#include "sim/eventq.hh" using namespace std; -using namespace TheISA; - -PhysicalMemory::PhysicalMemory(const Params *p) - : MemObject(p), pmemAddr(NULL), lat(p->latency), lat_var(p->latency_var), - _size(params()->range.size()), _start(params()->range.start) -{ - if (size() % TheISA::PageBytes != 0) - panic("Memory Size not divisible by page size\n"); - - // create the appropriate number of ports - for (int i = 0; i < p->port_port_connection_count; ++i) { - ports.push_back(new MemoryPort(csprintf("%s-port%d", name(), i), - this)); - } - - if (params()->null) - return; - - - 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(), sysconf(_SC_PAGESIZE)), - PROT_READ | PROT_WRITE, map_flags, fd, 0); - } - - if (pmemAddr == (void *)MAP_FAILED) { - perror("mmap"); - if (params()->file == "") - fatal("Could not mmap!\n"); - else - fatal("Could not find file: %s\n", params()->file); - } - - //If requested, initialize all the memory to 0 - if (p->zero) - memset(pmemAddr, 0, size()); -} - -void -PhysicalMemory::init() -{ - for (PortIterator p = ports.begin(); p != ports.end(); ++p) { - if (!(*p)->isConnected()) { - fatal("PhysicalMemory port %s is unconnected!\n", (*p)->name()); - } else { - (*p)->sendRangeChange(); - } - } -} - -PhysicalMemory::~PhysicalMemory() -{ - if (pmemAddr) - munmap((char*)pmemAddr, size()); -} - -void -PhysicalMemory::regStats() -{ - using namespace Stats; - - bytesRead - .name(name() + ".bytes_read") - .desc("Number of bytes read from this memory") - ; - bytesInstRead - .name(name() + ".bytes_inst_read") - .desc("Number of instructions bytes read from this memory") - ; - bytesWritten - .name(name() + ".bytes_written") - .desc("Number of bytes written to this memory") - ; - numReads - .name(name() + ".num_reads") - .desc("Number of read requests responded to by this memory") - ; - numWrites - .name(name() + ".num_writes") - .desc("Number of write requests responded to by this memory") - ; - numOther - .name(name() + ".num_other") - .desc("Number of other requests responded to by this memory") - ; - bwRead - .name(name() + ".bw_read") - .desc("Total read bandwidth from this memory (bytes/s)") - .precision(0) - .prereq(bytesRead) - ; - bwInstRead - .name(name() + ".bw_inst_read") - .desc("Instruction read bandwidth from this memory (bytes/s)") - .precision(0) - .prereq(bytesInstRead) - ; - bwWrite - .name(name() + ".bw_write") - .desc("Write bandwidth from this memory (bytes/s)") - .precision(0) - .prereq(bytesWritten) - ; - bwTotal - .name(name() + ".bw_total") - .desc("Total bandwidth to/from this memory (bytes/s)") - .precision(0) - .prereq(bwTotal) - ; - bwRead = bytesRead / simSeconds; - bwInstRead = bytesInstRead / simSeconds; - bwWrite = bytesWritten / simSeconds; - bwTotal = (bytesRead + bytesWritten) / simSeconds; -} -unsigned -PhysicalMemory::deviceBlockSize() const -{ - //Can accept anysize request - return 0; -} - -Tick -PhysicalMemory::calculateLatency(PacketPtr pkt) -{ - Tick latency = lat; - if (lat_var != 0) - latency += random_mt.random<Tick>(0, lat_var); - return latency; -} - - - -// Add load-locked to tracking list. Should only be called if the -// operation is a load and the LLSC flag is set. -void -PhysicalMemory::trackLoadLocked(PacketPtr pkt) +PhysicalMemory::PhysicalMemory(const vector<AbstractMemory*>& _memories) : + size(0) { - Request *req = pkt->req; - Addr paddr = LockedAddr::mask(req->getPaddr()); + for (vector<AbstractMemory*>::const_iterator m = _memories.begin(); + m != _memories.end(); ++m) { + // only add the memory if it is part of the global address map + if ((*m)->isInAddrMap()) { + memories.push_back(*m); - // 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; + // calculate the total size once and for all + size += (*m)->size(); - for (i = lockedAddrList.begin(); i != lockedAddrList.end(); ++i) { - if (i->matchesContext(req)) { - DPRINTF(LLSC, "Modifying lock record: context %d addr %#x\n", - req->contextId(), paddr); - i->addr = paddr; - return; + // add the range to our interval tree and make sure it does not + // intersect an existing range + if (addrMap.insert((*m)->getAddrRange(), *m) == addrMap.end()) + fatal("Memory address range for %s is overlapping\n", + (*m)->name()); } + DPRINTF(BusAddrRanges, + "Skipping memory %s that is not in global address map\n", + (*m)->name()); } - - // no record for this xc: need to allocate a new one - DPRINTF(LLSC, "Adding lock record: context %d addr %#x\n", - req->contextId(), paddr); - lockedAddrList.push_front(LockedAddr(req)); + rangeCache.invalidate(); } - -// 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 -PhysicalMemory::checkLockedAddrList(PacketPtr pkt) -{ - Request *req = pkt->req; - Addr paddr = LockedAddr::mask(req->getPaddr()); - bool isLLSC = pkt->isLLSC(); - - // Initialize return value. Non-conditional stores always - // succeed. Assume conditional stores will fail until proven - // otherwise. - bool success = !isLLSC; - - // 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 - - if (isLLSC && i->matchesContext(req)) { - // it's a store conditional, and as far as the memory - // system can tell, the requesting context's lock is - // still valid. - DPRINTF(LLSC, "StCond success: context %d addr %#x\n", - req->contextId(), paddr); - success = true; - } - - // Get rid of our record of this lock and advance to next - DPRINTF(LLSC, "Erasing lock record: context %d addr %#x\n", - i->contextId, paddr); - i = lockedAddrList.erase(i); - } - else { - // no match: advance to next record - ++i; +PhysicalMemory::isMemAddr(Addr addr) const +{ + // see if the address is within the last matched range + if (addr != rangeCache) { + // lookup in the interval tree + range_map<Addr, AbstractMemory*>::const_iterator r = + addrMap.find(addr); + if (r == addrMap.end()) { + // not in the cache, and not in the tree + return false; } + // the range is in the tree, update the cache + rangeCache = r->first; } - if (isLLSC) { - req->setExtraData(success ? 1 : 0); - } - - return success; -} - - -#if TRACING_ON - -#define CASE(A, T) \ - case sizeof(T): \ - DPRINTF(MemoryAccess,"%s of size %i on address 0x%x data 0x%x\n", \ - A, pkt->getSize(), pkt->getAddr(), pkt->get<T>()); \ - 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: \ - DPRINTF(MemoryAccess, "%s of size %i on address 0x%x\n", \ - A, pkt->getSize(), pkt->getAddr()); \ - DDUMP(MemoryAccess, pkt->getPtr<uint8_t>(), pkt->getSize());\ - } \ - } while (0) - -#else - -#define TRACE_PACKET(A) - -#endif - -Tick -PhysicalMemory::doAtomicAccess(PacketPtr pkt) -{ - assert(pkt->getAddr() >= start() && - pkt->getAddr() + pkt->getSize() <= start() + size()); - - if (pkt->memInhibitAsserted()) { - DPRINTF(MemoryAccess, "mem inhibited on 0x%x: not responding\n", - pkt->getAddr()); - return 0; - } - - uint8_t *hostAddr = pmemAddr + pkt->getAddr() - start(); - - if (pkt->cmd == MemCmd::SwapReq) { - IntReg overwrite_val; - bool overwrite_mem; - uint64_t condition_val64; - uint32_t condition_val32; - - if (!pmemAddr) - panic("Swap only works if there is real memory (i.e. null=False)"); - 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 - std::memcpy(&overwrite_val, pkt->getPtr<uint8_t>(), pkt->getSize()); - std::memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize()); + assert(addrMap.find(addr) != addrMap.end()); - if (pkt->req->isCondSwap()) { - if (pkt->getSize() == sizeof(uint64_t)) { - condition_val64 = pkt->req->getExtraData(); - overwrite_mem = !std::memcmp(&condition_val64, hostAddr, - sizeof(uint64_t)); - } else if (pkt->getSize() == sizeof(uint32_t)) { - condition_val32 = (uint32_t)pkt->req->getExtraData(); - overwrite_mem = !std::memcmp(&condition_val32, hostAddr, - sizeof(uint32_t)); - } else - panic("Invalid size for conditional read/write\n"); - } - - if (overwrite_mem) - std::memcpy(hostAddr, &overwrite_val, pkt->getSize()); - - assert(!pkt->req->isInstFetch()); - TRACE_PACKET("Read/Write"); - numOther++; - } else if (pkt->isRead()) { - assert(!pkt->isWrite()); - if (pkt->isLLSC()) { - trackLoadLocked(pkt); - } - if (pmemAddr) - memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize()); - TRACE_PACKET(pkt->req->isInstFetch() ? "IFetch" : "Read"); - numReads++; - bytesRead += pkt->getSize(); - if (pkt->req->isInstFetch()) - bytesInstRead += pkt->getSize(); - } else if (pkt->isWrite()) { - if (writeOK(pkt)) { - if (pmemAddr) - memcpy(hostAddr, pkt->getPtr<uint8_t>(), pkt->getSize()); - assert(!pkt->req->isInstFetch()); - TRACE_PACKET("Write"); - numWrites++; - bytesWritten += pkt->getSize(); - } - } else if (pkt->isInvalidate()) { - //upgrade or invalidate - if (pkt->needsResponse()) { - pkt->makeAtomicResponse(); - } - } else { - panic("unimplemented"); - } - - if (pkt->needsResponse()) { - pkt->makeAtomicResponse(); - } - return calculateLatency(pkt); -} - - -void -PhysicalMemory::doFunctionalAccess(PacketPtr pkt) -{ - assert(pkt->getAddr() >= start() && - pkt->getAddr() + pkt->getSize() <= start() + size()); - - - uint8_t *hostAddr = pmemAddr + pkt->getAddr() - start(); - - if (pkt->isRead()) { - if (pmemAddr) - memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize()); - TRACE_PACKET("Read"); - pkt->makeAtomicResponse(); - } else if (pkt->isWrite()) { - if (pmemAddr) - memcpy(hostAddr, pkt->getPtr<uint8_t>(), pkt->getSize()); - TRACE_PACKET("Write"); - pkt->makeAtomicResponse(); - } else if (pkt->isPrint()) { - Packet::PrintReqState *prs = - dynamic_cast<Packet::PrintReqState*>(pkt->senderState); - // Need to call printLabels() explicitly since we're not going - // 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); - } else { - panic("PhysicalMemory: unimplemented functional command %s", - pkt->cmdString()); - } -} - - -SlavePort & -PhysicalMemory::getSlavePort(const std::string &if_name, int idx) -{ - if (if_name != "port") { - return MemObject::getSlavePort(if_name, idx); - } else { - if (idx >= static_cast<int>(ports.size())) { - fatal("PhysicalMemory::getSlavePort: unknown index %d\n", idx); - } - - return *ports[idx]; - } -} - -PhysicalMemory::MemoryPort::MemoryPort(const std::string &_name, - PhysicalMemory *_memory) - : SimpleTimingPort(_name, _memory), memory(_memory) -{ } - -AddrRangeList -PhysicalMemory::MemoryPort::getAddrRanges() -{ - return memory->getAddrRanges(); + // either matched the cache or found in the tree + return true; } AddrRangeList -PhysicalMemory::getAddrRanges() +PhysicalMemory::getConfAddrRanges() const { + // this could be done once in the constructor, but since it is unlikely to + // be called more than once the iteration should not be a problem AddrRangeList ranges; - ranges.push_back(RangeSize(start(), size())); - return ranges; -} - -unsigned -PhysicalMemory::MemoryPort::deviceBlockSize() const -{ - return memory->deviceBlockSize(); -} - -Tick -PhysicalMemory::MemoryPort::recvAtomic(PacketPtr pkt) -{ - return memory->doAtomicAccess(pkt); -} - -void -PhysicalMemory::MemoryPort::recvFunctional(PacketPtr pkt) -{ - pkt->pushLabel(memory->name()); - - if (!queue.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); - } - - pkt->popLabel(); -} - -unsigned int -PhysicalMemory::drain(Event *de) -{ - int count = 0; - for (PortIterator pi = ports.begin(); pi != ports.end(); ++pi) { - count += (*pi)->drain(de); + for (vector<AbstractMemory*>::const_iterator m = memories.begin(); + m != memories.end(); ++m) { + if ((*m)->isConfReported()) { + ranges.push_back((*m)->getAddrRange()); + } } - if (count) - changeState(Draining); - else - changeState(Drained); - return count; + return ranges; } void -PhysicalMemory::serialize(ostream &os) +PhysicalMemory::access(PacketPtr pkt) { - if (!pmemAddr) - return; - - gzFile compressedMem; - string filename = name() + ".physmem"; - - SERIALIZE_SCALAR(filename); - SERIALIZE_SCALAR(_size); - - // 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); - - if (gzwrite(compressedMem, pmemAddr, size()) != (int)size()) { - 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); - - 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); + assert(pkt->isRequest()); + Addr addr = pkt->getAddr(); + range_map<Addr, AbstractMemory*>::const_iterator m = addrMap.find(addr); + assert(m != addrMap.end()); + m->second->access(pkt); } void -PhysicalMemory::unserialize(Checkpoint *cp, const string §ion) -{ - if (!pmemAddr) - return; - - gzFile compressedMem; - long *tempPage; - long *pmem_current; - uint64_t curSize; - uint32_t bytesRead; - const uint32_t chunkSize = 16384; - - 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); - - // unmap file that was mmapped in the constructor - // 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 - munmap((char*)pmemAddr, size()); - - UNSERIALIZE_SCALAR(_size); - if (size() > params()->range.size()) - fatal("Memory size has changed! size %lld, param size %lld\n", - size(), params()->range.size()); - - pmemAddr = (uint8_t *)mmap(NULL, size(), - PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); - - if (pmemAddr == (void *)MAP_FAILED) { - 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 */ - while (curSize < size()) { - bytesRead = gzread(compressedMem, tempPage, chunkSize); - if (bytesRead == 0) - break; - - assert(bytesRead % sizeof(long) == 0); - - for (uint32_t x = 0; x < bytesRead / sizeof(long); x++) - { - if (*(tempPage+x) != 0) { - pmem_current = (long*)(pmemAddr + curSize + x * sizeof(long)); - *pmem_current = *(tempPage+x); - } - } - curSize += bytesRead; - } - - free(tempPage); - - if (gzclose(compressedMem)) - fatal("Close failed on physical memory checkpoint file '%s'\n", - filename); - - 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])); -} - -PhysicalMemory * -PhysicalMemoryParams::create() +PhysicalMemory::functionalAccess(PacketPtr pkt) { - return new PhysicalMemory(this); + assert(pkt->isRequest()); + Addr addr = pkt->getAddr(); + range_map<Addr, AbstractMemory*>::const_iterator m = addrMap.find(addr); + assert(m != addrMap.end()); + m->second->functionalAccess(pkt); } |