physical.cc revision 2522
12567SN/A/*
22567SN/A * Copyright (c) 2001-2005 The Regents of The University of Michigan
32567SN/A * All rights reserved.
42567SN/A *
52567SN/A * Redistribution and use in source and binary forms, with or without
62567SN/A * modification, are permitted provided that the following conditions are
72567SN/A * met: redistributions of source code must retain the above copyright
82567SN/A * notice, this list of conditions and the following disclaimer;
92567SN/A * redistributions in binary form must reproduce the above copyright
102567SN/A * notice, this list of conditions and the following disclaimer in the
112567SN/A * documentation and/or other materials provided with the distribution;
122567SN/A * neither the name of the copyright holders nor the names of its
132567SN/A * contributors may be used to endorse or promote products derived from
142567SN/A * this software without specific prior written permission.
152567SN/A *
162567SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
172567SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
182567SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
192567SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
202567SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
212567SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
222567SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232567SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242567SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252567SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
262567SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272665Ssaidi@eecs.umich.edu */
282665Ssaidi@eecs.umich.edu
292567SN/A#include <sys/types.h>
302567SN/A#include <sys/mman.h>
312567SN/A#include <errno.h>
322567SN/A#include <fcntl.h>
332567SN/A#include <unistd.h>
342567SN/A#include <zlib.h>
352567SN/A
362567SN/A#include <cstdio>
372567SN/A#include <iostream>
382567SN/A#include <string>
392567SN/A
404762Snate@binkert.org
412567SN/A#include "base/misc.hh"
422567SN/A#include "config/full_system.hh"
432567SN/A#include "mem/physical.hh"
442567SN/A#include "sim/host.hh"
452567SN/A#include "sim/builder.hh"
462567SN/A#include "sim/eventq.hh"
474762Snate@binkert.org#include "arch/isa_traits.hh"
482567SN/A
492650Ssaidi@eecs.umich.edu
502567SN/Ausing namespace std;
518706Sandreas.hansson@arm.comusing namespace TheISA;
528706Sandreas.hansson@arm.com
532567SN/APhysicalMemory::MemResponseEvent::MemResponseEvent(Packet &pkt, MemoryPort* _m)
542567SN/A    : Event(&mainEventQueue, CPU_Tick_Pri), pkt(pkt), memoryPort(_m)
552567SN/A{
562567SN/A
579292Sandreas.hansson@arm.com    this->setFlags(AutoDelete);
589292Sandreas.hansson@arm.com}
592567SN/A
602567SN/Avoid
612567SN/APhysicalMemory::MemResponseEvent::process()
622567SN/A{
632567SN/A    memoryPort->sendTiming(pkt);
642567SN/A}
652567SN/A
662567SN/Aconst char *
672567SN/APhysicalMemory::MemResponseEvent::description()
682567SN/A{
693745Sgblack@eecs.umich.edu    return "Physical Memory Timing Access respnse event";
703745Sgblack@eecs.umich.edu}
713745Sgblack@eecs.umich.edu
723745Sgblack@eecs.umich.eduPhysicalMemory::PhysicalMemory(const string &n)
733745Sgblack@eecs.umich.edu    : MemObject(n), base_addr(0), pmem_addr(NULL)
743745Sgblack@eecs.umich.edu{
753745Sgblack@eecs.umich.edu    // Hardcoded to 128 MB for now.
763745Sgblack@eecs.umich.edu    pmem_size = 1 << 27;
773745Sgblack@eecs.umich.edu
782567SN/A    if (pmem_size % TheISA::PageBytes != 0)
792567SN/A        panic("Memory Size not divisible by page size\n");
802567SN/A
812567SN/A    int map_flags = MAP_ANON | MAP_PRIVATE;
822567SN/A    pmem_addr = (uint8_t *)mmap(NULL, pmem_size, PROT_READ | PROT_WRITE,
832567SN/A                                map_flags, -1, 0);
842567SN/A
852567SN/A    if (pmem_addr == (void *)MAP_FAILED) {
862567SN/A        perror("mmap");
873745Sgblack@eecs.umich.edu        fatal("Could not mmap!\n");
883745Sgblack@eecs.umich.edu    }
893745Sgblack@eecs.umich.edu
903745Sgblack@eecs.umich.edu    page_ptr = 0;
913745Sgblack@eecs.umich.edu}
923745Sgblack@eecs.umich.edu
933745Sgblack@eecs.umich.eduPhysicalMemory::~PhysicalMemory()
943745Sgblack@eecs.umich.edu{
953745Sgblack@eecs.umich.edu    if (pmem_addr)
962650Ssaidi@eecs.umich.edu        munmap(pmem_addr, pmem_size);
972650Ssaidi@eecs.umich.edu    //Remove memPorts?
982650Ssaidi@eecs.umich.edu}
992567SN/A
1002567SN/AAddr
1012567SN/APhysicalMemory::new_page()
1022567SN/A{
1032567SN/A    Addr return_addr = page_ptr << LogVMPageSize;
1047741Sgblack@eecs.umich.edu    return_addr += base_addr;
1057741Sgblack@eecs.umich.edu
1062567SN/A    ++page_ptr;
1072567SN/A    return return_addr;
1082567SN/A}
1092567SN/A
1102567SN/Aint
1112567SN/APhysicalMemory::deviceBlockSize()
1127741Sgblack@eecs.umich.edu{
1137741Sgblack@eecs.umich.edu    //Can accept anysize request
1142567SN/A    return 0;
1152567SN/A}
1162567SN/A
1172567SN/Abool
1182567SN/APhysicalMemory::doTimingAccess (Packet &pkt, MemoryPort* memoryPort)
1192567SN/A{
1207741Sgblack@eecs.umich.edu    doFunctionalAccess(pkt);
1217741Sgblack@eecs.umich.edu
1222567SN/A    MemResponseEvent* response = new MemResponseEvent(pkt, memoryPort);
1232567SN/A    response->schedule(curTick + lat);
1242567SN/A
1252567SN/A    return true;
1267741Sgblack@eecs.umich.edu}
1277741Sgblack@eecs.umich.edu
1283553Sgblack@eecs.umich.eduTick
1293553Sgblack@eecs.umich.eduPhysicalMemory::doAtomicAccess(Packet &pkt)
1303553Sgblack@eecs.umich.edu{
1313553Sgblack@eecs.umich.edu    doFunctionalAccess(pkt);
1322567SN/A    return curTick + lat;
1332567SN/A}
1342567SN/A
1352567SN/Avoid
136PhysicalMemory::doFunctionalAccess(Packet &pkt)
137{
138    assert(pkt.addr + pkt.size < pmem_size);
139
140    switch (pkt.cmd) {
141      case Read:
142        memcpy(pkt.data, pmem_addr + pkt.addr - base_addr, pkt.size);
143        break;
144      case Write:
145        memcpy(pmem_addr + pkt.addr - base_addr, pkt.data, pkt.size);
146        break;
147      default:
148        panic("unimplemented");
149    }
150
151    pkt.result = Success;
152}
153
154Port *
155PhysicalMemory::getPort(const std::string &if_name)
156{
157    if (if_name == "") {
158        if (port != NULL)
159           panic("PhysicalMemory::getPort: additional port requested to memory!");
160        port = new MemoryPort(this);
161        return port;
162    } else if (if_name == "functional") {
163        /* special port for functional writes at startup. */
164        return new MemoryPort(this);
165    } else {
166        panic("PhysicalMemory::getPort: unknown port %s requested", if_name);
167    }
168}
169
170void
171PhysicalMemory::recvStatusChange(Port::Status status)
172{
173    panic("??");
174}
175
176PhysicalMemory::MemoryPort::MemoryPort(PhysicalMemory *_memory)
177    : memory(_memory)
178{ }
179
180void
181PhysicalMemory::MemoryPort::recvStatusChange(Port::Status status)
182{
183    memory->recvStatusChange(status);
184}
185
186void
187PhysicalMemory::MemoryPort::getDeviceAddressRanges(AddrRangeList &resp,
188                                            AddrRangeList &snoop)
189{
190    memory->getAddressRanges(resp, snoop);
191}
192
193void
194PhysicalMemory::getAddressRanges(AddrRangeList &resp, AddrRangeList &snoop)
195{
196    snoop.clear();
197    resp.clear();
198    resp.push_back(RangeSize(base_addr, pmem_size));
199}
200
201int
202PhysicalMemory::MemoryPort::deviceBlockSize()
203{
204    return memory->deviceBlockSize();
205}
206
207bool
208PhysicalMemory::MemoryPort::recvTiming(Packet &pkt)
209{
210    return memory->doTimingAccess(pkt, this);
211}
212
213Tick
214PhysicalMemory::MemoryPort::recvAtomic(Packet &pkt)
215{
216    return memory->doAtomicAccess(pkt);
217}
218
219void
220PhysicalMemory::MemoryPort::recvFunctional(Packet &pkt)
221{
222    memory->doFunctionalAccess(pkt);
223}
224
225
226
227void
228PhysicalMemory::serialize(ostream &os)
229{
230    gzFile compressedMem;
231    string filename = name() + ".physmem";
232
233    SERIALIZE_SCALAR(pmem_size);
234    SERIALIZE_SCALAR(filename);
235
236    // write memory file
237    string thefile = Checkpoint::dir() + "/" + filename.c_str();
238    int fd = creat(thefile.c_str(), 0664);
239    if (fd < 0) {
240        perror("creat");
241        fatal("Can't open physical memory checkpoint file '%s'\n", filename);
242    }
243
244    compressedMem = gzdopen(fd, "wb");
245    if (compressedMem == NULL)
246        fatal("Insufficient memory to allocate compression state for %s\n",
247                filename);
248
249    if (gzwrite(compressedMem, pmem_addr, pmem_size) != pmem_size) {
250        fatal("Write failed on physical memory checkpoint file '%s'\n",
251              filename);
252    }
253
254    if (gzclose(compressedMem))
255        fatal("Close failed on physical memory checkpoint file '%s'\n",
256              filename);
257}
258
259void
260PhysicalMemory::unserialize(Checkpoint *cp, const string &section)
261{
262    gzFile compressedMem;
263    long *tempPage;
264    long *pmem_current;
265    uint64_t curSize;
266    uint32_t bytesRead;
267    const int chunkSize = 16384;
268
269
270    // unmap file that was mmaped in the constructor
271    munmap(pmem_addr, pmem_size);
272
273    string filename;
274
275    UNSERIALIZE_SCALAR(pmem_size);
276    UNSERIALIZE_SCALAR(filename);
277
278    filename = cp->cptDir + "/" + filename;
279
280    // mmap memoryfile
281    int fd = open(filename.c_str(), O_RDONLY);
282    if (fd < 0) {
283        perror("open");
284        fatal("Can't open physical memory checkpoint file '%s'", filename);
285    }
286
287    compressedMem = gzdopen(fd, "rb");
288    if (compressedMem == NULL)
289        fatal("Insufficient memory to allocate compression state for %s\n",
290                filename);
291
292
293    pmem_addr = (uint8_t *)mmap(NULL, pmem_size, PROT_READ | PROT_WRITE,
294                                MAP_ANON | MAP_PRIVATE, -1, 0);
295
296    if (pmem_addr == (void *)MAP_FAILED) {
297        perror("mmap");
298        fatal("Could not mmap physical memory!\n");
299    }
300
301    curSize = 0;
302    tempPage = (long*)malloc(chunkSize);
303    if (tempPage == NULL)
304        fatal("Unable to malloc memory to read file %s\n", filename);
305
306    /* Only copy bytes that are non-zero, so we don't give the VM system hell */
307    while (curSize < pmem_size) {
308        bytesRead = gzread(compressedMem, tempPage, chunkSize);
309        if (bytesRead != chunkSize && bytesRead != pmem_size - curSize)
310            fatal("Read failed on physical memory checkpoint file '%s'"
311                  " got %d bytes, expected %d or %d bytes\n",
312                  filename, bytesRead, chunkSize, pmem_size-curSize);
313
314        assert(bytesRead % sizeof(long) == 0);
315
316        for (int x = 0; x < bytesRead/sizeof(long); x++)
317        {
318             if (*(tempPage+x) != 0) {
319                 pmem_current = (long*)(pmem_addr + curSize + x * sizeof(long));
320                 *pmem_current = *(tempPage+x);
321             }
322        }
323        curSize += bytesRead;
324    }
325
326    free(tempPage);
327
328    if (gzclose(compressedMem))
329        fatal("Close failed on physical memory checkpoint file '%s'\n",
330              filename);
331
332}
333
334
335BEGIN_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory)
336
337    Param<string> file;
338    Param<Range<Addr> > range;
339
340END_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory)
341
342BEGIN_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)
343
344    INIT_PARAM_DFLT(file, "memory mapped file", ""),
345    INIT_PARAM(range, "Device Address Range")
346
347END_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)
348
349CREATE_SIM_OBJECT(PhysicalMemory)
350{
351
352    return new PhysicalMemory(getInstanceName());
353}
354
355REGISTER_SIM_OBJECT("PhysicalMemory", PhysicalMemory)
356