physical.cc revision 2665
12391SN/A/* 22391SN/A * Copyright (c) 2001-2005 The Regents of The University of Michigan 32391SN/A * All rights reserved. 42391SN/A * 52391SN/A * Redistribution and use in source and binary forms, with or without 62391SN/A * modification, are permitted provided that the following conditions are 72391SN/A * met: redistributions of source code must retain the above copyright 82391SN/A * notice, this list of conditions and the following disclaimer; 92391SN/A * redistributions in binary form must reproduce the above copyright 102391SN/A * notice, this list of conditions and the following disclaimer in the 112391SN/A * documentation and/or other materials provided with the distribution; 122391SN/A * neither the name of the copyright holders nor the names of its 132391SN/A * contributors may be used to endorse or promote products derived from 142391SN/A * this software without specific prior written permission. 152391SN/A * 162391SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172391SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182391SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192391SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202391SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212391SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222391SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232391SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242391SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252391SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262391SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272665Ssaidi@eecs.umich.edu * 282665Ssaidi@eecs.umich.edu * Authors: Ron Dreslinski 292391SN/A */ 302391SN/A 312391SN/A#include <sys/types.h> 322391SN/A#include <sys/mman.h> 332391SN/A#include <errno.h> 342391SN/A#include <fcntl.h> 352391SN/A#include <unistd.h> 362391SN/A#include <zlib.h> 372391SN/A 382391SN/A#include <iostream> 392391SN/A#include <string> 402391SN/A 412391SN/A 422391SN/A#include "base/misc.hh" 432391SN/A#include "config/full_system.hh" 442592SN/A#include "mem/packet_impl.hh" 452394SN/A#include "mem/physical.hh" 462391SN/A#include "sim/host.hh" 472391SN/A#include "sim/builder.hh" 482415SN/A#include "sim/eventq.hh" 492423SN/A#include "arch/isa_traits.hh" 502391SN/A 512394SN/A 522391SN/Ausing namespace std; 532423SN/Ausing namespace TheISA; 542391SN/A 552630SN/APhysicalMemory::MemResponseEvent::MemResponseEvent(Packet *pkt, MemoryPort* _m) 562415SN/A : Event(&mainEventQueue, CPU_Tick_Pri), pkt(pkt), memoryPort(_m) 572415SN/A{ 582415SN/A 592415SN/A this->setFlags(AutoDelete); 602415SN/A} 612415SN/A 622415SN/Avoid 632415SN/APhysicalMemory::MemResponseEvent::process() 642415SN/A{ 652415SN/A memoryPort->sendTiming(pkt); 662415SN/A} 672415SN/A 682415SN/Aconst char * 692415SN/APhysicalMemory::MemResponseEvent::description() 702415SN/A{ 712415SN/A return "Physical Memory Timing Access respnse event"; 722415SN/A} 732415SN/A 742565SN/APhysicalMemory::PhysicalMemory(const string &n, Tick latency) 752565SN/A : MemObject(n),base_addr(0), pmem_addr(NULL), port(NULL), lat(latency) 762391SN/A{ 772391SN/A // Hardcoded to 128 MB for now. 782391SN/A pmem_size = 1 << 27; 792391SN/A 802391SN/A if (pmem_size % TheISA::PageBytes != 0) 812391SN/A panic("Memory Size not divisible by page size\n"); 822391SN/A 832391SN/A int map_flags = MAP_ANON | MAP_PRIVATE; 842391SN/A pmem_addr = (uint8_t *)mmap(NULL, pmem_size, PROT_READ | PROT_WRITE, 852391SN/A map_flags, -1, 0); 862391SN/A 872391SN/A if (pmem_addr == (void *)MAP_FAILED) { 882391SN/A perror("mmap"); 892391SN/A fatal("Could not mmap!\n"); 902391SN/A } 912391SN/A 922391SN/A page_ptr = 0; 932391SN/A} 942391SN/A 952541SN/Avoid 962541SN/APhysicalMemory::init() 972541SN/A{ 982541SN/A if (!port) 992541SN/A panic("PhysicalMemory not connected to anything!"); 1002541SN/A port->sendStatusChange(Port::RangeChange); 1012541SN/A} 1022541SN/A 1032391SN/APhysicalMemory::~PhysicalMemory() 1042391SN/A{ 1052391SN/A if (pmem_addr) 1062391SN/A munmap(pmem_addr, pmem_size); 1072416SN/A //Remove memPorts? 1082391SN/A} 1092391SN/A 1102391SN/AAddr 1112391SN/APhysicalMemory::new_page() 1122391SN/A{ 1132391SN/A Addr return_addr = page_ptr << LogVMPageSize; 1142391SN/A return_addr += base_addr; 1152391SN/A 1162391SN/A ++page_ptr; 1172391SN/A return return_addr; 1182391SN/A} 1192391SN/A 1202408SN/Aint 1212408SN/APhysicalMemory::deviceBlockSize() 1222408SN/A{ 1232409SN/A //Can accept anysize request 1242409SN/A return 0; 1252408SN/A} 1262408SN/A 1272413SN/Abool 1282630SN/APhysicalMemory::doTimingAccess (Packet *pkt, MemoryPort* memoryPort) 1292413SN/A{ 1302413SN/A doFunctionalAccess(pkt); 1312415SN/A 1322639Sstever@eecs.umich.edu // turn packet around to go back to requester 1332641Sstever@eecs.umich.edu pkt->makeTimingResponse(); 1342416SN/A MemResponseEvent* response = new MemResponseEvent(pkt, memoryPort); 1352415SN/A response->schedule(curTick + lat); 1362415SN/A 1372413SN/A return true; 1382413SN/A} 1392413SN/A 1402413SN/ATick 1412630SN/APhysicalMemory::doAtomicAccess(Packet *pkt) 1422413SN/A{ 1432413SN/A doFunctionalAccess(pkt); 1442662Sstever@eecs.umich.edu return lat; 1452413SN/A} 1462413SN/A 1472413SN/Avoid 1482630SN/APhysicalMemory::doFunctionalAccess(Packet *pkt) 1492413SN/A{ 1502641Sstever@eecs.umich.edu assert(pkt->getAddr() + pkt->getSize() < pmem_size); 1512414SN/A 1522630SN/A switch (pkt->cmd) { 1532641Sstever@eecs.umich.edu case Packet::ReadReq: 1542641Sstever@eecs.umich.edu memcpy(pkt->getPtr<uint8_t>(), 1552641Sstever@eecs.umich.edu pmem_addr + pkt->getAddr() - base_addr, 1562641Sstever@eecs.umich.edu pkt->getSize()); 1572418SN/A break; 1582641Sstever@eecs.umich.edu case Packet::WriteReq: 1592641Sstever@eecs.umich.edu memcpy(pmem_addr + pkt->getAddr() - base_addr, 1602641Sstever@eecs.umich.edu pkt->getPtr<uint8_t>(), 1612641Sstever@eecs.umich.edu pkt->getSize()); 1622631SN/A // temporary hack: will need to add real LL/SC implementation 1632631SN/A // for cacheless systems later. 1642631SN/A if (pkt->req->getFlags() & LOCKED) { 1652631SN/A pkt->req->setScResult(1); 1662631SN/A } 1672418SN/A break; 1682413SN/A default: 1692413SN/A panic("unimplemented"); 1702413SN/A } 1712420SN/A 1722641Sstever@eecs.umich.edu pkt->result = Packet::Success; 1732413SN/A} 1742413SN/A 1752413SN/APort * 1762499SN/APhysicalMemory::getPort(const std::string &if_name) 1772413SN/A{ 1782499SN/A if (if_name == "") { 1792499SN/A if (port != NULL) 1802499SN/A panic("PhysicalMemory::getPort: additional port requested to memory!"); 1812640Sstever@eecs.umich.edu port = new MemoryPort(name() + "-port", this); 1822499SN/A return port; 1832519SN/A } else if (if_name == "functional") { 1842519SN/A /* special port for functional writes at startup. */ 1852640Sstever@eecs.umich.edu return new MemoryPort(name() + "-funcport", this); 1862462SN/A } else { 1872462SN/A panic("PhysicalMemory::getPort: unknown port %s requested", if_name); 1882462SN/A } 1892413SN/A} 1902413SN/A 1912413SN/Avoid 1922413SN/APhysicalMemory::recvStatusChange(Port::Status status) 1932413SN/A{ 1942413SN/A} 1952413SN/A 1962640Sstever@eecs.umich.eduPhysicalMemory::MemoryPort::MemoryPort(const std::string &_name, 1972640Sstever@eecs.umich.edu PhysicalMemory *_memory) 1982640Sstever@eecs.umich.edu : Port(_name), memory(_memory) 1992413SN/A{ } 2002413SN/A 2012413SN/Avoid 2022413SN/APhysicalMemory::MemoryPort::recvStatusChange(Port::Status status) 2032413SN/A{ 2042413SN/A memory->recvStatusChange(status); 2052413SN/A} 2062413SN/A 2072413SN/Avoid 2082522SN/APhysicalMemory::MemoryPort::getDeviceAddressRanges(AddrRangeList &resp, 2092522SN/A AddrRangeList &snoop) 2102413SN/A{ 2112522SN/A memory->getAddressRanges(resp, snoop); 2122497SN/A} 2132497SN/A 2142497SN/Avoid 2152522SN/APhysicalMemory::getAddressRanges(AddrRangeList &resp, AddrRangeList &snoop) 2162497SN/A{ 2172522SN/A snoop.clear(); 2182522SN/A resp.clear(); 2192522SN/A resp.push_back(RangeSize(base_addr, pmem_size)); 2202413SN/A} 2212413SN/A 2222415SN/Aint 2232415SN/APhysicalMemory::MemoryPort::deviceBlockSize() 2242415SN/A{ 2252415SN/A return memory->deviceBlockSize(); 2262415SN/A} 2272413SN/A 2282413SN/Abool 2292630SN/APhysicalMemory::MemoryPort::recvTiming(Packet *pkt) 2302413SN/A{ 2312416SN/A return memory->doTimingAccess(pkt, this); 2322413SN/A} 2332413SN/A 2342413SN/ATick 2352630SN/APhysicalMemory::MemoryPort::recvAtomic(Packet *pkt) 2362413SN/A{ 2372413SN/A return memory->doAtomicAccess(pkt); 2382413SN/A} 2392413SN/A 2402413SN/Avoid 2412630SN/APhysicalMemory::MemoryPort::recvFunctional(Packet *pkt) 2422413SN/A{ 2432413SN/A memory->doFunctionalAccess(pkt); 2442413SN/A} 2452413SN/A 2462413SN/A 2472413SN/A 2482391SN/Avoid 2492391SN/APhysicalMemory::serialize(ostream &os) 2502391SN/A{ 2512391SN/A gzFile compressedMem; 2522391SN/A string filename = name() + ".physmem"; 2532391SN/A 2542391SN/A SERIALIZE_SCALAR(pmem_size); 2552391SN/A SERIALIZE_SCALAR(filename); 2562391SN/A 2572391SN/A // write memory file 2582391SN/A string thefile = Checkpoint::dir() + "/" + filename.c_str(); 2592391SN/A int fd = creat(thefile.c_str(), 0664); 2602391SN/A if (fd < 0) { 2612391SN/A perror("creat"); 2622391SN/A fatal("Can't open physical memory checkpoint file '%s'\n", filename); 2632391SN/A } 2642391SN/A 2652391SN/A compressedMem = gzdopen(fd, "wb"); 2662391SN/A if (compressedMem == NULL) 2672391SN/A fatal("Insufficient memory to allocate compression state for %s\n", 2682391SN/A filename); 2692391SN/A 2702391SN/A if (gzwrite(compressedMem, pmem_addr, pmem_size) != pmem_size) { 2712391SN/A fatal("Write failed on physical memory checkpoint file '%s'\n", 2722391SN/A filename); 2732391SN/A } 2742391SN/A 2752391SN/A if (gzclose(compressedMem)) 2762391SN/A fatal("Close failed on physical memory checkpoint file '%s'\n", 2772391SN/A filename); 2782391SN/A} 2792391SN/A 2802391SN/Avoid 2812391SN/APhysicalMemory::unserialize(Checkpoint *cp, const string §ion) 2822391SN/A{ 2832391SN/A gzFile compressedMem; 2842391SN/A long *tempPage; 2852391SN/A long *pmem_current; 2862391SN/A uint64_t curSize; 2872391SN/A uint32_t bytesRead; 2882391SN/A const int chunkSize = 16384; 2892391SN/A 2902391SN/A 2912391SN/A // unmap file that was mmaped in the constructor 2922391SN/A munmap(pmem_addr, pmem_size); 2932391SN/A 2942391SN/A string filename; 2952391SN/A 2962391SN/A UNSERIALIZE_SCALAR(pmem_size); 2972391SN/A UNSERIALIZE_SCALAR(filename); 2982391SN/A 2992391SN/A filename = cp->cptDir + "/" + filename; 3002391SN/A 3012391SN/A // mmap memoryfile 3022391SN/A int fd = open(filename.c_str(), O_RDONLY); 3032391SN/A if (fd < 0) { 3042391SN/A perror("open"); 3052391SN/A fatal("Can't open physical memory checkpoint file '%s'", filename); 3062391SN/A } 3072391SN/A 3082391SN/A compressedMem = gzdopen(fd, "rb"); 3092391SN/A if (compressedMem == NULL) 3102391SN/A fatal("Insufficient memory to allocate compression state for %s\n", 3112391SN/A filename); 3122391SN/A 3132391SN/A 3142391SN/A pmem_addr = (uint8_t *)mmap(NULL, pmem_size, PROT_READ | PROT_WRITE, 3152391SN/A MAP_ANON | MAP_PRIVATE, -1, 0); 3162391SN/A 3172391SN/A if (pmem_addr == (void *)MAP_FAILED) { 3182391SN/A perror("mmap"); 3192391SN/A fatal("Could not mmap physical memory!\n"); 3202391SN/A } 3212391SN/A 3222391SN/A curSize = 0; 3232391SN/A tempPage = (long*)malloc(chunkSize); 3242391SN/A if (tempPage == NULL) 3252391SN/A fatal("Unable to malloc memory to read file %s\n", filename); 3262391SN/A 3272391SN/A /* Only copy bytes that are non-zero, so we don't give the VM system hell */ 3282391SN/A while (curSize < pmem_size) { 3292391SN/A bytesRead = gzread(compressedMem, tempPage, chunkSize); 3302391SN/A if (bytesRead != chunkSize && bytesRead != pmem_size - curSize) 3312391SN/A fatal("Read failed on physical memory checkpoint file '%s'" 3322391SN/A " got %d bytes, expected %d or %d bytes\n", 3332391SN/A filename, bytesRead, chunkSize, pmem_size-curSize); 3342391SN/A 3352391SN/A assert(bytesRead % sizeof(long) == 0); 3362391SN/A 3372391SN/A for (int x = 0; x < bytesRead/sizeof(long); x++) 3382391SN/A { 3392391SN/A if (*(tempPage+x) != 0) { 3402391SN/A pmem_current = (long*)(pmem_addr + curSize + x * sizeof(long)); 3412391SN/A *pmem_current = *(tempPage+x); 3422391SN/A } 3432391SN/A } 3442391SN/A curSize += bytesRead; 3452391SN/A } 3462391SN/A 3472391SN/A free(tempPage); 3482391SN/A 3492391SN/A if (gzclose(compressedMem)) 3502391SN/A fatal("Close failed on physical memory checkpoint file '%s'\n", 3512391SN/A filename); 3522391SN/A 3532391SN/A} 3542391SN/A 3552413SN/A 3562391SN/ABEGIN_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory) 3572391SN/A 3582391SN/A Param<string> file; 3592391SN/A Param<Range<Addr> > range; 3602565SN/A Param<Tick> latency; 3612391SN/A 3622391SN/AEND_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory) 3632391SN/A 3642391SN/ABEGIN_INIT_SIM_OBJECT_PARAMS(PhysicalMemory) 3652391SN/A 3662391SN/A INIT_PARAM_DFLT(file, "memory mapped file", ""), 3672565SN/A INIT_PARAM(range, "Device Address Range"), 3682565SN/A INIT_PARAM(latency, "Memory access latency") 3692391SN/A 3702391SN/AEND_INIT_SIM_OBJECT_PARAMS(PhysicalMemory) 3712391SN/A 3722391SN/ACREATE_SIM_OBJECT(PhysicalMemory) 3732391SN/A{ 3742391SN/A 3752565SN/A return new PhysicalMemory(getInstanceName(), latency); 3762391SN/A} 3772391SN/A 3782391SN/AREGISTER_SIM_OBJECT("PhysicalMemory", PhysicalMemory) 379