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 &section)
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