Add checkpoint parameters (together with corresponding serialization
and unserialization) for VMA list of class MemState into a separate
section named 'vmalist'.
Without these VMA list parameters, a page table fault will occur when
running with --restore-simpoint-checkpoint, because of an empty VMA
list. For example:
$ ./build/RISCV/gem5.debug --debug-flags=Exec configs/example/se.py \
-c tests/test-progs/hello/bin/riscv/linux/hello \
--cpu-type=NonCachingSimpleCPU --restore-simpoint-checkpoint \
--checkpoint-dir m5out/ -r 2
...
2404000: system.switch_cpus: T0 : @_int_malloc+3392 : sd a5, 8(a0) \
: MemWrite : D=0x000000000001ed21 A=0x862e8
panic: Page table fault when accessing virtual address 0x862e8
...
Example checkpoint output:
[system.cpu.workload.vmalist]
size=3
[system.cpu.workload.vmalist.Vma0]
name=stack
addrRangeStart=...
addrRangeEnd=...
[system.cpu.workload.vmalist.Vma1]
name=heap
addrRangeStart=...
addrRangeEnd=...
[system.cpu.workload.vmalist.Vma2]
...
Change-Id: Ib2fa7ad2c34fe667ce95bc4b10a1affcf60d9c1f
Signed-off-by: Ian Jiang <ianjiang.ict@gmail.com>
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/31875
Reviewed-by: Daniel Carvalho <odanrc@yahoo.com.br>
Reviewed-by: Bobby R. Bruce <bbruce@ucdavis.edu>
Reviewed-by: Alexandru Duțu <alexandru.dutu@amd.com>
Maintainer: Jason Lowe-Power <power.jg@gmail.com>
Tested-by: kokoro <noreply+kokoro@google.com>
272 lines
10 KiB
C++
272 lines
10 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 <list>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "config/the_isa.hh"
|
|
#include "debug/Vma.hh"
|
|
#include "mem/page_table.hh"
|
|
#include "mem/se_translating_port_proxy.hh"
|
|
#include "sim/serialize.hh"
|
|
#include "sim/vma.hh"
|
|
|
|
class Process;
|
|
class 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());
|
|
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;
|
|
paramIn(cp, "name", name);
|
|
paramIn(cp, "addrRangeStart", start);
|
|
paramIn(cp, "addrRangeEnd", end);
|
|
_vmaList.emplace_back(AddrRange(start, end), _pageBytes, name);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Print the list of VMAs in a format similar to /proc/self/maps
|
|
*/
|
|
std::string printVmaList();
|
|
|
|
private:
|
|
/**
|
|
* 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;
|
|
};
|
|
|
|
#endif
|