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