X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmem%2Fphysical.cc;h=5f92976f9dedc35ed7b45c32bd6d91dd8cb23eef;hb=7122b83d8f92d77bccae432b4e90ba12f1babad5;hp=e8b978ec8fe1126fb793d6aa6489869b7658e5b3;hpb=85424bef192c02a47c0d46c2d99ac0a5d6e55a99;p=gem5.git diff --git a/src/mem/physical.cc b/src/mem/physical.cc index e8b978ec8..5f92976f9 100644 --- a/src/mem/physical.cc +++ b/src/mem/physical.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 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,574 +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 -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#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"); - - 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() -{ - if (ports.size() == 0) { - fatal("PhysicalMemory object %s is unconnected!", name()); - } - - for (PortIterator pi = ports.begin(); pi != ports.end(); ++pi) { - if (*pi) - (*pi)->sendStatusChange(Port::RangeChange); - } -} -PhysicalMemory::~PhysicalMemory() +PhysicalMemory::PhysicalMemory(const vector& _memories) : + size(0) { - if (pmemAddr) - munmap((char*)pmemAddr, size()); -} - -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(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) -{ - Request *req = pkt->req; - Addr paddr = LockedAddr::mask(req->getPaddr()); + for (vector::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::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::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::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); - } + assert(addrMap.find(addr) != addrMap.end()); - return success; + // either matched the cache or found in the tree + return true; } - -#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()); \ - 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(), pkt->getSize());\ - } \ - } while (0) - -#else - -#define TRACE_PACKET(A) - -#endif - -Tick -PhysicalMemory::doAtomicAccess(PacketPtr pkt) +AddrRangeList +PhysicalMemory::getConfAddrRanges() const { - 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(), pkt->getSize()); - std::memcpy(pkt->getPtr(), hostAddr, pkt->getSize()); - - 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"); + // 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; + for (vector::const_iterator m = memories.begin(); + m != memories.end(); ++m) { + if ((*m)->isConfReported()) { + ranges.push_back((*m)->getAddrRange()); } - - if (overwrite_mem) - std::memcpy(hostAddr, &overwrite_val, pkt->getSize()); - - assert(!pkt->req->isInstFetch()); - TRACE_PACKET("Read/Write"); - } else if (pkt->isRead()) { - assert(!pkt->isWrite()); - if (pkt->isLLSC()) { - trackLoadLocked(pkt); - } - if (pmemAddr) - memcpy(pkt->getPtr(), hostAddr, pkt->getSize()); - TRACE_PACKET(pkt->req->isInstFetch() ? "IFetch" : "Read"); - } else if (pkt->isWrite()) { - if (writeOK(pkt)) { - if (pmemAddr) - memcpy(hostAddr, pkt->getPtr(), pkt->getSize()); - assert(!pkt->req->isInstFetch()); - TRACE_PACKET("Write"); - } - } else if (pkt->isInvalidate()) { - //upgrade or invalidate - if (pkt->needsResponse()) { - pkt->makeAtomicResponse(); - } - } else { - panic("unimplemented"); } - if (pkt->needsResponse()) { - pkt->makeAtomicResponse(); - } - return calculateLatency(pkt); + return ranges; } - void -PhysicalMemory::doFunctionalAccess(PacketPtr pkt) +PhysicalMemory::access(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(), hostAddr, pkt->getSize()); - TRACE_PACKET("Read"); - pkt->makeAtomicResponse(); - } else if (pkt->isWrite()) { - if (pmemAddr) - memcpy(hostAddr, pkt->getPtr(), pkt->getSize()); - TRACE_PACKET("Write"); - pkt->makeAtomicResponse(); - } else if (pkt->isPrint()) { - Packet::PrintReqState *prs = - dynamic_cast(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()); - } -} - - -Port * -PhysicalMemory::getPort(const std::string &if_name, int idx) -{ - // 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); - } - - if (if_name != "port") { - panic("PhysicalMemory::getPort: unknown port %s requested", if_name); - } - - if (idx >= (int)ports.size()) { - ports.resize(idx + 1); - } - - 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; -} - - -void -PhysicalMemory::recvStatusChange(Port::Status status) -{ -} - -PhysicalMemory::MemoryPort::MemoryPort(const std::string &_name, - PhysicalMemory *_memory) - : SimpleTimingPort(_name, _memory), memory(_memory) -{ } - -void -PhysicalMemory::MemoryPort::recvStatusChange(Port::Status status) -{ - memory->recvStatusChange(status); -} - -void -PhysicalMemory::MemoryPort::getDeviceAddressRanges(AddrRangeList &resp, - bool &snoop) -{ - memory->getAddressRanges(resp, snoop); -} - -void -PhysicalMemory::getAddressRanges(AddrRangeList &resp, bool &snoop) -{ - snoop = false; - resp.clear(); - resp.push_back(RangeSize(start(), size())); -} - -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 (!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); - } - - if (count) - changeState(Draining); - else - changeState(Drained); - return count; + assert(pkt->isRequest()); + Addr addr = pkt->getAddr(); + range_map::const_iterator m = addrMap.find(addr); + assert(m != addrMap.end()); + m->second->access(pkt); } void -PhysicalMemory::serialize(ostream &os) -{ - 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::iterator i = lockedAddrList.begin(); - - vector lal_addr; - vector 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); -} - -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!\n"); - - 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 lal_addr; - vector 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::const_iterator m = addrMap.find(addr); + assert(m != addrMap.end()); + m->second->functionalAccess(pkt); }