abstract_mem.cc revision 2914
12810SN/A/* 22810SN/A * Copyright (c) 2001-2005 The Regents of The University of Michigan 32810SN/A * All rights reserved. 42810SN/A * 52810SN/A * Redistribution and use in source and binary forms, with or without 62810SN/A * modification, are permitted provided that the following conditions are 72810SN/A * met: redistributions of source code must retain the above copyright 82810SN/A * notice, this list of conditions and the following disclaimer; 92810SN/A * redistributions in binary form must reproduce the above copyright 102810SN/A * notice, this list of conditions and the following disclaimer in the 112810SN/A * documentation and/or other materials provided with the distribution; 122810SN/A * neither the name of the copyright holders nor the names of its 132810SN/A * contributors may be used to endorse or promote products derived from 142810SN/A * this software without specific prior written permission. 152810SN/A * 162810SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172810SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182810SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192810SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202810SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212810SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222810SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232810SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242810SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252810SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262810SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272810SN/A * 282810SN/A * Authors: Ron Dreslinski 292810SN/A * Ali Saidi 302810SN/A */ 312810SN/A 322810SN/A#include <sys/types.h> 332810SN/A#include <sys/mman.h> 342810SN/A#include <errno.h> 352810SN/A#include <fcntl.h> 362810SN/A#include <unistd.h> 372810SN/A#include <zlib.h> 382810SN/A 394626SN/A#include <iostream> 404626SN/A#include <string> 415314SN/A 422810SN/A 432810SN/A#include "base/misc.hh" 444626SN/A#include "config/full_system.hh" 454626SN/A#include "mem/packet_impl.hh" 462810SN/A#include "mem/physical.hh" 472810SN/A#include "sim/host.hh" 482810SN/A#include "sim/builder.hh" 493374SN/A#include "sim/eventq.hh" 502810SN/A#include "arch/isa_traits.hh" 515314SN/A 524626SN/A 534626SN/Ausing namespace std; 542810SN/Ausing namespace TheISA; 554626SN/A 564626SN/A 574626SN/APhysicalMemory::PhysicalMemory(const string &n, Tick latency) 585875Ssteve.reinhardt@amd.com : MemObject(n),base_addr(0), pmem_addr(NULL), port(NULL), lat(latency) 595875Ssteve.reinhardt@amd.com{ 605875Ssteve.reinhardt@amd.com // Hardcoded to 128 MB for now. 615875Ssteve.reinhardt@amd.com pmem_size = 1 << 27; 625875Ssteve.reinhardt@amd.com 635875Ssteve.reinhardt@amd.com if (pmem_size % TheISA::PageBytes != 0) 645875Ssteve.reinhardt@amd.com panic("Memory Size not divisible by page size\n"); 654871SN/A 664871SN/A int map_flags = MAP_ANON | MAP_PRIVATE; 674666SN/A pmem_addr = (uint8_t *)mmap(NULL, pmem_size, PROT_READ | PROT_WRITE, 684626SN/A map_flags, -1, 0); 695875Ssteve.reinhardt@amd.com 705318SN/A if (pmem_addr == (void *)MAP_FAILED) { 715318SN/A perror("mmap"); 724626SN/A fatal("Could not mmap!\n"); 735318SN/A } 745875Ssteve.reinhardt@amd.com 757823Ssteve.reinhardt@amd.com page_ptr = 0; 765875Ssteve.reinhardt@amd.com} 774626SN/A 784626SN/Avoid 794626SN/APhysicalMemory::init() 804903SN/A{ 814903SN/A if (!port) 824903SN/A panic("PhysicalMemory not connected to anything!"); 835314SN/A port->sendStatusChange(Port::RangeChange); 844903SN/A} 854903SN/A 864903SN/APhysicalMemory::~PhysicalMemory() 874903SN/A{ 884903SN/A if (pmem_addr) 894903SN/A munmap(pmem_addr, pmem_size); 904903SN/A //Remove memPorts? 914903SN/A} 925318SN/A 935875Ssteve.reinhardt@amd.comAddr 944903SN/APhysicalMemory::new_page() 954908SN/A{ 964920SN/A Addr return_addr = page_ptr << LogVMPageSize; 975314SN/A return_addr += base_addr; 985314SN/A 994903SN/A ++page_ptr; 1004903SN/A return return_addr; 1012810SN/A} 1022810SN/A 1032810SN/Aint 1042810SN/APhysicalMemory::deviceBlockSize() 1052810SN/A{ 1062810SN/A //Can accept anysize request 1072810SN/A return 0; 1084626SN/A} 1094626SN/A 1104626SN/A 1114666SN/ATick 1124871SN/APhysicalMemory::doFunctionalAccess(Packet *pkt) 1134666SN/A{ 1144666SN/A assert(pkt->getAddr() + pkt->getSize() < pmem_size); 1154666SN/A 1164666SN/A switch (pkt->cmd) { 1174626SN/A case Packet::ReadReq: 1182810SN/A memcpy(pkt->getPtr<uint8_t>(), 1194626SN/A pmem_addr + pkt->getAddr() - base_addr, 1204626SN/A pkt->getSize()); 1214626SN/A break; 1224626SN/A case Packet::WriteReq: 1233374SN/A memcpy(pmem_addr + pkt->getAddr() - base_addr, 1242810SN/A pkt->getPtr<uint8_t>(), 1254626SN/A pkt->getSize()); 1265730SSteve.Reinhardt@amd.com // temporary hack: will need to add real LL/SC implementation 1275730SSteve.Reinhardt@amd.com // for cacheless systems later. 1284903SN/A if (pkt->req->getFlags() & LOCKED) { 1294626SN/A pkt->req->setScResult(1); 1305314SN/A } 1314665SN/A break; 1324626SN/A default: 1334626SN/A panic("unimplemented"); 1344626SN/A } 1354908SN/A 1364908SN/A pkt->result = Packet::Success; 1377667Ssteve.reinhardt@amd.com return lat; 1387667Ssteve.reinhardt@amd.com} 1397667Ssteve.reinhardt@amd.com 1407667Ssteve.reinhardt@amd.comPort * 1417667Ssteve.reinhardt@amd.comPhysicalMemory::getPort(const std::string &if_name, int idx) 1427667Ssteve.reinhardt@amd.com{ 1437667Ssteve.reinhardt@amd.com if (if_name == "port" && idx == -1) { 1447667Ssteve.reinhardt@amd.com if (port != NULL) 1457667Ssteve.reinhardt@amd.com panic("PhysicalMemory::getPort: additional port requested to memory!"); 1467667Ssteve.reinhardt@amd.com port = new MemoryPort(name() + "-port", this); 1477667Ssteve.reinhardt@amd.com return port; 1487667Ssteve.reinhardt@amd.com } else if (if_name == "functional") { 1497667Ssteve.reinhardt@amd.com /* special port for functional writes at startup. */ 1507667Ssteve.reinhardt@amd.com return new MemoryPort(name() + "-funcport", this); 1517667Ssteve.reinhardt@amd.com } else { 1527667Ssteve.reinhardt@amd.com panic("PhysicalMemory::getPort: unknown port %s requested", if_name); 1537667Ssteve.reinhardt@amd.com } 1547667Ssteve.reinhardt@amd.com} 1557667Ssteve.reinhardt@amd.com 1567667Ssteve.reinhardt@amd.comvoid 1577667Ssteve.reinhardt@amd.comPhysicalMemory::recvStatusChange(Port::Status status) 1587667Ssteve.reinhardt@amd.com{ 1594665SN/A} 1602810SN/A 1616221Snate@binkert.orgPhysicalMemory::MemoryPort::MemoryPort(const std::string &_name, 1622810SN/A PhysicalMemory *_memory) 1636227Snate@binkert.org : SimpleTimingPort(_name), memory(_memory) 1642810SN/A{ } 1654668SN/A 1664668SN/Avoid 1674668SN/APhysicalMemory::MemoryPort::recvStatusChange(Port::Status status) 1684668SN/A{ 1694668SN/A memory->recvStatusChange(status); 1702810SN/A} 1712810SN/A 1722810SN/Avoid 1732810SN/APhysicalMemory::MemoryPort::getDeviceAddressRanges(AddrRangeList &resp, 1742810SN/A AddrRangeList &snoop) 1754626SN/A{ 1762810SN/A memory->getAddressRanges(resp, snoop); 1772810SN/A} 1782810SN/A 1792810SN/Avoid 1802810SN/APhysicalMemory::getAddressRanges(AddrRangeList &resp, AddrRangeList &snoop) 1812810SN/A{ 1822810SN/A snoop.clear(); 1833374SN/A resp.clear(); 1844903SN/A resp.push_back(RangeSize(base_addr, pmem_size)); 1852810SN/A} 1864903SN/A 1874665SN/Aint 1882810SN/APhysicalMemory::MemoryPort::deviceBlockSize() 1894626SN/A{ 1904626SN/A return memory->deviceBlockSize(); 1914626SN/A} 1922810SN/A 1932810SN/Abool 1943374SN/APhysicalMemory::MemoryPort::recvTiming(Packet *pkt) 1952810SN/A{ 1962810SN/A assert(pkt->result != Packet::Nacked); 1973374SN/A 1982982SN/A Tick latency = memory->doFunctionalAccess(pkt); 1992810SN/A 2004666SN/A pkt->makeTimingResponse(); 2014666SN/A sendTiming(pkt, latency); 2022810SN/A 2037667Ssteve.reinhardt@amd.com return true; 2044908SN/A} 2055318SN/A 2065318SN/ATick 2072810SN/APhysicalMemory::MemoryPort::recvAtomic(Packet *pkt) 2082810SN/A{ 2092810SN/A return memory->doFunctionalAccess(pkt); 2102810SN/A} 2112810SN/A 2122810SN/Avoid 2133374SN/APhysicalMemory::MemoryPort::recvFunctional(Packet *pkt) 2142810SN/A{ 2152810SN/A memory->doFunctionalAccess(pkt); 2164666SN/A} 2174902SN/A 2182810SN/Aunsigned int 2192810SN/APhysicalMemory::drain(Event *de) 2202810SN/A{ 2212810SN/A int count = port->drain(de); 2222810SN/A if (count) 2232810SN/A changeState(Draining); 2242810SN/A else 2252810SN/A changeState(Drained); 2262810SN/A return count; 2272810SN/A} 2285730SSteve.Reinhardt@amd.com 2292810SN/Avoid 2302810SN/APhysicalMemory::serialize(ostream &os) 2312810SN/A{ 2322810SN/A gzFile compressedMem; 2332810SN/A string filename = name() + ".physmem"; 2344903SN/A 2352810SN/A SERIALIZE_SCALAR(pmem_size); 2362810SN/A SERIALIZE_SCALAR(filename); 2374899SN/A 2384899SN/A // write memory file 2394899SN/A string thefile = Checkpoint::dir() + "/" + filename.c_str(); 2405730SSteve.Reinhardt@amd.com int fd = creat(thefile.c_str(), 0664); 2414899SN/A if (fd < 0) { 2424899SN/A perror("creat"); 2432810SN/A fatal("Can't open physical memory checkpoint file '%s'\n", filename); 2442810SN/A } 2452810SN/A 2465730SSteve.Reinhardt@amd.com compressedMem = gzdopen(fd, "wb"); 2475730SSteve.Reinhardt@amd.com if (compressedMem == NULL) 2485730SSteve.Reinhardt@amd.com fatal("Insufficient memory to allocate compression state for %s\n", 2495730SSteve.Reinhardt@amd.com filename); 2505730SSteve.Reinhardt@amd.com 2512810SN/A if (gzwrite(compressedMem, pmem_addr, pmem_size) != pmem_size) { 2522810SN/A fatal("Write failed on physical memory checkpoint file '%s'\n", 2532810SN/A filename); 2542810SN/A } 2552810SN/A 2562810SN/A if (gzclose(compressedMem)) 2572810SN/A fatal("Close failed on physical memory checkpoint file '%s'\n", 2584903SN/A filename); 2592810SN/A} 2602810SN/A 2615730SSteve.Reinhardt@amd.comvoid 2622810SN/APhysicalMemory::unserialize(Checkpoint *cp, const string §ion) 2634630SN/A{ 2644630SN/A gzFile compressedMem; 2654630SN/A long *tempPage; 2665875Ssteve.reinhardt@amd.com long *pmem_current; 2672810SN/A uint64_t curSize; 2682810SN/A uint32_t bytesRead; 2694665SN/A const int chunkSize = 16384; 2704665SN/A 2714671SN/A 2724668SN/A // unmap file that was mmaped in the constructor 2735314SN/A munmap(pmem_addr, pmem_size); 2744920SN/A 2752810SN/A string filename; 2765314SN/A 2772810SN/A UNSERIALIZE_SCALAR(pmem_size); 2785314SN/A UNSERIALIZE_SCALAR(filename); 2795314SN/A 2805314SN/A filename = cp->cptDir + "/" + filename; 2812810SN/A 2822810SN/A // mmap memoryfile 2832810SN/A int fd = open(filename.c_str(), O_RDONLY); 284 if (fd < 0) { 285 perror("open"); 286 fatal("Can't open physical memory checkpoint file '%s'", filename); 287 } 288 289 compressedMem = gzdopen(fd, "rb"); 290 if (compressedMem == NULL) 291 fatal("Insufficient memory to allocate compression state for %s\n", 292 filename); 293 294 295 pmem_addr = (uint8_t *)mmap(NULL, pmem_size, PROT_READ | PROT_WRITE, 296 MAP_ANON | MAP_PRIVATE, -1, 0); 297 298 if (pmem_addr == (void *)MAP_FAILED) { 299 perror("mmap"); 300 fatal("Could not mmap physical memory!\n"); 301 } 302 303 curSize = 0; 304 tempPage = (long*)malloc(chunkSize); 305 if (tempPage == NULL) 306 fatal("Unable to malloc memory to read file %s\n", filename); 307 308 /* Only copy bytes that are non-zero, so we don't give the VM system hell */ 309 while (curSize < pmem_size) { 310 bytesRead = gzread(compressedMem, tempPage, chunkSize); 311 if (bytesRead != chunkSize && bytesRead != pmem_size - curSize) 312 fatal("Read failed on physical memory checkpoint file '%s'" 313 " got %d bytes, expected %d or %d bytes\n", 314 filename, bytesRead, chunkSize, pmem_size-curSize); 315 316 assert(bytesRead % sizeof(long) == 0); 317 318 for (int x = 0; x < bytesRead/sizeof(long); x++) 319 { 320 if (*(tempPage+x) != 0) { 321 pmem_current = (long*)(pmem_addr + curSize + x * sizeof(long)); 322 *pmem_current = *(tempPage+x); 323 } 324 } 325 curSize += bytesRead; 326 } 327 328 free(tempPage); 329 330 if (gzclose(compressedMem)) 331 fatal("Close failed on physical memory checkpoint file '%s'\n", 332 filename); 333 334} 335 336 337BEGIN_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory) 338 339 Param<string> file; 340 Param<Range<Addr> > range; 341 Param<Tick> latency; 342 343END_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory) 344 345BEGIN_INIT_SIM_OBJECT_PARAMS(PhysicalMemory) 346 347 INIT_PARAM_DFLT(file, "memory mapped file", ""), 348 INIT_PARAM(range, "Device Address Range"), 349 INIT_PARAM(latency, "Memory access latency") 350 351END_INIT_SIM_OBJECT_PARAMS(PhysicalMemory) 352 353CREATE_SIM_OBJECT(PhysicalMemory) 354{ 355 356 return new PhysicalMemory(getInstanceName(), latency); 357} 358 359REGISTER_SIM_OBJECT("PhysicalMemory", PhysicalMemory) 360