abstract_mem.cc revision 6820
17860SN/A/* 27860SN/A * Copyright (c) 2001-2005 The Regents of The University of Michigan 311960Sgabeblack@google.com * All rights reserved. 411960Sgabeblack@google.com * 511960Sgabeblack@google.com * Redistribution and use in source and binary forms, with or without 611960Sgabeblack@google.com * modification, are permitted provided that the following conditions are 711960Sgabeblack@google.com * met: redistributions of source code must retain the above copyright 811960Sgabeblack@google.com * notice, this list of conditions and the following disclaimer; 911960Sgabeblack@google.com * redistributions in binary form must reproduce the above copyright 1011960Sgabeblack@google.com * notice, this list of conditions and the following disclaimer in the 1111960Sgabeblack@google.com * documentation and/or other materials provided with the distribution; 1211960Sgabeblack@google.com * neither the name of the copyright holders nor the names of its 1311960Sgabeblack@google.com * contributors may be used to endorse or promote products derived from 1411960Sgabeblack@google.com * this software without specific prior written permission. 1511960Sgabeblack@google.com * 1611960Sgabeblack@google.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1711960Sgabeblack@google.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1811960Sgabeblack@google.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1911960Sgabeblack@google.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2011960Sgabeblack@google.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2111960Sgabeblack@google.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2211960Sgabeblack@google.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2311960Sgabeblack@google.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2411960Sgabeblack@google.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2511960Sgabeblack@google.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2611960Sgabeblack@google.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2711960Sgabeblack@google.com * 2811960Sgabeblack@google.com * Authors: Ron Dreslinski 2911960Sgabeblack@google.com * Ali Saidi 3011960Sgabeblack@google.com */ 3111960Sgabeblack@google.com 3211960Sgabeblack@google.com#include <sys/types.h> 3311960Sgabeblack@google.com#include <sys/mman.h> 3411960Sgabeblack@google.com#include <errno.h> 3511960Sgabeblack@google.com#include <fcntl.h> 3611960Sgabeblack@google.com#include <unistd.h> 3711960Sgabeblack@google.com#include <zlib.h> 3811960Sgabeblack@google.com 3911960Sgabeblack@google.com#include <cstdio> 4011960Sgabeblack@google.com#include <iostream> 4111960Sgabeblack@google.com#include <string> 4211960Sgabeblack@google.com 4311960Sgabeblack@google.com#include "arch/registers.hh" 4411960Sgabeblack@google.com#include "base/misc.hh" 4511960Sgabeblack@google.com#include "base/random.hh" 4611960Sgabeblack@google.com#include "base/types.hh" 4711960Sgabeblack@google.com#include "config/full_system.hh" 4811960Sgabeblack@google.com#include "config/the_isa.hh" 4911960Sgabeblack@google.com#include "mem/packet_access.hh" 5011960Sgabeblack@google.com#include "mem/physical.hh" 5111960Sgabeblack@google.com#include "sim/eventq.hh" 5211960Sgabeblack@google.com 5311960Sgabeblack@google.comusing namespace std; 5411960Sgabeblack@google.comusing namespace TheISA; 5511960Sgabeblack@google.com 5611960Sgabeblack@google.comPhysicalMemory::PhysicalMemory(const Params *p) 5711960Sgabeblack@google.com : MemObject(p), pmemAddr(NULL), pagePtr(0), 5811960Sgabeblack@google.com lat(p->latency), lat_var(p->latency_var), 5911960Sgabeblack@google.com cachedSize(params()->range.size()), cachedStart(params()->range.start) 6011960Sgabeblack@google.com{ 6111960Sgabeblack@google.com if (params()->range.size() % TheISA::PageBytes != 0) 6211960Sgabeblack@google.com panic("Memory Size not divisible by page size\n"); 6311960Sgabeblack@google.com 6411960Sgabeblack@google.com if (params()->null) 6511960Sgabeblack@google.com return; 6611960Sgabeblack@google.com 6711960Sgabeblack@google.com int map_flags = MAP_ANON | MAP_PRIVATE; 6811960Sgabeblack@google.com pmemAddr = (uint8_t *)mmap(NULL, params()->range.size(), 6911960Sgabeblack@google.com PROT_READ | PROT_WRITE, map_flags, -1, 0); 7011960Sgabeblack@google.com 7111960Sgabeblack@google.com if (pmemAddr == (void *)MAP_FAILED) { 7211960Sgabeblack@google.com perror("mmap"); 7311960Sgabeblack@google.com fatal("Could not mmap!\n"); 7411960Sgabeblack@google.com } 7511960Sgabeblack@google.com 7611960Sgabeblack@google.com //If requested, initialize all the memory to 0 7711960Sgabeblack@google.com if (p->zero) 7811960Sgabeblack@google.com memset(pmemAddr, 0, p->range.size()); 7911960Sgabeblack@google.com} 8011960Sgabeblack@google.com 8111960Sgabeblack@google.comvoid 8211960Sgabeblack@google.comPhysicalMemory::init() 8311960Sgabeblack@google.com{ 8411960Sgabeblack@google.com if (ports.size() == 0) { 8511960Sgabeblack@google.com fatal("PhysicalMemory object %s is unconnected!", name()); 8611960Sgabeblack@google.com } 8711960Sgabeblack@google.com 8811960Sgabeblack@google.com for (PortIterator pi = ports.begin(); pi != ports.end(); ++pi) { 8911960Sgabeblack@google.com if (*pi) 9011960Sgabeblack@google.com (*pi)->sendStatusChange(Port::RangeChange); 9111960Sgabeblack@google.com } 9211960Sgabeblack@google.com} 9311960Sgabeblack@google.com 9411960Sgabeblack@google.comPhysicalMemory::~PhysicalMemory() 9511960Sgabeblack@google.com{ 9611960Sgabeblack@google.com if (pmemAddr) 9711960Sgabeblack@google.com munmap((char*)pmemAddr, params()->range.size()); 9811960Sgabeblack@google.com //Remove memPorts? 9911960Sgabeblack@google.com} 10011960Sgabeblack@google.com 10111960Sgabeblack@google.comAddr 10211960Sgabeblack@google.comPhysicalMemory::new_page() 10311960Sgabeblack@google.com{ 10411960Sgabeblack@google.com Addr return_addr = pagePtr << LogVMPageSize; 10511960Sgabeblack@google.com return_addr += start(); 10611960Sgabeblack@google.com 10711960Sgabeblack@google.com ++pagePtr; 10811960Sgabeblack@google.com return return_addr; 10911960Sgabeblack@google.com} 11011960Sgabeblack@google.com 11111960Sgabeblack@google.comunsigned 11211960Sgabeblack@google.comPhysicalMemory::deviceBlockSize() const 11311960Sgabeblack@google.com{ 11411960Sgabeblack@google.com //Can accept anysize request 11511960Sgabeblack@google.com return 0; 11611960Sgabeblack@google.com} 11711960Sgabeblack@google.com 11811960Sgabeblack@google.comTick 11911960Sgabeblack@google.comPhysicalMemory::calculateLatency(PacketPtr pkt) 12011960Sgabeblack@google.com{ 12111960Sgabeblack@google.com Tick latency = lat; 12211960Sgabeblack@google.com if (lat_var != 0) 12311960Sgabeblack@google.com latency += random_mt.random<Tick>(0, lat_var); 12411960Sgabeblack@google.com return latency; 12511960Sgabeblack@google.com} 12611960Sgabeblack@google.com 12711960Sgabeblack@google.com 12811960Sgabeblack@google.com 12911960Sgabeblack@google.com// Add load-locked to tracking list. Should only be called if the 13011960Sgabeblack@google.com// operation is a load and the LLSC flag is set. 13111960Sgabeblack@google.comvoid 13211960Sgabeblack@google.comPhysicalMemory::trackLoadLocked(PacketPtr pkt) 13311960Sgabeblack@google.com{ 13411960Sgabeblack@google.com Request *req = pkt->req; 13511960Sgabeblack@google.com Addr paddr = LockedAddr::mask(req->getPaddr()); 13611960Sgabeblack@google.com 13711960Sgabeblack@google.com // first we check if we already have a locked addr for this 13811960Sgabeblack@google.com // xc. Since each xc only gets one, we just update the 13911960Sgabeblack@google.com // existing record with the new address. 14011960Sgabeblack@google.com list<LockedAddr>::iterator i; 14111960Sgabeblack@google.com 14211960Sgabeblack@google.com for (i = lockedAddrList.begin(); i != lockedAddrList.end(); ++i) { 14311960Sgabeblack@google.com if (i->matchesContext(req)) { 14411960Sgabeblack@google.com DPRINTF(LLSC, "Modifying lock record: context %d addr %#x\n", 14511960Sgabeblack@google.com req->contextId(), paddr); 14611960Sgabeblack@google.com i->addr = paddr; 14711960Sgabeblack@google.com return; 14811960Sgabeblack@google.com } 14911960Sgabeblack@google.com } 15011960Sgabeblack@google.com 15111960Sgabeblack@google.com // no record for this xc: need to allocate a new one 15211960Sgabeblack@google.com DPRINTF(LLSC, "Adding lock record: context %d addr %#x\n", 15311960Sgabeblack@google.com req->contextId(), paddr); 15411960Sgabeblack@google.com lockedAddrList.push_front(LockedAddr(req)); 15511960Sgabeblack@google.com} 15611960Sgabeblack@google.com 15711960Sgabeblack@google.com 15811960Sgabeblack@google.com// Called on *writes* only... both regular stores and 15911960Sgabeblack@google.com// store-conditional operations. Check for conventional stores which 16011960Sgabeblack@google.com// conflict with locked addresses, and for success/failure of store 16111960Sgabeblack@google.com// conditionals. 16211960Sgabeblack@google.combool 16311960Sgabeblack@google.comPhysicalMemory::checkLockedAddrList(PacketPtr pkt) 16411960Sgabeblack@google.com{ 16511960Sgabeblack@google.com Request *req = pkt->req; 16611960Sgabeblack@google.com Addr paddr = LockedAddr::mask(req->getPaddr()); 16711960Sgabeblack@google.com bool isLLSC = pkt->isLLSC(); 16811960Sgabeblack@google.com 16911960Sgabeblack@google.com // Initialize return value. Non-conditional stores always 17011960Sgabeblack@google.com // succeed. Assume conditional stores will fail until proven 17111960Sgabeblack@google.com // otherwise. 17211960Sgabeblack@google.com bool success = !isLLSC; 17311960Sgabeblack@google.com 17411960Sgabeblack@google.com // Iterate over list. Note that there could be multiple matching 17511960Sgabeblack@google.com // records, as more than one context could have done a load locked 17611960Sgabeblack@google.com // to this location. 17711960Sgabeblack@google.com list<LockedAddr>::iterator i = lockedAddrList.begin(); 17811960Sgabeblack@google.com 17911960Sgabeblack@google.com while (i != lockedAddrList.end()) { 18011960Sgabeblack@google.com 18111960Sgabeblack@google.com if (i->addr == paddr) { 18211960Sgabeblack@google.com // we have a matching address 18311960Sgabeblack@google.com 18411960Sgabeblack@google.com if (isLLSC && i->matchesContext(req)) { 18511960Sgabeblack@google.com // it's a store conditional, and as far as the memory 18611960Sgabeblack@google.com // system can tell, the requesting context's lock is 18711960Sgabeblack@google.com // still valid. 18811960Sgabeblack@google.com DPRINTF(LLSC, "StCond success: context %d addr %#x\n", 18911960Sgabeblack@google.com req->contextId(), paddr); 19011960Sgabeblack@google.com success = true; 19111960Sgabeblack@google.com } 19211960Sgabeblack@google.com 19311960Sgabeblack@google.com // Get rid of our record of this lock and advance to next 19411960Sgabeblack@google.com DPRINTF(LLSC, "Erasing lock record: context %d addr %#x\n", 19511960Sgabeblack@google.com i->contextId, paddr); 19611960Sgabeblack@google.com i = lockedAddrList.erase(i); 19711960Sgabeblack@google.com } 19811960Sgabeblack@google.com else { 19911960Sgabeblack@google.com // no match: advance to next record 20011960Sgabeblack@google.com ++i; 20111960Sgabeblack@google.com } 20211960Sgabeblack@google.com } 20311960Sgabeblack@google.com 20411960Sgabeblack@google.com if (isLLSC) { 20511960Sgabeblack@google.com req->setExtraData(success ? 1 : 0); 20611960Sgabeblack@google.com } 20711960Sgabeblack@google.com 20811960Sgabeblack@google.com return success; 20911960Sgabeblack@google.com} 21011960Sgabeblack@google.com 21111960Sgabeblack@google.com 21211960Sgabeblack@google.com#if TRACING_ON 21311960Sgabeblack@google.com 21411960Sgabeblack@google.com#define CASE(A, T) \ 21511960Sgabeblack@google.com case sizeof(T): \ 21611960Sgabeblack@google.com DPRINTF(MemoryAccess,"%s of size %i on address 0x%x data 0x%x\n", \ 21711960Sgabeblack@google.com A, pkt->getSize(), pkt->getAddr(), pkt->get<T>()); \ 21811960Sgabeblack@google.com break 21911960Sgabeblack@google.com 22011960Sgabeblack@google.com 22111960Sgabeblack@google.com#define TRACE_PACKET(A) \ 22211960Sgabeblack@google.com do { \ 22311960Sgabeblack@google.com switch (pkt->getSize()) { \ 22411960Sgabeblack@google.com CASE(A, uint64_t); \ 22511960Sgabeblack@google.com CASE(A, uint32_t); \ 22611960Sgabeblack@google.com CASE(A, uint16_t); \ 22711960Sgabeblack@google.com CASE(A, uint8_t); \ 22811960Sgabeblack@google.com default: \ 22911960Sgabeblack@google.com DPRINTF(MemoryAccess, "%s of size %i on address 0x%x\n", \ 23011960Sgabeblack@google.com A, pkt->getSize(), pkt->getAddr()); \ 23111960Sgabeblack@google.com } \ 23211960Sgabeblack@google.com } while (0) 23311960Sgabeblack@google.com 23411960Sgabeblack@google.com#else 23511960Sgabeblack@google.com 23611960Sgabeblack@google.com#define TRACE_PACKET(A) 23711960Sgabeblack@google.com 23811960Sgabeblack@google.com#endif 23911960Sgabeblack@google.com 24011960Sgabeblack@google.comTick 24111960Sgabeblack@google.comPhysicalMemory::doAtomicAccess(PacketPtr pkt) 24211960Sgabeblack@google.com{ 24311960Sgabeblack@google.com assert(pkt->getAddr() >= start() && 24411960Sgabeblack@google.com pkt->getAddr() + pkt->getSize() <= start() + size()); 24511960Sgabeblack@google.com 24611960Sgabeblack@google.com if (pkt->memInhibitAsserted()) { 24711960Sgabeblack@google.com DPRINTF(MemoryAccess, "mem inhibited on 0x%x: not responding\n", 24811960Sgabeblack@google.com pkt->getAddr()); 24911960Sgabeblack@google.com return 0; 25011960Sgabeblack@google.com } 25111960Sgabeblack@google.com 25211960Sgabeblack@google.com uint8_t *hostAddr = pmemAddr + pkt->getAddr() - start(); 25311960Sgabeblack@google.com 25411960Sgabeblack@google.com if (pkt->cmd == MemCmd::SwapReq) { 25511960Sgabeblack@google.com IntReg overwrite_val; 25611960Sgabeblack@google.com bool overwrite_mem; 25711960Sgabeblack@google.com uint64_t condition_val64; 25811960Sgabeblack@google.com uint32_t condition_val32; 25911960Sgabeblack@google.com 26011960Sgabeblack@google.com if (!pmemAddr) 26111960Sgabeblack@google.com panic("Swap only works if there is real memory (i.e. null=False)"); 26211960Sgabeblack@google.com assert(sizeof(IntReg) >= pkt->getSize()); 26311960Sgabeblack@google.com 26411960Sgabeblack@google.com overwrite_mem = true; 26511960Sgabeblack@google.com // keep a copy of our possible write value, and copy what is at the 26611960Sgabeblack@google.com // memory address into the packet 26711960Sgabeblack@google.com std::memcpy(&overwrite_val, pkt->getPtr<uint8_t>(), pkt->getSize()); 26811960Sgabeblack@google.com std::memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize()); 26911960Sgabeblack@google.com 27011960Sgabeblack@google.com if (pkt->req->isCondSwap()) { 27111960Sgabeblack@google.com if (pkt->getSize() == sizeof(uint64_t)) { 27211960Sgabeblack@google.com condition_val64 = pkt->req->getExtraData(); 27311960Sgabeblack@google.com overwrite_mem = !std::memcmp(&condition_val64, hostAddr, 27411960Sgabeblack@google.com sizeof(uint64_t)); 27511960Sgabeblack@google.com } else if (pkt->getSize() == sizeof(uint32_t)) { 27611960Sgabeblack@google.com condition_val32 = (uint32_t)pkt->req->getExtraData(); 27711960Sgabeblack@google.com overwrite_mem = !std::memcmp(&condition_val32, hostAddr, 27811960Sgabeblack@google.com sizeof(uint32_t)); 27911960Sgabeblack@google.com } else 28011960Sgabeblack@google.com panic("Invalid size for conditional read/write\n"); 28111960Sgabeblack@google.com } 28211960Sgabeblack@google.com 28311960Sgabeblack@google.com if (overwrite_mem) 28411960Sgabeblack@google.com std::memcpy(hostAddr, &overwrite_val, pkt->getSize()); 28511960Sgabeblack@google.com 28611960Sgabeblack@google.com assert(!pkt->req->isInstFetch()); 28711960Sgabeblack@google.com TRACE_PACKET("Read/Write"); 28811960Sgabeblack@google.com } else if (pkt->isRead()) { 28911960Sgabeblack@google.com assert(!pkt->isWrite()); 29011960Sgabeblack@google.com if (pkt->isLLSC()) { 29111960Sgabeblack@google.com trackLoadLocked(pkt); 29211960Sgabeblack@google.com } 29311960Sgabeblack@google.com if (pmemAddr) 29411960Sgabeblack@google.com memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize()); 29511960Sgabeblack@google.com TRACE_PACKET(pkt->req->isInstFetch() ? "IFetch" : "Read"); 29611960Sgabeblack@google.com } else if (pkt->isWrite()) { 29711960Sgabeblack@google.com if (writeOK(pkt)) { 29811960Sgabeblack@google.com if (pmemAddr) 29911960Sgabeblack@google.com memcpy(hostAddr, pkt->getPtr<uint8_t>(), pkt->getSize()); 30011960Sgabeblack@google.com assert(!pkt->req->isInstFetch()); 30111960Sgabeblack@google.com TRACE_PACKET("Write"); 30211960Sgabeblack@google.com } 30311960Sgabeblack@google.com } else if (pkt->isInvalidate()) { 30411960Sgabeblack@google.com //upgrade or invalidate 30511960Sgabeblack@google.com if (pkt->needsResponse()) { 30611960Sgabeblack@google.com pkt->makeAtomicResponse(); 30711960Sgabeblack@google.com } 30811960Sgabeblack@google.com } else { 30911960Sgabeblack@google.com panic("unimplemented"); 31011960Sgabeblack@google.com } 31111960Sgabeblack@google.com 31211960Sgabeblack@google.com if (pkt->needsResponse()) { 31311960Sgabeblack@google.com pkt->makeAtomicResponse(); 31411960Sgabeblack@google.com } 31511960Sgabeblack@google.com return calculateLatency(pkt); 31611960Sgabeblack@google.com} 31711960Sgabeblack@google.com 31811960Sgabeblack@google.com 31911960Sgabeblack@google.comvoid 32011960Sgabeblack@google.comPhysicalMemory::doFunctionalAccess(PacketPtr pkt) 32111960Sgabeblack@google.com{ 32211960Sgabeblack@google.com assert(pkt->getAddr() >= start() && 32311960Sgabeblack@google.com pkt->getAddr() + pkt->getSize() <= start() + size()); 32411960Sgabeblack@google.com 32511960Sgabeblack@google.com 32611960Sgabeblack@google.com uint8_t *hostAddr = pmemAddr + pkt->getAddr() - start(); 32711960Sgabeblack@google.com 32811960Sgabeblack@google.com if (pkt->isRead()) { 32911960Sgabeblack@google.com if (pmemAddr) 33011960Sgabeblack@google.com memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize()); 33111960Sgabeblack@google.com TRACE_PACKET("Read"); 33211960Sgabeblack@google.com pkt->makeAtomicResponse(); 33311960Sgabeblack@google.com } else if (pkt->isWrite()) { 33411960Sgabeblack@google.com if (pmemAddr) 33511960Sgabeblack@google.com memcpy(hostAddr, pkt->getPtr<uint8_t>(), pkt->getSize()); 33611960Sgabeblack@google.com TRACE_PACKET("Write"); 33711960Sgabeblack@google.com pkt->makeAtomicResponse(); 33811960Sgabeblack@google.com } else if (pkt->isPrint()) { 33911960Sgabeblack@google.com Packet::PrintReqState *prs = 34011960Sgabeblack@google.com dynamic_cast<Packet::PrintReqState*>(pkt->senderState); 34111960Sgabeblack@google.com // Need to call printLabels() explicitly since we're not going 34211960Sgabeblack@google.com // through printObj(). 34311960Sgabeblack@google.com prs->printLabels(); 34411960Sgabeblack@google.com // Right now we just print the single byte at the specified address. 34511960Sgabeblack@google.com ccprintf(prs->os, "%s%#x\n", prs->curPrefix(), *hostAddr); 34611960Sgabeblack@google.com } else { 34711960Sgabeblack@google.com panic("PhysicalMemory: unimplemented functional command %s", 34811960Sgabeblack@google.com pkt->cmdString()); 34911960Sgabeblack@google.com } 35011960Sgabeblack@google.com} 35111960Sgabeblack@google.com 35211960Sgabeblack@google.com 35311960Sgabeblack@google.comPort * 35411960Sgabeblack@google.comPhysicalMemory::getPort(const std::string &if_name, int idx) 35511960Sgabeblack@google.com{ 35611960Sgabeblack@google.com // Accept request for "functional" port for backwards compatibility 35711960Sgabeblack@google.com // with places where this function is called from C++. I'd prefer 35811960Sgabeblack@google.com // to move all these into Python someday. 35911960Sgabeblack@google.com if (if_name == "functional") { 36011960Sgabeblack@google.com return new MemoryPort(csprintf("%s-functional", name()), this); 36111960Sgabeblack@google.com } 36211960Sgabeblack@google.com 36311960Sgabeblack@google.com if (if_name != "port") { 36411960Sgabeblack@google.com panic("PhysicalMemory::getPort: unknown port %s requested", if_name); 36511960Sgabeblack@google.com } 36611960Sgabeblack@google.com 36711960Sgabeblack@google.com if (idx >= (int)ports.size()) { 36811960Sgabeblack@google.com ports.resize(idx + 1); 36911960Sgabeblack@google.com } 37011960Sgabeblack@google.com 37111960Sgabeblack@google.com if (ports[idx] != NULL) { 37211960Sgabeblack@google.com panic("PhysicalMemory::getPort: port %d already assigned", idx); 37311960Sgabeblack@google.com } 37411960Sgabeblack@google.com 37511960Sgabeblack@google.com MemoryPort *port = 37611960Sgabeblack@google.com new MemoryPort(csprintf("%s-port%d", name(), idx), this); 37711960Sgabeblack@google.com 37811960Sgabeblack@google.com ports[idx] = port; 37911960Sgabeblack@google.com return port; 38011960Sgabeblack@google.com} 38111960Sgabeblack@google.com 38211960Sgabeblack@google.com 38311960Sgabeblack@google.comvoid 38411960Sgabeblack@google.comPhysicalMemory::recvStatusChange(Port::Status status) 38511960Sgabeblack@google.com{ 38611960Sgabeblack@google.com} 38711960Sgabeblack@google.com 38811960Sgabeblack@google.comPhysicalMemory::MemoryPort::MemoryPort(const std::string &_name, 38911960Sgabeblack@google.com PhysicalMemory *_memory) 39011960Sgabeblack@google.com : SimpleTimingPort(_name, _memory), memory(_memory) 39111960Sgabeblack@google.com{ } 39211960Sgabeblack@google.com 39311960Sgabeblack@google.comvoid 39411960Sgabeblack@google.comPhysicalMemory::MemoryPort::recvStatusChange(Port::Status status) 39511960Sgabeblack@google.com{ 39611960Sgabeblack@google.com memory->recvStatusChange(status); 39711960Sgabeblack@google.com} 39811960Sgabeblack@google.com 39911960Sgabeblack@google.comvoid 40011960Sgabeblack@google.comPhysicalMemory::MemoryPort::getDeviceAddressRanges(AddrRangeList &resp, 40111960Sgabeblack@google.com bool &snoop) 40211960Sgabeblack@google.com{ 40311960Sgabeblack@google.com memory->getAddressRanges(resp, snoop); 40411960Sgabeblack@google.com} 40511960Sgabeblack@google.com 40611960Sgabeblack@google.comvoid 40711960Sgabeblack@google.comPhysicalMemory::getAddressRanges(AddrRangeList &resp, bool &snoop) 40811960Sgabeblack@google.com{ 40911960Sgabeblack@google.com snoop = false; 41011960Sgabeblack@google.com resp.clear(); 41111960Sgabeblack@google.com resp.push_back(RangeSize(start(), params()->range.size())); 41211960Sgabeblack@google.com} 41311960Sgabeblack@google.com 41411960Sgabeblack@google.comunsigned 41511960Sgabeblack@google.comPhysicalMemory::MemoryPort::deviceBlockSize() const 41611960Sgabeblack@google.com{ 41711960Sgabeblack@google.com return memory->deviceBlockSize(); 41811960Sgabeblack@google.com} 41911960Sgabeblack@google.com 42011960Sgabeblack@google.comTick 42111960Sgabeblack@google.comPhysicalMemory::MemoryPort::recvAtomic(PacketPtr pkt) 42211960Sgabeblack@google.com{ 42311960Sgabeblack@google.com return memory->doAtomicAccess(pkt); 42411960Sgabeblack@google.com} 42511960Sgabeblack@google.com 42611960Sgabeblack@google.comvoid 42711960Sgabeblack@google.comPhysicalMemory::MemoryPort::recvFunctional(PacketPtr pkt) 42811960Sgabeblack@google.com{ 42911960Sgabeblack@google.com pkt->pushLabel(memory->name()); 43011960Sgabeblack@google.com 43111960Sgabeblack@google.com if (!checkFunctional(pkt)) { 43211960Sgabeblack@google.com // Default implementation of SimpleTimingPort::recvFunctional() 43311960Sgabeblack@google.com // calls recvAtomic() and throws away the latency; we can save a 43411960Sgabeblack@google.com // little here by just not calculating the latency. 43511960Sgabeblack@google.com memory->doFunctionalAccess(pkt); 43611960Sgabeblack@google.com } 43711960Sgabeblack@google.com 43811960Sgabeblack@google.com pkt->popLabel(); 43911960Sgabeblack@google.com} 44011960Sgabeblack@google.com 44111960Sgabeblack@google.comunsigned int 44211960Sgabeblack@google.comPhysicalMemory::drain(Event *de) 44311960Sgabeblack@google.com{ 44411960Sgabeblack@google.com int count = 0; 44511960Sgabeblack@google.com for (PortIterator pi = ports.begin(); pi != ports.end(); ++pi) { 44611960Sgabeblack@google.com count += (*pi)->drain(de); 44711960Sgabeblack@google.com } 44811960Sgabeblack@google.com 44911960Sgabeblack@google.com if (count) 45011960Sgabeblack@google.com changeState(Draining); 45111960Sgabeblack@google.com else 45211960Sgabeblack@google.com changeState(Drained); 45311960Sgabeblack@google.com return count; 45411960Sgabeblack@google.com} 45511960Sgabeblack@google.com 45611960Sgabeblack@google.comvoid 45711960Sgabeblack@google.comPhysicalMemory::serialize(ostream &os) 45811960Sgabeblack@google.com{ 45911960Sgabeblack@google.com if (!pmemAddr) 46011960Sgabeblack@google.com return; 46111960Sgabeblack@google.com 46211960Sgabeblack@google.com gzFile compressedMem; 46311960Sgabeblack@google.com string filename = name() + ".physmem"; 46411960Sgabeblack@google.com 46511960Sgabeblack@google.com SERIALIZE_SCALAR(filename); 46611960Sgabeblack@google.com 46711960Sgabeblack@google.com // write memory file 46811960Sgabeblack@google.com string thefile = Checkpoint::dir() + "/" + filename.c_str(); 46911960Sgabeblack@google.com int fd = creat(thefile.c_str(), 0664); 47011960Sgabeblack@google.com if (fd < 0) { 47111960Sgabeblack@google.com perror("creat"); 47211960Sgabeblack@google.com fatal("Can't open physical memory checkpoint file '%s'\n", filename); 47311960Sgabeblack@google.com } 47411960Sgabeblack@google.com 47511960Sgabeblack@google.com compressedMem = gzdopen(fd, "wb"); 47611960Sgabeblack@google.com if (compressedMem == NULL) 47711960Sgabeblack@google.com fatal("Insufficient memory to allocate compression state for %s\n", 47811960Sgabeblack@google.com filename); 47911960Sgabeblack@google.com 48011960Sgabeblack@google.com if (gzwrite(compressedMem, pmemAddr, params()->range.size()) != 48111960Sgabeblack@google.com (int)params()->range.size()) { 48211960Sgabeblack@google.com fatal("Write failed on physical memory checkpoint file '%s'\n", 48311960Sgabeblack@google.com filename); 48411960Sgabeblack@google.com } 48511960Sgabeblack@google.com 48611960Sgabeblack@google.com if (gzclose(compressedMem)) 48711960Sgabeblack@google.com fatal("Close failed on physical memory checkpoint file '%s'\n", 48811960Sgabeblack@google.com filename); 48911960Sgabeblack@google.com} 49011960Sgabeblack@google.com 49111960Sgabeblack@google.comvoid 49211960Sgabeblack@google.comPhysicalMemory::unserialize(Checkpoint *cp, const string §ion) 49311960Sgabeblack@google.com{ 49411960Sgabeblack@google.com if (!pmemAddr) 49511960Sgabeblack@google.com return; 49611960Sgabeblack@google.com 49711960Sgabeblack@google.com gzFile compressedMem; 49811960Sgabeblack@google.com long *tempPage; 49911960Sgabeblack@google.com long *pmem_current; 50011960Sgabeblack@google.com uint64_t curSize; 50111960Sgabeblack@google.com uint32_t bytesRead; 50211960Sgabeblack@google.com const uint32_t chunkSize = 16384; 50311960Sgabeblack@google.com 50411960Sgabeblack@google.com string filename; 50511960Sgabeblack@google.com 50611960Sgabeblack@google.com UNSERIALIZE_SCALAR(filename); 50711960Sgabeblack@google.com 50811960Sgabeblack@google.com filename = cp->cptDir + "/" + filename; 50911960Sgabeblack@google.com 51011960Sgabeblack@google.com // mmap memoryfile 51111960Sgabeblack@google.com int fd = open(filename.c_str(), O_RDONLY); 51211960Sgabeblack@google.com if (fd < 0) { 51311960Sgabeblack@google.com perror("open"); 51411960Sgabeblack@google.com fatal("Can't open physical memory checkpoint file '%s'", filename); 51511960Sgabeblack@google.com } 51611960Sgabeblack@google.com 51711960Sgabeblack@google.com compressedMem = gzdopen(fd, "rb"); 51811960Sgabeblack@google.com if (compressedMem == NULL) 51911960Sgabeblack@google.com fatal("Insufficient memory to allocate compression state for %s\n", 52011960Sgabeblack@google.com filename); 52111960Sgabeblack@google.com 52211960Sgabeblack@google.com // unmap file that was mmaped in the constructor 52311960Sgabeblack@google.com // This is done here to make sure that gzip and open don't muck with our 52411960Sgabeblack@google.com // nice large space of memory before we reallocate it 52511960Sgabeblack@google.com munmap((char*)pmemAddr, params()->range.size()); 52611960Sgabeblack@google.com 52711960Sgabeblack@google.com pmemAddr = (uint8_t *)mmap(NULL, params()->range.size(), 52811960Sgabeblack@google.com PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); 52911960Sgabeblack@google.com 53011960Sgabeblack@google.com if (pmemAddr == (void *)MAP_FAILED) { 53111960Sgabeblack@google.com perror("mmap"); 53211960Sgabeblack@google.com fatal("Could not mmap physical memory!\n"); 53311960Sgabeblack@google.com } 53411960Sgabeblack@google.com 53511960Sgabeblack@google.com curSize = 0; 53611960Sgabeblack@google.com tempPage = (long*)malloc(chunkSize); 53711960Sgabeblack@google.com if (tempPage == NULL) 53811960Sgabeblack@google.com fatal("Unable to malloc memory to read file %s\n", filename); 53911960Sgabeblack@google.com 54011960Sgabeblack@google.com /* Only copy bytes that are non-zero, so we don't give the VM system hell */ 54111960Sgabeblack@google.com while (curSize < params()->range.size()) { 54211960Sgabeblack@google.com bytesRead = gzread(compressedMem, tempPage, chunkSize); 54311960Sgabeblack@google.com if (bytesRead == 0) 54411960Sgabeblack@google.com break; 54511960Sgabeblack@google.com 54611960Sgabeblack@google.com assert(bytesRead % sizeof(long) == 0); 54711960Sgabeblack@google.com 54811960Sgabeblack@google.com for (uint32_t x = 0; x < bytesRead / sizeof(long); x++) 54911960Sgabeblack@google.com { 55011960Sgabeblack@google.com if (*(tempPage+x) != 0) { 55111960Sgabeblack@google.com pmem_current = (long*)(pmemAddr + curSize + x * sizeof(long)); 55211960Sgabeblack@google.com *pmem_current = *(tempPage+x); 55311960Sgabeblack@google.com } 55411960Sgabeblack@google.com } 55511960Sgabeblack@google.com curSize += bytesRead; 55611960Sgabeblack@google.com } 55711960Sgabeblack@google.com 55811960Sgabeblack@google.com free(tempPage); 55911960Sgabeblack@google.com 56011960Sgabeblack@google.com if (gzclose(compressedMem)) 56111960Sgabeblack@google.com fatal("Close failed on physical memory checkpoint file '%s'\n", 56211960Sgabeblack@google.com filename); 56311960Sgabeblack@google.com 56411960Sgabeblack@google.com} 56511960Sgabeblack@google.com 56611960Sgabeblack@google.comPhysicalMemory * 56711960Sgabeblack@google.comPhysicalMemoryParams::create() 56811960Sgabeblack@google.com{ 56911960Sgabeblack@google.com return new PhysicalMemory(this); 57011960Sgabeblack@google.com} 57111960Sgabeblack@google.com