physical.cc revision 10482
12810SN/A/* 29614Srene.dejong@arm.com * Copyright (c) 2012, 2014 ARM Limited 38856Sandreas.hansson@arm.com * All rights reserved 48856Sandreas.hansson@arm.com * 58856Sandreas.hansson@arm.com * The license below extends only to copyright in the software and shall 68856Sandreas.hansson@arm.com * not be construed as granting a license to any other intellectual 78856Sandreas.hansson@arm.com * property including but not limited to intellectual property relating 88856Sandreas.hansson@arm.com * to a hardware implementation of the functionality of the software 98856Sandreas.hansson@arm.com * licensed hereunder. You may use the software subject to the license 108856Sandreas.hansson@arm.com * terms below provided that you ensure that this notice is replicated 118856Sandreas.hansson@arm.com * unmodified and in its entirety in all distributions of the software, 128856Sandreas.hansson@arm.com * modified or unmodified, in source code or in binary form. 138856Sandreas.hansson@arm.com * 142810SN/A * Redistribution and use in source and binary forms, with or without 152810SN/A * modification, are permitted provided that the following conditions are 162810SN/A * met: redistributions of source code must retain the above copyright 172810SN/A * notice, this list of conditions and the following disclaimer; 182810SN/A * redistributions in binary form must reproduce the above copyright 192810SN/A * notice, this list of conditions and the following disclaimer in the 202810SN/A * documentation and/or other materials provided with the distribution; 212810SN/A * neither the name of the copyright holders nor the names of its 222810SN/A * contributors may be used to endorse or promote products derived from 232810SN/A * this software without specific prior written permission. 242810SN/A * 252810SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 262810SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 272810SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 282810SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 292810SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 302810SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 312810SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 322810SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 332810SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 342810SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 352810SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 362810SN/A * 372810SN/A * Authors: Andreas Hansson 382810SN/A */ 392810SN/A 402810SN/A#include <sys/mman.h> 412810SN/A#include <sys/types.h> 422810SN/A#include <sys/user.h> 432810SN/A#include <fcntl.h> 442810SN/A#include <unistd.h> 452810SN/A#include <zlib.h> 462810SN/A 472810SN/A#include <cerrno> 488232Snate@binkert.org#include <climits> 499152Satgutier@umich.edu#include <cstdio> 509795Sandreas.hansson@arm.com#include <iostream> 519795Sandreas.hansson@arm.com#include <string> 5210263Satgutier@umich.edu 535338Sstever@gmail.com#include "base/trace.hh" 549795Sandreas.hansson@arm.com#include "debug/AddrRanges.hh" 555338Sstever@gmail.com#include "debug/Checkpoint.hh" 568786Sgblack@eecs.umich.edu#include "mem/abstract_mem.hh" 572810SN/A#include "mem/physical.hh" 582810SN/A 592810SN/Ausing namespace std; 608856Sandreas.hansson@arm.com 618856Sandreas.hansson@arm.comPhysicalMemory::PhysicalMemory(const string& _name, 628856Sandreas.hansson@arm.com const vector<AbstractMemory*>& _memories) : 638922Swilliam.wang@arm.com _name(_name), size(0) 648914Sandreas.hansson@arm.com{ 658856Sandreas.hansson@arm.com // add the memories from the system to the address map as 668856Sandreas.hansson@arm.com // appropriate 674475SN/A for (const auto& m : _memories) { 6811053Sandreas.hansson@arm.com // only add the memory if it is part of the global address map 695034SN/A if (m->isInAddrMap()) { 7010360Sandreas.hansson@arm.com memories.push_back(m); 7110622Smitch.hayenga@arm.com 7210622Smitch.hayenga@arm.com // calculate the total size once and for all 734628SN/A size += m->size(); 7411053Sandreas.hansson@arm.com 7510693SMarco.Balboni@ARM.com // add the range to our interval tree and make sure it does not 7610693SMarco.Balboni@ARM.com // intersect an existing range 7710693SMarco.Balboni@ARM.com fatal_if(addrMap.insert(m->getAddrRange(), m) == addrMap.end(), 789263Smrinmoy.ghosh@arm.com "Memory address range for %s is overlapping\n", 795034SN/A m->name()); 806122SSteve.Reinhardt@amd.com } else { 8110884Sandreas.hansson@arm.com // this type of memory is used e.g. as reference memory by 824626SN/A // Ruby, and they also needs a backing store, but should 8310360Sandreas.hansson@arm.com // not be part of the global address map 844626SN/A DPRINTF(AddrRanges, 855034SN/A "Skipping memory %s that is not in global address map\n", 868883SAli.Saidi@ARM.com m->name()); 878833Sdam.sunwoo@arm.com 884458SN/A // sanity check 892810SN/A fatal_if(m->getAddrRange().interleaved(), 902810SN/A "Memory %s that is not in the global address map cannot " 913013SN/A "be interleaved\n", m->name()); 928856Sandreas.hansson@arm.com 932810SN/A // simply do it independently, also note that this kind of 943013SN/A // memories are allowed to overlap in the logic address 9510714Sandreas.hansson@arm.com // map 962810SN/A vector<AbstractMemory*> unmapped_mems{m}; 979614Srene.dejong@arm.com createBackingStore(m->getAddrRange(), unmapped_mems); 989614Srene.dejong@arm.com } 999614Srene.dejong@arm.com } 10010345SCurtis.Dunham@arm.com 10110714Sandreas.hansson@arm.com // iterate over the increasing addresses and chunks of contiguous 10210345SCurtis.Dunham@arm.com // space to be mapped to backing store, create it and inform the 1039614Srene.dejong@arm.com // memories 1042810SN/A vector<AddrRange> intlv_ranges; 1052810SN/A vector<AbstractMemory*> curr_memories; 1062810SN/A for (const auto& r : addrMap) { 1078856Sandreas.hansson@arm.com // simply skip past all memories that are null and hence do 1082810SN/A // not need any backing store 1093013SN/A if (!r.second->isNull()) { 11010714Sandreas.hansson@arm.com // if the range is interleaved then save it for now 1113013SN/A if (r.first.interleaved()) { 1128856Sandreas.hansson@arm.com // if we already got interleaved ranges that are not 11310714Sandreas.hansson@arm.com // part of the same range, then first do a merge 1148922Swilliam.wang@arm.com // before we add the new one 1152897SN/A if (!intlv_ranges.empty() && 1162810SN/A !intlv_ranges.back().mergesWith(r.first)) { 1172810SN/A AddrRange merged_range(intlv_ranges); 11810344Sandreas.hansson@arm.com createBackingStore(merged_range, curr_memories); 11910344Sandreas.hansson@arm.com intlv_ranges.clear(); 12010344Sandreas.hansson@arm.com curr_memories.clear(); 12110714Sandreas.hansson@arm.com } 12210344Sandreas.hansson@arm.com intlv_ranges.push_back(r.first); 12310344Sandreas.hansson@arm.com curr_memories.push_back(r.second); 12410344Sandreas.hansson@arm.com } else { 12510713Sandreas.hansson@arm.com vector<AbstractMemory*> single_memory{r.second}; 12610344Sandreas.hansson@arm.com createBackingStore(r.first, single_memory); 1272844SN/A } 1282810SN/A } 1292858SN/A } 1302858SN/A 1318856Sandreas.hansson@arm.com // if there is still interleaved ranges waiting to be merged, go 1328922Swilliam.wang@arm.com // ahead and do it 1338711Sandreas.hansson@arm.com if (!intlv_ranges.empty()) { 1342858SN/A AddrRange merged_range(intlv_ranges); 1352858SN/A createBackingStore(merged_range, curr_memories); 1369294Sandreas.hansson@arm.com } 1379294Sandreas.hansson@arm.com} 1388922Swilliam.wang@arm.com 1398922Swilliam.wang@arm.comvoid 1408922Swilliam.wang@arm.comPhysicalMemory::createBackingStore(AddrRange range, 1418922Swilliam.wang@arm.com const vector<AbstractMemory*>& _memories) 1428922Swilliam.wang@arm.com{ 1438922Swilliam.wang@arm.com panic_if(range.interleaved(), 1448922Swilliam.wang@arm.com "Cannot create backing store for interleaved range %s\n", 1458922Swilliam.wang@arm.com range.to_string()); 1469294Sandreas.hansson@arm.com 1479294Sandreas.hansson@arm.com // perform the actual mmap 1488922Swilliam.wang@arm.com DPRINTF(AddrRanges, "Creating backing store for range %s with size %d\n", 1498922Swilliam.wang@arm.com range.to_string(), range.size()); 1508922Swilliam.wang@arm.com int map_flags = MAP_ANON | MAP_PRIVATE; 1518922Swilliam.wang@arm.com uint8_t* pmem = (uint8_t*) mmap(NULL, range.size(), 1528922Swilliam.wang@arm.com PROT_READ | PROT_WRITE, 1538922Swilliam.wang@arm.com map_flags, -1, 0); 1548922Swilliam.wang@arm.com 1554628SN/A if (pmem == (uint8_t*) MAP_FAILED) { 15610821Sandreas.hansson@arm.com perror("mmap"); 15710821Sandreas.hansson@arm.com fatal("Could not mmap %d bytes for range %s!\n", range.size(), 15810821Sandreas.hansson@arm.com range.to_string()); 15910821Sandreas.hansson@arm.com } 16010821Sandreas.hansson@arm.com 16110821Sandreas.hansson@arm.com // remember this backing store so we can checkpoint it and unmap 16210821Sandreas.hansson@arm.com // it appropriately 16310821Sandreas.hansson@arm.com backingStore.push_back(make_pair(range, pmem)); 16410821Sandreas.hansson@arm.com 16510821Sandreas.hansson@arm.com // point the memories to their backing store 16610821Sandreas.hansson@arm.com for (const auto& m : _memories) { 1672858SN/A DPRINTF(AddrRanges, "Mapping memory %s to backing store\n", 1682810SN/A m->name()); 1692810SN/A m->setBackingStore(pmem); 1702810SN/A } 1712810SN/A} 1722810SN/A 1734022SN/APhysicalMemory::~PhysicalMemory() 1744022SN/A{ 1754022SN/A // unmap the backing store 1762810SN/A for (auto& s : backingStore) 1772810SN/A munmap((char*)s.second, s.first.size()); 1788833Sdam.sunwoo@arm.com} 1792810SN/A 1802810SN/Abool 1812810SN/APhysicalMemory::isMemAddr(Addr addr) const 1822810SN/A{ 1838833Sdam.sunwoo@arm.com // see if the address is within the last matched range 1848833Sdam.sunwoo@arm.com if (!rangeCache.contains(addr)) { 1858833Sdam.sunwoo@arm.com // lookup in the interval tree 1862810SN/A const auto& r = addrMap.find(addr); 1872810SN/A if (r == addrMap.end()) { 1884871SN/A // not in the cache, and not in the tree 1894871SN/A return false; 1904871SN/A } 1914871SN/A // the range is in the tree, update the cache 19210885Sandreas.hansson@arm.com rangeCache = r->first; 19310885Sandreas.hansson@arm.com } 1944871SN/A 1954871SN/A assert(addrMap.find(addr) != addrMap.end()); 1964871SN/A 1974871SN/A // either matched the cache or found in the tree 1984871SN/A return true; 1992810SN/A} 2002810SN/A 2012810SN/AAddrRangeList 2028833Sdam.sunwoo@arm.comPhysicalMemory::getConfAddrRanges() const 2032810SN/A{ 2044871SN/A // this could be done once in the constructor, but since it is unlikely to 2058833Sdam.sunwoo@arm.com // be called more than once the iteration should not be a problem 2068833Sdam.sunwoo@arm.com AddrRangeList ranges; 2078833Sdam.sunwoo@arm.com vector<AddrRange> intlv_ranges; 2082810SN/A for (const auto& r : addrMap) { 2092810SN/A if (r.second->isConfReported()) { 2102810SN/A // if the range is interleaved then save it for now 2112810SN/A if (r.first.interleaved()) { 2128833Sdam.sunwoo@arm.com // if we already got interleaved ranges that are not 2132810SN/A // part of the same range, then first do a merge 2144871SN/A // before we add the new one 2158833Sdam.sunwoo@arm.com if (!intlv_ranges.empty() && 2168833Sdam.sunwoo@arm.com !intlv_ranges.back().mergesWith(r.first)) { 2178833Sdam.sunwoo@arm.com ranges.push_back(AddrRange(intlv_ranges)); 2182810SN/A intlv_ranges.clear(); 2192810SN/A } 2204022SN/A intlv_ranges.push_back(r.first); 2214022SN/A } else { 2224022SN/A // keep the current range 2232810SN/A ranges.push_back(r.first); 2242810SN/A } 2258833Sdam.sunwoo@arm.com } 2262810SN/A } 2272810SN/A 2282810SN/A // if there is still interleaved ranges waiting to be merged, 2292810SN/A // go ahead and do it 2308833Sdam.sunwoo@arm.com if (!intlv_ranges.empty()) { 2318833Sdam.sunwoo@arm.com ranges.push_back(AddrRange(intlv_ranges)); 2328833Sdam.sunwoo@arm.com } 2332810SN/A 2342810SN/A return ranges; 2352810SN/A} 2362810SN/A 2372810SN/Avoid 2388833Sdam.sunwoo@arm.comPhysicalMemory::access(PacketPtr pkt) 2392810SN/A{ 2404871SN/A assert(pkt->isRequest()); 2418833Sdam.sunwoo@arm.com Addr addr = pkt->getAddr(); 2428833Sdam.sunwoo@arm.com const auto& m = addrMap.find(addr); 2438833Sdam.sunwoo@arm.com assert(m != addrMap.end()); 2442810SN/A m->second->access(pkt); 2452810SN/A} 2462810SN/A 2472810SN/Avoid 2488833Sdam.sunwoo@arm.comPhysicalMemory::functionalAccess(PacketPtr pkt) 2492810SN/A{ 2504871SN/A assert(pkt->isRequest()); 2518833Sdam.sunwoo@arm.com Addr addr = pkt->getAddr(); 2528833Sdam.sunwoo@arm.com const auto& m = addrMap.find(addr); 2538833Sdam.sunwoo@arm.com assert(m != addrMap.end()); 2542810SN/A m->second->functionalAccess(pkt); 2552810SN/A} 2564022SN/A 2574022SN/Avoid 2584022SN/APhysicalMemory::serialize(ostream& os) 2592810SN/A{ 2602810SN/A // serialize all the locked addresses and their context ids 2618833Sdam.sunwoo@arm.com vector<Addr> lal_addr; 2622810SN/A vector<int> lal_cid; 2632810SN/A 2642810SN/A for (auto& m : memories) { 2652810SN/A const list<LockedAddr>& locked_addrs = m->getLockedAddrList(); 2668833Sdam.sunwoo@arm.com for (const auto& l : locked_addrs) { 2678833Sdam.sunwoo@arm.com lal_addr.push_back(l.addr); 2688833Sdam.sunwoo@arm.com lal_cid.push_back(l.contextId); 2692810SN/A } 2702810SN/A } 2712810SN/A 2722810SN/A arrayParamOut(os, "lal_addr", lal_addr); 2732810SN/A arrayParamOut(os, "lal_cid", lal_cid); 2748833Sdam.sunwoo@arm.com 2752810SN/A // serialize the backing stores 2764871SN/A unsigned int nbr_of_stores = backingStore.size(); 2778833Sdam.sunwoo@arm.com SERIALIZE_SCALAR(nbr_of_stores); 2788833Sdam.sunwoo@arm.com 2798833Sdam.sunwoo@arm.com unsigned int store_id = 0; 2802810SN/A // store each backing store memory segment in a file 2812810SN/A for (auto& s : backingStore) { 2822810SN/A nameOut(os, csprintf("%s.store%d", name(), store_id)); 2832810SN/A serializeStore(os, store_id++, s.first, s.second); 2848833Sdam.sunwoo@arm.com } 2852810SN/A} 2864871SN/A 2878833Sdam.sunwoo@arm.comvoid 2888833Sdam.sunwoo@arm.comPhysicalMemory::serializeStore(ostream& os, unsigned int store_id, 2898833Sdam.sunwoo@arm.com AddrRange range, uint8_t* pmem) 2902810SN/A{ 2912810SN/A // we cannot use the address range for the name as the 2924022SN/A // memories that are not part of the address map can overlap 2934022SN/A string filename = name() + ".store" + to_string(store_id) + ".pmem"; 2944022SN/A long range_size = range.size(); 2952810SN/A 2962810SN/A DPRINTF(Checkpoint, "Serializing physical memory %s with size %d\n", 2972810SN/A filename, range_size); 2982810SN/A 2992810SN/A SERIALIZE_SCALAR(store_id); 3002810SN/A SERIALIZE_SCALAR(filename); 3018833Sdam.sunwoo@arm.com SERIALIZE_SCALAR(range_size); 3022810SN/A 3038833Sdam.sunwoo@arm.com // write memory file 3048833Sdam.sunwoo@arm.com string filepath = Checkpoint::dir() + "/" + filename.c_str(); 3058833Sdam.sunwoo@arm.com gzFile compressed_mem = gzopen(filepath.c_str(), "wb"); 3062810SN/A if (compressed_mem == NULL) 3072810SN/A fatal("Can't open physical memory checkpoint file '%s'\n", 3082810SN/A filename); 3092810SN/A 3102810SN/A uint64_t pass_size = 0; 3118833Sdam.sunwoo@arm.com 3122810SN/A // gzwrite fails if (int)len < 0 (gzwrite returns int) 3132810SN/A for (uint64_t written = 0; written < range.size(); 3148833Sdam.sunwoo@arm.com written += pass_size) { 3158833Sdam.sunwoo@arm.com pass_size = (uint64_t)INT_MAX < (range.size() - written) ? 3168833Sdam.sunwoo@arm.com (uint64_t)INT_MAX : (range.size() - written); 3172810SN/A 3182810SN/A if (gzwrite(compressed_mem, pmem + written, 3192810SN/A (unsigned int) pass_size) != (int) pass_size) { 3202810SN/A fatal("Write failed on physical memory checkpoint file '%s'\n", 3218833Sdam.sunwoo@arm.com filename); 3222810SN/A } 3232810SN/A } 3248833Sdam.sunwoo@arm.com 3258833Sdam.sunwoo@arm.com // close the compressed stream and check that the exit status 3268833Sdam.sunwoo@arm.com // is zero 3272810SN/A if (gzclose(compressed_mem)) 3282810SN/A fatal("Close failed on physical memory checkpoint file '%s'\n", 3294022SN/A filename); 3304022SN/A 3314022SN/A} 3322810SN/A 3332810SN/Avoid 3342810SN/APhysicalMemory::unserialize(Checkpoint* cp, const string& section) 3352810SN/A{ 3362810SN/A // unserialize the locked addresses and map them to the 3372810SN/A // appropriate memory controller 3388833Sdam.sunwoo@arm.com vector<Addr> lal_addr; 3392810SN/A vector<int> lal_cid; 3408833Sdam.sunwoo@arm.com arrayParamIn(cp, section, "lal_addr", lal_addr); 3418833Sdam.sunwoo@arm.com arrayParamIn(cp, section, "lal_cid", lal_cid); 3428833Sdam.sunwoo@arm.com for(size_t i = 0; i < lal_addr.size(); ++i) { 3432810SN/A const auto& m = addrMap.find(lal_addr[i]); 3442810SN/A m->second->addLockedAddr(LockedAddr(lal_addr[i], lal_cid[i])); 3452810SN/A } 3462810SN/A 3472810SN/A // unserialize the backing stores 3488833Sdam.sunwoo@arm.com unsigned int nbr_of_stores; 3492810SN/A UNSERIALIZE_SCALAR(nbr_of_stores); 3502810SN/A 3518833Sdam.sunwoo@arm.com for (unsigned int i = 0; i < nbr_of_stores; ++i) { 3528833Sdam.sunwoo@arm.com unserializeStore(cp, csprintf("%s.store%d", section, i)); 3538833Sdam.sunwoo@arm.com } 3542810SN/A 3552810SN/A} 3562810SN/A 3572810SN/Avoid 3588833Sdam.sunwoo@arm.comPhysicalMemory::unserializeStore(Checkpoint* cp, const string& section) 3592810SN/A{ 3602810SN/A const uint32_t chunk_size = 16384; 3618833Sdam.sunwoo@arm.com 3628833Sdam.sunwoo@arm.com unsigned int store_id; 3638833Sdam.sunwoo@arm.com UNSERIALIZE_SCALAR(store_id); 3642810SN/A 3652810SN/A string filename; 3664022SN/A UNSERIALIZE_SCALAR(filename); 3674022SN/A string filepath = cp->cptDir + "/" + filename; 3684022SN/A 3692810SN/A // mmap memoryfile 3702810SN/A gzFile compressed_mem = gzopen(filepath.c_str(), "rb"); 3712810SN/A if (compressed_mem == NULL) 3722810SN/A fatal("Can't open physical memory checkpoint file '%s'", filename); 3732810SN/A 3742810SN/A // we've already got the actual backing store mapped 3752810SN/A uint8_t* pmem = backingStore[store_id].second; 3762810SN/A AddrRange range = backingStore[store_id].first; 3778833Sdam.sunwoo@arm.com 3788833Sdam.sunwoo@arm.com long range_size; 3798833Sdam.sunwoo@arm.com UNSERIALIZE_SCALAR(range_size); 3808833Sdam.sunwoo@arm.com 3812810SN/A DPRINTF(Checkpoint, "Unserializing physical memory %s with size %d\n", 3822810SN/A filename, range_size); 3832810SN/A 3842810SN/A if (range_size != range.size()) 3852810SN/A fatal("Memory range size has changed! Saw %lld, expected %lld\n", 3868833Sdam.sunwoo@arm.com range_size, range.size()); 3872810SN/A 3882810SN/A uint64_t curr_size = 0; 3898833Sdam.sunwoo@arm.com long* temp_page = new long[chunk_size]; 3908833Sdam.sunwoo@arm.com long* pmem_current; 3918833Sdam.sunwoo@arm.com uint32_t bytes_read; 3922810SN/A while (curr_size < range.size()) { 3932810SN/A bytes_read = gzread(compressed_mem, temp_page, chunk_size); 3942810SN/A if (bytes_read == 0) 3952810SN/A break; 3968833Sdam.sunwoo@arm.com 3972810SN/A assert(bytes_read % sizeof(long) == 0); 3982810SN/A 3998833Sdam.sunwoo@arm.com for (uint32_t x = 0; x < bytes_read / sizeof(long); x++) { 4008833Sdam.sunwoo@arm.com // Only copy bytes that are non-zero, so we don't give 4018833Sdam.sunwoo@arm.com // the VM system hell 4022810SN/A if (*(temp_page + x) != 0) { 4032810SN/A pmem_current = (long*)(pmem + curr_size + x * sizeof(long)); 4042810SN/A *pmem_current = *(temp_page + x); 4052810SN/A } 4062810SN/A } 4072810SN/A curr_size += bytes_read; 4082810SN/A } 4092810SN/A 4102810SN/A delete[] temp_page; 4112810SN/A 4122810SN/A if (gzclose(compressed_mem)) 4132810SN/A fatal("Close failed on physical memory checkpoint file '%s'\n", 4142810SN/A filename); 4152810SN/A} 4162810SN/A