physical.cc revision 2391
17754SWilliam.Wang@arm.com/*
27754SWilliam.Wang@arm.com * Copyright (c) 2001-2005 The Regents of The University of Michigan
37754SWilliam.Wang@arm.com * All rights reserved.
47754SWilliam.Wang@arm.com *
57754SWilliam.Wang@arm.com * Redistribution and use in source and binary forms, with or without
67754SWilliam.Wang@arm.com * modification, are permitted provided that the following conditions are
77754SWilliam.Wang@arm.com * met: redistributions of source code must retain the above copyright
87754SWilliam.Wang@arm.com * notice, this list of conditions and the following disclaimer;
97754SWilliam.Wang@arm.com * redistributions in binary form must reproduce the above copyright
107754SWilliam.Wang@arm.com * notice, this list of conditions and the following disclaimer in the
117754SWilliam.Wang@arm.com * documentation and/or other materials provided with the distribution;
127754SWilliam.Wang@arm.com * neither the name of the copyright holders nor the names of its
137754SWilliam.Wang@arm.com * contributors may be used to endorse or promote products derived from
147754SWilliam.Wang@arm.com * this software without specific prior written permission.
157754SWilliam.Wang@arm.com *
167754SWilliam.Wang@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
177754SWilliam.Wang@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
187754SWilliam.Wang@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
197754SWilliam.Wang@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
207754SWilliam.Wang@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
217754SWilliam.Wang@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
227754SWilliam.Wang@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
237754SWilliam.Wang@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
247754SWilliam.Wang@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
257754SWilliam.Wang@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
267754SWilliam.Wang@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
277754SWilliam.Wang@arm.com */
287754SWilliam.Wang@arm.com
297754SWilliam.Wang@arm.com#include <sys/types.h>
307754SWilliam.Wang@arm.com#include <sys/mman.h>
317754SWilliam.Wang@arm.com#include <errno.h>
327754SWilliam.Wang@arm.com#include <fcntl.h>
337754SWilliam.Wang@arm.com#include <unistd.h>
347754SWilliam.Wang@arm.com#include <zlib.h>
357754SWilliam.Wang@arm.com
367754SWilliam.Wang@arm.com#include <cstdio>
377754SWilliam.Wang@arm.com#include <iostream>
387754SWilliam.Wang@arm.com#include <string>
397754SWilliam.Wang@arm.com
407950SAli.Saidi@ARM.com
417950SAli.Saidi@ARM.com#include "base/misc.hh"
427754SWilliam.Wang@arm.com#include "config/full_system.hh"
437754SWilliam.Wang@arm.com#if FULL_SYSTEM
4411793Sbrandon.potter@amd.com#include "mem/functional/memory_control.hh"
4511793Sbrandon.potter@amd.com#endif
4611793Sbrandon.potter@amd.com#include "mem/functional/physical.hh"
479330Schander.sudanthi@arm.com#include "sim/host.hh"
488245Snate@binkert.org#include "sim/builder.hh"
497754SWilliam.Wang@arm.com#include "targetarch/isa_traits.hh"
507950SAli.Saidi@ARM.com
517754SWilliam.Wang@arm.comusing namespace std;
527754SWilliam.Wang@arm.com
537754SWilliam.Wang@arm.com#if FULL_SYSTEM
547754SWilliam.Wang@arm.comPhysicalMemory::PhysicalMemory(const string &n, Range<Addr> range,
559808Sstever@gmail.com                               MemoryController *mmu, const std::string &fname)
569808Sstever@gmail.com    : FunctionalMemory(n), base_addr(range.start), pmem_size(range.size()),
579808Sstever@gmail.com      pmem_addr(NULL)
587754SWilliam.Wang@arm.com{
597950SAli.Saidi@ARM.com    if (pmem_size % TheISA::PageBytes != 0)
607950SAli.Saidi@ARM.com        panic("Memory Size not divisible by page size\n");
617950SAli.Saidi@ARM.com
627950SAli.Saidi@ARM.com    mmu->add_child(this, range);
637950SAli.Saidi@ARM.com
647950SAli.Saidi@ARM.com    int fd = -1;
657754SWilliam.Wang@arm.com
667754SWilliam.Wang@arm.com    if (!fname.empty()) {
677754SWilliam.Wang@arm.com        fd = open(fname.c_str(), O_RDWR | O_CREAT, 0644);
687754SWilliam.Wang@arm.com        if (fd == -1) {
697754SWilliam.Wang@arm.com            perror("open");
707754SWilliam.Wang@arm.com            fatal("Could not open physical memory file: %s\n", fname);
717754SWilliam.Wang@arm.com        }
727754SWilliam.Wang@arm.com        ftruncate(fd, pmem_size);
737754SWilliam.Wang@arm.com    }
747754SWilliam.Wang@arm.com
757754SWilliam.Wang@arm.com    int map_flags = (fd == -1) ? (MAP_ANON | MAP_PRIVATE) : MAP_SHARED;
767754SWilliam.Wang@arm.com    pmem_addr = (uint8_t *)mmap(NULL, pmem_size, PROT_READ | PROT_WRITE,
777754SWilliam.Wang@arm.com                                map_flags, fd, 0);
787950SAli.Saidi@ARM.com
797754SWilliam.Wang@arm.com    if (fd != -1)
807754SWilliam.Wang@arm.com        close(fd);
817754SWilliam.Wang@arm.com
827950SAli.Saidi@ARM.com    if (pmem_addr == (void *)MAP_FAILED) {
837950SAli.Saidi@ARM.com        perror("mmap");
847950SAli.Saidi@ARM.com        fatal("Could not mmap!\n");
857950SAli.Saidi@ARM.com    }
867950SAli.Saidi@ARM.com
877950SAli.Saidi@ARM.com    page_ptr = 0;
887754SWilliam.Wang@arm.com}
897754SWilliam.Wang@arm.com#endif
907754SWilliam.Wang@arm.com
917950SAli.Saidi@ARM.comPhysicalMemory::PhysicalMemory(const string &n)
927950SAli.Saidi@ARM.com    : FunctionalMemory(n), base_addr(0), pmem_addr(NULL)
937950SAli.Saidi@ARM.com{
947950SAli.Saidi@ARM.com    // Hardcoded to 128 MB for now.
957950SAli.Saidi@ARM.com    pmem_size = 1 << 27;
967950SAli.Saidi@ARM.com
977950SAli.Saidi@ARM.com    if (pmem_size % TheISA::PageBytes != 0)
987950SAli.Saidi@ARM.com        panic("Memory Size not divisible by page size\n");
997754SWilliam.Wang@arm.com
1007754SWilliam.Wang@arm.com    int map_flags = MAP_ANON | MAP_PRIVATE;
1017754SWilliam.Wang@arm.com    pmem_addr = (uint8_t *)mmap(NULL, pmem_size, PROT_READ | PROT_WRITE,
1027754SWilliam.Wang@arm.com                                map_flags, -1, 0);
1037754SWilliam.Wang@arm.com
1047950SAli.Saidi@ARM.com    if (pmem_addr == (void *)MAP_FAILED) {
1057950SAli.Saidi@ARM.com        perror("mmap");
1067754SWilliam.Wang@arm.com        fatal("Could not mmap!\n");
1077754SWilliam.Wang@arm.com    }
1089806Sstever@gmail.com
1097754SWilliam.Wang@arm.com    page_ptr = 0;
1107754SWilliam.Wang@arm.com}
1117754SWilliam.Wang@arm.com
1127754SWilliam.Wang@arm.comPhysicalMemory::~PhysicalMemory()
1137754SWilliam.Wang@arm.com{
1147754SWilliam.Wang@arm.com    if (pmem_addr)
1157754SWilliam.Wang@arm.com        munmap(pmem_addr, pmem_size);
1167754SWilliam.Wang@arm.com}
1177754SWilliam.Wang@arm.com
1187754SWilliam.Wang@arm.comAddr
1197754SWilliam.Wang@arm.comPhysicalMemory::new_page()
1207754SWilliam.Wang@arm.com{
1217754SWilliam.Wang@arm.com    Addr return_addr = page_ptr << LogVMPageSize;
1227754SWilliam.Wang@arm.com    return_addr += base_addr;
1237754SWilliam.Wang@arm.com
1247754SWilliam.Wang@arm.com    ++page_ptr;
1257754SWilliam.Wang@arm.com    return return_addr;
1267754SWilliam.Wang@arm.com}
1277754SWilliam.Wang@arm.com
1287754SWilliam.Wang@arm.com//
1297754SWilliam.Wang@arm.com// little helper for better prot_* error messages
1307754SWilliam.Wang@arm.com//
1317754SWilliam.Wang@arm.comvoid
1327754SWilliam.Wang@arm.comPhysicalMemory::prot_access_error(Addr addr, int size, const string &func)
1337754SWilliam.Wang@arm.com{
1347754SWilliam.Wang@arm.com    panic("invalid physical memory access!\n"
1357754SWilliam.Wang@arm.com          "%s: %s(addr=%#x, size=%d) out of range (max=%#x)\n",
1367754SWilliam.Wang@arm.com          name(), func, addr, size, pmem_size - 1);
1377754SWilliam.Wang@arm.com}
1387754SWilliam.Wang@arm.com
1397754SWilliam.Wang@arm.comvoid
1407754SWilliam.Wang@arm.comPhysicalMemory::prot_read(Addr addr, uint8_t *p, int size)
1417754SWilliam.Wang@arm.com{
1427754SWilliam.Wang@arm.com    if (addr + size >= pmem_size)
1437754SWilliam.Wang@arm.com        prot_access_error(addr, size, "prot_read");
1447754SWilliam.Wang@arm.com
1457950SAli.Saidi@ARM.com    memcpy(p, pmem_addr + addr - base_addr, size);
1467754SWilliam.Wang@arm.com}
1477754SWilliam.Wang@arm.com
1487754SWilliam.Wang@arm.comvoid
1497754SWilliam.Wang@arm.comPhysicalMemory::prot_write(Addr addr, const uint8_t *p, int size)
1507950SAli.Saidi@ARM.com{
1517950SAli.Saidi@ARM.com    if (addr + size >= pmem_size)
1527950SAli.Saidi@ARM.com        prot_access_error(addr, size, "prot_write");
1537754SWilliam.Wang@arm.com
1547754SWilliam.Wang@arm.com    memcpy(pmem_addr + addr - base_addr, p, size);
1557950SAli.Saidi@ARM.com}
1567950SAli.Saidi@ARM.com
1577950SAli.Saidi@ARM.comvoid
1587754SWilliam.Wang@arm.comPhysicalMemory::prot_memset(Addr addr, uint8_t val, int size)
1597754SWilliam.Wang@arm.com{
1607950SAli.Saidi@ARM.com    if (addr + size >= pmem_size)
1617754SWilliam.Wang@arm.com        prot_access_error(addr, size, "prot_memset");
1627754SWilliam.Wang@arm.com
1637754SWilliam.Wang@arm.com    memset(pmem_addr + addr - base_addr, val, size);
1647754SWilliam.Wang@arm.com}
1657754SWilliam.Wang@arm.com
1667754SWilliam.Wang@arm.comvoid
1677754SWilliam.Wang@arm.comPhysicalMemory::serialize(ostream &os)
1687754SWilliam.Wang@arm.com{
1697754SWilliam.Wang@arm.com    gzFile compressedMem;
1707754SWilliam.Wang@arm.com    string filename = name() + ".physmem";
1717950SAli.Saidi@ARM.com
1727950SAli.Saidi@ARM.com    SERIALIZE_SCALAR(pmem_size);
1737950SAli.Saidi@ARM.com    SERIALIZE_SCALAR(filename);
1747950SAli.Saidi@ARM.com
1757950SAli.Saidi@ARM.com    // write memory file
1767950SAli.Saidi@ARM.com    string thefile = Checkpoint::dir() + "/" + filename.c_str();
1777950SAli.Saidi@ARM.com    int fd = creat(thefile.c_str(), 0664);
1787950SAli.Saidi@ARM.com    if (fd < 0) {
1797950SAli.Saidi@ARM.com        perror("creat");
1807950SAli.Saidi@ARM.com        fatal("Can't open physical memory checkpoint file '%s'\n", filename);
1817950SAli.Saidi@ARM.com    }
1827950SAli.Saidi@ARM.com
1837950SAli.Saidi@ARM.com    compressedMem = gzdopen(fd, "wb");
1847950SAli.Saidi@ARM.com    if (compressedMem == NULL)
1857950SAli.Saidi@ARM.com        fatal("Insufficient memory to allocate compression state for %s\n",
1867950SAli.Saidi@ARM.com                filename);
1877950SAli.Saidi@ARM.com
1887950SAli.Saidi@ARM.com    if (gzwrite(compressedMem, pmem_addr, pmem_size) != pmem_size) {
1897950SAli.Saidi@ARM.com        fatal("Write failed on physical memory checkpoint file '%s'\n",
1907950SAli.Saidi@ARM.com              filename);
1917950SAli.Saidi@ARM.com    }
1927950SAli.Saidi@ARM.com
1937950SAli.Saidi@ARM.com    if (gzclose(compressedMem))
1947950SAli.Saidi@ARM.com        fatal("Close failed on physical memory checkpoint file '%s'\n",
1957950SAli.Saidi@ARM.com              filename);
1967950SAli.Saidi@ARM.com}
1977950SAli.Saidi@ARM.com
1987950SAli.Saidi@ARM.comvoid
1997950SAli.Saidi@ARM.comPhysicalMemory::unserialize(Checkpoint *cp, const string &section)
2007950SAli.Saidi@ARM.com{
2017950SAli.Saidi@ARM.com    gzFile compressedMem;
2027950SAli.Saidi@ARM.com    long *tempPage;
2037950SAli.Saidi@ARM.com    long *pmem_current;
2047950SAli.Saidi@ARM.com    uint64_t curSize;
2057950SAli.Saidi@ARM.com    uint32_t bytesRead;
2067950SAli.Saidi@ARM.com    const int chunkSize = 16384;
2077950SAli.Saidi@ARM.com
2087950SAli.Saidi@ARM.com
2097950SAli.Saidi@ARM.com    // unmap file that was mmaped in the constructor
2107950SAli.Saidi@ARM.com    munmap(pmem_addr, pmem_size);
2117950SAli.Saidi@ARM.com
2129049Schander.sudanthi@arm.com    string filename;
2137950SAli.Saidi@ARM.com
2147950SAli.Saidi@ARM.com    UNSERIALIZE_SCALAR(pmem_size);
2157950SAli.Saidi@ARM.com    UNSERIALIZE_SCALAR(filename);
2167950SAli.Saidi@ARM.com
2177950SAli.Saidi@ARM.com    filename = cp->cptDir + "/" + filename;
2187950SAli.Saidi@ARM.com
2197950SAli.Saidi@ARM.com    // mmap memoryfile
2207950SAli.Saidi@ARM.com    int fd = open(filename.c_str(), O_RDONLY);
2217950SAli.Saidi@ARM.com    if (fd < 0) {
2227950SAli.Saidi@ARM.com        perror("open");
2237950SAli.Saidi@ARM.com        fatal("Can't open physical memory checkpoint file '%s'", filename);
2247950SAli.Saidi@ARM.com    }
2257950SAli.Saidi@ARM.com
2267950SAli.Saidi@ARM.com    compressedMem = gzdopen(fd, "rb");
2277950SAli.Saidi@ARM.com    if (compressedMem == NULL)
2287950SAli.Saidi@ARM.com        fatal("Insufficient memory to allocate compression state for %s\n",
2297950SAli.Saidi@ARM.com                filename);
2307950SAli.Saidi@ARM.com
2317950SAli.Saidi@ARM.com
2327950SAli.Saidi@ARM.com    pmem_addr = (uint8_t *)mmap(NULL, pmem_size, PROT_READ | PROT_WRITE,
2337950SAli.Saidi@ARM.com                                MAP_ANON | MAP_PRIVATE, -1, 0);
2347950SAli.Saidi@ARM.com
2357950SAli.Saidi@ARM.com    if (pmem_addr == (void *)MAP_FAILED) {
2367950SAli.Saidi@ARM.com        perror("mmap");
2377950SAli.Saidi@ARM.com        fatal("Could not mmap physical memory!\n");
2387950SAli.Saidi@ARM.com    }
2397950SAli.Saidi@ARM.com
2407950SAli.Saidi@ARM.com    curSize = 0;
2417950SAli.Saidi@ARM.com    tempPage = (long*)malloc(chunkSize);
2427950SAli.Saidi@ARM.com    if (tempPage == NULL)
2437950SAli.Saidi@ARM.com        fatal("Unable to malloc memory to read file %s\n", filename);
2447950SAli.Saidi@ARM.com
2457950SAli.Saidi@ARM.com    /* Only copy bytes that are non-zero, so we don't give the VM system hell */
2467950SAli.Saidi@ARM.com    while (curSize < pmem_size) {
2477950SAli.Saidi@ARM.com        bytesRead = gzread(compressedMem, tempPage, chunkSize);
2487950SAli.Saidi@ARM.com        if (bytesRead != chunkSize && bytesRead != pmem_size - curSize)
2497950SAli.Saidi@ARM.com            fatal("Read failed on physical memory checkpoint file '%s'"
2507950SAli.Saidi@ARM.com                  " got %d bytes, expected %d or %d bytes\n",
2517950SAli.Saidi@ARM.com                  filename, bytesRead, chunkSize, pmem_size-curSize);
2527950SAli.Saidi@ARM.com
2537950SAli.Saidi@ARM.com        assert(bytesRead % sizeof(long) == 0);
2547950SAli.Saidi@ARM.com
2557950SAli.Saidi@ARM.com        for (int x = 0; x < bytesRead/sizeof(long); x++)
2567950SAli.Saidi@ARM.com        {
2577754SWilliam.Wang@arm.com             if (*(tempPage+x) != 0) {
2587754SWilliam.Wang@arm.com                 pmem_current = (long*)(pmem_addr + curSize + x * sizeof(long));
2597950SAli.Saidi@ARM.com                 *pmem_current = *(tempPage+x);
2607950SAli.Saidi@ARM.com             }
2617754SWilliam.Wang@arm.com        }
2627950SAli.Saidi@ARM.com        curSize += bytesRead;
2637754SWilliam.Wang@arm.com    }
2647754SWilliam.Wang@arm.com
2657754SWilliam.Wang@arm.com    free(tempPage);
2667950SAli.Saidi@ARM.com
2677950SAli.Saidi@ARM.com    if (gzclose(compressedMem))
2687950SAli.Saidi@ARM.com        fatal("Close failed on physical memory checkpoint file '%s'\n",
2697950SAli.Saidi@ARM.com              filename);
2707950SAli.Saidi@ARM.com
2717950SAli.Saidi@ARM.com}
2727950SAli.Saidi@ARM.com
2737950SAli.Saidi@ARM.comBEGIN_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory)
2747950SAli.Saidi@ARM.com
2757950SAli.Saidi@ARM.com    Param<string> file;
2767950SAli.Saidi@ARM.com#if FULL_SYSTEM
2777950SAli.Saidi@ARM.com    SimObjectParam<MemoryController *> mmu;
2787950SAli.Saidi@ARM.com#endif
2797950SAli.Saidi@ARM.com    Param<Range<Addr> > range;
2807950SAli.Saidi@ARM.com
2817950SAli.Saidi@ARM.comEND_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory)
2827950SAli.Saidi@ARM.com
2837950SAli.Saidi@ARM.comBEGIN_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)
2847950SAli.Saidi@ARM.com
2857950SAli.Saidi@ARM.com    INIT_PARAM_DFLT(file, "memory mapped file", ""),
2867950SAli.Saidi@ARM.com#if FULL_SYSTEM
2877950SAli.Saidi@ARM.com    INIT_PARAM(mmu, "Memory Controller"),
2887950SAli.Saidi@ARM.com#endif
2897950SAli.Saidi@ARM.com    INIT_PARAM(range, "Device Address Range")
2907950SAli.Saidi@ARM.com
2917950SAli.Saidi@ARM.comEND_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)
2927950SAli.Saidi@ARM.com
2937950SAli.Saidi@ARM.comCREATE_SIM_OBJECT(PhysicalMemory)
2947950SAli.Saidi@ARM.com{
2957950SAli.Saidi@ARM.com#if FULL_SYSTEM
2967950SAli.Saidi@ARM.com    if (mmu) {
2977950SAli.Saidi@ARM.com        return new PhysicalMemory(getInstanceName(), range, mmu, file);
2987950SAli.Saidi@ARM.com    }
2997950SAli.Saidi@ARM.com#endif
3007950SAli.Saidi@ARM.com
3017950SAli.Saidi@ARM.com    return new PhysicalMemory(getInstanceName());
3027950SAli.Saidi@ARM.com}
3037950SAli.Saidi@ARM.com
3047950SAli.Saidi@ARM.comREGISTER_SIM_OBJECT("PhysicalMemory", PhysicalMemory)
3057950SAli.Saidi@ARM.com