Files
gem5/src/sim/mem_state.hh
Emin Gadzhiev f96513fd04 sim,sim-se: Fix restoring of VMAs of memory-mapped files
This patch fixes a problem that occurs when restoring from
a checkpoint where Mapped File Buffers are not restored. This
causes errors and unexpected behavior during further execution.
Since the checkpoint already has the size of the
area (address range) and the file name, only the offset is
missing to restore the Mapped File Buffer. Having the offset
value, it's possible to open those files for which an offset is
specified and create a VMA with a Mapped File Buffer.

Change-Id: Ib9dfa174cda6348b966b892184c36daeaba80e81
Signed-off-by: Emin Gadzhiev <e.gadzhiev.mhk@gmail.com>
Issue-On: https://gem5.atlassian.net/browse/GEM5-1302
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/66311
Reviewed-by: Jason Lowe-Power <power.jg@gmail.com>
Tested-by: kokoro <noreply+kokoro@google.com>
Maintainer: Jason Lowe-Power <power.jg@gmail.com>
2022-12-15 21:38:01 +00:00

303 lines
11 KiB
C++

/*
* 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