physical.cc revision 2420
18889Sgeoffrey.blake@arm.com/*
28889Sgeoffrey.blake@arm.com * Copyright (c) 2001-2005 The Regents of The University of Michigan
38889Sgeoffrey.blake@arm.com * All rights reserved.
48889Sgeoffrey.blake@arm.com *
58889Sgeoffrey.blake@arm.com * Redistribution and use in source and binary forms, with or without
68889Sgeoffrey.blake@arm.com * modification, are permitted provided that the following conditions are
78889Sgeoffrey.blake@arm.com * met: redistributions of source code must retain the above copyright
88889Sgeoffrey.blake@arm.com * notice, this list of conditions and the following disclaimer;
98889Sgeoffrey.blake@arm.com * redistributions in binary form must reproduce the above copyright
108889Sgeoffrey.blake@arm.com * notice, this list of conditions and the following disclaimer in the
118889Sgeoffrey.blake@arm.com * documentation and/or other materials provided with the distribution;
128889Sgeoffrey.blake@arm.com * neither the name of the copyright holders nor the names of its
138889Sgeoffrey.blake@arm.com * contributors may be used to endorse or promote products derived from
148889Sgeoffrey.blake@arm.com * this software without specific prior written permission.
158889Sgeoffrey.blake@arm.com *
168889Sgeoffrey.blake@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
178889Sgeoffrey.blake@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
188889Sgeoffrey.blake@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
198889Sgeoffrey.blake@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
208889Sgeoffrey.blake@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
218889Sgeoffrey.blake@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
228889Sgeoffrey.blake@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
238889Sgeoffrey.blake@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
248889Sgeoffrey.blake@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
258889Sgeoffrey.blake@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
268889Sgeoffrey.blake@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
278889Sgeoffrey.blake@arm.com */
288889Sgeoffrey.blake@arm.com
298889Sgeoffrey.blake@arm.com#include <sys/types.h>
308889Sgeoffrey.blake@arm.com#include <sys/mman.h>
318889Sgeoffrey.blake@arm.com#include <errno.h>
328889Sgeoffrey.blake@arm.com#include <fcntl.h>
338889Sgeoffrey.blake@arm.com#include <unistd.h>
348889Sgeoffrey.blake@arm.com#include <zlib.h>
358889Sgeoffrey.blake@arm.com
368889Sgeoffrey.blake@arm.com#include <cstdio>
378889Sgeoffrey.blake@arm.com#include <iostream>
388889Sgeoffrey.blake@arm.com#include <string>
398889Sgeoffrey.blake@arm.com
408889Sgeoffrey.blake@arm.com
418983Snate@binkert.org#include "base/misc.hh"
428889Sgeoffrey.blake@arm.com#include "config/full_system.hh"
438889Sgeoffrey.blake@arm.com#include "mem/physical.hh"
448889Sgeoffrey.blake@arm.com#include "sim/host.hh"
458889Sgeoffrey.blake@arm.com#include "sim/builder.hh"
468889Sgeoffrey.blake@arm.com#include "sim/eventq.hh"
478889Sgeoffrey.blake@arm.com#include "targetarch/isa_traits.hh"
488889Sgeoffrey.blake@arm.com
498889Sgeoffrey.blake@arm.com
508889Sgeoffrey.blake@arm.comusing namespace std;
518889Sgeoffrey.blake@arm.com
528889Sgeoffrey.blake@arm.comPhysicalMemory::MemResponseEvent::MemResponseEvent(Packet &pkt, MemoryPort* _m)
538889Sgeoffrey.blake@arm.com    : Event(&mainEventQueue, CPU_Tick_Pri), pkt(pkt), memoryPort(_m)
548889Sgeoffrey.blake@arm.com{
558889Sgeoffrey.blake@arm.com
568889Sgeoffrey.blake@arm.com    this->setFlags(AutoDelete);
578889Sgeoffrey.blake@arm.com}
588889Sgeoffrey.blake@arm.com
598889Sgeoffrey.blake@arm.comvoid
608889Sgeoffrey.blake@arm.comPhysicalMemory::MemResponseEvent::process()
618889Sgeoffrey.blake@arm.com{
628889Sgeoffrey.blake@arm.com    memoryPort->sendTiming(pkt);
638889Sgeoffrey.blake@arm.com}
648889Sgeoffrey.blake@arm.com
658889Sgeoffrey.blake@arm.comconst char *
668889Sgeoffrey.blake@arm.comPhysicalMemory::MemResponseEvent::description()
678889Sgeoffrey.blake@arm.com{
688889Sgeoffrey.blake@arm.com    return "Physical Memory Timing Access respnse event";
698889Sgeoffrey.blake@arm.com}
708889Sgeoffrey.blake@arm.com
718889Sgeoffrey.blake@arm.comPhysicalMemory::PhysicalMemory(const string &n)
728889Sgeoffrey.blake@arm.com    : Memory(n), base_addr(0), pmem_addr(NULL)
738889Sgeoffrey.blake@arm.com{
748889Sgeoffrey.blake@arm.com    // Hardcoded to 128 MB for now.
758889Sgeoffrey.blake@arm.com    pmem_size = 1 << 27;
768889Sgeoffrey.blake@arm.com
778889Sgeoffrey.blake@arm.com    if (pmem_size % TheISA::PageBytes != 0)
788889Sgeoffrey.blake@arm.com        panic("Memory Size not divisible by page size\n");
798889Sgeoffrey.blake@arm.com
808889Sgeoffrey.blake@arm.com    int map_flags = MAP_ANON | MAP_PRIVATE;
818889Sgeoffrey.blake@arm.com    pmem_addr = (uint8_t *)mmap(NULL, pmem_size, PROT_READ | PROT_WRITE,
828889Sgeoffrey.blake@arm.com                                map_flags, -1, 0);
838889Sgeoffrey.blake@arm.com
848889Sgeoffrey.blake@arm.com    if (pmem_addr == (void *)MAP_FAILED) {
858889Sgeoffrey.blake@arm.com        perror("mmap");
868889Sgeoffrey.blake@arm.com        fatal("Could not mmap!\n");
878889Sgeoffrey.blake@arm.com    }
888889Sgeoffrey.blake@arm.com
898889Sgeoffrey.blake@arm.com    page_ptr = 0;
908889Sgeoffrey.blake@arm.com}
918889Sgeoffrey.blake@arm.com
928889Sgeoffrey.blake@arm.comPhysicalMemory::~PhysicalMemory()
938889Sgeoffrey.blake@arm.com{
948889Sgeoffrey.blake@arm.com    if (pmem_addr)
958889Sgeoffrey.blake@arm.com        munmap(pmem_addr, pmem_size);
968889Sgeoffrey.blake@arm.com    //Remove memPorts?
978889Sgeoffrey.blake@arm.com}
988889Sgeoffrey.blake@arm.com
998889Sgeoffrey.blake@arm.comAddr
1008889Sgeoffrey.blake@arm.comPhysicalMemory::new_page()
1018889Sgeoffrey.blake@arm.com{
1028889Sgeoffrey.blake@arm.com    Addr return_addr = page_ptr << LogVMPageSize;
1038889Sgeoffrey.blake@arm.com    return_addr += base_addr;
1048889Sgeoffrey.blake@arm.com
1058889Sgeoffrey.blake@arm.com    ++page_ptr;
1068889Sgeoffrey.blake@arm.com    return return_addr;
1078889Sgeoffrey.blake@arm.com}
1088889Sgeoffrey.blake@arm.com
1098889Sgeoffrey.blake@arm.comPort *
1108889Sgeoffrey.blake@arm.comPhysicalMemory::addPort(std::string portName)
1118889Sgeoffrey.blake@arm.com{
1128889Sgeoffrey.blake@arm.com    memoryPortList[portName] = new MemoryPort(this);
1138889Sgeoffrey.blake@arm.com    return memoryPortList[portName];
1148889Sgeoffrey.blake@arm.com}
1158889Sgeoffrey.blake@arm.com
1168889Sgeoffrey.blake@arm.com//
1178889Sgeoffrey.blake@arm.com// little helper for better prot_* error messages
1188889Sgeoffrey.blake@arm.com//
1198889Sgeoffrey.blake@arm.comvoid
1208889Sgeoffrey.blake@arm.comPhysicalMemory::prot_access_error(Addr addr, int size, Command func)
1218889Sgeoffrey.blake@arm.com{
1228889Sgeoffrey.blake@arm.com    panic("invalid physical memory access!\n"
1238889Sgeoffrey.blake@arm.com          "%s: %i(addr=%#x, size=%d) out of range (max=%#x)\n",
1248889Sgeoffrey.blake@arm.com          name(), func, addr, size, pmem_size - 1);
1258889Sgeoffrey.blake@arm.com}
1268889Sgeoffrey.blake@arm.com
1278889Sgeoffrey.blake@arm.comvoid
1288889Sgeoffrey.blake@arm.comPhysicalMemory::prot_memset(Addr addr, uint8_t val, int size)
1298889Sgeoffrey.blake@arm.com{
1308889Sgeoffrey.blake@arm.com    if (addr + size >= pmem_size)
1318889Sgeoffrey.blake@arm.com        prot_access_error(addr, size, Write);
1328889Sgeoffrey.blake@arm.com
1338889Sgeoffrey.blake@arm.com    memset(pmem_addr + addr - base_addr, val, size);
1348889Sgeoffrey.blake@arm.com}
1358889Sgeoffrey.blake@arm.com
1368889Sgeoffrey.blake@arm.comint
1378889Sgeoffrey.blake@arm.comPhysicalMemory::deviceBlockSize()
1388889Sgeoffrey.blake@arm.com{
1398889Sgeoffrey.blake@arm.com    //Can accept anysize request
1408889Sgeoffrey.blake@arm.com    return 0;
1418889Sgeoffrey.blake@arm.com}
1428889Sgeoffrey.blake@arm.com
1438889Sgeoffrey.blake@arm.combool
1448889Sgeoffrey.blake@arm.comPhysicalMemory::doTimingAccess (Packet &pkt, MemoryPort* memoryPort)
1458889Sgeoffrey.blake@arm.com{
1468889Sgeoffrey.blake@arm.com    doFunctionalAccess(pkt);
1478889Sgeoffrey.blake@arm.com
1488889Sgeoffrey.blake@arm.com    MemResponseEvent* response = new MemResponseEvent(pkt, memoryPort);
1498889Sgeoffrey.blake@arm.com    response->schedule(curTick + lat);
1508889Sgeoffrey.blake@arm.com
1518889Sgeoffrey.blake@arm.com    return true;
1528889Sgeoffrey.blake@arm.com}
1538889Sgeoffrey.blake@arm.com
1548889Sgeoffrey.blake@arm.comTick
1558889Sgeoffrey.blake@arm.comPhysicalMemory::doAtomicAccess(Packet &pkt)
1568889Sgeoffrey.blake@arm.com{
1578983Snate@binkert.org    doFunctionalAccess(pkt);
1588889Sgeoffrey.blake@arm.com    return curTick + lat;
1598889Sgeoffrey.blake@arm.com}
1608889Sgeoffrey.blake@arm.com
1618889Sgeoffrey.blake@arm.comvoid
1628889Sgeoffrey.blake@arm.comPhysicalMemory::doFunctionalAccess(Packet &pkt)
1638889Sgeoffrey.blake@arm.com{
1648889Sgeoffrey.blake@arm.com    if (pkt.addr + pkt.size >= pmem_size)
1658889Sgeoffrey.blake@arm.com            prot_access_error(pkt.addr, pkt.size, pkt.cmd);
1668889Sgeoffrey.blake@arm.com
1678889Sgeoffrey.blake@arm.com    switch (pkt.cmd) {
1688889Sgeoffrey.blake@arm.com      case Read:
1699055Ssaidi@eecs.umich.edu        memcpy(pkt.data, pmem_addr + pkt.addr - base_addr, pkt.size);
1708889Sgeoffrey.blake@arm.com        break;
1718889Sgeoffrey.blake@arm.com      case Write:
1728889Sgeoffrey.blake@arm.com        memcpy(pmem_addr + pkt.addr - base_addr, pkt.data, pkt.size);
1738889Sgeoffrey.blake@arm.com        break;
1748889Sgeoffrey.blake@arm.com      default:
1758889Sgeoffrey.blake@arm.com        panic("unimplemented");
1768889Sgeoffrey.blake@arm.com    }
1778889Sgeoffrey.blake@arm.com
1788889Sgeoffrey.blake@arm.com    pkt.result = Success;
1798983Snate@binkert.org}
1808983Snate@binkert.org
1818889Sgeoffrey.blake@arm.comPort *
1828983Snate@binkert.orgPhysicalMemory::getPort(const char *if_name)
1838889Sgeoffrey.blake@arm.com{
1848889Sgeoffrey.blake@arm.com    if (memoryPortList.find(if_name) != memoryPortList.end())
1858889Sgeoffrey.blake@arm.com        return memoryPortList[if_name];
1868889Sgeoffrey.blake@arm.com    else
1878889Sgeoffrey.blake@arm.com        panic("Looking for a port that didn't exist\n");
1888889Sgeoffrey.blake@arm.com}
1898889Sgeoffrey.blake@arm.com
190void
191PhysicalMemory::recvStatusChange(Port::Status status)
192{
193    panic("??");
194}
195
196PhysicalMemory::MemoryPort::MemoryPort(PhysicalMemory *_memory)
197    : memory(_memory)
198{ }
199
200void
201PhysicalMemory::MemoryPort::recvStatusChange(Port::Status status)
202{
203    memory->recvStatusChange(status);
204}
205
206void
207PhysicalMemory::MemoryPort::getDeviceAddressRanges(AddrRangeList &range_list,
208                                           bool &owner)
209{
210    panic("??");
211}
212
213int
214PhysicalMemory::MemoryPort::deviceBlockSize()
215{
216    return memory->deviceBlockSize();
217}
218
219bool
220PhysicalMemory::MemoryPort::recvTiming(Packet &pkt)
221{
222    return memory->doTimingAccess(pkt, this);
223}
224
225Tick
226PhysicalMemory::MemoryPort::recvAtomic(Packet &pkt)
227{
228    return memory->doAtomicAccess(pkt);
229}
230
231void
232PhysicalMemory::MemoryPort::recvFunctional(Packet &pkt)
233{
234    memory->doFunctionalAccess(pkt);
235}
236
237
238
239void
240PhysicalMemory::serialize(ostream &os)
241{
242    gzFile compressedMem;
243    string filename = name() + ".physmem";
244
245    SERIALIZE_SCALAR(pmem_size);
246    SERIALIZE_SCALAR(filename);
247
248    // write memory file
249    string thefile = Checkpoint::dir() + "/" + filename.c_str();
250    int fd = creat(thefile.c_str(), 0664);
251    if (fd < 0) {
252        perror("creat");
253        fatal("Can't open physical memory checkpoint file '%s'\n", filename);
254    }
255
256    compressedMem = gzdopen(fd, "wb");
257    if (compressedMem == NULL)
258        fatal("Insufficient memory to allocate compression state for %s\n",
259                filename);
260
261    if (gzwrite(compressedMem, pmem_addr, pmem_size) != pmem_size) {
262        fatal("Write failed on physical memory checkpoint file '%s'\n",
263              filename);
264    }
265
266    if (gzclose(compressedMem))
267        fatal("Close failed on physical memory checkpoint file '%s'\n",
268              filename);
269}
270
271void
272PhysicalMemory::unserialize(Checkpoint *cp, const string &section)
273{
274    gzFile compressedMem;
275    long *tempPage;
276    long *pmem_current;
277    uint64_t curSize;
278    uint32_t bytesRead;
279    const int chunkSize = 16384;
280
281
282    // unmap file that was mmaped in the constructor
283    munmap(pmem_addr, pmem_size);
284
285    string filename;
286
287    UNSERIALIZE_SCALAR(pmem_size);
288    UNSERIALIZE_SCALAR(filename);
289
290    filename = cp->cptDir + "/" + filename;
291
292    // mmap memoryfile
293    int fd = open(filename.c_str(), O_RDONLY);
294    if (fd < 0) {
295        perror("open");
296        fatal("Can't open physical memory checkpoint file '%s'", filename);
297    }
298
299    compressedMem = gzdopen(fd, "rb");
300    if (compressedMem == NULL)
301        fatal("Insufficient memory to allocate compression state for %s\n",
302                filename);
303
304
305    pmem_addr = (uint8_t *)mmap(NULL, pmem_size, PROT_READ | PROT_WRITE,
306                                MAP_ANON | MAP_PRIVATE, -1, 0);
307
308    if (pmem_addr == (void *)MAP_FAILED) {
309        perror("mmap");
310        fatal("Could not mmap physical memory!\n");
311    }
312
313    curSize = 0;
314    tempPage = (long*)malloc(chunkSize);
315    if (tempPage == NULL)
316        fatal("Unable to malloc memory to read file %s\n", filename);
317
318    /* Only copy bytes that are non-zero, so we don't give the VM system hell */
319    while (curSize < pmem_size) {
320        bytesRead = gzread(compressedMem, tempPage, chunkSize);
321        if (bytesRead != chunkSize && bytesRead != pmem_size - curSize)
322            fatal("Read failed on physical memory checkpoint file '%s'"
323                  " got %d bytes, expected %d or %d bytes\n",
324                  filename, bytesRead, chunkSize, pmem_size-curSize);
325
326        assert(bytesRead % sizeof(long) == 0);
327
328        for (int x = 0; x < bytesRead/sizeof(long); x++)
329        {
330             if (*(tempPage+x) != 0) {
331                 pmem_current = (long*)(pmem_addr + curSize + x * sizeof(long));
332                 *pmem_current = *(tempPage+x);
333             }
334        }
335        curSize += bytesRead;
336    }
337
338    free(tempPage);
339
340    if (gzclose(compressedMem))
341        fatal("Close failed on physical memory checkpoint file '%s'\n",
342              filename);
343
344}
345
346
347BEGIN_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory)
348
349    Param<string> file;
350#if FULL_SYSTEM
351    SimObjectParam<MemoryController *> mmu;
352#endif
353    Param<Range<Addr> > range;
354
355END_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory)
356
357BEGIN_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)
358
359    INIT_PARAM_DFLT(file, "memory mapped file", ""),
360#if FULL_SYSTEM
361    INIT_PARAM(mmu, "Memory Controller"),
362#endif
363    INIT_PARAM(range, "Device Address Range")
364
365END_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)
366
367CREATE_SIM_OBJECT(PhysicalMemory)
368{
369#if FULL_SYSTEM
370    if (mmu) {
371        return new PhysicalMemory(getInstanceName(), range, mmu, file);
372    }
373#endif
374
375    return new PhysicalMemory(getInstanceName());
376}
377
378REGISTER_SIM_OBJECT("PhysicalMemory", PhysicalMemory)
379