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

Change subject: sim-se,tests: Add Region class and basic tests
......................................................................

sim-se,tests: Add Region class and basic tests

The Region class encapsulates address information for regions
of the process address space. For instance, it can be used
to represent the stack, data, and heap areas.

Change-Id: Ib8c1616c7a63392cac1d8fc9f14ed0c141755cf7
---
M src/sim/SConscript
A src/sim/region.cc
A src/sim/region.hh
A src/sim/region.test.cc
4 files changed, 559 insertions(+), 0 deletions(-)



diff --git a/src/sim/SConscript b/src/sim/SConscript
index aacdb34..d35787f 100644
--- a/src/sim/SConscript
+++ b/src/sim/SConscript
@@ -89,6 +89,8 @@
     Source('pseudo_inst.cc')
     Source('syscall_emul.cc')
     Source('syscall_desc.cc')
+    Source('region.cc')
+    GTest('region.test', 'region.test.cc', 'region.cc')

 if env['TARGET_ISA'] != 'x86':
     Source('microcode_rom.cc')
diff --git a/src/sim/region.cc b/src/sim/region.cc
new file mode 100644
index 0000000..79095fd
--- /dev/null
+++ b/src/sim/region.cc
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2019 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: Brandon Potter
+ */
+
+#include "sim/region.hh"
+
+#include <cassert>
+#include <functional>
+
+Region::Region()
+{
+    _valid = false;
+}
+
+Region::Region(Addr b, Addr c, Addr m, Addr p)
+    : _max(m), _pagesize(p)
+{
+    /**
+     * The interface expects base and cursor to be page aligned.
+     */
+    if (b % _pagesize || c % _pagesize)
+        _valid = false;
+
+    /**
+     * The interface expects base and cursor to be different values.
+     * If the values are the same, the class cannot know which direction
+     * the region should expand.
+     */
+    if (b == c)
+        _valid = false;
+
+    /**
+     * Determine which direction the region should expand.
+     */
+    _up = c > b;
+
+    /**
+     * Normalize the start and end addresses for the AddrRange class.
+ * Note: this does not alter either Region::base or Region::cursor since
+     * b and c are just temporaries on the call stack.
+     */
+    if (!_up)
+        std::swap(b, c);
+
+    _range = std::unique_ptr<AddrRange>(new AddrRange(b, c));
+}
+
+Region::Region(const Region& other)
+{
+    _up = other._up;
+    _max = other._max;
+    _range = std::unique_ptr<AddrRange>(new AddrRange(*other._range));
+    _valid = other._valid;
+    _pagesize = other._pagesize;
+}
+
+Region&
+Region::operator=(Region other)
+{
+    swap(*this, other);
+    return *this;
+}
+
+void
+swap(Region &l, Region &r)
+{
+    std::swap(l._up, r._up);
+    std::swap(l._max, r._max);
+    std::swap(l._range, r._range);
+    std::swap(l._valid, r._valid);
+    std::swap(l._pagesize, r._pagesize);
+}
+
+Addr
+Region::base() const
+{
+    return _up ? _range->start() : _range->end();
+}
+
+void
+Region::base(Addr b)
+{
+    Region temp(b, cursor(), _max, _pagesize);
+    swap(*this, temp);
+}
+
+Addr
+Region::cursor() const
+{
+    return _up ? _range->end() : _range->start();
+}
+
+void
+Region::cursor(Addr c)
+{
+    Region temp(base(), c, _max, _pagesize);
+    swap(*this, temp);
+}
+
+Addr
+Region::size() const
+{
+    return _range->size();
+}
+
+Addr
+Region::max() const
+{
+    return _max;
+}
+
+bool
+Region::max(Addr m)
+{
+    /**
+     * Avoid setting max when the current allocation size exceeds it.
+     * There's no clear way to reduce the size in the case since the
+     * application already has the memory.
+     */
+    if (size() > m)
+        return false;
+
+    Region temp(base(), cursor(), m, _pagesize);
+    swap(*this, temp);
+    return true;
+}
+
+bool
+Region::expand(long unsigned num_pages)
+{
+    assert(_valid);
+
+    Addr requested_pages = num_pages * _pagesize;
+
+    /**
+     * Check that the expansion does not exceed the max. If it does
+     * exceed the max, return a failure here to pass the problem
+     * up to the requester.
+     */
+    if (size() + requested_pages > max())
+        return false;
+
+    /**
+     * Figure out which operation needs to be used to adjust the
+     * cursor address. The operation depends on which direction
+     * the region is expanding.
+     */
+    std::function<Addr (Addr, Addr)> operation;
+    if (_up)
+        operation = std::plus<Addr>();
+    else
+        operation = std::minus<Addr>();
+
+    /**
+     * Modify the cursor to expand address range.
+     */
+    cursor(operation(cursor(), requested_pages));
+    return true;
+}
+
+bool
+Region::contract(long unsigned num_pages)
+{
+    assert(_valid);
+
+    Addr released_pages = num_pages * _pagesize;
+
+    /**
+     * Check that the reduction does not exceed the region size. If it
+     * does exceed the region size, return a failure here to pass the
+     * problem up to the requester.
+     */
+    if (released_pages > size())
+        return false;
+
+    /**
+     * Figure out which operation needs to be used to adjust the
+     * cursor address. The operation depends on which direction
+     * the region is shrinking.
+     */
+    std::function<Addr (Addr, Addr)> operation;
+    if (_up)
+        operation = std::minus<Addr>();
+    else
+        operation = std::plus<Addr>();
+
+    /**
+     * Modify the cursor to shrink address range.
+     */
+    cursor(operation(cursor(), released_pages));
+    return true;
+}
+
+bool
+Region::valid() const
+{
+    return _valid;
+}
diff --git a/src/sim/region.hh b/src/sim/region.hh
new file mode 100644
index 0000000..593f406
--- /dev/null
+++ b/src/sim/region.hh
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2019 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: Brandon Potter
+ */
+
+#ifndef SRC_SIM_REGION_HH
+#define SRC_SIM_REGION_HH
+
+#include <memory>
+
+#include "base/addr_range.hh"
+#include "base/types.hh"
+
+class AddrRange;
+
+class Region
+{
+  public:
+    Region();
+    Region(Addr base, Addr cursor, Addr max = MaxAddr,
+           Addr pagesize = 0x1000);
+    Region(const Region&);
+    Region& operator=(Region);
+    friend void swap(Region&, Region&);
+
+    /**
+     * Get starting address.
+     *
+     * @return First byte of region.
+     */
+    Addr base() const;
+
+    /**
+     * Get current end of region (byte address).
+     *
+     * The byte address changes during program execution.
+     *
+     * @return Current end of region (byte address).
+     */
+    Addr cursor() const;
+
+    /**
+     * Get region's current size.
+     *
+     * @return Total bytes in current region.
+     */
+    Addr size() const;
+
+    /**
+     * Get maximum size of region.
+     *
+     * The operating system may set a limit on region growth.
+     * For example, `ulimit` on Linux.
+     *
+     * @return Maximum bytes in region.
+     */
+    Addr max() const;
+
+    /**
+     * Set maximum size of region.
+     *
+     * The operating system may set a limit on stack region growth.
+     * For example, `ulimit -s` on Linux.
+     *
+     * @param max Maximum bytes in stack region.
+     */
+    bool max(Addr max);
+
+    /**
+     * Expand region in its growth direction.
+     *
+     * The expansion occurs in page increments.
+     * @param num_pages The number of pages to extend the region.
+     */
+    bool expand(long unsigned num_pages);
+
+    /**
+     * Shrink region against its growth direction.
+     *
+     * The contraction occurs in page increments.
+     * @param num_pages The number of pages to shrink the region.
+     */
+    bool contract(long unsigned num_pages);
+
+    /**
+     * Get valid field.
+     *
+     * @return Boolean value which reports initialization status.
+     */
+    bool valid() const;
+
+    /**
+     * Determine if region contains address.
+     *
+     * @param a Address to check.
+     * @return true if address is in region.
+     */
+    bool contains(const Addr& a) const
+    {
+        return a >= base() && a < cursor();
+    }
+
+  private:
+    /**
+     * Set starting address.
+     *
+     * @param base First byte of region.
+     */
+    void base(Addr base);
+
+    /**
+     * Set current end of region (byte address).
+     *
+     * The byte address changes during program execution.
+     *
+     * @param cursor Current end of region (byte address).
+     */
+    void cursor(Addr cursor);
+
+  private:
+    /**
+     * Region is adaptor for AddrRange.
+     * AddrRange provides extra interfaces which are not necessary to
+     * create a region abstraction.
+     */
+    std::unique_ptr<AddrRange> _range;
+
+    /**
+     * Maximum number of bytes a region can hold.
+     * Most region are unlimited by default.
+     */
+    Addr _max;
+
+    /**
+     * Size in bytes of a page size for the system.
+     */
+    Addr _pagesize;
+
+    /**
+     * Records errors during initialization.
+     */
+    bool _valid = true;
+
+    /**
+     * Store region's growth direction inside address space.
+     */
+    bool _up;
+
+};
+
+#endif
diff --git a/src/sim/region.test.cc b/src/sim/region.test.cc
new file mode 100644
index 0000000..13d3ef0
--- /dev/null
+++ b/src/sim/region.test.cc
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2019 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: Brandon Potter
+ */
+
+#include <gtest/gtest.h>
+
+#include "sim/region.hh"
+
+/**
+ * The following tests check the Region class.
+ * Region objects hold information about process address space mappings.
+ * These objects can be found throughout the syscall emulation source code.
+ */
+
+TEST(RegionTest, EmptyRegion)
+{
+    Region empty(0x0, 0x0);
+    EXPECT_FALSE(empty.valid());
+}
+
+TEST(RegionTest, UnalignedRegion)
+{
+    Region reg(0x0D00, 0x7482);
+    EXPECT_FALSE(reg.valid());
+}
+
+TEST(RegionTest, ExpandByPage)
+{
+    Region reg(0x1000, 0x2000);
+    EXPECT_EQ(reg.cursor(), 0x2000);
+    EXPECT_TRUE(reg.expand(1));
+    EXPECT_EQ(reg.cursor(), 0x3000);
+}
+
+TEST(RegionTest, ExpandMultiplePages)
+{
+    Region reg(0x1000, 0x2000);
+    EXPECT_EQ(reg.cursor(), 0x2000);
+    EXPECT_TRUE(reg.expand(4));
+    EXPECT_EQ(reg.cursor(), 0x6000);
+}
+
+TEST(RegionTest, ExpandTooMuch)
+{
+    Region reg(0x1000, 0x2000, 0x7000);
+    EXPECT_FALSE(reg.expand(7));
+    EXPECT_EQ(reg.cursor(), 0x2000);
+}
+
+TEST(RegionTest, ContractPage)
+{
+    Region reg(0x1000, 0x2000);
+    EXPECT_EQ(reg.cursor(), 0x2000);
+    EXPECT_TRUE(reg.contract(1));
+
+    // The region should be empty.
+    EXPECT_EQ(reg.cursor(), reg.base());
+    EXPECT_FALSE(reg.valid());
+}
+
+TEST(RegionTest, ContractMultiplePages)
+{
+    Region reg(0x1000, 0x4000);
+    EXPECT_EQ(reg.cursor(), 0x4000);
+    EXPECT_TRUE(reg.contract(2));
+    EXPECT_EQ(reg.cursor(), 0x2000);
+}
+
+TEST(RegionTest, ContractTooMuch)
+{
+    Region reg(0x1000, 0x2000);
+    EXPECT_FALSE(reg.contract(2));
+    EXPECT_EQ(reg.cursor(), 0x2000);
+}
+
+TEST(RegionTest, SetMax)
+{
+    Region reg(0x1000, 0x2000, 0x4000);
+    EXPECT_TRUE(reg.max(0x6000));
+    EXPECT_EQ(reg.max(), 0x6000);
+}
+
+TEST(RegionTest, SetMaxLessThanCurrentSize)
+{
+    Region reg(0x0, 0x4000);
+    EXPECT_FALSE(reg.max(0x2000));
+    EXPECT_EQ(reg.max(), MaxAddr);
+}
+
+TEST(RegionTest, ContainsAddrAtBase)
+{
+    Region reg(0x0, 0x1000);
+    EXPECT_TRUE(reg.contains(reg.base()));
+}
+
+TEST(RegionTest, ContainsAddrAtCursor)
+{
+    Region reg(0x0, 0x1000);
+    EXPECT_FALSE(reg.contains(reg.cursor()));
+}
+
+TEST(RegionTest, ContainsAddrInRegion)
+{
+    Region reg(0x0, 0x1000);
+    EXPECT_TRUE(reg.contains(0xCAB));
+}
+
+TEST(RegionTest, X8664Stack)
+{
+    Region stack(0x7FFFFFFFF000, 0x7FFFFFFFE000, 0x800000);
+    EXPECT_EQ(0x7FFFFFFFF000, stack.base());
+    EXPECT_EQ(0x7FFFFFFFE000, stack.cursor());
+    EXPECT_EQ(0x800000, stack.max());
+    EXPECT_EQ(0x1000, stack.size());
+
+    EXPECT_TRUE(stack.expand(31));
+    EXPECT_EQ(stack.cursor(), 0x7FFFFFFDF000);
+    EXPECT_EQ(stack.size(), 0x20000);
+
+    EXPECT_TRUE(stack.contract(1));
+    EXPECT_EQ(stack.cursor(), 0x7FFFFFFE0000);
+    EXPECT_EQ(stack.size(), 0x1F000);
+
+    EXPECT_FALSE(stack.expand(1000000));
+    EXPECT_EQ(stack.cursor(), 0x7FFFFFFE0000);
+    EXPECT_EQ(stack.size(), 0x1F000);
+
+    EXPECT_FALSE(stack.contract(40));
+    EXPECT_EQ(stack.cursor(), 0x7FFFFFFE0000);
+    EXPECT_EQ(stack.size(), 0x1F000);
+}

--
To view, visit https://gem5-review.googlesource.com/c/public/gem5/+/23143
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: Ib8c1616c7a63392cac1d8fc9f14ed0c141755cf7
Gerrit-Change-Number: 23143
Gerrit-PatchSet: 1
Gerrit-Owner: Brandon Potter <brandon.pot...@amd.com>
Gerrit-MessageType: newchange
_______________________________________________
gem5-dev mailing list
gem5-dev@gem5.org
http://m5sim.org/mailman/listinfo/gem5-dev

Reply via email to