| /* | |
| * Copyright (c) 2017-2020 Advanced Micro Devices, Inc. | |
| * All rights reserved. | |
| * | |
| * Redistribution and use in source and binary forms, with or without | |
| * modification, are permitted provided that the following conditions are | |
| * met: redistributions of source code must retain the above copyright | |
| * notice, this list of conditions and the following disclaimer; | |
| * redistributions in binary form must reproduce the above copyright | |
| * notice, this list of conditions and the following disclaimer in the | |
| * documentation and/or other materials provided with the distribution; | |
| * neither the name of the copyright holders nor the names of its | |
| * contributors may be used to endorse or promote products derived from | |
| * this software without specific prior written permission. | |
| * | |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| */ | |
| #ifndef SRC_SIM_MEM_STATE_HH | |
| #define SRC_SIM_MEM_STATE_HH | |
| #include <fcntl.h> | |
| #include <unistd.h> | |
| #include <list> | |
| #include <memory> | |
| #include <string> | |
| #include <vector> | |
| #include "debug/Vma.hh" | |
| #include "mem/page_table.hh" | |
| #include "mem/se_translating_port_proxy.hh" | |
| #include "sim/serialize.hh" | |
| #include "sim/vma.hh" | |
| namespace gem5 | |
| { | |
| class Process; | |
| struct ProcessParams; | |
| class System; | |
| /** | |
| * This class holds the memory state for the Process class and all of its | |
| * derived, architecture-specific children. | |
| * | |
| * The class represents the Process' address space which may change | |
| * dynamically while the simulation is running. They are updated by system | |
| * calls and faults. Each change represents a modification to the process | |
| * address space. | |
| * | |
| * The class is meant to be allocated dynamically and shared through a | |
| * pointer interface. Multiple process can potentially share portions of their | |
| * virtual address space if specific options are passed into the clone(2) | |
| * system call. | |
| */ | |
| class MemState : public Serializable | |
| { | |
| public: | |
| MemState(Process *owner, Addr brk_point, Addr stack_base, | |
| Addr max_stack_size, Addr next_thread_stack_base, | |
| Addr mmap_end); | |
| MemState& operator=(const MemState &in); | |
| /** | |
| * Change the Process owner in case this MemState is copied. | |
| */ | |
| void resetOwner(Process *owner); | |
| /** | |
| * Get/set base addresses and sizes for the stack and data segments of | |
| * the process' memory. | |
| */ | |
| Addr getBrkPoint() const { return _brkPoint; } | |
| Addr getStackBase() const { return _stackBase; } | |
| Addr getStackSize() const { return _stackSize; } | |
| Addr getMaxStackSize() const { return _maxStackSize; } | |
| Addr getStackMin() const { return _stackMin; } | |
| Addr getNextThreadStackBase() const { return _nextThreadStackBase; } | |
| Addr getMmapEnd() const { return _mmapEnd; } | |
| void setBrkPoint(Addr brk_point) { _brkPoint = brk_point; } | |
| void setStackBase(Addr stack_base) { _stackBase = stack_base; } | |
| void setStackSize(Addr stack_size) { _stackSize = stack_size; } | |
| void setMaxStackSize(Addr max_stack) { _maxStackSize = max_stack; } | |
| void setStackMin(Addr stack_min) { _stackMin = stack_min; } | |
| void setNextThreadStackBase(Addr ntsb) { _nextThreadStackBase = ntsb; } | |
| void setMmapEnd(Addr mmap_end) { _mmapEnd = mmap_end; } | |
| /* | |
| * Extend the end of the mmap region by length bytes. Once a contiguous | |
| * region of free virtual memory is found the start of that region is | |
| * returned. | |
| */ | |
| Addr extendMmap(Addr length); | |
| /** | |
| * Check if any page in the virtual address range from start_addr to | |
| * start_addr + length is already mapped in the page table. | |
| * | |
| * @param start_addr Starting address of region to check. | |
| * @param length Length of the range to check. | |
| * | |
| * @return true if all pages in the range are unmapped in page table | |
| */ | |
| bool isUnmapped(Addr start_addr, Addr length); | |
| /** | |
| * Add a new memory region. The region represents a contiguous virtual | |
| * address range which can map to physical memory or a host-backed file. | |
| * Regions which are not file-backed should use -1 for sim_fd and 0 for | |
| * offset. | |
| * | |
| * @param start_addr Starting address of the region. | |
| * @param length Size of the region. | |
| * @param name Name of region. Optional. | |
| * @param sim_fd File descriptor for file-backed regions or -1. | |
| * @param offset Offset in file in which region starts. | |
| */ | |
| void mapRegion(Addr start_addr, Addr length, | |
| const std::string& name="anon", int sim_fd=-1, | |
| Addr offset=0); | |
| /** | |
| * Unmap a pre-existing region. Depending on the range being unmapped | |
| * the resulting new regions will either be split, resized, or | |
| * removed completely. | |
| * | |
| * @param start_addr Starting address of region to unmap. | |
| * @param length Size of region to unmap. | |
| */ | |
| void unmapRegion(Addr start_addr, Addr length); | |
| /** | |
| * Remap a pre-existing region. This changes the virtual address | |
| * range of the region. This will result in regions being expanded | |
| * if there is overlap with another region or simply moving the range | |
| * otherwise. | |
| * | |
| * @param start_addr Start address of region being remapped. | |
| * @param new_start_addr New start address of the region. | |
| * @param length Length of the newly remapped region. | |
| */ | |
| void remapRegion(Addr start_addr, Addr new_start_addr, Addr length); | |
| /** | |
| * Change the end of a process' program break. This represents the end | |
| * of the heap segment of a process. | |
| * | |
| * @param old_brk Old program break address | |
| * @param new_brk New program break address | |
| */ | |
| void updateBrkRegion(Addr old_brk, Addr new_brk); | |
| /** | |
| * Attempt to fix up a fault at vaddr by allocating a page. The fault | |
| * likely occurred because a virtual page which does not have physical | |
| * page assignment is being accessed. | |
| * | |
| * @param vaddr The virtual address which is causing the fault. | |
| * @return Whether the fault has been fixed. | |
| */ | |
| bool fixupFault(Addr vaddr); | |
| /** | |
| * Given the vaddr and size, this method will chunk the allocation into | |
| * page granularity and then request physical pages (frames) from the | |
| * system object. After retrieving a frame, the method updates the page | |
| * table mappings. | |
| * | |
| * @param vaddr The virtual address in need of a frame allocation. | |
| * @param size The size in bytes of the requested mapping. | |
| * @param clobber This flag specifies whether mappings in the page tables | |
| * can be overwritten and replaced with the new mapping. | |
| */ | |
| void allocateMem(Addr vaddr, int64_t size, bool clobber = false); | |
| void | |
| serialize(CheckpointOut &cp) const override | |
| { | |
| paramOut(cp, "brkPoint", _brkPoint); | |
| paramOut(cp, "stackBase", _stackBase); | |
| paramOut(cp, "stackSize", _stackSize); | |
| paramOut(cp, "maxStackSize", _maxStackSize); | |
| paramOut(cp, "stackMin", _stackMin); | |
| paramOut(cp, "nextThreadStackBase", _nextThreadStackBase); | |
| paramOut(cp, "mmapEnd", _mmapEnd); | |
| ScopedCheckpointSection sec(cp, "vmalist"); | |
| paramOut(cp, "size", _vmaList.size()); | |
| int count = 0; | |
| for (auto vma : _vmaList) { | |
| ScopedCheckpointSection sec(cp, csprintf("Vma%d", count++)); | |
| paramOut(cp, "name", vma.getName()); | |
| if (vma.hasHostBuf()) { | |
| paramOut(cp, "fileOffset", vma.getFileMappingOffset()); | |
| } | |
| paramOut(cp, "addrRangeStart", vma.start()); | |
| paramOut(cp, "addrRangeEnd", vma.end()); | |
| } | |
| } | |
| void | |
| unserialize(CheckpointIn &cp) override | |
| { | |
| paramIn(cp, "brkPoint", _brkPoint); | |
| paramIn(cp, "stackBase", _stackBase); | |
| paramIn(cp, "stackSize", _stackSize); | |
| paramIn(cp, "maxStackSize", _maxStackSize); | |
| paramIn(cp, "stackMin", _stackMin); | |
| paramIn(cp, "nextThreadStackBase", _nextThreadStackBase); | |
| paramIn(cp, "mmapEnd", _mmapEnd); | |
| int count; | |
| ScopedCheckpointSection sec(cp, "vmalist"); | |
| paramIn(cp, "size", count); | |
| for (int i = 0; i < count; ++i) { | |
| ScopedCheckpointSection sec(cp, csprintf("Vma%d", i)); | |
| std::string name; | |
| Addr start; | |
| Addr end; | |
| off_t offset = 0; | |
| int host_fd = -1; | |
| paramIn(cp, "name", name); | |
| if (optParamIn(cp, "fileOffset", offset, false)) { | |
| host_fd = open(name.c_str(), O_RDONLY); | |
| fatal_if(host_fd < 0, | |
| "Failed to open %s file " | |
| "while unserializing file-backed VMA\n", name); | |
| } | |
| paramIn(cp, "addrRangeStart", start); | |
| paramIn(cp, "addrRangeEnd", end); | |
| _vmaList.emplace_back(AddrRange(start, end), _pageBytes, name, | |
| host_fd, offset); | |
| close(host_fd); | |
| } | |
| } | |
| /** | |
| * Print the list of VMAs in a format similar to /proc/self/maps | |
| */ | |
| std::string printVmaList(); | |
| private: | |
| /** | |
| * @param | |
| */ | |
| void replicatePage(const MemState &in, Addr vaddr, Addr new_paddr, | |
| bool alloc_page); | |
| /** | |
| * @param | |
| */ | |
| System * system() const; | |
| /** | |
| * Owner process of MemState. Used to manipulate page tables. | |
| */ | |
| Process * _ownerProcess; | |
| Addr _pageBytes; | |
| Addr _brkPoint; | |
| Addr _stackBase; | |
| Addr _stackSize; | |
| Addr _maxStackSize; | |
| Addr _stackMin; | |
| Addr _nextThreadStackBase; | |
| Addr _mmapEnd; | |
| /** | |
| * Keeps record of the furthest mapped heap location. | |
| */ | |
| Addr _endBrkPoint; | |
| /** | |
| * The _vmaList member is a list of virtual memory areas in the target | |
| * application space that have been allocated by the target. In most | |
| * operating systems, lazy allocation is used and these structures (or | |
| * equivalent ones) are used to track the valid address ranges. | |
| * | |
| * This could use a more efficient data structure like an interval | |
| * tree, but it is unclear whether the vmas will be modified often enough | |
| * for the improvement in lookup time to matter. Unmapping VMAs currently | |
| * modifies the list while iterating so the STL container must either | |
| * support this or the unmapping method must be changed. | |
| */ | |
| std::list<VMA> _vmaList; | |
| }; | |
| } // namespace gem5 | |
| #endif |