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 §ion) 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