Gabe Black has uploaded this change for review. ( https://gem5-review.googlesource.com/c/public/gem5/+/50758 )

Change subject: mem: Add a translation gen helper class.
......................................................................

mem: Add a translation gen helper class.

This class helps translate a region of memory one chunk at a time. The
generator returns an iterator through its begin and end methods which
can be used as part of a regular for loop, or as part of a range based
for loop. The iterator points to a Range object which holds the virtual
and physical address of the translation, the size of the region included
in the translation, and a Fault if the translation of that chunk
faulted.

When incrementing the iterator, if there was no fault it simply moves
ahead to the next region and attempts to translate it using a virtual
method implemented by subclasses. It's up to the subclass to determine
if there is now a fault, how many bytes have been translated if, for
instance, the page size is variable, and what the translated physical
address is.

If there was a fault, the iterator does not increment, it just clears
the fault and tries the previous translation again. This gives consumers
of the translation generator a chance to fix up faulting addresses
without having to abort the whole process and try again. This might be
useful if, for instance, you've reached the end of the stack and a new
page needs to be demand-paged in.

Change-Id: I8c4023845d989fe3781b1b73ab12f7c8855c9171
---
A src/mem/translation_gen.hh
1 file changed, 192 insertions(+), 0 deletions(-)



diff --git a/src/mem/translation_gen.hh b/src/mem/translation_gen.hh
new file mode 100644
index 0000000..36aea2c
--- /dev/null
+++ b/src/mem/translation_gen.hh
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2021 Google Inc.
+ *
+ * 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 __MEM_TRANSLATION_GEN_HH__
+#define __MEM_TRANSLATION_GEN_HH__
+
+#include <iterator>
+#include <memory>
+
+#include "base/types.hh"
+#include "sim/faults.hh"
+
+namespace gem5
+{
+
+class TranslationGenConstIterator;
+
+class TranslationGen
+{
+  public:
+    struct Range
+    {
+        Addr vaddr;
+        Addr size = 0;
+
+        Addr paddr = 0;
+        Fault fault = NoFault;
+
+        bool
+        operator == (const Range &other) const
+        {
+            return other.vaddr == vaddr && other.size == size &&
+                other.paddr == paddr && other.fault == fault;
+        }
+    };
+
+  protected:
+    virtual void translate(Range &range) const = 0;
+
+    Addr _start;
+    Addr _size;
+
+  public:
+    TranslationGen(Addr new_start, Addr new_size) :
+        _start(new_start), _size(new_size)
+    {}
+    virtual ~TranslationGen() {}
+
+    Addr start() const { return _start; }
+    Addr size() const { return _size; }
+
+    friend class TranslationGenConstIterator;
+    using const_iterator = TranslationGenConstIterator;
+
+    inline const_iterator begin() const;
+    inline const_iterator end() const;
+};
+
+using TranslationGenPtr = std::unique_ptr<TranslationGen>;
+
+class TranslationGenConstIterator
+{
+  private:
+    TranslationGen::Range current = {0};
+    const TranslationGen *gen = nullptr;
+    bool end = true;
+
+    friend class TranslationGen;
+
+    TranslationGenConstIterator() {}
+    TranslationGenConstIterator(const TranslationGen *parent, Addr start) :
+        current{start}, gen(parent), end(false)
+    {}
+
+    bool
+    done()
+    {
+        assert(gen);
+        return current.vaddr >= gen->start() + gen->size();
+    }
+
+  public:
+    using value_type = TranslationGen::Range;
+    using reference = const value_type &;
+    using pointer = const value_type *;
+    using iterator_category = std::forward_iterator_tag;
+
+    TranslationGenConstIterator(const TranslationGenConstIterator &other) :
+        current(other.current), gen(other.gen)
+    {}
+
+    TranslationGenConstIterator &
+    operator = (const TranslationGenConstIterator &other)
+    {
+        gen = other.gen;
+        current = other.current;
+        return *this;
+    }
+
+    reference operator * () { return current; }
+    pointer operator -> () { return &current; }
+
+    TranslationGenConstIterator &
+    operator ++ ()
+    {
+        panic_if(end, "Can't increment end iterator.");
+        assert(gen);
+
+        if (current.fault == NoFault) {
+            // If the last translation was successful, move forward.
+            current.vaddr += current.size;
+        } else {
+            // If not, clear out the fault and try again, assuming the
+            // caller has fixed whatever the problem was.
+            current.fault = NoFault;
+        }
+
+        current.paddr = 0;
+        // Set the size to however much is left, aka the maximum.
+        current.size = gen->size() - (current.vaddr - gen->start());
+
+        if (current.size == 0) {
+            // Transform into the end iterator.
+            end = true;
+            current.vaddr = 0;
+            gen = nullptr;
+        } else {
+            gen->translate(current);
+        }
+        return *this;
+    }
+
+    TranslationGenConstIterator
+    operator ++ (int)
+    {
+        const auto orig(*this);
+        ++*this;
+        return orig;
+    }
+
+    bool
+    operator == (const TranslationGenConstIterator &other) const
+    {
+        return other.gen == gen && other.current == current;
+    }
+
+    bool
+    operator != (const TranslationGenConstIterator &other) const
+    {
+        return !(*this == other);
+    }
+};
+
+TranslationGenConstIterator
+TranslationGen::begin() const
+{
+    return const_iterator(this, start());
+}
+
+TranslationGenConstIterator
+TranslationGen::end() const
+{
+    return const_iterator();
+}
+
+} // namespace gem5
+
+#endif // __MEM_TRANSLATION_GEN_HH__

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

Gerrit-Project: public/gem5
Gerrit-Branch: develop
Gerrit-Change-Id: I8c4023845d989fe3781b1b73ab12f7c8855c9171
Gerrit-Change-Number: 50758
Gerrit-PatchSet: 1
Gerrit-Owner: Gabe Black <[email protected]>
Gerrit-MessageType: newchange
_______________________________________________
gem5-dev mailing list -- [email protected]
To unsubscribe send an email to [email protected]
%(web_page_url)slistinfo%(cgiext)s/%(_internal_name)s

Reply via email to