abstract_mem.cc revision 4626
12568SN/A/*
211192Sandreas.hansson@arm.com * Copyright (c) 2001-2005 The Regents of The University of Michigan
38713Sandreas.hansson@arm.com * All rights reserved.
48713Sandreas.hansson@arm.com *
58713Sandreas.hansson@arm.com * Redistribution and use in source and binary forms, with or without
68713Sandreas.hansson@arm.com * modification, are permitted provided that the following conditions are
78713Sandreas.hansson@arm.com * met: redistributions of source code must retain the above copyright
88713Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer;
98713Sandreas.hansson@arm.com * redistributions in binary form must reproduce the above copyright
108713Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer in the
118713Sandreas.hansson@arm.com * documentation and/or other materials provided with the distribution;
128713Sandreas.hansson@arm.com * neither the name of the copyright holders nor the names of its
138713Sandreas.hansson@arm.com * contributors may be used to endorse or promote products derived from
142568SN/A * this software without specific prior written permission.
152568SN/A *
162568SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
172568SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
182568SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
192568SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
202568SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
212568SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
222568SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232568SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242568SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252568SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
262568SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272568SN/A *
282568SN/A * Authors: Ron Dreslinski
292568SN/A *          Ali Saidi
302568SN/A */
312568SN/A
322568SN/A#include <sys/types.h>
332568SN/A#include <sys/mman.h>
342568SN/A#include <errno.h>
352568SN/A#include <fcntl.h>
362568SN/A#include <unistd.h>
372568SN/A#include <zlib.h>
382568SN/A
392665Ssaidi@eecs.umich.edu#include <iostream>
402665Ssaidi@eecs.umich.edu#include <string>
412665Ssaidi@eecs.umich.edu
428713Sandreas.hansson@arm.com#include "arch/isa_traits.hh"
432568SN/A#include "base/misc.hh"
442568SN/A#include "config/full_system.hh"
452568SN/A#include "mem/packet_access.hh"
462982Sstever@eecs.umich.edu#include "mem/physical.hh"
4710405Sandreas.hansson@arm.com#include "sim/builder.hh"
488713Sandreas.hansson@arm.com#include "sim/eventq.hh"
492568SN/A#include "sim/host.hh"
502568SN/A
512568SN/Ausing namespace std;
529164Sandreas.hansson@arm.comusing namespace TheISA;
532568SN/A
544762Snate@binkert.orgPhysicalMemory::PhysicalMemory(Params *p)
552568SN/A    : MemObject(p->name), pmemAddr(NULL), lat(p->latency), _params(p)
569164Sandreas.hansson@arm.com{
579164Sandreas.hansson@arm.com    if (params()->addrRange.size() % TheISA::PageBytes != 0)
588851Sandreas.hansson@arm.com        panic("Memory Size not divisible by page size\n");
599180Sandreas.hansson@arm.com
609235Sandreas.hansson@arm.com    int map_flags = MAP_ANON | MAP_PRIVATE;
619164Sandreas.hansson@arm.com    pmemAddr =
629164Sandreas.hansson@arm.com        (uint8_t *)mmap(NULL, params()->addrRange.size(),
639164Sandreas.hansson@arm.com                        PROT_READ | PROT_WRITE, map_flags, -1, 0);
648851Sandreas.hansson@arm.com
658713Sandreas.hansson@arm.com    if (pmemAddr == (void *)MAP_FAILED) {
668713Sandreas.hansson@arm.com        perror("mmap");
678713Sandreas.hansson@arm.com        fatal("Could not mmap!\n");
689164Sandreas.hansson@arm.com    }
699164Sandreas.hansson@arm.com
708851Sandreas.hansson@arm.com    //If requested, initialize all the memory to 0
719180Sandreas.hansson@arm.com    if(params()->zero)
729164Sandreas.hansson@arm.com        memset(pmemAddr, 0, params()->addrRange.size());
739164Sandreas.hansson@arm.com
742643Sstever@eecs.umich.edu    pagePtr = 0;
752643Sstever@eecs.umich.edu}
762643Sstever@eecs.umich.edu
774435Ssaidi@eecs.umich.eduvoid
785034Smilesck@eecs.umich.eduPhysicalMemory::init()
799180Sandreas.hansson@arm.com{
809180Sandreas.hansson@arm.com    if (ports.size() == 0) {
819180Sandreas.hansson@arm.com        fatal("PhysicalMemory object %s is unconnected!", name());
829180Sandreas.hansson@arm.com    }
832643Sstever@eecs.umich.edu
842643Sstever@eecs.umich.edu    for (PortIterator pi = ports.begin(); pi != ports.end(); ++pi) {
852643Sstever@eecs.umich.edu        if (*pi)
869294Sandreas.hansson@arm.com            (*pi)->sendStatusChange(Port::RangeChange);
879294Sandreas.hansson@arm.com    }
888922Swilliam.wang@arm.com}
898922Swilliam.wang@arm.com
908922Swilliam.wang@arm.comPhysicalMemory::~PhysicalMemory()
918922Swilliam.wang@arm.com{
928922Swilliam.wang@arm.com    if (pmemAddr)
938922Swilliam.wang@arm.com        munmap((char*)pmemAddr, params()->addrRange.size());
948922Swilliam.wang@arm.com    //Remove memPorts?
958922Swilliam.wang@arm.com}
969294Sandreas.hansson@arm.com
979294Sandreas.hansson@arm.comAddr
982643Sstever@eecs.umich.eduPhysicalMemory::new_page()
998713Sandreas.hansson@arm.com{
1008922Swilliam.wang@arm.com    Addr return_addr = pagePtr << LogVMPageSize;
1018922Swilliam.wang@arm.com    return_addr += start();
1028922Swilliam.wang@arm.com
1038922Swilliam.wang@arm.com    ++pagePtr;
1042643Sstever@eecs.umich.edu    return return_addr;
1052643Sstever@eecs.umich.edu}
1062568SN/A
1072568SN/Aint
1082568SN/APhysicalMemory::deviceBlockSize()
1098713Sandreas.hansson@arm.com{
1108713Sandreas.hansson@arm.com    //Can accept anysize request
11110405Sandreas.hansson@arm.com    return 0;
1124432Ssaidi@eecs.umich.edu}
1138713Sandreas.hansson@arm.com
1148713Sandreas.hansson@arm.comTick
1152568SN/APhysicalMemory::calculateLatency(PacketPtr pkt)
1162568SN/A{
1174433Ssaidi@eecs.umich.edu    return lat;
1189786Sandreas.hansson@arm.com}
1194433Ssaidi@eecs.umich.edu
1208713Sandreas.hansson@arm.com
1214435Ssaidi@eecs.umich.edu
1224435Ssaidi@eecs.umich.edu// Add load-locked to tracking list.  Should only be called if the
1234435Ssaidi@eecs.umich.edu// operation is a load and the LOCKED flag is set.
1249786Sandreas.hansson@arm.comvoid
1254435Ssaidi@eecs.umich.eduPhysicalMemory::trackLoadLocked(PacketPtr pkt)
1269164Sandreas.hansson@arm.com{
1274433Ssaidi@eecs.umich.edu    Request *req = pkt->req;
1282568SN/A    Addr paddr = LockedAddr::mask(req->getPaddr());
1292568SN/A
1308975Sandreas.hansson@arm.com    // first we check if we already have a locked addr for this
1312568SN/A    // xc.  Since each xc only gets one, we just update the
1328713Sandreas.hansson@arm.com    // existing record with the new address.
1338713Sandreas.hansson@arm.com    list<LockedAddr>::iterator i;
1349164Sandreas.hansson@arm.com
1358949Sandreas.hansson@arm.com    for (i = lockedAddrList.begin(); i != lockedAddrList.end(); ++i) {
1362643Sstever@eecs.umich.edu        if (i->matchesContext(req)) {
1379164Sandreas.hansson@arm.com            DPRINTF(LLSC, "Modifying lock record: cpu %d thread %d addr %#x\n",
1384450Ssaidi@eecs.umich.edu                    req->getCpuNum(), req->getThreadNum(), paddr);
13911193Sandreas.hansson@arm.com            i->addr = paddr;
14011193Sandreas.hansson@arm.com            return;
14111193Sandreas.hansson@arm.com        }
14211193Sandreas.hansson@arm.com    }
14310694SMarco.Balboni@ARM.com
1449549Sandreas.hansson@arm.com    // no record for this xc: need to allocate a new one
14511193Sandreas.hansson@arm.com    DPRINTF(LLSC, "Adding lock record: cpu %d thread %d addr %#x\n",
14611193Sandreas.hansson@arm.com            req->getCpuNum(), req->getThreadNum(), paddr);
1478713Sandreas.hansson@arm.com    lockedAddrList.push_front(LockedAddr(req));
1488713Sandreas.hansson@arm.com}
1498713Sandreas.hansson@arm.com
1508713Sandreas.hansson@arm.com
1518713Sandreas.hansson@arm.com// Called on *writes* only... both regular stores and
1528975Sandreas.hansson@arm.com// store-conditional operations.  Check for conventional stores which
1538713Sandreas.hansson@arm.com// conflict with locked addresses, and for success/failure of store
1549164Sandreas.hansson@arm.com// conditionals.
1558949Sandreas.hansson@arm.combool
1568713Sandreas.hansson@arm.comPhysicalMemory::checkLockedAddrList(PacketPtr pkt)
15711192Sandreas.hansson@arm.com{
15811192Sandreas.hansson@arm.com    Request *req = pkt->req;
15911192Sandreas.hansson@arm.com    Addr paddr = LockedAddr::mask(req->getPaddr());
16011192Sandreas.hansson@arm.com    bool isLocked = pkt->isLocked();
16111192Sandreas.hansson@arm.com
16211192Sandreas.hansson@arm.com    // Initialize return value.  Non-conditional stores always
16311192Sandreas.hansson@arm.com    // succeed.  Assume conditional stores will fail until proven
16411192Sandreas.hansson@arm.com    // otherwise.
16511192Sandreas.hansson@arm.com    bool success = !isLocked;
16611192Sandreas.hansson@arm.com
16711192Sandreas.hansson@arm.com    // Iterate over list.  Note that there could be multiple matching
16811192Sandreas.hansson@arm.com    // records, as more than one context could have done a load locked
16911192Sandreas.hansson@arm.com    // to this location.
17011192Sandreas.hansson@arm.com    list<LockedAddr>::iterator i = lockedAddrList.begin();
1719164Sandreas.hansson@arm.com
1729164Sandreas.hansson@arm.com    while (i != lockedAddrList.end()) {
1739164Sandreas.hansson@arm.com
1748713Sandreas.hansson@arm.com        if (i->addr == paddr) {
1759786Sandreas.hansson@arm.com            // we have a matching address
1768851Sandreas.hansson@arm.com
1779164Sandreas.hansson@arm.com            if (isLocked && i->matchesContext(req)) {
1789164Sandreas.hansson@arm.com                // it's a store conditional, and as far as the memory
1799786Sandreas.hansson@arm.com                // system can tell, the requesting context's lock is
1809786Sandreas.hansson@arm.com                // still valid.
18111192Sandreas.hansson@arm.com                DPRINTF(LLSC, "StCond success: cpu %d thread %d addr %#x\n",
1829786Sandreas.hansson@arm.com                        req->getCpuNum(), req->getThreadNum(), paddr);
1839786Sandreas.hansson@arm.com                success = true;
1849786Sandreas.hansson@arm.com            }
1859786Sandreas.hansson@arm.com
1869786Sandreas.hansson@arm.com            // Get rid of our record of this lock and advance to next
1879786Sandreas.hansson@arm.com            DPRINTF(LLSC, "Erasing lock record: cpu %d thread %d addr %#x\n",
1889786Sandreas.hansson@arm.com                    i->cpuNum, i->threadNum, paddr);
1899786Sandreas.hansson@arm.com            i = lockedAddrList.erase(i);
1909786Sandreas.hansson@arm.com        }
1919549Sandreas.hansson@arm.com        else {
1929786Sandreas.hansson@arm.com            // no match: advance to next record
1939786Sandreas.hansson@arm.com            ++i;
1949786Sandreas.hansson@arm.com        }
1959786Sandreas.hansson@arm.com    }
1969786Sandreas.hansson@arm.com
1979786Sandreas.hansson@arm.com    if (isLocked) {
19811193Sandreas.hansson@arm.com        req->setExtraData(success ? 1 : 0);
19911193Sandreas.hansson@arm.com    }
20011193Sandreas.hansson@arm.com
20111193Sandreas.hansson@arm.com    return success;
20211193Sandreas.hansson@arm.com}
20310694SMarco.Balboni@ARM.com
2049549Sandreas.hansson@arm.com
20511193Sandreas.hansson@arm.com#if TRACING_ON
20611193Sandreas.hansson@arm.com
2074433Ssaidi@eecs.umich.edu#define CASE(A, T)                                                      \
2085562Snate@binkert.org  case sizeof(T):                                                       \
2094433Ssaidi@eecs.umich.edu    DPRINTF(MemoryAccess, A " of size %i on address 0x%x data 0x%x\n",  \
2109164Sandreas.hansson@arm.com            pkt->getSize(), pkt->getAddr(), pkt->get<T>());             \
2119164Sandreas.hansson@arm.com  break
2129164Sandreas.hansson@arm.com
2139164Sandreas.hansson@arm.com
2149164Sandreas.hansson@arm.com#define TRACE_PACKET(A)                                                 \
2152657Ssaidi@eecs.umich.edu    do {                                                                \
2162657Ssaidi@eecs.umich.edu        switch (pkt->getSize()) {                                       \
2174433Ssaidi@eecs.umich.edu          CASE(A, uint64_t);                                            \
2189164Sandreas.hansson@arm.com          CASE(A, uint32_t);                                            \
2194433Ssaidi@eecs.umich.edu          CASE(A, uint16_t);                                            \
2209164Sandreas.hansson@arm.com          CASE(A, uint8_t);                                             \
2219164Sandreas.hansson@arm.com          default:                                                      \
2229164Sandreas.hansson@arm.com            DPRINTF(MemoryAccess, A " of size %i on address 0x%x\n",    \
22310713Sandreas.hansson@arm.com                    pkt->getSize(), pkt->getAddr());                    \
2244433Ssaidi@eecs.umich.edu        }                                                               \
2254433Ssaidi@eecs.umich.edu    } while (0)
2264433Ssaidi@eecs.umich.edu
2274433Ssaidi@eecs.umich.edu#else
2289164Sandreas.hansson@arm.com
2292657Ssaidi@eecs.umich.edu#define TRACE_PACKET(A)
2302643Sstever@eecs.umich.edu
2312643Sstever@eecs.umich.edu#endif
2322643Sstever@eecs.umich.edu
2332643Sstever@eecs.umich.eduTick
2349164Sandreas.hansson@arm.comPhysicalMemory::doAtomicAccess(PacketPtr pkt)
2359164Sandreas.hansson@arm.com{
2362568SN/A    assert(pkt->getAddr() >= start() &&
2378713Sandreas.hansson@arm.com           pkt->getAddr() + pkt->getSize() <= start() + size());
2389164Sandreas.hansson@arm.com
2398713Sandreas.hansson@arm.com    if (pkt->memInhibitAsserted()) {
24010922Sandreas.hansson@arm.com        DPRINTF(MemoryAccess, "mem inhibited on 0x%x: not responding\n",
2418713Sandreas.hansson@arm.com                pkt->getAddr());
2428713Sandreas.hansson@arm.com        return 0;
2438713Sandreas.hansson@arm.com    }
2448713Sandreas.hansson@arm.com
2459164Sandreas.hansson@arm.com    uint8_t *hostAddr = pmemAddr + pkt->getAddr() - start();
2468713Sandreas.hansson@arm.com
2478713Sandreas.hansson@arm.com    if (pkt->cmd == MemCmd::SwapReq) {
2488713Sandreas.hansson@arm.com        IntReg overwrite_val;
2498713Sandreas.hansson@arm.com        bool overwrite_mem;
2508713Sandreas.hansson@arm.com        uint64_t condition_val64;
2519164Sandreas.hansson@arm.com        uint32_t condition_val32;
2529164Sandreas.hansson@arm.com
2538713Sandreas.hansson@arm.com        assert(sizeof(IntReg) >= pkt->getSize());
2549164Sandreas.hansson@arm.com
25510922Sandreas.hansson@arm.com        overwrite_mem = true;
2562568SN/A        // keep a copy of our possible write value, and copy what is at the
2572568SN/A        // memory address into the packet
2582568SN/A        std::memcpy(&overwrite_val, pkt->getPtr<uint8_t>(), pkt->getSize());
2599164Sandreas.hansson@arm.com        std::memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize());
2602568SN/A
2619164Sandreas.hansson@arm.com        if (pkt->req->isCondSwap()) {
2622568SN/A            if (pkt->getSize() == sizeof(uint64_t)) {
2639164Sandreas.hansson@arm.com                condition_val64 = pkt->req->getExtraData();
2642643Sstever@eecs.umich.edu                overwrite_mem = !std::memcmp(&condition_val64, hostAddr,
2659164Sandreas.hansson@arm.com                                             sizeof(uint64_t));
2662643Sstever@eecs.umich.edu            } else if (pkt->getSize() == sizeof(uint32_t)) {
2679029Sandreas.hansson@arm.com                condition_val32 = (uint32_t)pkt->req->getExtraData();
2682643Sstever@eecs.umich.edu                overwrite_mem = !std::memcmp(&condition_val32, hostAddr,
2699164Sandreas.hansson@arm.com                                             sizeof(uint32_t));
2709164Sandreas.hansson@arm.com            } else
2714432Ssaidi@eecs.umich.edu                panic("Invalid size for conditional read/write\n");
2728975Sandreas.hansson@arm.com        }
2732643Sstever@eecs.umich.edu
2749164Sandreas.hansson@arm.com        if (overwrite_mem)
2759164Sandreas.hansson@arm.com            std::memcpy(hostAddr, &overwrite_val, pkt->getSize());
2762657Ssaidi@eecs.umich.edu
2772657Ssaidi@eecs.umich.edu        TRACE_PACKET("Read/Write");
2789164Sandreas.hansson@arm.com    } else if (pkt->isRead()) {
2799786Sandreas.hansson@arm.com        assert(!pkt->isWrite());
2809164Sandreas.hansson@arm.com        if (pkt->isLocked()) {
2819786Sandreas.hansson@arm.com            trackLoadLocked(pkt);
2829648Sdam.sunwoo@arm.com        }
2832657Ssaidi@eecs.umich.edu        memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize());
2849164Sandreas.hansson@arm.com        TRACE_PACKET("Read");
2859164Sandreas.hansson@arm.com    } else if (pkt->isWrite()) {
2869164Sandreas.hansson@arm.com        if (writeOK(pkt)) {
2879164Sandreas.hansson@arm.com            memcpy(hostAddr, pkt->getPtr<uint8_t>(), pkt->getSize());
2889164Sandreas.hansson@arm.com            TRACE_PACKET("Write");
2899164Sandreas.hansson@arm.com        }
2902643Sstever@eecs.umich.edu    } else if (pkt->isInvalidate()) {
2914986Ssaidi@eecs.umich.edu        //upgrade or invalidate
2929164Sandreas.hansson@arm.com        if (pkt->needsResponse()) {
2939164Sandreas.hansson@arm.com            pkt->makeAtomicResponse();
2942568SN/A        }
2952568SN/A    } else {
2968713Sandreas.hansson@arm.com        panic("unimplemented");
2979164Sandreas.hansson@arm.com    }
2988713Sandreas.hansson@arm.com
2999164Sandreas.hansson@arm.com    if (pkt->needsResponse()) {
3008713Sandreas.hansson@arm.com        pkt->makeAtomicResponse();
3019164Sandreas.hansson@arm.com    }
3028713Sandreas.hansson@arm.com    return calculateLatency(pkt);
3039164Sandreas.hansson@arm.com}
3048713Sandreas.hansson@arm.com
3059029Sandreas.hansson@arm.com
3068713Sandreas.hansson@arm.comvoid
3079164Sandreas.hansson@arm.comPhysicalMemory::doFunctionalAccess(PacketPtr pkt)
3089164Sandreas.hansson@arm.com{
3098713Sandreas.hansson@arm.com    assert(pkt->getAddr() >= start() &&
3108975Sandreas.hansson@arm.com           pkt->getAddr() + pkt->getSize() <= start() + size());
3118713Sandreas.hansson@arm.com
3129164Sandreas.hansson@arm.com    uint8_t *hostAddr = pmemAddr + pkt->getAddr() - start();
3139164Sandreas.hansson@arm.com
3148713Sandreas.hansson@arm.com    if (pkt->cmd == MemCmd::ReadReq) {
3159164Sandreas.hansson@arm.com        memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize());
3169164Sandreas.hansson@arm.com        TRACE_PACKET("Read");
3179164Sandreas.hansson@arm.com    } else if (pkt->cmd == MemCmd::WriteReq) {
3189164Sandreas.hansson@arm.com        memcpy(hostAddr, pkt->getPtr<uint8_t>(), pkt->getSize());
3199164Sandreas.hansson@arm.com        TRACE_PACKET("Write");
3209786Sandreas.hansson@arm.com    } else {
3219164Sandreas.hansson@arm.com        panic("PhysicalMemory: unimplemented functional command %s",
3229786Sandreas.hansson@arm.com              pkt->cmdString());
3239648Sdam.sunwoo@arm.com    }
3248713Sandreas.hansson@arm.com
3258713Sandreas.hansson@arm.com    pkt->result = Packet::Success;
3269164Sandreas.hansson@arm.com}
3279164Sandreas.hansson@arm.com
3289164Sandreas.hansson@arm.com
3299164Sandreas.hansson@arm.comPort *
3309164Sandreas.hansson@arm.comPhysicalMemory::getPort(const std::string &if_name, int idx)
3319164Sandreas.hansson@arm.com{
33210713Sandreas.hansson@arm.com    // Accept request for "functional" port for backwards compatibility
3338713Sandreas.hansson@arm.com    // with places where this function is called from C++.  I'd prefer
3348713Sandreas.hansson@arm.com    // to move all these into Python someday.
3358713Sandreas.hansson@arm.com    if (if_name == "functional") {
3369164Sandreas.hansson@arm.com        return new MemoryPort(csprintf("%s-functional", name()), this);
3379164Sandreas.hansson@arm.com    }
3388713Sandreas.hansson@arm.com
3392568SN/A    if (if_name != "port") {
3402657Ssaidi@eecs.umich.edu        panic("PhysicalMemory::getPort: unknown port %s requested", if_name);
34110713Sandreas.hansson@arm.com    }
3422568SN/A
3439786Sandreas.hansson@arm.com    if (idx >= ports.size()) {
3442568SN/A        ports.resize(idx+1);
3452568SN/A    }
3468713Sandreas.hansson@arm.com
34710713Sandreas.hansson@arm.com    if (ports[idx] != NULL) {
3482568SN/A        panic("PhysicalMemory::getPort: port %d already assigned", idx);
3499786Sandreas.hansson@arm.com    }
3502568SN/A
3512568SN/A    MemoryPort *port =
3528713Sandreas.hansson@arm.com        new MemoryPort(csprintf("%s-port%d", name(), idx), this);
3538713Sandreas.hansson@arm.com
3548713Sandreas.hansson@arm.com    ports[idx] = port;
3559180Sandreas.hansson@arm.com    return port;
3568713Sandreas.hansson@arm.com}
3578713Sandreas.hansson@arm.com
3582568SN/A
3598713Sandreas.hansson@arm.comvoid
3602568SN/APhysicalMemory::recvStatusChange(Port::Status status)
3615314Sstever@gmail.com{
3625314Sstever@gmail.com}
3638713Sandreas.hansson@arm.com
3649786Sandreas.hansson@arm.comPhysicalMemory::MemoryPort::MemoryPort(const std::string &_name,
3659029Sandreas.hansson@arm.com                                       PhysicalMemory *_memory)
3667668Ssteve.reinhardt@amd.com    : SimpleTimingPort(_name), memory(_memory)
3674626Sstever@eecs.umich.edu{ }
3687668Ssteve.reinhardt@amd.com
3692568SN/Avoid
3702568SN/APhysicalMemory::MemoryPort::recvStatusChange(Port::Status status)
3718713Sandreas.hansson@arm.com{
3728851Sandreas.hansson@arm.com    memory->recvStatusChange(status);
3738713Sandreas.hansson@arm.com}
3748713Sandreas.hansson@arm.com
3758713Sandreas.hansson@arm.comvoid
3765314Sstever@gmail.comPhysicalMemory::MemoryPort::getDeviceAddressRanges(AddrRangeList &resp,
3775314Sstever@gmail.com                                                   bool &snoop)
3784626Sstever@eecs.umich.edu{
3798851Sandreas.hansson@arm.com    memory->getAddressRanges(resp, snoop);
3808713Sandreas.hansson@arm.com}
3818713Sandreas.hansson@arm.com
3828713Sandreas.hansson@arm.comvoid
3838713Sandreas.hansson@arm.comPhysicalMemory::getAddressRanges(AddrRangeList &resp, bool &snoop)
3848713Sandreas.hansson@arm.com{
3858713Sandreas.hansson@arm.com    snoop = false;
3869786Sandreas.hansson@arm.com    resp.clear();
3878713Sandreas.hansson@arm.com    resp.push_back(RangeSize(start(), params()->addrRange.size()));
3889164Sandreas.hansson@arm.com}
3899029Sandreas.hansson@arm.com
3908713Sandreas.hansson@arm.comint
3918713Sandreas.hansson@arm.comPhysicalMemory::MemoryPort::deviceBlockSize()
3928713Sandreas.hansson@arm.com{
3938713Sandreas.hansson@arm.com    return memory->deviceBlockSize();
3948713Sandreas.hansson@arm.com}
3958713Sandreas.hansson@arm.com
3968713Sandreas.hansson@arm.comTick
3972568SN/APhysicalMemory::MemoryPort::recvAtomic(PacketPtr pkt)
3982568SN/A{
3998711Sandreas.hansson@arm.com    return memory->doAtomicAccess(pkt);
4009090Sandreas.hansson@arm.com}
4012568SN/A
4028711Sandreas.hansson@arm.comvoid
4032568SN/APhysicalMemory::MemoryPort::recvFunctional(PacketPtr pkt)
4042568SN/A{
4054762Snate@binkert.org    checkFunctional(pkt);
4064762Snate@binkert.org
4072568SN/A    // Default implementation of SimpleTimingPort::recvFunctional()
4084762Snate@binkert.org    // calls recvAtomic() and throws away the latency; we can save a
4092568SN/A    // little here by just not calculating the latency.
410    memory->doFunctionalAccess(pkt);
411}
412
413unsigned int
414PhysicalMemory::drain(Event *de)
415{
416    int count = 0;
417    for (PortIterator pi = ports.begin(); pi != ports.end(); ++pi) {
418        count += (*pi)->drain(de);
419    }
420
421    if (count)
422        changeState(Draining);
423    else
424        changeState(Drained);
425    return count;
426}
427
428void
429PhysicalMemory::serialize(ostream &os)
430{
431    gzFile compressedMem;
432    string filename = name() + ".physmem";
433
434    SERIALIZE_SCALAR(filename);
435
436    // write memory file
437    string thefile = Checkpoint::dir() + "/" + filename.c_str();
438    int fd = creat(thefile.c_str(), 0664);
439    if (fd < 0) {
440        perror("creat");
441        fatal("Can't open physical memory checkpoint file '%s'\n", filename);
442    }
443
444    compressedMem = gzdopen(fd, "wb");
445    if (compressedMem == NULL)
446        fatal("Insufficient memory to allocate compression state for %s\n",
447                filename);
448
449    if (gzwrite(compressedMem, pmemAddr, params()->addrRange.size()) != params()->addrRange.size()) {
450        fatal("Write failed on physical memory checkpoint file '%s'\n",
451              filename);
452    }
453
454    if (gzclose(compressedMem))
455        fatal("Close failed on physical memory checkpoint file '%s'\n",
456              filename);
457}
458
459void
460PhysicalMemory::unserialize(Checkpoint *cp, const string &section)
461{
462    gzFile compressedMem;
463    long *tempPage;
464    long *pmem_current;
465    uint64_t curSize;
466    uint32_t bytesRead;
467    const int chunkSize = 16384;
468
469
470    string filename;
471
472    UNSERIALIZE_SCALAR(filename);
473
474    filename = cp->cptDir + "/" + filename;
475
476    // mmap memoryfile
477    int fd = open(filename.c_str(), O_RDONLY);
478    if (fd < 0) {
479        perror("open");
480        fatal("Can't open physical memory checkpoint file '%s'", filename);
481    }
482
483    compressedMem = gzdopen(fd, "rb");
484    if (compressedMem == NULL)
485        fatal("Insufficient memory to allocate compression state for %s\n",
486                filename);
487
488    // unmap file that was mmaped in the constructor
489    // This is done here to make sure that gzip and open don't muck with our
490    // nice large space of memory before we reallocate it
491    munmap((char*)pmemAddr, params()->addrRange.size());
492
493    pmemAddr = (uint8_t *)mmap(NULL, params()->addrRange.size(), PROT_READ | PROT_WRITE,
494                                MAP_ANON | MAP_PRIVATE, -1, 0);
495
496    if (pmemAddr == (void *)MAP_FAILED) {
497        perror("mmap");
498        fatal("Could not mmap physical memory!\n");
499    }
500
501    curSize = 0;
502    tempPage = (long*)malloc(chunkSize);
503    if (tempPage == NULL)
504        fatal("Unable to malloc memory to read file %s\n", filename);
505
506    /* Only copy bytes that are non-zero, so we don't give the VM system hell */
507    while (curSize < params()->addrRange.size()) {
508        bytesRead = gzread(compressedMem, tempPage, chunkSize);
509        if (bytesRead != chunkSize && bytesRead != params()->addrRange.size() - curSize)
510            fatal("Read failed on physical memory checkpoint file '%s'"
511                  " got %d bytes, expected %d or %d bytes\n",
512                  filename, bytesRead, chunkSize, params()->addrRange.size()-curSize);
513
514        assert(bytesRead % sizeof(long) == 0);
515
516        for (int x = 0; x < bytesRead/sizeof(long); x++)
517        {
518             if (*(tempPage+x) != 0) {
519                 pmem_current = (long*)(pmemAddr + curSize + x * sizeof(long));
520                 *pmem_current = *(tempPage+x);
521             }
522        }
523        curSize += bytesRead;
524    }
525
526    free(tempPage);
527
528    if (gzclose(compressedMem))
529        fatal("Close failed on physical memory checkpoint file '%s'\n",
530              filename);
531
532}
533
534
535BEGIN_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory)
536
537    Param<string> file;
538    Param<Range<Addr> > range;
539    Param<Tick> latency;
540    Param<bool> zero;
541
542END_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory)
543
544BEGIN_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)
545
546    INIT_PARAM_DFLT(file, "memory mapped file", ""),
547    INIT_PARAM(range, "Device Address Range"),
548    INIT_PARAM(latency, "Memory access latency"),
549    INIT_PARAM(zero, "Zero initialize memory")
550
551END_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)
552
553CREATE_SIM_OBJECT(PhysicalMemory)
554{
555    PhysicalMemory::Params *p = new PhysicalMemory::Params;
556    p->name = getInstanceName();
557    p->addrRange = range;
558    p->latency = latency;
559    p->zero = zero;
560    return new PhysicalMemory(p);
561}
562
563REGISTER_SIM_OBJECT("PhysicalMemory", PhysicalMemory)
564