Brandon Potter has uploaded this change for review. ( https://gem5-review.googlesource.com/c/public/gem5/+/12307

Change subject: syscall_emul: support lazy physical page allocs
......................................................................

syscall_emul: support lazy physical page allocs

This patch introduces Virtual Memory Areas (VMAs) to the
Process class. Instead of binding virtual pages to physical
pages during mmap/remap, we instead create a VMA that covers
the region. Physical pages are allocated only if the virtual
page is actually touched by the program. The binding occurs in
fixupStackFault, renamed to fixupFault. Delaying the binding
allows SE mode to support sparse usages of mmap.

Change-Id: I2caa0f3c9622d810474ea1b1ad717820b2de9437
---
M src/base/addr_range.hh
A src/base/mapped_buf.hh
M src/mem/SConscript
A src/mem/vma.cc
A src/mem/vma.hh
M src/sim/mem_state.hh
M src/sim/syscall_emul.cc
M src/sim/syscall_emul.hh
8 files changed, 436 insertions(+), 150 deletions(-)



diff --git a/src/base/addr_range.hh b/src/base/addr_range.hh
index b243d68..35b9266 100644
--- a/src/base/addr_range.hh
+++ b/src/base/addr_range.hh
@@ -72,13 +72,15 @@
 class AddrRange
 {

-  private:
+  protected:

     /// Private fields for the start and end of the range
     /// Both _start and _end are part of the range.
     Addr _start;
     Addr _end;

+  private:
+
     /// The high bit of the slice that is used for interleaving
     uint8_t intlvHighBit;

diff --git a/src/base/mapped_buf.hh b/src/base/mapped_buf.hh
new file mode 100644
index 0000000..4e05100
--- /dev/null
+++ b/src/base/mapped_buf.hh
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2016 Advanced Micro Devices, Inc.
+ * All rights reserved.
+ *
+ * For use for simulation and test purposes only
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. Neither the name of the copyright holder 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 HOLDER 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.
+ *
+ * Authors: Michael LeBeane
+ */
+
+#ifndef __BASE_MAPPED_BUF_HH__
+#define __BASE_MAPPED_BUF_HH__
+
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+#include "base/logging.hh"
+#include "base/types.hh"
+
+/**
+ * MappedFileBuffer is a wrapper around a region of host memory backed by a
+ * file. The constructor attempts to map a file from host memory, and the
+ * destructor attempts to unmap it.  If there is a problem with the host
+ * mapping/unmapping, then we panic.
+ */
+struct MappedFileBuffer
+{
+    char *buf;          // Host buffer ptr
+    uint64_t len;       // Length of host ptr
+
+    MappedFileBuffer(int fd, uint64_t length, uint64_t offset)
+        : buf(nullptr), len(0)
+    {
+        struct stat file_stat;
+        if (fstat(fd, &file_stat) > 0)
+            panic("mmap: cannot stat file");
+        // Don't bother mapping more than the actual file size
+        len = std::min((uint64_t)file_stat.st_size - offset, length);
+        // cannot call mmap with len == 0
+        if (len) {
+ buf = (char *)mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, offset);
+            if (buf == MAP_FAILED)
+                panic("mmap: failed to map file into host address space");
+        }
+    }
+
+    ~MappedFileBuffer()
+    {
+        if (buf)
+            if (munmap(buf, len) == -1)
+                panic("mmap: failed to unmap file-backed host memory");
+    }
+};
+
+#endif // __BASE_MAPPED_BUF_HH__
diff --git a/src/mem/SConscript b/src/mem/SConscript
index 7c0d426..8e20a14 100644
--- a/src/mem/SConscript
+++ b/src/mem/SConscript
@@ -75,6 +75,7 @@
     Source('fs_translating_port_proxy.cc')
     Source('se_translating_port_proxy.cc')
     Source('page_table.cc')
+    Source('vma.cc')

 if env['HAVE_DRAMSIM']:
     SimObject('DRAMSim2.py')
diff --git a/src/mem/vma.cc b/src/mem/vma.cc
new file mode 100644
index 0000000..a35c355
--- /dev/null
+++ b/src/mem/vma.cc
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2017 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.
+ *
+ * Author: Michael LeBeane
+ *         Brandon Potter
+ */
+
+#include "mem/vma.hh"
+
+void
+VMA::fillMemPages(Addr start, Addr size, SETranslatingPortProxy &port) const
+{
+    auto offset = start - _start;
+
+    /**
+     * Try to copy a full page, but don't overrun the size of the file.
+     */
+    if (offset < _hostBufLen) {
+        auto size = std::min(_hostBufLen - offset, TheISA::PageBytes);
+        port.writeBlob(start, (uint8_t*) _hostBuf + offset, size);
+    }
+}
+
+bool
+VMA::isStrictSuperset(const AddrRange &r) const
+{
+    return (r.start() > _start && r.end() < _end);
+}
+
+void
+VMA::sliceRegionRight(Addr slice_addr)
+{
+    if (hasHostBuf()) {
+        auto nonoverlap_len = slice_addr - _start;
+        _hostBufLen = std::min(_hostBufLen, nonoverlap_len);
+    }
+
+    _end = slice_addr - 1;
+
+    CHECK();
+}
+
+void
+VMA::sliceRegionLeft(Addr slice_addr)
+{
+    if (hasHostBuf()) {
+        auto overlap_len = slice_addr - _start + 1;
+
+        if (overlap_len >= _hostBufLen) {
+            _hostBufLen = 0;
+            _hostBuf = nullptr;
+            _origHostBuf = nullptr;
+        } else {
+            _hostBufLen -= overlap_len;
+        }
+
+        _hostBuf += overlap_len;
+    }
+
+    _start = slice_addr + 1;
+
+    CHECK();
+}
+
+void
+VMA::CHECK()
+{
+    /**
+     * Avoid regions without a length.
+     */
+    assert(_start != _end);
+
+    /**
+     * Avoid regions with an end point before the start point
+     */
+    assert(_start < _end);
+
+    /**
+     *  Avoid non-aligned regions; we assume in the code that the
+     *  regions are page aligned so consider this to be a bug.
+     */
+    assert(!(_start % TheISA::PageBytes));
+    assert(!((_end + 1) % TheISA::PageBytes));
+}
diff --git a/src/mem/vma.hh b/src/mem/vma.hh
new file mode 100644
index 0000000..841714d
--- /dev/null
+++ b/src/mem/vma.hh
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2017 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.
+ *
+ * Author: Michael LeBeane
+ */
+
+#ifndef SRC_MEM_VMA_HH
+#define SRC_MEM_VMA_HH
+
+#include "base/addr_range.hh"
+#include "base/mapped_buf.hh"
+#include "base/types.hh"
+#include "mem/se_translating_port_proxy.hh"
+
+class VMA : public AddrRange
+{
+  public:
+    VMA(Addr sa, uint64_t len, int fd, int off)
+        : AddrRange(sa, sa + len - 1), _origHostBuf(nullptr),
+          _hostBuf(nullptr), _hostBufLen(0)
+    {
+        if (fd != -1) {
+ _origHostBuf = std::make_shared<MappedFileBuffer>(fd, len, off);
+            _hostBuf = _origHostBuf->buf;
+            _hostBufLen = _origHostBuf->len;
+        }
+
+        CHECK();
+    }
+
+    /**
+     * Remap the virtual memory area starting at new_start.
+     */
+    void remap(Addr new_start)
+    {
+        _end = new_start + size() - 1;
+        _start = new_start;
+
+        CHECK();
+    }
+
+    /**
+     * Check if the virtual memory area has an equivalent buffer on the
+     * host machine.
+     */
+    bool hasHostBuf() const { return _origHostBuf != nullptr; }
+
+    /**
+     * Copy memory from a buffer which resides on the host machine into a
+     * section of memory on the target.
+     */
+    void fillMemPages(Addr start, Addr size,
+                      SETranslatingPortProxy &port) const;
+
+    /**
+     * Returns true if desired range exists within this virtual memory area
+     * and does not include the start and end addresses.
+     */
+    bool isStrictSuperset(const AddrRange &range) const;
+
+    /**
+     * Remove the address range to the right of slice_addr.
+     */
+    void sliceRegionRight(Addr slice_addr);
+
+    /**
+     * Remove the address range to the left of slice_addr.
+     */
+    void sliceRegionLeft(Addr slice_addr);
+
+  private:
+    void CHECK();
+    /**
+     * The host file backing will be chopped up and reassigned as pages are
+     * mapped, remapped, and unmapped. In addition to the current host
+     * pointer and length, each virtual memory area will also keep a
+ * reference-counted handle to the original host memory. The last virtual
+     * memory area to die cleans up the host memory it handles.
+     */
+    std::shared_ptr<MappedFileBuffer> _origHostBuf;
+
+    /**
+     * Host buffer ptr for this virtual memory area.
+     */
+    char *_hostBuf;
+
+    /**
+     * Length of host buffer for this virtual memory area.
+     */
+    Addr _hostBufLen;
+};
+
+#endif
diff --git a/src/sim/mem_state.hh b/src/sim/mem_state.hh
index a8485c8..b74c3e5 100644
--- a/src/sim/mem_state.hh
+++ b/src/sim/mem_state.hh
@@ -39,6 +39,7 @@

 #include "mem/page_table.hh"
 #include "mem/se_translating_port_proxy.hh"
+#include "mem/vma.hh"
 #include "sim/serialize.hh"

 class Process;
@@ -87,6 +88,14 @@

     const SETranslatingPortProxy& getVirtMem() const { return _virtMem; }

+ void mapVMARegion(Addr start_addr, Addr length, int sim_fd, Addr offset);
+
+    void unmapVMARegion(Addr start_addr, Addr length);
+
+    void remapVMARegion(Addr start_addr, Addr new_start_addr, Addr length);
+
+    void updateBrkRegion(Addr old_brk, Addr new_brk);
+
     /**
* This method returns a flag which specifies the direction of growth for
      * the mmap region in process address space.
@@ -224,6 +233,18 @@
     Addr _endBrkPoint;

     /**
+     * The _vmaList member is 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.
+     */
+    std::list<VMA> _vmaList;
+
+    /**
* The _virtMem member acts as a proxy for accessing virtual memory. This * handle is responsible for reading and writing blobs and strings both to
      * and from the virtual memory space for Process objects.
diff --git a/src/sim/syscall_emul.cc b/src/sim/syscall_emul.cc
index 515da26..0fb4b95 100644
--- a/src/sim/syscall_emul.cc
+++ b/src/sim/syscall_emul.cc
@@ -220,44 +220,20 @@
     auto p = tc->getProcessPtr();
     Addr new_brk = p->getSyscallArg(tc, index);

-    std::shared_ptr<MemState> mem_state = p->memState;
+    auto mem_state = p->memState;
     Addr brk_point = mem_state->getBrkPoint();

     // in Linux at least, brk(0) returns the current break value
// (note that the syscall and the glibc function have different behavior)
-    if (new_brk == 0)
+    if (!new_brk || (new_brk == brk_point))
         return brk_point;

-    if (new_brk > brk_point) {
-        // might need to allocate some new pages
-        for (ChunkGenerator gen(brk_point,
-                                new_brk - brk_point,
-                                PageBytes); !gen.done(); gen.next()) {
-            if (!p->pTable->translate(gen.addr()))
- p->allocateMem(roundDown(gen.addr(), PageBytes), PageBytes);
-
-            // if the address is already there, zero it out
-            else {
-                uint8_t zero = 0;
-                SETranslatingPortProxy &tp = tc->getMemProxy();
-
-                // split non-page aligned accesses
-                Addr next_page = roundUp(gen.addr(), PageBytes);
-                uint32_t size_needed = next_page - gen.addr();
-                tp.memsetBlob(gen.addr(), zero, size_needed);
-                if (gen.addr() + PageBytes > next_page &&
-                    next_page < new_brk &&
-                    p->pTable->translate(next_page)) {
-                    size_needed = PageBytes - size_needed;
-                    tp.memsetBlob(next_page, zero, size_needed);
-                }
-            }
-        }
-    }
-
+    mem_state->updateBrkRegion(brk_point, new_brk);
     mem_state->setBrkPoint(new_brk);
+
     DPRINTF_SYSCALL(Verbose, "brk: break point changed to: %#X\n",
                     mem_state->getBrkPoint());
+
     return mem_state->getBrkPoint();
 }

@@ -340,9 +316,24 @@
 SyscallReturn
 munmapFunc(SyscallDesc *desc, int num, ThreadContext *tc)
 {
-    // With mmap more fully implemented, it might be worthwhile to bite
-    // the bullet and implement munmap. Should allow us to reuse simulated
-    // memory.
+    // Even if the system is currently not capable of recycling physical
+    // pages, there is no reason we can't unmap them so that we trigger
+    // appropriate seg faults when the application mistakenly tries to
+    // access them again.
+    int index = 0;
+    auto p = tc->getProcessPtr();
+    Addr start = p->getSyscallArg(tc, index);
+    uint64_t length = p->getSyscallArg(tc, index);
+
+    if (start & (TheISA::PageBytes - 1) || !length) {
+        return -EINVAL;
+    }
+
+    length = roundUp(length, TheISA::PageBytes);
+
+    auto mem_state = p->memState;
+    mem_state->unmapVMARegion(start, length);
+
     return 0;
 }

diff --git a/src/sim/syscall_emul.hh b/src/sim/syscall_emul.hh
index dfc6ac0..3f61b59 100644
--- a/src/sim/syscall_emul.hh
+++ b/src/sim/syscall_emul.hh
@@ -1076,8 +1076,9 @@

     new_length = roundUp(new_length, TheISA::PageBytes);

+    auto mem_state = process->memState;
+
     if (new_length > old_length) {
-        std::shared_ptr<MemState> mem_state = process->memState;
         Addr mmap_end = mem_state->getMmapEnd();

         if ((start + old_length) == mmap_end &&
@@ -1085,7 +1086,7 @@
             // This case cannot occur when growing downward, as
             // start is greater than or equal to mmap_end.
             uint64_t diff = new_length - old_length;
-            process->allocateMem(mmap_end, diff);
+            mem_state->mapVMARegion(mmap_end, diff, -1, 0);
             mem_state->setMmapEnd(mmap_end + diff);
             return start;
         } else {
@@ -1095,38 +1096,44 @@
             } else {
                 uint64_t new_start = provided_address;
                 if (!use_provided_address) {
-                    new_start = process->mmapGrowsDown() ?
+                    new_start = mem_state->mmapGrowsDown() ?
                                 mmap_end - new_length : mmap_end;
-                    mmap_end = process->mmapGrowsDown() ?
+                    mmap_end = mem_state->mmapGrowsDown() ?
                                new_start : mmap_end + new_length;
                     mem_state->setMmapEnd(mmap_end);
                 }

-                process->pTable->remap(start, old_length, new_start);
                 warn("mremapping to new vaddr %08p-%08p, adding %d\n",
                      new_start, new_start + new_length,
                      new_length - old_length);
+
                 // add on the remaining unallocated pages
-                process->allocateMem(new_start + old_length,
+                mem_state->allocateMem(new_start + old_length,
                                      new_length - old_length,
                                      use_provided_address /* clobber */);
+
                 if (use_provided_address &&
                     ((new_start + new_length > mem_state->getMmapEnd() &&
-                      !process->mmapGrowsDown()) ||
+                      !mem_state->mmapGrowsDown()) ||
                     (new_start < mem_state->getMmapEnd() &&
-                      process->mmapGrowsDown()))) {
+                      mem_state->mmapGrowsDown()))) {
// something fishy going on here, at least notify the user
                     // @todo: increase mmap_end?
                     warn("mmap region limit exceeded with MREMAP_FIXED\n");
                 }
                 warn("returning %08p as start\n", new_start);
+                mem_state->remapVMARegion(start, new_start, old_length);
+                mem_state->mapVMARegion(new_start, new_length, -1, 0);
                 return new_start;
             }
         }
     } else {
+        // Shrink a region
         if (use_provided_address && provided_address != start)
-            process->pTable->remap(start, new_length, provided_address);
- process->pTable->unmap(start + new_length, old_length - new_length);
+            mem_state->remapVMARegion(start, provided_address, new_length);
+        if (new_length != old_length)
+            mem_state->unmapVMARegion(start + new_length,
+                                      old_length - new_length);
         return use_provided_address ? provided_address : start;
     }
 }
@@ -1683,26 +1690,28 @@
     }

     if ((prot & PROT_WRITE) && (tgt_flags & OS::TGT_MAP_SHARED)) {
-        // With shared mmaps, there are two cases to consider:
- // 1) anonymous: writes should modify the mapping and this should be
-        // visible to observers who share the mapping. Currently, it's
-        // difficult to update the shared mapping because there's no
-        // structure which maintains information about the which virtual
-        // memory areas are shared. If that structure existed, it would be
-        // possible to make the translations point to the same frames.
-        // 2) file-backed: writes should modify the mapping and the file
- // which is backed by the mapping. The shared mapping problem is the
-        // same as what was mentioned about the anonymous mappings. For
-        // file-backed mappings, the writes to the file are difficult
-        // because it requires syncing what the mapping holds with the file
-        // that resides on the host system. So, any write on a real system
-        // would cause the change to be propagated to the file mapping at
-        // some point in the future (the inode is tracked along with the
-        // mapping). This isn't guaranteed to always happen, but it usually
-        // works well enough. The guarantee is provided by the msync system
- // call. We could force the change through with shared mappings with
-        // a call to msync, but that again would require more information
-        // than we currently maintain.
+        /**
+         * With shared mmaps, there are two cases to consider:
+ * 1) anonymous: writes should modify the mapping and this should be
+         * visible to observers who share the mapping. Currently, it's
+         * difficult to update the shared mapping because there's no
+         * structure which maintains information about the which virtual
+         * memory areas are shared. If that structure existed, it would be
+         * possible to make the translations point to the same frames.
+         * 2) file-backed: writes should modify the mapping and the file
+ * which is backed by the mapping. The shared mapping problem is the
+         * same as what was mentioned about the anonymous mappings. For
+         * file-backed mappings, the writes to the file are difficult
+         * because it requires syncing what the mapping holds with the file
+         * that resides on the host system. So, any write on a real system
+         * would cause the change to be propagated to the file mapping at
+         * some point in the future (the inode is tracked along with the
+         * mapping). This isn't guaranteed to always happen, but it usually
+         * works well enough. The guarantee is provided by the msync system
+ * call. We could force the change through with shared mappings with
+         * a call to msync, but that again would require more information
+         * than we currently maintain.
+         */
         warn("mmap: writing to shared mmap region is currently "
              "unsupported. The write succeeds on the target, but it "
              "will not be propagated to the host or shared mappings");
@@ -1711,7 +1720,6 @@
     length = roundUp(length, TheISA::PageBytes);

     int sim_fd = -1;
-    uint8_t *pmap = nullptr;
     if (!(tgt_flags & OS::TGT_MAP_ANONYMOUS)) {
         std::shared_ptr<FDEntry> fdep = (*p->fds)[tgt_fd];

@@ -1727,86 +1735,14 @@
             return -EBADF;
         sim_fd = ffdp->getSimFD();

- pmap = (decltype(pmap))mmap(nullptr, length, PROT_READ, MAP_PRIVATE,
-                                    sim_fd, offset);
-
-        if (pmap == (decltype(pmap))-1) {
-            warn("mmap: failed to map file into host address space");
-            return -errno;
-        }
-    }
-
-    // Extend global mmap region if necessary. Note that we ignore the
-    // start address unless MAP_FIXED is specified.
-    if (!(tgt_flags & OS::TGT_MAP_FIXED)) {
-        std::shared_ptr<MemState> mem_state = p->memState;
-        Addr mmap_end = mem_state->getMmapEnd();
-
-        start = p->mmapGrowsDown() ? mmap_end - length : mmap_end;
-        mmap_end = p->mmapGrowsDown() ? start : mmap_end + length;
-
-        mem_state->setMmapEnd(mmap_end);
-    }
-
-    DPRINTF_SYSCALL(Verbose, " mmap range is 0x%x - 0x%x\n",
-                    start, start + length - 1);
-
-    // We only allow mappings to overwrite existing mappings if
-    // TGT_MAP_FIXED is set. Otherwise it shouldn't be a problem
-    // because we ignore the start hint if TGT_MAP_FIXED is not set.
-    int clobber = tgt_flags & OS::TGT_MAP_FIXED;
-    if (clobber) {
-        for (auto tc : p->system->threadContexts) {
-            // If we might be overwriting old mappings, we need to
-            // invalidate potentially stale mappings out of the TLBs.
-            tc->getDTBPtr()->flushAll();
-            tc->getITBPtr()->flushAll();
-        }
-    }
-
-    // Allocate physical memory and map it in. If the page table is already
-    // mapped and clobber is not set, the simulator will issue throw a
-    // fatal and bail out of the simulation.
-    p->allocateMem(start, length, clobber);
-
-    // Transfer content into target address space.
-    SETranslatingPortProxy &tp = tc->getMemProxy();
-    if (tgt_flags & OS::TGT_MAP_ANONYMOUS) {
- // In general, we should zero the mapped area for anonymous mappings,
-        // with something like:
-        //     tp.memsetBlob(start, 0, length);
-        // However, given that we don't support sparse mappings, and
-        // some applications can map a couple of gigabytes of space
-        // (intending sparse usage), that can get painfully expensive.
-        // Fortunately, since we don't properly implement munmap either,
-        // there's no danger of remapping used memory, so for now all
-        // newly mapped memory should already be zeroed so we can skip it.
-    } else {
-        // It is possible to mmap an area larger than a file, however
-        // accessing unmapped portions the system triggers a "Bus error"
-        // on the host. We must know when to stop copying the file from
-        // the host into the target address space.
-        struct stat file_stat;
-        if (fstat(sim_fd, &file_stat) > 0)
-            fatal("mmap: cannot stat file");
-
-        // Copy the portion of the file that is resident. This requires
-        // checking both the mmap size and the filesize that we are
-        // trying to mmap into this space; the mmap size also depends
-        // on the specified offset into the file.
-        uint64_t size = std::min((uint64_t)file_stat.st_size - offset,
-                                 length);
-        tp.writeBlob(start, pmap, size);
-
-        // Cleanup the mmap region before exiting this function.
-        munmap(pmap, length);
-
-        // Maintain the symbol table for dynamic executables.
-        // The loader will call mmap to map the images into its address
-        // space and we intercept that here. We can verify that we are
- // executing inside the loader by checking the program counter value. - // XXX: with multiprogrammed workloads or multi-node configurations,
-        // this will not work since there is a single global symbol table.
+        /**
+         * Maintain the symbol table for dynamic executables.
+         * The loader will call mmap to map the images into its address
+         * space and we intercept that here. We can verify that we are
+ * executing inside the loader by checking the program counter value. + * XXX: with multiprogrammed workloads or multi-node configurations,
+         * this will not work since there is a single global symbol table.
+         */
         ObjectFile *interpreter = p->getInterpreter();
         if (interpreter) {
             Addr text_start = interpreter->textBase();
@@ -1815,8 +1751,6 @@
             Addr pc = tc->pcState().pc();

             if (pc >= text_start && pc < text_end) {
-                std::shared_ptr<FDEntry> fdep = (*p->fds)[tgt_fd];
-                auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep);
                 ObjectFile *lib = createObjectFile(ffdp->getFileName());

                 if (lib) {
@@ -1825,12 +1759,44 @@
                 }
             }
         }
-
-        // Note that we do not zero out the remainder of the mapping. This
-        // is done by a real system, but it probably will not affect
-        // execution (hopefully).
     }

+    auto mem_state = p->memState;
+
+    /**
+ * Extend global mmap region if necessary. Note that we ignore the start
+     * address unless MAP_FIXED is specified.
+     */
+    if (!(tgt_flags & OS::TGT_MAP_FIXED)) {
+        start = mem_state->mmapGrowsDown() ?
+                mem_state->getMmapEnd() - length :
+                mem_state->getMmapEnd();
+        mem_state->setMmapEnd(mem_state->mmapGrowsDown() ? start :
+                              mem_state->getMmapEnd() + length);
+    }
+
+    DPRINTF_SYSCALL(Verbose, " mmap range is 0x%x - 0x%x\n",
+                    start, start + length - 1);
+
+    /**
+     * We only allow mappings to overwrite existing mappings if
+     * TGT_MAP_FIXED is set. Otherwise it shouldn't be a problem
+     * because we ignore the start hint if TGT_MAP_FIXED is not set.
+     */
+    if (tgt_flags & OS::TGT_MAP_FIXED) {
+        /**
+         * We might already have some old VMAs mapped to this region, so
+         * make sure to clear em out!
+         */
+        mem_state->unmapVMARegion(start, length);
+    }
+
+    /**
+     * Setup the correct VMA for this region.  The physical pages will be
+     * mapped lazily.
+     */
+    mem_state->mapVMARegion(start, length, sim_fd, offset);
+
     return start;
 }


--
To view, visit https://gem5-review.googlesource.com/c/public/gem5/+/12307
To unsubscribe, or for help writing mail filters, visit https://gem5-review.googlesource.com/settings

Gerrit-Project: public/gem5
Gerrit-Branch: master
Gerrit-Change-Id: I2caa0f3c9622d810474ea1b1ad717820b2de9437
Gerrit-Change-Number: 12307
Gerrit-PatchSet: 1
Gerrit-Owner: Brandon Potter <[email protected]>
Gerrit-MessageType: newchange
_______________________________________________
gem5-dev mailing list
[email protected]
http://m5sim.org/mailman/listinfo/gem5-dev

Reply via email to