physical.cc revision 2640
14338Sgblack@eecs.umich.edu/*
24338Sgblack@eecs.umich.edu * Copyright (c) 2001-2005 The Regents of The University of Michigan
34338Sgblack@eecs.umich.edu * All rights reserved.
44338Sgblack@eecs.umich.edu *
54338Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
67087Snate@binkert.org * modification, are permitted provided that the following conditions are
77087Snate@binkert.org * met: redistributions of source code must retain the above copyright
87087Snate@binkert.org * notice, this list of conditions and the following disclaimer;
97087Snate@binkert.org * redistributions in binary form must reproduce the above copyright
107087Snate@binkert.org * notice, this list of conditions and the following disclaimer in the
117087Snate@binkert.org * documentation and/or other materials provided with the distribution;
127087Snate@binkert.org * neither the name of the copyright holders nor the names of its
137087Snate@binkert.org * contributors may be used to endorse or promote products derived from
144338Sgblack@eecs.umich.edu * this software without specific prior written permission.
157087Snate@binkert.org *
167087Snate@binkert.org * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
177087Snate@binkert.org * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
187087Snate@binkert.org * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
197087Snate@binkert.org * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
207087Snate@binkert.org * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
217087Snate@binkert.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
227087Snate@binkert.org * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
234338Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
247087Snate@binkert.org * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
254338Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
264338Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
274338Sgblack@eecs.umich.edu */
284338Sgblack@eecs.umich.edu
294338Sgblack@eecs.umich.edu#include <sys/types.h>
304338Sgblack@eecs.umich.edu#include <sys/mman.h>
314338Sgblack@eecs.umich.edu#include <errno.h>
324338Sgblack@eecs.umich.edu#include <fcntl.h>
334338Sgblack@eecs.umich.edu#include <unistd.h>
344338Sgblack@eecs.umich.edu#include <zlib.h>
354338Sgblack@eecs.umich.edu
364338Sgblack@eecs.umich.edu#include <iostream>
374338Sgblack@eecs.umich.edu#include <string>
384338Sgblack@eecs.umich.edu
394338Sgblack@eecs.umich.edu
404519Sgblack@eecs.umich.edu#include "base/misc.hh"
414519Sgblack@eecs.umich.edu#include "config/full_system.hh"
424519Sgblack@eecs.umich.edu#include "mem/packet_impl.hh"
434519Sgblack@eecs.umich.edu#include "mem/physical.hh"
444338Sgblack@eecs.umich.edu#include "sim/host.hh"
454338Sgblack@eecs.umich.edu#include "sim/builder.hh"
464519Sgblack@eecs.umich.edu#include "sim/eventq.hh"
474519Sgblack@eecs.umich.edu#include "arch/isa_traits.hh"
484519Sgblack@eecs.umich.edu
494534Sgblack@eecs.umich.edu
504534Sgblack@eecs.umich.eduusing namespace std;
514519Sgblack@eecs.umich.eduusing namespace TheISA;
524519Sgblack@eecs.umich.edu
534519Sgblack@eecs.umich.eduPhysicalMemory::MemResponseEvent::MemResponseEvent(Packet *pkt, MemoryPort* _m)
545666Sgblack@eecs.umich.edu    : Event(&mainEventQueue, CPU_Tick_Pri), pkt(pkt), memoryPort(_m)
555666Sgblack@eecs.umich.edu{
565666Sgblack@eecs.umich.edu
575666Sgblack@eecs.umich.edu    this->setFlags(AutoDelete);
585666Sgblack@eecs.umich.edu}
595666Sgblack@eecs.umich.edu
605666Sgblack@eecs.umich.eduvoid
615788Sgblack@eecs.umich.eduPhysicalMemory::MemResponseEvent::process()
628607Sgblack@eecs.umich.edu{
638607Sgblack@eecs.umich.edu    memoryPort->sendTiming(pkt);
645666Sgblack@eecs.umich.edu}
655666Sgblack@eecs.umich.edu
665666Sgblack@eecs.umich.educonst char *
675666Sgblack@eecs.umich.eduPhysicalMemory::MemResponseEvent::description()
685666Sgblack@eecs.umich.edu{
695666Sgblack@eecs.umich.edu    return "Physical Memory Timing Access respnse event";
705666Sgblack@eecs.umich.edu}
715666Sgblack@eecs.umich.edu
726345Sgblack@eecs.umich.eduPhysicalMemory::PhysicalMemory(const string &n, Tick latency)
735666Sgblack@eecs.umich.edu    : MemObject(n),base_addr(0), pmem_addr(NULL), port(NULL), lat(latency)
745667Sgblack@eecs.umich.edu{
755666Sgblack@eecs.umich.edu    // Hardcoded to 128 MB for now.
765666Sgblack@eecs.umich.edu    pmem_size = 1 << 27;
775666Sgblack@eecs.umich.edu
785040Sgblack@eecs.umich.edu    if (pmem_size % TheISA::PageBytes != 0)
794519Sgblack@eecs.umich.edu        panic("Memory Size not divisible by page size\n");
804519Sgblack@eecs.umich.edu
814519Sgblack@eecs.umich.edu    int map_flags = MAP_ANON | MAP_PRIVATE;
827620Sgblack@eecs.umich.edu    pmem_addr = (uint8_t *)mmap(NULL, pmem_size, PROT_READ | PROT_WRITE,
837620Sgblack@eecs.umich.edu                                map_flags, -1, 0);
847620Sgblack@eecs.umich.edu
854519Sgblack@eecs.umich.edu    if (pmem_addr == (void *)MAP_FAILED) {
865666Sgblack@eecs.umich.edu        perror("mmap");
875666Sgblack@eecs.umich.edu        fatal("Could not mmap!\n");
885666Sgblack@eecs.umich.edu    }
897620Sgblack@eecs.umich.edu
905666Sgblack@eecs.umich.edu    page_ptr = 0;
915666Sgblack@eecs.umich.edu}
925666Sgblack@eecs.umich.edu
934338Sgblack@eecs.umich.eduvoid
94PhysicalMemory::init()
95{
96    if (!port)
97        panic("PhysicalMemory not connected to anything!");
98    port->sendStatusChange(Port::RangeChange);
99}
100
101PhysicalMemory::~PhysicalMemory()
102{
103    if (pmem_addr)
104        munmap(pmem_addr, pmem_size);
105    //Remove memPorts?
106}
107
108Addr
109PhysicalMemory::new_page()
110{
111    Addr return_addr = page_ptr << LogVMPageSize;
112    return_addr += base_addr;
113
114    ++page_ptr;
115    return return_addr;
116}
117
118int
119PhysicalMemory::deviceBlockSize()
120{
121    //Can accept anysize request
122    return 0;
123}
124
125bool
126PhysicalMemory::doTimingAccess (Packet *pkt, MemoryPort* memoryPort)
127{
128    doFunctionalAccess(pkt);
129
130    // turn packet around to go back to requester
131    pkt->dest = pkt->src;
132    MemResponseEvent* response = new MemResponseEvent(pkt, memoryPort);
133    response->schedule(curTick + lat);
134
135    return true;
136}
137
138Tick
139PhysicalMemory::doAtomicAccess(Packet *pkt)
140{
141    doFunctionalAccess(pkt);
142    pkt->time = curTick + lat;
143    return curTick + lat;
144}
145
146void
147PhysicalMemory::doFunctionalAccess(Packet *pkt)
148{
149    assert(pkt->addr + pkt->size < pmem_size);
150
151    switch (pkt->cmd) {
152      case Read:
153        memcpy(pkt->getPtr<uint8_t>(), pmem_addr + pkt->addr - base_addr,
154                pkt->size);
155        break;
156      case Write:
157        memcpy(pmem_addr + pkt->addr - base_addr, pkt->getPtr<uint8_t>(),
158                pkt->size);
159        // temporary hack: will need to add real LL/SC implementation
160        // for cacheless systems later.
161        if (pkt->req->getFlags() & LOCKED) {
162            pkt->req->setScResult(1);
163        }
164        break;
165      default:
166        panic("unimplemented");
167    }
168
169    pkt->result = Success;
170}
171
172Port *
173PhysicalMemory::getPort(const std::string &if_name)
174{
175    if (if_name == "") {
176        if (port != NULL)
177           panic("PhysicalMemory::getPort: additional port requested to memory!");
178        port = new MemoryPort(name() + "-port", this);
179        return port;
180    } else if (if_name == "functional") {
181        /* special port for functional writes at startup. */
182        return new MemoryPort(name() + "-funcport", this);
183    } else {
184        panic("PhysicalMemory::getPort: unknown port %s requested", if_name);
185    }
186}
187
188void
189PhysicalMemory::recvStatusChange(Port::Status status)
190{
191}
192
193PhysicalMemory::MemoryPort::MemoryPort(const std::string &_name,
194                                       PhysicalMemory *_memory)
195    : Port(_name), memory(_memory)
196{ }
197
198void
199PhysicalMemory::MemoryPort::recvStatusChange(Port::Status status)
200{
201    memory->recvStatusChange(status);
202}
203
204void
205PhysicalMemory::MemoryPort::getDeviceAddressRanges(AddrRangeList &resp,
206                                            AddrRangeList &snoop)
207{
208    memory->getAddressRanges(resp, snoop);
209}
210
211void
212PhysicalMemory::getAddressRanges(AddrRangeList &resp, AddrRangeList &snoop)
213{
214    snoop.clear();
215    resp.clear();
216    resp.push_back(RangeSize(base_addr, pmem_size));
217}
218
219int
220PhysicalMemory::MemoryPort::deviceBlockSize()
221{
222    return memory->deviceBlockSize();
223}
224
225bool
226PhysicalMemory::MemoryPort::recvTiming(Packet *pkt)
227{
228    return memory->doTimingAccess(pkt, this);
229}
230
231Tick
232PhysicalMemory::MemoryPort::recvAtomic(Packet *pkt)
233{
234    return memory->doAtomicAccess(pkt);
235}
236
237void
238PhysicalMemory::MemoryPort::recvFunctional(Packet *pkt)
239{
240    memory->doFunctionalAccess(pkt);
241}
242
243
244
245void
246PhysicalMemory::serialize(ostream &os)
247{
248    gzFile compressedMem;
249    string filename = name() + ".physmem";
250
251    SERIALIZE_SCALAR(pmem_size);
252    SERIALIZE_SCALAR(filename);
253
254    // write memory file
255    string thefile = Checkpoint::dir() + "/" + filename.c_str();
256    int fd = creat(thefile.c_str(), 0664);
257    if (fd < 0) {
258        perror("creat");
259        fatal("Can't open physical memory checkpoint file '%s'\n", filename);
260    }
261
262    compressedMem = gzdopen(fd, "wb");
263    if (compressedMem == NULL)
264        fatal("Insufficient memory to allocate compression state for %s\n",
265                filename);
266
267    if (gzwrite(compressedMem, pmem_addr, pmem_size) != pmem_size) {
268        fatal("Write failed on physical memory checkpoint file '%s'\n",
269              filename);
270    }
271
272    if (gzclose(compressedMem))
273        fatal("Close failed on physical memory checkpoint file '%s'\n",
274              filename);
275}
276
277void
278PhysicalMemory::unserialize(Checkpoint *cp, const string &section)
279{
280    gzFile compressedMem;
281    long *tempPage;
282    long *pmem_current;
283    uint64_t curSize;
284    uint32_t bytesRead;
285    const int chunkSize = 16384;
286
287
288    // unmap file that was mmaped in the constructor
289    munmap(pmem_addr, pmem_size);
290
291    string filename;
292
293    UNSERIALIZE_SCALAR(pmem_size);
294    UNSERIALIZE_SCALAR(filename);
295
296    filename = cp->cptDir + "/" + filename;
297
298    // mmap memoryfile
299    int fd = open(filename.c_str(), O_RDONLY);
300    if (fd < 0) {
301        perror("open");
302        fatal("Can't open physical memory checkpoint file '%s'", filename);
303    }
304
305    compressedMem = gzdopen(fd, "rb");
306    if (compressedMem == NULL)
307        fatal("Insufficient memory to allocate compression state for %s\n",
308                filename);
309
310
311    pmem_addr = (uint8_t *)mmap(NULL, pmem_size, PROT_READ | PROT_WRITE,
312                                MAP_ANON | MAP_PRIVATE, -1, 0);
313
314    if (pmem_addr == (void *)MAP_FAILED) {
315        perror("mmap");
316        fatal("Could not mmap physical memory!\n");
317    }
318
319    curSize = 0;
320    tempPage = (long*)malloc(chunkSize);
321    if (tempPage == NULL)
322        fatal("Unable to malloc memory to read file %s\n", filename);
323
324    /* Only copy bytes that are non-zero, so we don't give the VM system hell */
325    while (curSize < pmem_size) {
326        bytesRead = gzread(compressedMem, tempPage, chunkSize);
327        if (bytesRead != chunkSize && bytesRead != pmem_size - curSize)
328            fatal("Read failed on physical memory checkpoint file '%s'"
329                  " got %d bytes, expected %d or %d bytes\n",
330                  filename, bytesRead, chunkSize, pmem_size-curSize);
331
332        assert(bytesRead % sizeof(long) == 0);
333
334        for (int x = 0; x < bytesRead/sizeof(long); x++)
335        {
336             if (*(tempPage+x) != 0) {
337                 pmem_current = (long*)(pmem_addr + curSize + x * sizeof(long));
338                 *pmem_current = *(tempPage+x);
339             }
340        }
341        curSize += bytesRead;
342    }
343
344    free(tempPage);
345
346    if (gzclose(compressedMem))
347        fatal("Close failed on physical memory checkpoint file '%s'\n",
348              filename);
349
350}
351
352
353BEGIN_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory)
354
355    Param<string> file;
356    Param<Range<Addr> > range;
357    Param<Tick> latency;
358
359END_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory)
360
361BEGIN_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)
362
363    INIT_PARAM_DFLT(file, "memory mapped file", ""),
364    INIT_PARAM(range, "Device Address Range"),
365    INIT_PARAM(latency, "Memory access latency")
366
367END_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)
368
369CREATE_SIM_OBJECT(PhysicalMemory)
370{
371
372    return new PhysicalMemory(getInstanceName(), latency);
373}
374
375REGISTER_SIM_OBJECT("PhysicalMemory", PhysicalMemory)
376