physical.cc revision 2541
12SN/A/*
21762SN/A * Copyright (c) 2001-2005 The Regents of The University of Michigan
32SN/A * All rights reserved.
42SN/A *
52SN/A * Redistribution and use in source and binary forms, with or without
62SN/A * modification, are permitted provided that the following conditions are
72SN/A * met: redistributions of source code must retain the above copyright
82SN/A * notice, this list of conditions and the following disclaimer;
92SN/A * redistributions in binary form must reproduce the above copyright
102SN/A * notice, this list of conditions and the following disclaimer in the
112SN/A * documentation and/or other materials provided with the distribution;
122SN/A * neither the name of the copyright holders nor the names of its
132SN/A * contributors may be used to endorse or promote products derived from
142SN/A * this software without specific prior written permission.
152SN/A *
162SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
172SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
182SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
192SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
202SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
212SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
222SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
262SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272665Ssaidi@eecs.umich.edu */
282665Ssaidi@eecs.umich.edu
292665Ssaidi@eecs.umich.edu#include <sys/types.h>
302665Ssaidi@eecs.umich.edu#include <sys/mman.h>
312SN/A#include <errno.h>
322SN/A#include <fcntl.h>
332SN/A#include <unistd.h>
342SN/A#include <zlib.h>
352SN/A
362SN/A#include <cstdio>
3775SN/A#include <iostream>
382SN/A#include <string>
392439SN/A
402439SN/A
41603SN/A#include "base/misc.hh"
422986Sgblack@eecs.umich.edu#include "config/full_system.hh"
43603SN/A#include "mem/physical.hh"
444762Snate@binkert.org#include "sim/host.hh"
452520SN/A#include "sim/builder.hh"
464762Snate@binkert.org#include "sim/eventq.hh"
472378SN/A#include "arch/isa_traits.hh"
482378SN/A
49722SN/A
502521SN/Ausing namespace std;
512378SN/Ausing namespace TheISA;
52312SN/A
531634SN/APhysicalMemory::MemResponseEvent::MemResponseEvent(Packet &pkt, MemoryPort* _m)
542680Sktlim@umich.edu    : Event(&mainEventQueue, CPU_Tick_Pri), pkt(pkt), memoryPort(_m)
551634SN/A{
562521SN/A
572378SN/A    this->setFlags(AutoDelete);
582378SN/A}
59803SN/A
603960Sgblack@eecs.umich.eduvoid
612378SN/APhysicalMemory::MemResponseEvent::process()
623536Sgblack@eecs.umich.edu{
633536Sgblack@eecs.umich.edu    memoryPort->sendTiming(pkt);
643536Sgblack@eecs.umich.edu}
653536Sgblack@eecs.umich.edu
662SN/Aconst char *
672SN/APhysicalMemory::MemResponseEvent::description()
682SN/A{
69603SN/A    return "Physical Memory Timing Access respnse event";
702901Ssaidi@eecs.umich.edu}
712902Ssaidi@eecs.umich.edu
722902Ssaidi@eecs.umich.eduPhysicalMemory::PhysicalMemory(const string &n)
734762Snate@binkert.org    : MemObject(n), base_addr(0), pmem_addr(NULL), port(NULL)
744762Snate@binkert.org{
754762Snate@binkert.org    // Hardcoded to 128 MB for now.
764762Snate@binkert.org    pmem_size = 1 << 27;
774762Snate@binkert.org
784762Snate@binkert.org    if (pmem_size % TheISA::PageBytes != 0)
792901Ssaidi@eecs.umich.edu        panic("Memory Size not divisible by page size\n");
802901Ssaidi@eecs.umich.edu
812901Ssaidi@eecs.umich.edu    int map_flags = MAP_ANON | MAP_PRIVATE;
822901Ssaidi@eecs.umich.edu    pmem_addr = (uint8_t *)mmap(NULL, pmem_size, PROT_READ | PROT_WRITE,
832901Ssaidi@eecs.umich.edu                                map_flags, -1, 0);
844762Snate@binkert.org
852901Ssaidi@eecs.umich.edu    if (pmem_addr == (void *)MAP_FAILED) {
862521SN/A        perror("mmap");
872SN/A        fatal("Could not mmap!\n");
882SN/A    }
892680Sktlim@umich.edu
905714Shsul@eecs.umich.edu    page_ptr = 0;
911806SN/A}
925713Shsul@eecs.umich.edu
935713Shsul@eecs.umich.eduvoid
945713Shsul@eecs.umich.eduPhysicalMemory::init()
955713Shsul@eecs.umich.edu{
965713Shsul@eecs.umich.edu    if (!port)
975714Shsul@eecs.umich.edu        panic("PhysicalMemory not connected to anything!");
981806SN/A    port->sendStatusChange(Port::RangeChange);
995714Shsul@eecs.umich.edu}
1001806SN/A
1011806SN/APhysicalMemory::~PhysicalMemory()
1025714Shsul@eecs.umich.edu{
1031806SN/A    if (pmem_addr)
104180SN/A        munmap(pmem_addr, pmem_size);
1052378SN/A    //Remove memPorts?
1062378SN/A}
1072378SN/A
1082378SN/AAddr
1092520SN/APhysicalMemory::new_page()
1102520SN/A{
1112520SN/A    Addr return_addr = page_ptr << LogVMPageSize;
1122521SN/A    return_addr += base_addr;
1132520SN/A
1141885SN/A    ++page_ptr;
1151070SN/A    return return_addr;
116954SN/A}
1171070SN/A
1181070SN/Aint
1191070SN/APhysicalMemory::deviceBlockSize()
1201070SN/A{
1211070SN/A    //Can accept anysize request
1221070SN/A    return 0;
1231070SN/A}
1241070SN/A
1251070SN/Abool
1261070SN/APhysicalMemory::doTimingAccess (Packet &pkt, MemoryPort* memoryPort)
1271070SN/A{
1281070SN/A    doFunctionalAccess(pkt);
1292378SN/A
1302378SN/A    MemResponseEvent* response = new MemResponseEvent(pkt, memoryPort);
1312378SN/A    response->schedule(curTick + lat);
1322378SN/A
1334997Sgblack@eecs.umich.edu    return true;
1344997Sgblack@eecs.umich.edu}
1354997Sgblack@eecs.umich.edu
1364997Sgblack@eecs.umich.eduTick
1374997Sgblack@eecs.umich.eduPhysicalMemory::doAtomicAccess(Packet &pkt)
1384997Sgblack@eecs.umich.edu{
1394997Sgblack@eecs.umich.edu    doFunctionalAccess(pkt);
1404997Sgblack@eecs.umich.edu    return curTick + lat;
1414997Sgblack@eecs.umich.edu}
1422378SN/A
1432378SN/Avoid
1442378SN/APhysicalMemory::doFunctionalAccess(Packet &pkt)
1451885SN/A{
1464762Snate@binkert.org    assert(pkt.addr + pkt.size < pmem_size);
1472901Ssaidi@eecs.umich.edu
1482424SN/A    switch (pkt.cmd) {
1491885SN/A      case Read:
1501885SN/A        memcpy(pkt.data, pmem_addr + pkt.addr - base_addr, pkt.size);
1511885SN/A        break;
1521885SN/A      case Write:
1531885SN/A        memcpy(pmem_addr + pkt.addr - base_addr, pkt.data, pkt.size);
1542158SN/A        break;
1551885SN/A      default:
1561885SN/A        panic("unimplemented");
1571885SN/A    }
1581885SN/A
1591885SN/A    pkt.result = Success;
1601885SN/A}
1612989Ssaidi@eecs.umich.edu
1621885SN/APort *
1631913SN/APhysicalMemory::getPort(const std::string &if_name)
1641885SN/A{
1651885SN/A    if (if_name == "") {
1661885SN/A        if (port != NULL)
1671885SN/A           panic("PhysicalMemory::getPort: additional port requested to memory!");
1681885SN/A        port = new MemoryPort(this);
1691885SN/A        return port;
1701885SN/A    } else if (if_name == "functional") {
1711885SN/A        /* special port for functional writes at startup. */
1721885SN/A        return new MemoryPort(this);
1731885SN/A    } else {
1741885SN/A        panic("PhysicalMemory::getPort: unknown port %s requested", if_name);
1752989Ssaidi@eecs.umich.edu    }
1761885SN/A}
1771885SN/A
1781885SN/Avoid
1791885SN/APhysicalMemory::recvStatusChange(Port::Status status)
1802378SN/A{
18177SN/A    panic("??");
1823536Sgblack@eecs.umich.edu}
1831070SN/A
1843960Sgblack@eecs.umich.eduPhysicalMemory::MemoryPort::MemoryPort(PhysicalMemory *_memory)
1851070SN/A    : memory(_memory)
1861070SN/A{ }
1874762Snate@binkert.org
1881070SN/Avoid
1892158SN/APhysicalMemory::MemoryPort::recvStatusChange(Port::Status status)
1902158SN/A{
1911070SN/A    memory->recvStatusChange(status);
1922158SN/A}
1931070SN/A
1942SN/Avoid
1952SN/APhysicalMemory::MemoryPort::getDeviceAddressRanges(AddrRangeList &resp,
1961129SN/A                                            AddrRangeList &snoop)
1971129SN/A{
1982158SN/A    memory->getAddressRanges(resp, snoop);
1992158SN/A}
2001070SN/A
2012378SN/Avoid
2022378SN/APhysicalMemory::getAddressRanges(AddrRangeList &resp, AddrRangeList &snoop)
2031070SN/A{
2041070SN/A    snoop.clear();
2051070SN/A    resp.clear();
2061070SN/A    resp.push_back(RangeSize(base_addr, pmem_size));
2071070SN/A}
2081070SN/A
2091070SN/Aint
2101070SN/APhysicalMemory::MemoryPort::deviceBlockSize()
2111070SN/A{
2121070SN/A    return memory->deviceBlockSize();
2131070SN/A}
2141070SN/A
2151070SN/Abool
2161070SN/APhysicalMemory::MemoryPort::recvTiming(Packet &pkt)
2171070SN/A{
2181070SN/A    return memory->doTimingAccess(pkt, this);
2191070SN/A}
2201070SN/A
2212378SN/ATick
2222378SN/APhysicalMemory::MemoryPort::recvAtomic(Packet &pkt)
2232378SN/A{
2242378SN/A    return memory->doAtomicAccess(pkt);
2252378SN/A}
2262378SN/A
2275718Shsul@eecs.umich.eduvoid
2285713Shsul@eecs.umich.eduPhysicalMemory::MemoryPort::recvFunctional(Packet &pkt)
2291070SN/A{
2301070SN/A    memory->doFunctionalAccess(pkt);
2311070SN/A}
2322SN/A
23377SN/A
2342SN/A
2352SN/Avoid
2362SN/APhysicalMemory::serialize(ostream &os)
2372SN/A{
2382SN/A    gzFile compressedMem;
2392SN/A    string filename = name() + ".physmem";
2402SN/A
2412SN/A    SERIALIZE_SCALAR(pmem_size);
2422SN/A    SERIALIZE_SCALAR(filename);
2432SN/A
2442158SN/A    // write memory file
2452158SN/A    string thefile = Checkpoint::dir() + "/" + filename.c_str();
2462SN/A    int fd = creat(thefile.c_str(), 0664);
2472SN/A    if (fd < 0) {
2482SN/A        perror("creat");
249        fatal("Can't open physical memory checkpoint file '%s'\n", filename);
250    }
251
252    compressedMem = gzdopen(fd, "wb");
253    if (compressedMem == NULL)
254        fatal("Insufficient memory to allocate compression state for %s\n",
255                filename);
256
257    if (gzwrite(compressedMem, pmem_addr, pmem_size) != pmem_size) {
258        fatal("Write failed on physical memory checkpoint file '%s'\n",
259              filename);
260    }
261
262    if (gzclose(compressedMem))
263        fatal("Close failed on physical memory checkpoint file '%s'\n",
264              filename);
265}
266
267void
268PhysicalMemory::unserialize(Checkpoint *cp, const string &section)
269{
270    gzFile compressedMem;
271    long *tempPage;
272    long *pmem_current;
273    uint64_t curSize;
274    uint32_t bytesRead;
275    const int chunkSize = 16384;
276
277
278    // unmap file that was mmaped in the constructor
279    munmap(pmem_addr, pmem_size);
280
281    string filename;
282
283    UNSERIALIZE_SCALAR(pmem_size);
284    UNSERIALIZE_SCALAR(filename);
285
286    filename = cp->cptDir + "/" + filename;
287
288    // mmap memoryfile
289    int fd = open(filename.c_str(), O_RDONLY);
290    if (fd < 0) {
291        perror("open");
292        fatal("Can't open physical memory checkpoint file '%s'", filename);
293    }
294
295    compressedMem = gzdopen(fd, "rb");
296    if (compressedMem == NULL)
297        fatal("Insufficient memory to allocate compression state for %s\n",
298                filename);
299
300
301    pmem_addr = (uint8_t *)mmap(NULL, pmem_size, PROT_READ | PROT_WRITE,
302                                MAP_ANON | MAP_PRIVATE, -1, 0);
303
304    if (pmem_addr == (void *)MAP_FAILED) {
305        perror("mmap");
306        fatal("Could not mmap physical memory!\n");
307    }
308
309    curSize = 0;
310    tempPage = (long*)malloc(chunkSize);
311    if (tempPage == NULL)
312        fatal("Unable to malloc memory to read file %s\n", filename);
313
314    /* Only copy bytes that are non-zero, so we don't give the VM system hell */
315    while (curSize < pmem_size) {
316        bytesRead = gzread(compressedMem, tempPage, chunkSize);
317        if (bytesRead != chunkSize && bytesRead != pmem_size - curSize)
318            fatal("Read failed on physical memory checkpoint file '%s'"
319                  " got %d bytes, expected %d or %d bytes\n",
320                  filename, bytesRead, chunkSize, pmem_size-curSize);
321
322        assert(bytesRead % sizeof(long) == 0);
323
324        for (int x = 0; x < bytesRead/sizeof(long); x++)
325        {
326             if (*(tempPage+x) != 0) {
327                 pmem_current = (long*)(pmem_addr + curSize + x * sizeof(long));
328                 *pmem_current = *(tempPage+x);
329             }
330        }
331        curSize += bytesRead;
332    }
333
334    free(tempPage);
335
336    if (gzclose(compressedMem))
337        fatal("Close failed on physical memory checkpoint file '%s'\n",
338              filename);
339
340}
341
342
343BEGIN_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory)
344
345    Param<string> file;
346    Param<Range<Addr> > range;
347
348END_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory)
349
350BEGIN_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)
351
352    INIT_PARAM_DFLT(file, "memory mapped file", ""),
353    INIT_PARAM(range, "Device Address Range")
354
355END_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)
356
357CREATE_SIM_OBJECT(PhysicalMemory)
358{
359
360    return new PhysicalMemory(getInstanceName());
361}
362
363REGISTER_SIM_OBJECT("PhysicalMemory", PhysicalMemory)
364