abstract_mem.cc revision 2413
113772Sjavier.bueno@metempsy.com/*
213772Sjavier.bueno@metempsy.com * Copyright (c) 2001-2005 The Regents of The University of Michigan
313772Sjavier.bueno@metempsy.com * All rights reserved.
413772Sjavier.bueno@metempsy.com *
513772Sjavier.bueno@metempsy.com * Redistribution and use in source and binary forms, with or without
613772Sjavier.bueno@metempsy.com * modification, are permitted provided that the following conditions are
713772Sjavier.bueno@metempsy.com * met: redistributions of source code must retain the above copyright
813772Sjavier.bueno@metempsy.com * notice, this list of conditions and the following disclaimer;
913772Sjavier.bueno@metempsy.com * redistributions in binary form must reproduce the above copyright
1013772Sjavier.bueno@metempsy.com * notice, this list of conditions and the following disclaimer in the
1113772Sjavier.bueno@metempsy.com * documentation and/or other materials provided with the distribution;
1213772Sjavier.bueno@metempsy.com * neither the name of the copyright holders nor the names of its
1313772Sjavier.bueno@metempsy.com * contributors may be used to endorse or promote products derived from
1413772Sjavier.bueno@metempsy.com * this software without specific prior written permission.
1513772Sjavier.bueno@metempsy.com *
1613772Sjavier.bueno@metempsy.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1713772Sjavier.bueno@metempsy.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1813772Sjavier.bueno@metempsy.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1913772Sjavier.bueno@metempsy.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2013772Sjavier.bueno@metempsy.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2113772Sjavier.bueno@metempsy.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2213772Sjavier.bueno@metempsy.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2313772Sjavier.bueno@metempsy.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2413772Sjavier.bueno@metempsy.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2513772Sjavier.bueno@metempsy.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2613772Sjavier.bueno@metempsy.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2713772Sjavier.bueno@metempsy.com */
2813772Sjavier.bueno@metempsy.com
2913772Sjavier.bueno@metempsy.com#include <sys/types.h>
3013772Sjavier.bueno@metempsy.com#include <sys/mman.h>
3113772Sjavier.bueno@metempsy.com#include <errno.h>
3213772Sjavier.bueno@metempsy.com#include <fcntl.h>
3313772Sjavier.bueno@metempsy.com#include <unistd.h>
3413772Sjavier.bueno@metempsy.com#include <zlib.h>
3513772Sjavier.bueno@metempsy.com
3613772Sjavier.bueno@metempsy.com#include <cstdio>
3713772Sjavier.bueno@metempsy.com#include <iostream>
3813772Sjavier.bueno@metempsy.com#include <string>
3913772Sjavier.bueno@metempsy.com
4013772Sjavier.bueno@metempsy.com
4113772Sjavier.bueno@metempsy.com#include "base/misc.hh"
4213772Sjavier.bueno@metempsy.com#include "config/full_system.hh"
4313772Sjavier.bueno@metempsy.com#if FULL_SYSTEM
4413772Sjavier.bueno@metempsy.com#include "mem/functional/memory_control.hh"
4513772Sjavier.bueno@metempsy.com#endif
4613963Sodanrc@yahoo.com.br#include "mem/physical.hh"
4713772Sjavier.bueno@metempsy.com#include "sim/host.hh"
4813772Sjavier.bueno@metempsy.com#include "sim/builder.hh"
4913772Sjavier.bueno@metempsy.com#include "targetarch/isa_traits.hh"
5013772Sjavier.bueno@metempsy.com
5113772Sjavier.bueno@metempsy.com
5213772Sjavier.bueno@metempsy.comusing namespace std;
5313772Sjavier.bueno@metempsy.com
5413772Sjavier.bueno@metempsy.com#if FULL_SYSTEM
5513772Sjavier.bueno@metempsy.comPhysicalMemory::PhysicalMemory(const string &n, Range<Addr> range,
5613772Sjavier.bueno@metempsy.com                               MemoryController *mmu, const std::string &fname)
5713772Sjavier.bueno@metempsy.com    : Memory(n), base_addr(range.start), pmem_size(range.size()),
5813772Sjavier.bueno@metempsy.com      pmem_addr(NULL)
5913772Sjavier.bueno@metempsy.com{
6013772Sjavier.bueno@metempsy.com    if (pmem_size % TheISA::PageBytes != 0)
6113772Sjavier.bueno@metempsy.com        panic("Memory Size not divisible by page size\n");
6213772Sjavier.bueno@metempsy.com
6313772Sjavier.bueno@metempsy.com    mmu->add_child(this, range);
6413772Sjavier.bueno@metempsy.com
6513772Sjavier.bueno@metempsy.com    int fd = -1;
6613772Sjavier.bueno@metempsy.com
6713772Sjavier.bueno@metempsy.com    if (!fname.empty()) {
6813772Sjavier.bueno@metempsy.com        fd = open(fname.c_str(), O_RDWR | O_CREAT, 0644);
6913772Sjavier.bueno@metempsy.com        if (fd == -1) {
7013772Sjavier.bueno@metempsy.com            perror("open");
7113772Sjavier.bueno@metempsy.com            fatal("Could not open physical memory file: %s\n", fname);
7213772Sjavier.bueno@metempsy.com        }
7313772Sjavier.bueno@metempsy.com        ftruncate(fd, pmem_size);
7413772Sjavier.bueno@metempsy.com    }
7513772Sjavier.bueno@metempsy.com
7613772Sjavier.bueno@metempsy.com    int map_flags = (fd == -1) ? (MAP_ANON | MAP_PRIVATE) : MAP_SHARED;
7713772Sjavier.bueno@metempsy.com    pmem_addr = (uint8_t *)mmap(NULL, pmem_size, PROT_READ | PROT_WRITE,
7813772Sjavier.bueno@metempsy.com                                map_flags, fd, 0);
7913772Sjavier.bueno@metempsy.com
8013772Sjavier.bueno@metempsy.com    if (fd != -1)
8113772Sjavier.bueno@metempsy.com        close(fd);
8213772Sjavier.bueno@metempsy.com
8313772Sjavier.bueno@metempsy.com    if (pmem_addr == (void *)MAP_FAILED) {
8413772Sjavier.bueno@metempsy.com        perror("mmap");
8513772Sjavier.bueno@metempsy.com        fatal("Could not mmap!\n");
8613772Sjavier.bueno@metempsy.com    }
8713772Sjavier.bueno@metempsy.com
8813963Sodanrc@yahoo.com.br    page_ptr = 0;
8913772Sjavier.bueno@metempsy.com}
9013772Sjavier.bueno@metempsy.com#endif
9113772Sjavier.bueno@metempsy.com
9213772Sjavier.bueno@metempsy.comPhysicalMemory::PhysicalMemory(const string &n)
9313772Sjavier.bueno@metempsy.com    : Memory(n), memoryPort(this), base_addr(0), pmem_addr(NULL)
9413772Sjavier.bueno@metempsy.com{
9513772Sjavier.bueno@metempsy.com    // Hardcoded to 128 MB for now.
9613772Sjavier.bueno@metempsy.com    pmem_size = 1 << 27;
9713963Sodanrc@yahoo.com.br
9813963Sodanrc@yahoo.com.br    if (pmem_size % TheISA::PageBytes != 0)
9913963Sodanrc@yahoo.com.br        panic("Memory Size not divisible by page size\n");
10013963Sodanrc@yahoo.com.br
10113963Sodanrc@yahoo.com.br    int map_flags = MAP_ANON | MAP_PRIVATE;
10213772Sjavier.bueno@metempsy.com    pmem_addr = (uint8_t *)mmap(NULL, pmem_size, PROT_READ | PROT_WRITE,
10313772Sjavier.bueno@metempsy.com                                map_flags, -1, 0);
10413772Sjavier.bueno@metempsy.com
10513772Sjavier.bueno@metempsy.com    if (pmem_addr == (void *)MAP_FAILED) {
10613772Sjavier.bueno@metempsy.com        perror("mmap");
10713772Sjavier.bueno@metempsy.com        fatal("Could not mmap!\n");
10813772Sjavier.bueno@metempsy.com    }
10913772Sjavier.bueno@metempsy.com
11013772Sjavier.bueno@metempsy.com    page_ptr = 0;
11113772Sjavier.bueno@metempsy.com}
11213963Sodanrc@yahoo.com.br
11313772Sjavier.bueno@metempsy.comPhysicalMemory::~PhysicalMemory()
11413772Sjavier.bueno@metempsy.com{
11513772Sjavier.bueno@metempsy.com    if (pmem_addr)
11613772Sjavier.bueno@metempsy.com        munmap(pmem_addr, pmem_size);
11713772Sjavier.bueno@metempsy.com}
11813772Sjavier.bueno@metempsy.com
11913772Sjavier.bueno@metempsy.comAddr
12013772Sjavier.bueno@metempsy.comPhysicalMemory::new_page()
12113772Sjavier.bueno@metempsy.com{
12213772Sjavier.bueno@metempsy.com    Addr return_addr = page_ptr << LogVMPageSize;
12313772Sjavier.bueno@metempsy.com    return_addr += base_addr;
12413772Sjavier.bueno@metempsy.com
12513772Sjavier.bueno@metempsy.com    ++page_ptr;
12613772Sjavier.bueno@metempsy.com    return return_addr;
12713772Sjavier.bueno@metempsy.com}
12813772Sjavier.bueno@metempsy.com
12913772Sjavier.bueno@metempsy.com//
13013772Sjavier.bueno@metempsy.com// little helper for better prot_* error messages
13113772Sjavier.bueno@metempsy.com//
13213772Sjavier.bueno@metempsy.comvoid
13313772Sjavier.bueno@metempsy.comPhysicalMemory::prot_access_error(Addr addr, int size, const string &func)
13413772Sjavier.bueno@metempsy.com{
13513772Sjavier.bueno@metempsy.com    panic("invalid physical memory access!\n"
13613772Sjavier.bueno@metempsy.com          "%s: %s(addr=%#x, size=%d) out of range (max=%#x)\n",
13713772Sjavier.bueno@metempsy.com          name(), func, addr, size, pmem_size - 1);
13813772Sjavier.bueno@metempsy.com}
13913772Sjavier.bueno@metempsy.com
14013772Sjavier.bueno@metempsy.comvoid
14113772Sjavier.bueno@metempsy.comPhysicalMemory::prot_read(Addr addr, uint8_t *p, int size)
14213772Sjavier.bueno@metempsy.com{
14313772Sjavier.bueno@metempsy.com    if (addr + size >= pmem_size)
14413772Sjavier.bueno@metempsy.com        prot_access_error(addr, size, "prot_read");
14513772Sjavier.bueno@metempsy.com
14613772Sjavier.bueno@metempsy.com    memcpy(p, pmem_addr + addr - base_addr, size);
14713772Sjavier.bueno@metempsy.com}
14813772Sjavier.bueno@metempsy.com
14913772Sjavier.bueno@metempsy.comvoid
15013772Sjavier.bueno@metempsy.comPhysicalMemory::prot_write(Addr addr, const uint8_t *p, int size)
15113772Sjavier.bueno@metempsy.com{
15213772Sjavier.bueno@metempsy.com    if (addr + size >= pmem_size)
15313772Sjavier.bueno@metempsy.com        prot_access_error(addr, size, "prot_write");
15413772Sjavier.bueno@metempsy.com
15513772Sjavier.bueno@metempsy.com    memcpy(pmem_addr + addr - base_addr, p, size);
15613772Sjavier.bueno@metempsy.com}
15713772Sjavier.bueno@metempsy.com
15813772Sjavier.bueno@metempsy.comvoid
15913772Sjavier.bueno@metempsy.comPhysicalMemory::prot_memset(Addr addr, uint8_t val, int size)
16013772Sjavier.bueno@metempsy.com{
16113772Sjavier.bueno@metempsy.com    if (addr + size >= pmem_size)
16213772Sjavier.bueno@metempsy.com        prot_access_error(addr, size, "prot_memset");
16313772Sjavier.bueno@metempsy.com
16413772Sjavier.bueno@metempsy.com    memset(pmem_addr + addr - base_addr, val, size);
16513772Sjavier.bueno@metempsy.com}
16613772Sjavier.bueno@metempsy.com
16713772Sjavier.bueno@metempsy.comint
16813772Sjavier.bueno@metempsy.comPhysicalMemory::deviceBlockSize()
16913772Sjavier.bueno@metempsy.com{
17013772Sjavier.bueno@metempsy.com    //Can accept anysize request
17113772Sjavier.bueno@metempsy.com    return 0;
17213772Sjavier.bueno@metempsy.com}
17313772Sjavier.bueno@metempsy.com
17413772Sjavier.bueno@metempsy.combool
17513772Sjavier.bueno@metempsy.comPhysicalMemory::doTimingAccess (Packet &pkt)
17613772Sjavier.bueno@metempsy.com{
17713772Sjavier.bueno@metempsy.com    doFunctionalAccess(pkt);
17813772Sjavier.bueno@metempsy.com    //Schedule a response event at curTick + lat;
17913772Sjavier.bueno@metempsy.com    return true;
18013772Sjavier.bueno@metempsy.com}
18113772Sjavier.bueno@metempsy.com
18213772Sjavier.bueno@metempsy.comTick
18313772Sjavier.bueno@metempsy.comPhysicalMemory::doAtomicAccess(Packet &pkt)
18413772Sjavier.bueno@metempsy.com{
18513772Sjavier.bueno@metempsy.com    doFunctionalAccess(pkt);
18613772Sjavier.bueno@metempsy.com    return curTick + lat;
18713772Sjavier.bueno@metempsy.com}
18813772Sjavier.bueno@metempsy.com
18913772Sjavier.bueno@metempsy.comvoid
19013772Sjavier.bueno@metempsy.comPhysicalMemory::doFunctionalAccess(Packet &pkt)
19113772Sjavier.bueno@metempsy.com{
19213772Sjavier.bueno@metempsy.com    switch (pkt.cmd) {
19313772Sjavier.bueno@metempsy.com      case Read:
19413772Sjavier.bueno@metempsy.com        prot_read(pkt.addr, (uint8_t *)pkt.data, pkt.size);
19513772Sjavier.bueno@metempsy.com
196      case Write:
197        prot_write(pkt.addr, (uint8_t *)pkt.data, pkt.size);
198
199      default:
200        panic("unimplemented");
201    }
202}
203
204Port *
205PhysicalMemory::getPort(const char *if_name)
206{
207    return &memoryPort;
208}
209
210void
211PhysicalMemory::recvStatusChange(Port::Status status)
212{
213    panic("??");
214}
215
216PhysicalMemory::MemoryPort::MemoryPort(PhysicalMemory *_memory)
217    : memory(_memory)
218{ }
219
220void
221PhysicalMemory::MemoryPort::recvStatusChange(Port::Status status)
222{
223    memory->recvStatusChange(status);
224}
225
226void
227PhysicalMemory::MemoryPort::getDeviceAddressRanges(AddrRangeList &range_list,
228                                           bool &owner)
229{
230    panic("??");
231}
232
233
234bool
235PhysicalMemory::MemoryPort::recvTiming(Packet &pkt)
236{
237    return memory->doTimingAccess(pkt);
238}
239
240Tick
241PhysicalMemory::MemoryPort::recvAtomic(Packet &pkt)
242{
243    return memory->doAtomicAccess(pkt);
244}
245
246void
247PhysicalMemory::MemoryPort::recvFunctional(Packet &pkt)
248{
249    memory->doFunctionalAccess(pkt);
250}
251
252
253
254void
255PhysicalMemory::serialize(ostream &os)
256{
257    gzFile compressedMem;
258    string filename = name() + ".physmem";
259
260    SERIALIZE_SCALAR(pmem_size);
261    SERIALIZE_SCALAR(filename);
262
263    // write memory file
264    string thefile = Checkpoint::dir() + "/" + filename.c_str();
265    int fd = creat(thefile.c_str(), 0664);
266    if (fd < 0) {
267        perror("creat");
268        fatal("Can't open physical memory checkpoint file '%s'\n", filename);
269    }
270
271    compressedMem = gzdopen(fd, "wb");
272    if (compressedMem == NULL)
273        fatal("Insufficient memory to allocate compression state for %s\n",
274                filename);
275
276    if (gzwrite(compressedMem, pmem_addr, pmem_size) != pmem_size) {
277        fatal("Write failed on physical memory checkpoint file '%s'\n",
278              filename);
279    }
280
281    if (gzclose(compressedMem))
282        fatal("Close failed on physical memory checkpoint file '%s'\n",
283              filename);
284}
285
286void
287PhysicalMemory::unserialize(Checkpoint *cp, const string &section)
288{
289    gzFile compressedMem;
290    long *tempPage;
291    long *pmem_current;
292    uint64_t curSize;
293    uint32_t bytesRead;
294    const int chunkSize = 16384;
295
296
297    // unmap file that was mmaped in the constructor
298    munmap(pmem_addr, pmem_size);
299
300    string filename;
301
302    UNSERIALIZE_SCALAR(pmem_size);
303    UNSERIALIZE_SCALAR(filename);
304
305    filename = cp->cptDir + "/" + filename;
306
307    // mmap memoryfile
308    int fd = open(filename.c_str(), O_RDONLY);
309    if (fd < 0) {
310        perror("open");
311        fatal("Can't open physical memory checkpoint file '%s'", filename);
312    }
313
314    compressedMem = gzdopen(fd, "rb");
315    if (compressedMem == NULL)
316        fatal("Insufficient memory to allocate compression state for %s\n",
317                filename);
318
319
320    pmem_addr = (uint8_t *)mmap(NULL, pmem_size, PROT_READ | PROT_WRITE,
321                                MAP_ANON | MAP_PRIVATE, -1, 0);
322
323    if (pmem_addr == (void *)MAP_FAILED) {
324        perror("mmap");
325        fatal("Could not mmap physical memory!\n");
326    }
327
328    curSize = 0;
329    tempPage = (long*)malloc(chunkSize);
330    if (tempPage == NULL)
331        fatal("Unable to malloc memory to read file %s\n", filename);
332
333    /* Only copy bytes that are non-zero, so we don't give the VM system hell */
334    while (curSize < pmem_size) {
335        bytesRead = gzread(compressedMem, tempPage, chunkSize);
336        if (bytesRead != chunkSize && bytesRead != pmem_size - curSize)
337            fatal("Read failed on physical memory checkpoint file '%s'"
338                  " got %d bytes, expected %d or %d bytes\n",
339                  filename, bytesRead, chunkSize, pmem_size-curSize);
340
341        assert(bytesRead % sizeof(long) == 0);
342
343        for (int x = 0; x < bytesRead/sizeof(long); x++)
344        {
345             if (*(tempPage+x) != 0) {
346                 pmem_current = (long*)(pmem_addr + curSize + x * sizeof(long));
347                 *pmem_current = *(tempPage+x);
348             }
349        }
350        curSize += bytesRead;
351    }
352
353    free(tempPage);
354
355    if (gzclose(compressedMem))
356        fatal("Close failed on physical memory checkpoint file '%s'\n",
357              filename);
358
359}
360
361
362BEGIN_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory)
363
364    Param<string> file;
365#if FULL_SYSTEM
366    SimObjectParam<MemoryController *> mmu;
367#endif
368    Param<Range<Addr> > range;
369
370END_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory)
371
372BEGIN_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)
373
374    INIT_PARAM_DFLT(file, "memory mapped file", ""),
375#if FULL_SYSTEM
376    INIT_PARAM(mmu, "Memory Controller"),
377#endif
378    INIT_PARAM(range, "Device Address Range")
379
380END_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)
381
382CREATE_SIM_OBJECT(PhysicalMemory)
383{
384#if FULL_SYSTEM
385    if (mmu) {
386        return new PhysicalMemory(getInstanceName(), range, mmu, file);
387    }
388#endif
389
390    return new PhysicalMemory(getInstanceName());
391}
392
393REGISTER_SIM_OBJECT("PhysicalMemory", PhysicalMemory)
394