abstract_mem.cc revision 9236:c38988024f1f
1/*
2 * Copyright (c) 2010-2012 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder.  You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Copyright (c) 2001-2005 The Regents of The University of Michigan
15 * All rights reserved.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions are
19 * met: redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer;
21 * redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution;
24 * neither the name of the copyright holders nor the names of its
25 * contributors may be used to endorse or promote products derived from
26 * this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 *
40 * Authors: Ron Dreslinski
41 *          Ali Saidi
42 *          Andreas Hansson
43 */
44
45#include <sys/mman.h>
46#include <sys/types.h>
47#include <sys/user.h>
48#include <fcntl.h>
49#include <unistd.h>
50#include <zlib.h>
51
52#include <cerrno>
53#include <cstdio>
54#include <climits>
55#include <iostream>
56#include <string>
57
58#include "arch/registers.hh"
59#include "config/the_isa.hh"
60#include "debug/LLSC.hh"
61#include "debug/MemoryAccess.hh"
62#include "mem/abstract_mem.hh"
63#include "mem/packet_access.hh"
64#include "sim/system.hh"
65
66using namespace std;
67
68AbstractMemory::AbstractMemory(const Params *p) :
69    MemObject(p), range(params()->range), pmemAddr(NULL),
70    confTableReported(p->conf_table_reported), inAddrMap(p->in_addr_map),
71    _system(NULL)
72{
73    if (size() % TheISA::PageBytes != 0)
74        panic("Memory Size not divisible by page size\n");
75
76    if (params()->null)
77        return;
78
79    int map_flags = MAP_ANON | MAP_PRIVATE;
80    pmemAddr = (uint8_t *)mmap(NULL, size(),
81                               PROT_READ | PROT_WRITE, map_flags, -1, 0);
82
83    if (pmemAddr == (void *)MAP_FAILED) {
84        perror("mmap");
85        fatal("Could not mmap!\n");
86    }
87
88    //If requested, initialize all the memory to 0
89    if (p->zero)
90        memset(pmemAddr, 0, size());
91}
92
93
94AbstractMemory::~AbstractMemory()
95{
96    if (pmemAddr)
97        munmap((char*)pmemAddr, size());
98}
99
100void
101AbstractMemory::regStats()
102{
103    using namespace Stats;
104
105    assert(system());
106
107    bytesRead
108        .init(system()->maxMasters())
109        .name(name() + ".bytes_read")
110        .desc("Number of bytes read from this memory")
111        .flags(total | nozero | nonan)
112        ;
113    for (int i = 0; i < system()->maxMasters(); i++) {
114        bytesRead.subname(i, system()->getMasterName(i));
115    }
116    bytesInstRead
117        .init(system()->maxMasters())
118        .name(name() + ".bytes_inst_read")
119        .desc("Number of instructions bytes read from this memory")
120        .flags(total | nozero | nonan)
121        ;
122    for (int i = 0; i < system()->maxMasters(); i++) {
123        bytesInstRead.subname(i, system()->getMasterName(i));
124    }
125    bytesWritten
126        .init(system()->maxMasters())
127        .name(name() + ".bytes_written")
128        .desc("Number of bytes written to this memory")
129        .flags(total | nozero | nonan)
130        ;
131    for (int i = 0; i < system()->maxMasters(); i++) {
132        bytesWritten.subname(i, system()->getMasterName(i));
133    }
134    numReads
135        .init(system()->maxMasters())
136        .name(name() + ".num_reads")
137        .desc("Number of read requests responded to by this memory")
138        .flags(total | nozero | nonan)
139        ;
140    for (int i = 0; i < system()->maxMasters(); i++) {
141        numReads.subname(i, system()->getMasterName(i));
142    }
143    numWrites
144        .init(system()->maxMasters())
145        .name(name() + ".num_writes")
146        .desc("Number of write requests responded to by this memory")
147        .flags(total | nozero | nonan)
148        ;
149    for (int i = 0; i < system()->maxMasters(); i++) {
150        numWrites.subname(i, system()->getMasterName(i));
151    }
152    numOther
153        .init(system()->maxMasters())
154        .name(name() + ".num_other")
155        .desc("Number of other requests responded to by this memory")
156        .flags(total | nozero | nonan)
157        ;
158    for (int i = 0; i < system()->maxMasters(); i++) {
159        numOther.subname(i, system()->getMasterName(i));
160    }
161    bwRead
162        .name(name() + ".bw_read")
163        .desc("Total read bandwidth from this memory (bytes/s)")
164        .precision(0)
165        .prereq(bytesRead)
166        .flags(total | nozero | nonan)
167        ;
168    for (int i = 0; i < system()->maxMasters(); i++) {
169        bwRead.subname(i, system()->getMasterName(i));
170    }
171
172    bwInstRead
173        .name(name() + ".bw_inst_read")
174        .desc("Instruction read bandwidth from this memory (bytes/s)")
175        .precision(0)
176        .prereq(bytesInstRead)
177        .flags(total | nozero | nonan)
178        ;
179    for (int i = 0; i < system()->maxMasters(); i++) {
180        bwInstRead.subname(i, system()->getMasterName(i));
181    }
182    bwWrite
183        .name(name() + ".bw_write")
184        .desc("Write bandwidth from this memory (bytes/s)")
185        .precision(0)
186        .prereq(bytesWritten)
187        .flags(total | nozero | nonan)
188        ;
189    for (int i = 0; i < system()->maxMasters(); i++) {
190        bwWrite.subname(i, system()->getMasterName(i));
191    }
192    bwTotal
193        .name(name() + ".bw_total")
194        .desc("Total bandwidth to/from this memory (bytes/s)")
195        .precision(0)
196        .prereq(bwTotal)
197        .flags(total | nozero | nonan)
198        ;
199    for (int i = 0; i < system()->maxMasters(); i++) {
200        bwTotal.subname(i, system()->getMasterName(i));
201    }
202    bwRead = bytesRead / simSeconds;
203    bwInstRead = bytesInstRead / simSeconds;
204    bwWrite = bytesWritten / simSeconds;
205    bwTotal = (bytesRead + bytesWritten) / simSeconds;
206}
207
208AddrRange
209AbstractMemory::getAddrRange() const
210{
211    return range;
212}
213
214// Add load-locked to tracking list.  Should only be called if the
215// operation is a load and the LLSC flag is set.
216void
217AbstractMemory::trackLoadLocked(PacketPtr pkt)
218{
219    Request *req = pkt->req;
220    Addr paddr = LockedAddr::mask(req->getPaddr());
221
222    // first we check if we already have a locked addr for this
223    // xc.  Since each xc only gets one, we just update the
224    // existing record with the new address.
225    list<LockedAddr>::iterator i;
226
227    for (i = lockedAddrList.begin(); i != lockedAddrList.end(); ++i) {
228        if (i->matchesContext(req)) {
229            DPRINTF(LLSC, "Modifying lock record: context %d addr %#x\n",
230                    req->contextId(), paddr);
231            i->addr = paddr;
232            return;
233        }
234    }
235
236    // no record for this xc: need to allocate a new one
237    DPRINTF(LLSC, "Adding lock record: context %d addr %#x\n",
238            req->contextId(), paddr);
239    lockedAddrList.push_front(LockedAddr(req));
240}
241
242
243// Called on *writes* only... both regular stores and
244// store-conditional operations.  Check for conventional stores which
245// conflict with locked addresses, and for success/failure of store
246// conditionals.
247bool
248AbstractMemory::checkLockedAddrList(PacketPtr pkt)
249{
250    Request *req = pkt->req;
251    Addr paddr = LockedAddr::mask(req->getPaddr());
252    bool isLLSC = pkt->isLLSC();
253
254    // Initialize return value.  Non-conditional stores always
255    // succeed.  Assume conditional stores will fail until proven
256    // otherwise.
257    bool allowStore = !isLLSC;
258
259    // Iterate over list.  Note that there could be multiple matching records,
260    // as more than one context could have done a load locked to this location.
261    // Only remove records when we succeed in finding a record for (xc, addr);
262    // then, remove all records with this address.  Failed store-conditionals do
263    // not blow unrelated reservations.
264    list<LockedAddr>::iterator i = lockedAddrList.begin();
265
266    if (isLLSC) {
267        while (i != lockedAddrList.end()) {
268            if (i->addr == paddr && i->matchesContext(req)) {
269                // it's a store conditional, and as far as the memory system can
270                // tell, the requesting context's lock is still valid.
271                DPRINTF(LLSC, "StCond success: context %d addr %#x\n",
272                        req->contextId(), paddr);
273                allowStore = true;
274                break;
275            }
276            // If we didn't find a match, keep searching!  Someone else may well
277            // have a reservation on this line here but we may find ours in just
278            // a little while.
279            i++;
280        }
281        req->setExtraData(allowStore ? 1 : 0);
282    }
283    // LLSCs that succeeded AND non-LLSC stores both fall into here:
284    if (allowStore) {
285        // We write address paddr.  However, there may be several entries with a
286        // reservation on this address (for other contextIds) and they must all
287        // be removed.
288        i = lockedAddrList.begin();
289        while (i != lockedAddrList.end()) {
290            if (i->addr == paddr) {
291                DPRINTF(LLSC, "Erasing lock record: context %d addr %#x\n",
292                        i->contextId, paddr);
293                i = lockedAddrList.erase(i);
294            } else {
295                i++;
296            }
297        }
298    }
299
300    return allowStore;
301}
302
303
304#if TRACING_ON
305
306#define CASE(A, T)                                                      \
307  case sizeof(T):                                                       \
308    DPRINTF(MemoryAccess,"%s of size %i on address 0x%x data 0x%x\n",   \
309            A, pkt->getSize(), pkt->getAddr(), pkt->get<T>());          \
310  break
311
312
313#define TRACE_PACKET(A)                                                 \
314    do {                                                                \
315        switch (pkt->getSize()) {                                       \
316          CASE(A, uint64_t);                                            \
317          CASE(A, uint32_t);                                            \
318          CASE(A, uint16_t);                                            \
319          CASE(A, uint8_t);                                             \
320          default:                                                      \
321            DPRINTF(MemoryAccess, "%s of size %i on address 0x%x\n",    \
322                    A, pkt->getSize(), pkt->getAddr());                 \
323            DDUMP(MemoryAccess, pkt->getPtr<uint8_t>(), pkt->getSize());\
324        }                                                               \
325    } while (0)
326
327#else
328
329#define TRACE_PACKET(A)
330
331#endif
332
333void
334AbstractMemory::access(PacketPtr pkt)
335{
336    assert(pkt->getAddr() >= range.start &&
337           (pkt->getAddr() + pkt->getSize() - 1) <= range.end);
338
339    if (pkt->memInhibitAsserted()) {
340        DPRINTF(MemoryAccess, "mem inhibited on 0x%x: not responding\n",
341                pkt->getAddr());
342        return;
343    }
344
345    uint8_t *hostAddr = pmemAddr + pkt->getAddr() - range.start;
346
347    if (pkt->cmd == MemCmd::SwapReq) {
348        TheISA::IntReg overwrite_val;
349        bool overwrite_mem;
350        uint64_t condition_val64;
351        uint32_t condition_val32;
352
353        if (!pmemAddr)
354            panic("Swap only works if there is real memory (i.e. null=False)");
355        assert(sizeof(TheISA::IntReg) >= pkt->getSize());
356
357        overwrite_mem = true;
358        // keep a copy of our possible write value, and copy what is at the
359        // memory address into the packet
360        std::memcpy(&overwrite_val, pkt->getPtr<uint8_t>(), pkt->getSize());
361        std::memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize());
362
363        if (pkt->req->isCondSwap()) {
364            if (pkt->getSize() == sizeof(uint64_t)) {
365                condition_val64 = pkt->req->getExtraData();
366                overwrite_mem = !std::memcmp(&condition_val64, hostAddr,
367                                             sizeof(uint64_t));
368            } else if (pkt->getSize() == sizeof(uint32_t)) {
369                condition_val32 = (uint32_t)pkt->req->getExtraData();
370                overwrite_mem = !std::memcmp(&condition_val32, hostAddr,
371                                             sizeof(uint32_t));
372            } else
373                panic("Invalid size for conditional read/write\n");
374        }
375
376        if (overwrite_mem)
377            std::memcpy(hostAddr, &overwrite_val, pkt->getSize());
378
379        assert(!pkt->req->isInstFetch());
380        TRACE_PACKET("Read/Write");
381        numOther[pkt->req->masterId()]++;
382    } else if (pkt->isRead()) {
383        assert(!pkt->isWrite());
384        if (pkt->isLLSC()) {
385            trackLoadLocked(pkt);
386        }
387        if (pmemAddr)
388            memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize());
389        TRACE_PACKET(pkt->req->isInstFetch() ? "IFetch" : "Read");
390        numReads[pkt->req->masterId()]++;
391        bytesRead[pkt->req->masterId()] += pkt->getSize();
392        if (pkt->req->isInstFetch())
393            bytesInstRead[pkt->req->masterId()] += pkt->getSize();
394    } else if (pkt->isWrite()) {
395        if (writeOK(pkt)) {
396            if (pmemAddr)
397                memcpy(hostAddr, pkt->getPtr<uint8_t>(), pkt->getSize());
398            assert(!pkt->req->isInstFetch());
399            TRACE_PACKET("Write");
400            numWrites[pkt->req->masterId()]++;
401            bytesWritten[pkt->req->masterId()] += pkt->getSize();
402        }
403    } else if (pkt->isInvalidate()) {
404        // no need to do anything
405    } else {
406        panic("unimplemented");
407    }
408
409    if (pkt->needsResponse()) {
410        pkt->makeResponse();
411    }
412}
413
414void
415AbstractMemory::functionalAccess(PacketPtr pkt)
416{
417    assert(pkt->getAddr() >= range.start &&
418           (pkt->getAddr() + pkt->getSize() - 1) <= range.end);
419
420    uint8_t *hostAddr = pmemAddr + pkt->getAddr() - range.start;
421
422    if (pkt->isRead()) {
423        if (pmemAddr)
424            memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize());
425        TRACE_PACKET("Read");
426        pkt->makeResponse();
427    } else if (pkt->isWrite()) {
428        if (pmemAddr)
429            memcpy(hostAddr, pkt->getPtr<uint8_t>(), pkt->getSize());
430        TRACE_PACKET("Write");
431        pkt->makeResponse();
432    } else if (pkt->isPrint()) {
433        Packet::PrintReqState *prs =
434            dynamic_cast<Packet::PrintReqState*>(pkt->senderState);
435        assert(prs);
436        // Need to call printLabels() explicitly since we're not going
437        // through printObj().
438        prs->printLabels();
439        // Right now we just print the single byte at the specified address.
440        ccprintf(prs->os, "%s%#x\n", prs->curPrefix(), *hostAddr);
441    } else {
442        panic("AbstractMemory: unimplemented functional command %s",
443              pkt->cmdString());
444    }
445}
446
447void
448AbstractMemory::serialize(ostream &os)
449{
450    if (!pmemAddr)
451        return;
452
453    gzFile compressedMem;
454    string filename = name() + ".physmem";
455    long _size = range.size();
456
457    SERIALIZE_SCALAR(filename);
458    SERIALIZE_SCALAR(_size);
459
460    // write memory file
461    string thefile = Checkpoint::dir() + "/" + filename.c_str();
462    int fd = creat(thefile.c_str(), 0664);
463    if (fd < 0) {
464        perror("creat");
465        fatal("Can't open physical memory checkpoint file '%s'\n", filename);
466    }
467
468    compressedMem = gzdopen(fd, "wb");
469    if (compressedMem == NULL)
470        fatal("Insufficient memory to allocate compression state for %s\n",
471                filename);
472
473    uint64_t pass_size = 0;
474    // gzwrite fails if (int)len < 0 (gzwrite returns int)
475    for (uint64_t written = 0; written < size(); written += pass_size) {
476        pass_size = (uint64_t)INT_MAX < (size() - written) ?
477            (uint64_t)INT_MAX : (size() - written);
478
479        if (gzwrite(compressedMem, pmemAddr + written,
480                    (unsigned int) pass_size) != (int)pass_size) {
481            fatal("Write failed on physical memory checkpoint file '%s'\n",
482                  filename);
483        }
484    }
485
486    if (gzclose(compressedMem))
487        fatal("Close failed on physical memory checkpoint file '%s'\n",
488              filename);
489
490    list<LockedAddr>::iterator i = lockedAddrList.begin();
491
492    vector<Addr> lal_addr;
493    vector<int> lal_cid;
494    while (i != lockedAddrList.end()) {
495        lal_addr.push_back(i->addr);
496        lal_cid.push_back(i->contextId);
497        i++;
498    }
499    arrayParamOut(os, "lal_addr", lal_addr);
500    arrayParamOut(os, "lal_cid", lal_cid);
501}
502
503void
504AbstractMemory::unserialize(Checkpoint *cp, const string &section)
505{
506    if (!pmemAddr)
507        return;
508
509    gzFile compressedMem;
510    long *tempPage;
511    long *pmem_current;
512    uint64_t curSize;
513    uint32_t bytesRead;
514    const uint32_t chunkSize = 16384;
515
516    string filename;
517
518    UNSERIALIZE_SCALAR(filename);
519
520    filename = cp->cptDir + "/" + filename;
521
522    // mmap memoryfile
523    int fd = open(filename.c_str(), O_RDONLY);
524    if (fd < 0) {
525        perror("open");
526        fatal("Can't open physical memory checkpoint file '%s'", filename);
527    }
528
529    compressedMem = gzdopen(fd, "rb");
530    if (compressedMem == NULL)
531        fatal("Insufficient memory to allocate compression state for %s\n",
532                filename);
533
534    // unmap file that was mmapped in the constructor
535    // This is done here to make sure that gzip and open don't muck with our
536    // nice large space of memory before we reallocate it
537    munmap((char*)pmemAddr, size());
538
539    long _size;
540    UNSERIALIZE_SCALAR(_size);
541    if (_size > params()->range.size())
542        fatal("Memory size has changed! size %lld, param size %lld\n",
543              _size, params()->range.size());
544
545    pmemAddr = (uint8_t *)mmap(NULL, size(),
546        PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
547
548    if (pmemAddr == (void *)MAP_FAILED) {
549        perror("mmap");
550        fatal("Could not mmap physical memory!\n");
551    }
552
553    curSize = 0;
554    tempPage = (long*)malloc(chunkSize);
555    if (tempPage == NULL)
556        fatal("Unable to malloc memory to read file %s\n", filename);
557
558    /* Only copy bytes that are non-zero, so we don't give the VM system hell */
559    while (curSize < size()) {
560        bytesRead = gzread(compressedMem, tempPage, chunkSize);
561        if (bytesRead == 0)
562            break;
563
564        assert(bytesRead % sizeof(long) == 0);
565
566        for (uint32_t x = 0; x < bytesRead / sizeof(long); x++)
567        {
568             if (*(tempPage+x) != 0) {
569                 pmem_current = (long*)(pmemAddr + curSize + x * sizeof(long));
570                 *pmem_current = *(tempPage+x);
571             }
572        }
573        curSize += bytesRead;
574    }
575
576    free(tempPage);
577
578    if (gzclose(compressedMem))
579        fatal("Close failed on physical memory checkpoint file '%s'\n",
580              filename);
581
582    vector<Addr> lal_addr;
583    vector<int> lal_cid;
584    arrayParamIn(cp, section, "lal_addr", lal_addr);
585    arrayParamIn(cp, section, "lal_cid", lal_cid);
586    for(int i = 0; i < lal_addr.size(); i++)
587        lockedAddrList.push_front(LockedAddr(lal_addr[i], lal_cid[i]));
588}
589