abstract_mem.cc revision 6329
13691SN/A/* 23691SN/A * Copyright (c) 2001-2005 The Regents of The University of Michigan 39449SAli.Saidi@ARM.com * All rights reserved. 410409Sandreas.hansson@arm.com * 510409Sandreas.hansson@arm.com * Redistribution and use in source and binary forms, with or without 68721SN/A * modification, are permitted provided that the following conditions are 711707Sandreas.hansson@arm.com * met: redistributions of source code must retain the above copyright 811707Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer; 911707Sandreas.hansson@arm.com * redistributions in binary form must reproduce the above copyright 1011707Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer in the 1111707Sandreas.hansson@arm.com * documentation and/or other materials provided with the distribution; 1210409Sandreas.hansson@arm.com * neither the name of the copyright holders nor the names of its 1310409Sandreas.hansson@arm.com * contributors may be used to endorse or promote products derived from 1410778Snilay@cs.wisc.edu * this software without specific prior written permission. 1510778Snilay@cs.wisc.edu * 1611530Sandreas.sandberg@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1710778Snilay@cs.wisc.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1810778Snilay@cs.wisc.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1910778Snilay@cs.wisc.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2010778Snilay@cs.wisc.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2110778Snilay@cs.wisc.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2210778Snilay@cs.wisc.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2310778Snilay@cs.wisc.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2410778Snilay@cs.wisc.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2510778Snilay@cs.wisc.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2610778Snilay@cs.wisc.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2710778Snilay@cs.wisc.edu * 2810778Snilay@cs.wisc.edu * Authors: Ron Dreslinski 2910778Snilay@cs.wisc.edu * Ali Saidi 3010778Snilay@cs.wisc.edu */ 3110778Snilay@cs.wisc.edu 3210778Snilay@cs.wisc.edu#include <sys/types.h> 3310778Snilay@cs.wisc.edu#include <sys/mman.h> 3410778Snilay@cs.wisc.edu#include <errno.h> 3510778Snilay@cs.wisc.edu#include <fcntl.h> 3610778Snilay@cs.wisc.edu#include <unistd.h> 3710778Snilay@cs.wisc.edu#include <zlib.h> 3810778Snilay@cs.wisc.edu 3910778Snilay@cs.wisc.edu#include <iostream> 4010778Snilay@cs.wisc.edu#include <string> 4110778Snilay@cs.wisc.edu 4210778Snilay@cs.wisc.edu#include "arch/registers.hh" 4310778Snilay@cs.wisc.edu#include "base/misc.hh" 4410778Snilay@cs.wisc.edu#include "base/random.hh" 4510778Snilay@cs.wisc.edu#include "base/types.hh" 4611530Sandreas.sandberg@arm.com#include "config/full_system.hh" 4711530Sandreas.sandberg@arm.com#include "mem/packet_access.hh" 4810778Snilay@cs.wisc.edu#include "mem/physical.hh" 4910778Snilay@cs.wisc.edu#include "sim/eventq.hh" 5010778Snilay@cs.wisc.edu 5110778Snilay@cs.wisc.eduusing namespace std; 5210778Snilay@cs.wisc.eduusing namespace TheISA; 5310778Snilay@cs.wisc.edu 5410778Snilay@cs.wisc.eduPhysicalMemory::PhysicalMemory(const Params *p) 5510778Snilay@cs.wisc.edu : MemObject(p), pmemAddr(NULL), pagePtr(0), 5610778Snilay@cs.wisc.edu lat(p->latency), lat_var(p->latency_var), 5710778Snilay@cs.wisc.edu cachedSize(params()->range.size()), cachedStart(params()->range.start) 5810778Snilay@cs.wisc.edu{ 5910778Snilay@cs.wisc.edu if (params()->range.size() % TheISA::PageBytes != 0) 6010778Snilay@cs.wisc.edu panic("Memory Size not divisible by page size\n"); 6110778Snilay@cs.wisc.edu 6210778Snilay@cs.wisc.edu if (params()->null) 6310778Snilay@cs.wisc.edu return; 6410778Snilay@cs.wisc.edu 6510778Snilay@cs.wisc.edu int map_flags = MAP_ANON | MAP_PRIVATE; 6610778Snilay@cs.wisc.edu pmemAddr = (uint8_t *)mmap(NULL, params()->range.size(), 6710778Snilay@cs.wisc.edu PROT_READ | PROT_WRITE, map_flags, -1, 0); 6810778Snilay@cs.wisc.edu 6910778Snilay@cs.wisc.edu if (pmemAddr == (void *)MAP_FAILED) { 7010778Snilay@cs.wisc.edu perror("mmap"); 7110778Snilay@cs.wisc.edu fatal("Could not mmap!\n"); 7210778Snilay@cs.wisc.edu } 7310778Snilay@cs.wisc.edu 7410778Snilay@cs.wisc.edu //If requested, initialize all the memory to 0 7510778Snilay@cs.wisc.edu if (p->zero) 7610778Snilay@cs.wisc.edu memset(pmemAddr, 0, p->range.size()); 7710778Snilay@cs.wisc.edu} 7810778Snilay@cs.wisc.edu 7910778Snilay@cs.wisc.eduvoid 8010778Snilay@cs.wisc.eduPhysicalMemory::init() 8111530Sandreas.sandberg@arm.com{ 8211530Sandreas.sandberg@arm.com if (ports.size() == 0) { 8311530Sandreas.sandberg@arm.com fatal("PhysicalMemory object %s is unconnected!", name()); 8411530Sandreas.sandberg@arm.com } 8511530Sandreas.sandberg@arm.com 8611530Sandreas.sandberg@arm.com for (PortIterator pi = ports.begin(); pi != ports.end(); ++pi) { 8711530Sandreas.sandberg@arm.com if (*pi) 8811530Sandreas.sandberg@arm.com (*pi)->sendStatusChange(Port::RangeChange); 8911530Sandreas.sandberg@arm.com } 9011530Sandreas.sandberg@arm.com} 9110778Snilay@cs.wisc.edu 9210778Snilay@cs.wisc.eduPhysicalMemory::~PhysicalMemory() 9310778Snilay@cs.wisc.edu{ 9410778Snilay@cs.wisc.edu if (pmemAddr) 9510778Snilay@cs.wisc.edu munmap((char*)pmemAddr, params()->range.size()); 9610778Snilay@cs.wisc.edu //Remove memPorts? 9710778Snilay@cs.wisc.edu} 9810778Snilay@cs.wisc.edu 9910778Snilay@cs.wisc.eduAddr 10010778Snilay@cs.wisc.eduPhysicalMemory::new_page() 10110778Snilay@cs.wisc.edu{ 10210778Snilay@cs.wisc.edu Addr return_addr = pagePtr << LogVMPageSize; 10310778Snilay@cs.wisc.edu return_addr += start(); 10410778Snilay@cs.wisc.edu 10510778Snilay@cs.wisc.edu ++pagePtr; 10610778Snilay@cs.wisc.edu return return_addr; 10710778Snilay@cs.wisc.edu} 10810778Snilay@cs.wisc.edu 10910778Snilay@cs.wisc.eduunsigned 11010778Snilay@cs.wisc.eduPhysicalMemory::deviceBlockSize() const 11110778Snilay@cs.wisc.edu{ 11210778Snilay@cs.wisc.edu //Can accept anysize request 11310778Snilay@cs.wisc.edu return 0; 11410778Snilay@cs.wisc.edu} 11510778Snilay@cs.wisc.edu 11610778Snilay@cs.wisc.eduTick 11710778Snilay@cs.wisc.eduPhysicalMemory::calculateLatency(PacketPtr pkt) 11810778Snilay@cs.wisc.edu{ 11910778Snilay@cs.wisc.edu Tick latency = lat; 12010778Snilay@cs.wisc.edu if (lat_var != 0) 12110778Snilay@cs.wisc.edu latency += random_mt.random<Tick>(0, lat_var); 12210778Snilay@cs.wisc.edu return latency; 12310778Snilay@cs.wisc.edu} 12410778Snilay@cs.wisc.edu 12510778Snilay@cs.wisc.edu 12610778Snilay@cs.wisc.edu 12710778Snilay@cs.wisc.edu// Add load-locked to tracking list. Should only be called if the 12810778Snilay@cs.wisc.edu// operation is a load and the LLSC flag is set. 12910778Snilay@cs.wisc.eduvoid 13010778Snilay@cs.wisc.eduPhysicalMemory::trackLoadLocked(PacketPtr pkt) 13110778Snilay@cs.wisc.edu{ 13210778Snilay@cs.wisc.edu Request *req = pkt->req; 13310778Snilay@cs.wisc.edu Addr paddr = LockedAddr::mask(req->getPaddr()); 13410778Snilay@cs.wisc.edu 13510778Snilay@cs.wisc.edu // first we check if we already have a locked addr for this 13610778Snilay@cs.wisc.edu // xc. Since each xc only gets one, we just update the 13710778Snilay@cs.wisc.edu // existing record with the new address. 13810778Snilay@cs.wisc.edu list<LockedAddr>::iterator i; 13910778Snilay@cs.wisc.edu 14011245Sandreas.sandberg@arm.com for (i = lockedAddrList.begin(); i != lockedAddrList.end(); ++i) { 14111245Sandreas.sandberg@arm.com if (i->matchesContext(req)) { 14211245Sandreas.sandberg@arm.com DPRINTF(LLSC, "Modifying lock record: context %d addr %#x\n", 14311245Sandreas.sandberg@arm.com req->contextId(), paddr); 14411245Sandreas.sandberg@arm.com i->addr = paddr; 14511245Sandreas.sandberg@arm.com return; 14611245Sandreas.sandberg@arm.com } 14711245Sandreas.sandberg@arm.com } 14811245Sandreas.sandberg@arm.com 14911245Sandreas.sandberg@arm.com // no record for this xc: need to allocate a new one 15011245Sandreas.sandberg@arm.com DPRINTF(LLSC, "Adding lock record: context %d addr %#x\n", 15111245Sandreas.sandberg@arm.com req->contextId(), paddr); 15211245Sandreas.sandberg@arm.com lockedAddrList.push_front(LockedAddr(req)); 15311245Sandreas.sandberg@arm.com} 15411245Sandreas.sandberg@arm.com 15511245Sandreas.sandberg@arm.com 15611245Sandreas.sandberg@arm.com// Called on *writes* only... both regular stores and 15711245Sandreas.sandberg@arm.com// store-conditional operations. Check for conventional stores which 15811245Sandreas.sandberg@arm.com// conflict with locked addresses, and for success/failure of store 15911245Sandreas.sandberg@arm.com// conditionals. 16011245Sandreas.sandberg@arm.combool 16111245Sandreas.sandberg@arm.comPhysicalMemory::checkLockedAddrList(PacketPtr pkt) 16211245Sandreas.sandberg@arm.com{ 16311245Sandreas.sandberg@arm.com Request *req = pkt->req; 16411245Sandreas.sandberg@arm.com Addr paddr = LockedAddr::mask(req->getPaddr()); 16511245Sandreas.sandberg@arm.com bool isLLSC = pkt->isLLSC(); 16611245Sandreas.sandberg@arm.com 16711245Sandreas.sandberg@arm.com // Initialize return value. Non-conditional stores always 16811687Sandreas.hansson@arm.com // succeed. Assume conditional stores will fail until proven 16911245Sandreas.sandberg@arm.com // otherwise. 17011687Sandreas.hansson@arm.com bool success = !isLLSC; 17111245Sandreas.sandberg@arm.com 17211245Sandreas.sandberg@arm.com // Iterate over list. Note that there could be multiple matching 17311245Sandreas.sandberg@arm.com // records, as more than one context could have done a load locked 17411245Sandreas.sandberg@arm.com // to this location. 17511245Sandreas.sandberg@arm.com list<LockedAddr>::iterator i = lockedAddrList.begin(); 17611245Sandreas.sandberg@arm.com 17711245Sandreas.sandberg@arm.com while (i != lockedAddrList.end()) { 17811245Sandreas.sandberg@arm.com 17911245Sandreas.sandberg@arm.com if (i->addr == paddr) { 18011245Sandreas.sandberg@arm.com // we have a matching address 18111245Sandreas.sandberg@arm.com 18211245Sandreas.sandberg@arm.com if (isLLSC && i->matchesContext(req)) { 18311245Sandreas.sandberg@arm.com // it's a store conditional, and as far as the memory 18411245Sandreas.sandberg@arm.com // system can tell, the requesting context's lock is 18511245Sandreas.sandberg@arm.com // still valid. 18611245Sandreas.sandberg@arm.com DPRINTF(LLSC, "StCond success: context %d addr %#x\n", 18711245Sandreas.sandberg@arm.com req->contextId(), paddr); 18811245Sandreas.sandberg@arm.com success = true; 18911245Sandreas.sandberg@arm.com } 19011245Sandreas.sandberg@arm.com 19111245Sandreas.sandberg@arm.com // Get rid of our record of this lock and advance to next 19211687Sandreas.hansson@arm.com DPRINTF(LLSC, "Erasing lock record: context %d addr %#x\n", 19311687Sandreas.hansson@arm.com i->contextId, paddr); 19411687Sandreas.hansson@arm.com i = lockedAddrList.erase(i); 19511687Sandreas.hansson@arm.com } 19611245Sandreas.sandberg@arm.com else { 19711245Sandreas.sandberg@arm.com // no match: advance to next record 19811245Sandreas.sandberg@arm.com ++i; 19910778Snilay@cs.wisc.edu } 20010778Snilay@cs.wisc.edu } 20110778Snilay@cs.wisc.edu 20210778Snilay@cs.wisc.edu if (isLLSC) { 20310778Snilay@cs.wisc.edu req->setExtraData(success ? 1 : 0); 20410778Snilay@cs.wisc.edu } 20510778Snilay@cs.wisc.edu 20610778Snilay@cs.wisc.edu return success; 20710778Snilay@cs.wisc.edu} 20810778Snilay@cs.wisc.edu 20910778Snilay@cs.wisc.edu 21010778Snilay@cs.wisc.edu#if TRACING_ON 21111530Sandreas.sandberg@arm.com 21211530Sandreas.sandberg@arm.com#define CASE(A, T) \ 21310778Snilay@cs.wisc.edu case sizeof(T): \ 21410778Snilay@cs.wisc.edu DPRINTF(MemoryAccess, A " of size %i on address 0x%x data 0x%x\n", \ 21510778Snilay@cs.wisc.edu pkt->getSize(), pkt->getAddr(), pkt->get<T>()); \ 21610778Snilay@cs.wisc.edu break 21710778Snilay@cs.wisc.edu 21810778Snilay@cs.wisc.edu 21910778Snilay@cs.wisc.edu#define TRACE_PACKET(A) \ 22010778Snilay@cs.wisc.edu do { \ 22110778Snilay@cs.wisc.edu switch (pkt->getSize()) { \ 22210778Snilay@cs.wisc.edu CASE(A, uint64_t); \ 22310778Snilay@cs.wisc.edu CASE(A, uint32_t); \ 22410778Snilay@cs.wisc.edu CASE(A, uint16_t); \ 22510778Snilay@cs.wisc.edu CASE(A, uint8_t); \ 22610778Snilay@cs.wisc.edu default: \ 22710778Snilay@cs.wisc.edu DPRINTF(MemoryAccess, A " of size %i on address 0x%x\n", \ 22810778Snilay@cs.wisc.edu pkt->getSize(), pkt->getAddr()); \ 22911606Sandreas.sandberg@arm.com } \ 23011606Sandreas.sandberg@arm.com } while (0) 23111606Sandreas.sandberg@arm.com 23211606Sandreas.sandberg@arm.com#else 23311606Sandreas.sandberg@arm.com 23411606Sandreas.sandberg@arm.com#define TRACE_PACKET(A) 23511530Sandreas.sandberg@arm.com 23610778Snilay@cs.wisc.edu#endif 23710778Snilay@cs.wisc.edu 23810778Snilay@cs.wisc.eduTick 23910778Snilay@cs.wisc.eduPhysicalMemory::doAtomicAccess(PacketPtr pkt) 24010778Snilay@cs.wisc.edu{ 24110778Snilay@cs.wisc.edu assert(pkt->getAddr() >= start() && 24210778Snilay@cs.wisc.edu pkt->getAddr() + pkt->getSize() <= start() + size()); 24310778Snilay@cs.wisc.edu 24410778Snilay@cs.wisc.edu if (pkt->memInhibitAsserted()) { 24510778Snilay@cs.wisc.edu DPRINTF(MemoryAccess, "mem inhibited on 0x%x: not responding\n", 24610778Snilay@cs.wisc.edu pkt->getAddr()); 24710778Snilay@cs.wisc.edu return 0; 24810778Snilay@cs.wisc.edu } 24910778Snilay@cs.wisc.edu 25010778Snilay@cs.wisc.edu uint8_t *hostAddr = pmemAddr + pkt->getAddr() - start(); 25110778Snilay@cs.wisc.edu 25210778Snilay@cs.wisc.edu if (pkt->cmd == MemCmd::SwapReq) { 25310778Snilay@cs.wisc.edu IntReg overwrite_val; 25410778Snilay@cs.wisc.edu bool overwrite_mem; 25510778Snilay@cs.wisc.edu uint64_t condition_val64; 25610778Snilay@cs.wisc.edu uint32_t condition_val32; 25710778Snilay@cs.wisc.edu 25810778Snilay@cs.wisc.edu if (!pmemAddr) 25910778Snilay@cs.wisc.edu panic("Swap only works if there is real memory (i.e. null=False)"); 26011570SCurtis.Dunham@arm.com assert(sizeof(IntReg) >= pkt->getSize()); 26110827Sandreas.hansson@arm.com 26211606Sandreas.sandberg@arm.com overwrite_mem = true; 26311606Sandreas.sandberg@arm.com // keep a copy of our possible write value, and copy what is at the 26410778Snilay@cs.wisc.edu // memory address into the packet 26511606Sandreas.sandberg@arm.com std::memcpy(&overwrite_val, pkt->getPtr<uint8_t>(), pkt->getSize()); 26611606Sandreas.sandberg@arm.com std::memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize()); 26710778Snilay@cs.wisc.edu 26810778Snilay@cs.wisc.edu if (pkt->req->isCondSwap()) { 26911606Sandreas.sandberg@arm.com if (pkt->getSize() == sizeof(uint64_t)) { 27010827Sandreas.hansson@arm.com condition_val64 = pkt->req->getExtraData(); 27111530Sandreas.sandberg@arm.com overwrite_mem = !std::memcmp(&condition_val64, hostAddr, 27211530Sandreas.sandberg@arm.com sizeof(uint64_t)); 27311530Sandreas.sandberg@arm.com } else if (pkt->getSize() == sizeof(uint32_t)) { 27410778Snilay@cs.wisc.edu condition_val32 = (uint32_t)pkt->req->getExtraData(); 27511530Sandreas.sandberg@arm.com overwrite_mem = !std::memcmp(&condition_val32, hostAddr, 27611530Sandreas.sandberg@arm.com sizeof(uint32_t)); 27710778Snilay@cs.wisc.edu } else 27810778Snilay@cs.wisc.edu panic("Invalid size for conditional read/write\n"); 27910778Snilay@cs.wisc.edu } 28010778Snilay@cs.wisc.edu 28110778Snilay@cs.wisc.edu if (overwrite_mem) 28210778Snilay@cs.wisc.edu std::memcpy(hostAddr, &overwrite_val, pkt->getSize()); 28310778Snilay@cs.wisc.edu 28410778Snilay@cs.wisc.edu TRACE_PACKET("Read/Write"); 28510778Snilay@cs.wisc.edu } else if (pkt->isRead()) { 28610778Snilay@cs.wisc.edu assert(!pkt->isWrite()); 28710778Snilay@cs.wisc.edu if (pkt->isLLSC()) { 28810778Snilay@cs.wisc.edu trackLoadLocked(pkt); 28910778Snilay@cs.wisc.edu } 29010778Snilay@cs.wisc.edu if (pmemAddr) 29110778Snilay@cs.wisc.edu memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize()); 29210778Snilay@cs.wisc.edu TRACE_PACKET("Read"); 29310778Snilay@cs.wisc.edu } else if (pkt->isWrite()) { 29410778Snilay@cs.wisc.edu if (writeOK(pkt)) { 29510778Snilay@cs.wisc.edu if (pmemAddr) 29610778Snilay@cs.wisc.edu memcpy(hostAddr, pkt->getPtr<uint8_t>(), pkt->getSize()); 29710778Snilay@cs.wisc.edu TRACE_PACKET("Write"); 29810778Snilay@cs.wisc.edu } 29910778Snilay@cs.wisc.edu } else if (pkt->isInvalidate()) { 30010778Snilay@cs.wisc.edu //upgrade or invalidate 30110778Snilay@cs.wisc.edu if (pkt->needsResponse()) { 30210778Snilay@cs.wisc.edu pkt->makeAtomicResponse(); 30310778Snilay@cs.wisc.edu } 30410778Snilay@cs.wisc.edu } else { 30510778Snilay@cs.wisc.edu panic("unimplemented"); 30610778Snilay@cs.wisc.edu } 30710778Snilay@cs.wisc.edu 30810778Snilay@cs.wisc.edu if (pkt->needsResponse()) { 30910778Snilay@cs.wisc.edu pkt->makeAtomicResponse(); 31010778Snilay@cs.wisc.edu } 31110778Snilay@cs.wisc.edu return calculateLatency(pkt); 31210778Snilay@cs.wisc.edu} 31310778Snilay@cs.wisc.edu 31410778Snilay@cs.wisc.edu 31510778Snilay@cs.wisc.eduvoid 31610778Snilay@cs.wisc.eduPhysicalMemory::doFunctionalAccess(PacketPtr pkt) 31710778Snilay@cs.wisc.edu{ 31810778Snilay@cs.wisc.edu assert(pkt->getAddr() >= start() && 31910778Snilay@cs.wisc.edu pkt->getAddr() + pkt->getSize() <= start() + size()); 32010778Snilay@cs.wisc.edu 32110778Snilay@cs.wisc.edu 32210778Snilay@cs.wisc.edu uint8_t *hostAddr = pmemAddr + pkt->getAddr() - start(); 32310778Snilay@cs.wisc.edu 32410778Snilay@cs.wisc.edu if (pkt->isRead()) { 32510778Snilay@cs.wisc.edu if (pmemAddr) 32611530Sandreas.sandberg@arm.com memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize()); 32711530Sandreas.sandberg@arm.com TRACE_PACKET("Read"); 32811530Sandreas.sandberg@arm.com pkt->makeAtomicResponse(); 32911530Sandreas.sandberg@arm.com } else if (pkt->isWrite()) { 33011530Sandreas.sandberg@arm.com if (pmemAddr) 33111530Sandreas.sandberg@arm.com memcpy(hostAddr, pkt->getPtr<uint8_t>(), pkt->getSize()); 33211530Sandreas.sandberg@arm.com TRACE_PACKET("Write"); 33311530Sandreas.sandberg@arm.com pkt->makeAtomicResponse(); 33411530Sandreas.sandberg@arm.com } else if (pkt->isPrint()) { 33511530Sandreas.sandberg@arm.com Packet::PrintReqState *prs = 33611530Sandreas.sandberg@arm.com dynamic_cast<Packet::PrintReqState*>(pkt->senderState); 33711530Sandreas.sandberg@arm.com // Need to call printLabels() explicitly since we're not going 33811530Sandreas.sandberg@arm.com // through printObj(). 33911530Sandreas.sandberg@arm.com prs->printLabels(); 34011530Sandreas.sandberg@arm.com // Right now we just print the single byte at the specified address. 34111530Sandreas.sandberg@arm.com ccprintf(prs->os, "%s%#x\n", prs->curPrefix(), *hostAddr); 34211530Sandreas.sandberg@arm.com } else { 34311530Sandreas.sandberg@arm.com panic("PhysicalMemory: unimplemented functional command %s", 34411530Sandreas.sandberg@arm.com pkt->cmdString()); 34511530Sandreas.sandberg@arm.com } 34611530Sandreas.sandberg@arm.com} 34711530Sandreas.sandberg@arm.com 34811530Sandreas.sandberg@arm.com 34910036SAli.Saidi@ARM.comPort * 35010036SAli.Saidi@ARM.comPhysicalMemory::getPort(const std::string &if_name, int idx) 35111530Sandreas.sandberg@arm.com{ 35210409Sandreas.hansson@arm.com // Accept request for "functional" port for backwards compatibility 35310409Sandreas.hansson@arm.com // with places where this function is called from C++. I'd prefer 3549729Sandreas.hansson@arm.com // to move all these into Python someday. 35510409Sandreas.hansson@arm.com if (if_name == "functional") { 35610409Sandreas.hansson@arm.com return new MemoryPort(csprintf("%s-functional", name()), this); 35710409Sandreas.hansson@arm.com } 35810409Sandreas.hansson@arm.com 3599055Ssaidi@eecs.umich.edu if (if_name != "port") { 36010409Sandreas.hansson@arm.com panic("PhysicalMemory::getPort: unknown port %s requested", if_name); 36110409Sandreas.hansson@arm.com } 36210409Sandreas.hansson@arm.com 3639729Sandreas.hansson@arm.com if (idx >= (int)ports.size()) { 36410409Sandreas.hansson@arm.com ports.resize(idx + 1); 36510409Sandreas.hansson@arm.com } 3669055Ssaidi@eecs.umich.edu 36710409Sandreas.hansson@arm.com if (ports[idx] != NULL) { 36810409Sandreas.hansson@arm.com panic("PhysicalMemory::getPort: port %d already assigned", idx); 36910409Sandreas.hansson@arm.com } 37010409Sandreas.hansson@arm.com 37110409Sandreas.hansson@arm.com MemoryPort *port = 37210409Sandreas.hansson@arm.com new MemoryPort(csprintf("%s-port%d", name(), idx), this); 37310409Sandreas.hansson@arm.com 37410409Sandreas.hansson@arm.com ports[idx] = port; 3759247Sandreas.hansson@arm.com return port; 37610409Sandreas.hansson@arm.com} 37710409Sandreas.hansson@arm.com 37810409Sandreas.hansson@arm.com 37910409Sandreas.hansson@arm.comvoid 38010409Sandreas.hansson@arm.comPhysicalMemory::recvStatusChange(Port::Status status) 38111530Sandreas.sandberg@arm.com{ 38211530Sandreas.sandberg@arm.com} 38310036SAli.Saidi@ARM.com 3848721SN/APhysicalMemory::MemoryPort::MemoryPort(const std::string &_name, 3858721SN/A PhysicalMemory *_memory) 3868721SN/A : SimpleTimingPort(_name, _memory), memory(_memory) 3878721SN/A{ } 38810409Sandreas.hansson@arm.com 3898721SN/Avoid 3908721SN/APhysicalMemory::MemoryPort::recvStatusChange(Port::Status status) 3918721SN/A{ 39210409Sandreas.hansson@arm.com memory->recvStatusChange(status); 3938721SN/A} 3948721SN/A 3958721SN/Avoid 39610409Sandreas.hansson@arm.comPhysicalMemory::MemoryPort::getDeviceAddressRanges(AddrRangeList &resp, 3976024SN/A bool &snoop) 3988721SN/A{ 3998721SN/A memory->getAddressRanges(resp, snoop); 40010409Sandreas.hansson@arm.com} 4018721SN/A 4028721SN/Avoid 40310409Sandreas.hansson@arm.comPhysicalMemory::getAddressRanges(AddrRangeList &resp, bool &snoop) 4048721SN/A{ 4058721SN/A snoop = false; 4068721SN/A resp.clear(); 4078721SN/A resp.push_back(RangeSize(start(), params()->range.size())); 4088721SN/A} 4098721SN/A 4108721SN/Aunsigned 4118721SN/APhysicalMemory::MemoryPort::deviceBlockSize() const 4126024SN/A{ 4136024SN/A return memory->deviceBlockSize(); 4148721SN/A} 4158721SN/A 41611530Sandreas.sandberg@arm.comTick 41711530Sandreas.sandberg@arm.comPhysicalMemory::MemoryPort::recvAtomic(PacketPtr pkt) 41811530Sandreas.sandberg@arm.com{ 41911530Sandreas.sandberg@arm.com return memory->doAtomicAccess(pkt); 42011530Sandreas.sandberg@arm.com} 42111530Sandreas.sandberg@arm.com 42211530Sandreas.sandberg@arm.comvoid 42311530Sandreas.sandberg@arm.comPhysicalMemory::MemoryPort::recvFunctional(PacketPtr pkt) 42411530Sandreas.sandberg@arm.com{ 42511530Sandreas.sandberg@arm.com pkt->pushLabel(memory->name()); 42610409Sandreas.hansson@arm.com 4278721SN/A if (!checkFunctional(pkt)) { 4288721SN/A // Default implementation of SimpleTimingPort::recvFunctional() 4293691SN/A // calls recvAtomic() and throws away the latency; we can save a 4309729Sandreas.hansson@arm.com // little here by just not calculating the latency. 43110409Sandreas.hansson@arm.com memory->doFunctionalAccess(pkt); 4329729Sandreas.hansson@arm.com } 4339729Sandreas.hansson@arm.com 4349449SAli.Saidi@ARM.com pkt->popLabel(); 43510409Sandreas.hansson@arm.com} 43610409Sandreas.hansson@arm.com 4379729Sandreas.hansson@arm.comunsigned int 4389729Sandreas.hansson@arm.comPhysicalMemory::drain(Event *de) 4399729Sandreas.hansson@arm.com{ 4409729Sandreas.hansson@arm.com int count = 0; 4419729Sandreas.hansson@arm.com for (PortIterator pi = ports.begin(); pi != ports.end(); ++pi) { 44210409Sandreas.hansson@arm.com count += (*pi)->drain(de); 4439729Sandreas.hansson@arm.com } 4449449SAli.Saidi@ARM.com 44510409Sandreas.hansson@arm.com if (count) 44610409Sandreas.hansson@arm.com changeState(Draining); 4479449SAli.Saidi@ARM.com else 4486127SN/A changeState(Drained); 4496127SN/A return count; 45010409Sandreas.hansson@arm.com} 45110409Sandreas.hansson@arm.com 4529729Sandreas.hansson@arm.comvoid 4539449SAli.Saidi@ARM.comPhysicalMemory::serialize(ostream &os) 45410409Sandreas.hansson@arm.com{ 4559449SAli.Saidi@ARM.com if (!pmemAddr) 4569449SAli.Saidi@ARM.com return; 4579490Sandreas.hansson@arm.com 4589490Sandreas.hansson@arm.com gzFile compressedMem; 4599449SAli.Saidi@ARM.com string filename = name() + ".physmem"; 4609449SAli.Saidi@ARM.com 46110409Sandreas.hansson@arm.com SERIALIZE_SCALAR(filename); 4629729Sandreas.hansson@arm.com 46310409Sandreas.hansson@arm.com // write memory file 4649729Sandreas.hansson@arm.com string thefile = Checkpoint::dir() + "/" + filename.c_str(); 46510409Sandreas.hansson@arm.com int fd = creat(thefile.c_str(), 0664); 46610409Sandreas.hansson@arm.com if (fd < 0) { 4679729Sandreas.hansson@arm.com perror("creat"); 46810409Sandreas.hansson@arm.com fatal("Can't open physical memory checkpoint file '%s'\n", filename); 4698721SN/A } 4709729Sandreas.hansson@arm.com 47110409Sandreas.hansson@arm.com compressedMem = gzdopen(fd, "wb"); 47210409Sandreas.hansson@arm.com if (compressedMem == NULL) 47310409Sandreas.hansson@arm.com fatal("Insufficient memory to allocate compression state for %s\n", 47410409Sandreas.hansson@arm.com filename); 4759729Sandreas.hansson@arm.com 47611245Sandreas.sandberg@arm.com if (gzwrite(compressedMem, pmemAddr, params()->range.size()) != 47711245Sandreas.sandberg@arm.com (int)params()->range.size()) { 47811245Sandreas.sandberg@arm.com fatal("Write failed on physical memory checkpoint file '%s'\n", 47911245Sandreas.sandberg@arm.com filename); 48011245Sandreas.sandberg@arm.com } 48111245Sandreas.sandberg@arm.com 48211245Sandreas.sandberg@arm.com if (gzclose(compressedMem)) 48311245Sandreas.sandberg@arm.com fatal("Close failed on physical memory checkpoint file '%s'\n", 48411245Sandreas.sandberg@arm.com filename); 48511245Sandreas.sandberg@arm.com} 48611245Sandreas.sandberg@arm.com 48711245Sandreas.sandberg@arm.comvoid 48811245Sandreas.sandberg@arm.comPhysicalMemory::unserialize(Checkpoint *cp, const string §ion) 48911245Sandreas.sandberg@arm.com{ 49011245Sandreas.sandberg@arm.com if (!pmemAddr) 49111245Sandreas.sandberg@arm.com return; 49211245Sandreas.sandberg@arm.com 49311245Sandreas.sandberg@arm.com gzFile compressedMem; 49411245Sandreas.sandberg@arm.com long *tempPage; 49511245Sandreas.sandberg@arm.com long *pmem_current; 49611245Sandreas.sandberg@arm.com uint64_t curSize; 49711245Sandreas.sandberg@arm.com uint32_t bytesRead; 49811245Sandreas.sandberg@arm.com const uint32_t chunkSize = 16384; 49911245Sandreas.sandberg@arm.com 50011245Sandreas.sandberg@arm.com string filename; 50111245Sandreas.sandberg@arm.com 50211245Sandreas.sandberg@arm.com UNSERIALIZE_SCALAR(filename); 50311245Sandreas.sandberg@arm.com 50411687Sandreas.hansson@arm.com filename = cp->cptDir + "/" + filename; 50511245Sandreas.sandberg@arm.com 50611687Sandreas.hansson@arm.com // mmap memoryfile 50711245Sandreas.sandberg@arm.com int fd = open(filename.c_str(), O_RDONLY); 50811245Sandreas.sandberg@arm.com if (fd < 0) { 50911245Sandreas.sandberg@arm.com perror("open"); 51011245Sandreas.sandberg@arm.com fatal("Can't open physical memory checkpoint file '%s'", filename); 51111245Sandreas.sandberg@arm.com } 51211245Sandreas.sandberg@arm.com 51311245Sandreas.sandberg@arm.com compressedMem = gzdopen(fd, "rb"); 51411245Sandreas.sandberg@arm.com if (compressedMem == NULL) 51511245Sandreas.sandberg@arm.com fatal("Insufficient memory to allocate compression state for %s\n", 51611245Sandreas.sandberg@arm.com filename); 51711245Sandreas.sandberg@arm.com 51811245Sandreas.sandberg@arm.com // unmap file that was mmaped in the constructor 51911245Sandreas.sandberg@arm.com // This is done here to make sure that gzip and open don't muck with our 52011245Sandreas.sandberg@arm.com // nice large space of memory before we reallocate it 52111245Sandreas.sandberg@arm.com munmap((char*)pmemAddr, params()->range.size()); 52211245Sandreas.sandberg@arm.com 52311245Sandreas.sandberg@arm.com pmemAddr = (uint8_t *)mmap(NULL, params()->range.size(), 52411245Sandreas.sandberg@arm.com PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); 52511245Sandreas.sandberg@arm.com 52611245Sandreas.sandberg@arm.com if (pmemAddr == (void *)MAP_FAILED) { 52711245Sandreas.sandberg@arm.com perror("mmap"); 52811687Sandreas.hansson@arm.com fatal("Could not mmap physical memory!\n"); 52911687Sandreas.hansson@arm.com } 53011687Sandreas.hansson@arm.com 53111687Sandreas.hansson@arm.com curSize = 0; 53211245Sandreas.sandberg@arm.com tempPage = (long*)malloc(chunkSize); 53311245Sandreas.sandberg@arm.com if (tempPage == NULL) 53411245Sandreas.sandberg@arm.com fatal("Unable to malloc memory to read file %s\n", filename); 53510778Snilay@cs.wisc.edu 53610778Snilay@cs.wisc.edu /* Only copy bytes that are non-zero, so we don't give the VM system hell */ 53710778Snilay@cs.wisc.edu while (curSize < params()->range.size()) { 53810778Snilay@cs.wisc.edu bytesRead = gzread(compressedMem, tempPage, chunkSize); 53910778Snilay@cs.wisc.edu if (bytesRead != chunkSize && 54010778Snilay@cs.wisc.edu bytesRead != params()->range.size() - curSize) 54110778Snilay@cs.wisc.edu fatal("Read failed on physical memory checkpoint file '%s'" 54210778Snilay@cs.wisc.edu " got %d bytes, expected %d or %d bytes\n", 54310778Snilay@cs.wisc.edu filename, bytesRead, chunkSize, 54410778Snilay@cs.wisc.edu params()->range.size() - curSize); 54510778Snilay@cs.wisc.edu 54610778Snilay@cs.wisc.edu assert(bytesRead % sizeof(long) == 0); 54711530Sandreas.sandberg@arm.com 54811530Sandreas.sandberg@arm.com for (uint32_t x = 0; x < bytesRead / sizeof(long); x++) 54910778Snilay@cs.wisc.edu { 55010778Snilay@cs.wisc.edu if (*(tempPage+x) != 0) { 55110778Snilay@cs.wisc.edu pmem_current = (long*)(pmemAddr + curSize + x * sizeof(long)); 55210778Snilay@cs.wisc.edu *pmem_current = *(tempPage+x); 55310778Snilay@cs.wisc.edu } 55410778Snilay@cs.wisc.edu } 55510778Snilay@cs.wisc.edu curSize += bytesRead; 55610778Snilay@cs.wisc.edu } 55710778Snilay@cs.wisc.edu 55810778Snilay@cs.wisc.edu free(tempPage); 55910778Snilay@cs.wisc.edu 56010778Snilay@cs.wisc.edu if (gzclose(compressedMem)) 56110778Snilay@cs.wisc.edu fatal("Close failed on physical memory checkpoint file '%s'\n", 56210778Snilay@cs.wisc.edu filename); 56310778Snilay@cs.wisc.edu 56410778Snilay@cs.wisc.edu} 56510778Snilay@cs.wisc.edu 56610778Snilay@cs.wisc.eduPhysicalMemory * 56710778Snilay@cs.wisc.eduPhysicalMemoryParams::create() 56810778Snilay@cs.wisc.edu{ 56911606Sandreas.sandberg@arm.com return new PhysicalMemory(this); 57011606Sandreas.sandberg@arm.com} 57111606Sandreas.sandberg@arm.com