/* * Copyright (c) 2004-2005 The Regents of The University of Michigan * 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 __SIM_PROXY_PTR_HH__ #define __SIM_PROXY_PTR_HH__ #include #include #include #include "base/logging.hh" #include "base/types.hh" #include "sim/guest_abi.hh" namespace gem5 { template class ProxyPtrBuffer { private: std::shared_ptr proxy; Addr ptr; size_t size; std::unique_ptr data; bool dirty = false; void markClean() { dirty = false; } public: std::shared_ptr getProxy() const { return proxy; } void markDirty() { dirty = true; } bool isDirty() { return dirty; } template T & as() { assert(sizeof(T) <= size); markDirty(); return *reinterpret_cast(data.get()); } template const T & asConst() const { assert(sizeof(T) <= size); return *reinterpret_cast(data.get()); } void flush(bool force=false) { if (force || isDirty()) { proxy->writeBlob(ptr, data.get(), size); markClean(); } } void load() { panic_if(isDirty(), "Overwriting dirty ProxyPtr."); proxy->readBlob(ptr, data.get(), size); } Addr addr() const { return ptr; } ProxyPtrBuffer(std::shared_ptr _proxy, Addr _ptr, size_t _size) : proxy(_proxy), ptr(_ptr), size(_size), data(new uint8_t[_size]) { load(); } ~ProxyPtrBuffer() { flush(); } }; template class ConstProxyPtr { protected: std::shared_ptr proxy; std::shared_ptr> buffer; template friend class ProxyPtr; void nullCheck() const { panic_if(!buffer, "Accessing null ProxyPtr."); } void setAddr(Addr ptr) { if (ptr) buffer.reset(new ProxyPtrBuffer(proxy, ptr, sizeof(T))); else buffer.reset((ProxyPtrBuffer *)nullptr); } ConstProxyPtr(Addr _ptr, std::shared_ptr _proxy) : proxy(_proxy) { setAddr(_ptr); } using CPP = ConstProxyPtr; public: using Type = T; template , int> = 0> explicit ConstProxyPtr(Addr _ptr, Args&&... args) : proxy(std::make_shared(args...)) { setAddr(_ptr); } template , int> = 0> explicit ConstProxyPtr(Args&&... args) : proxy(std::make_shared(args...)) { setAddr(0); } template >> ConstProxyPtr(const ConstProxyPtr &other) : proxy(other.proxy), buffer(other.buffer) {} ConstProxyPtr(const CPP &other) : proxy(other.proxy), buffer(other.buffer) {} void load() { nullCheck(); buffer->load(); } Addr addr() const { return buffer ? buffer->addr() : 0; } operator bool() const { return (bool)buffer; } template typename std::enable_if_t, CPP> operator + (A a) const { return CPP(addr() + a * sizeof(T), proxy); } template typename std::enable_if_t, CPP> operator - (A a) const { return CPP(addr() - a * sizeof(T), proxy); } ptrdiff_t operator - (const CPP &other) const { return (addr() - other.addr()) / sizeof(T); } CPP & operator = (const CPP &other) { proxy = other.proxy; buffer = other.buffer; return *this; } CPP & operator = (const Addr &a) { setAddr(a); return *this; } operator const T *() const { return buffer ? &buffer->template asConst() : nullptr; } const T & operator *() const { nullCheck(); return buffer->template asConst(); } const T * operator ->() const { nullCheck(); return &buffer->template asConst(); } }; template typename std::enable_if_t, ConstProxyPtr> operator + (A a, const ConstProxyPtr &other) { return other + a; } template class ProxyPtr : public ConstProxyPtr { protected: using CPP = ConstProxyPtr; using PP = ProxyPtr; ProxyPtr(Addr _ptr, std::shared_ptr _proxy) : CPP(_ptr, _proxy) {} public: template , int> = 0> explicit ProxyPtr(Addr _ptr, Args&&... args) : CPP(_ptr, args...) {} template , int> = 0> explicit ProxyPtr(Args&&... args) : CPP(0, args...) {} template && !std::is_same_v>> ProxyPtr(const ProxyPtr &other) : CPP(other) {} ProxyPtr(const PP &other) : CPP(other) {} operator bool() const { return (bool)this->buffer; } void flush(bool force=false) { this->nullCheck(); this->buffer->flush(force); } template typename std::enable_if_t, PP> operator + (A a) const { return PP(this->addr() + a * sizeof(T), this->proxy); } template typename std::enable_if_t, PP> operator - (A a) const { return PP(this->addr() - a * sizeof(T), this->proxy); } ptrdiff_t operator - (const PP &other) const { return (this->addr() - other.addr()) / sizeof(T); } PP & operator = (const PP &other) { this->proxy = other.proxy; this->buffer = other.buffer; return *this; } PP & operator = (const Addr &a) { this->setAddr(a); return *this; } using CPP::operator const T *; operator T *() const { return this->buffer ? &this->buffer->template as() : nullptr; } using CPP::operator *; T & operator *() const { this->nullCheck(); return this->buffer->template as(); } using CPP::operator ->; T * operator ->() const { this->nullCheck(); return &this->buffer->template as(); } }; template class ProxyPtr { protected: Addr _addr; public: ProxyPtr(Addr new_addr, ...) : _addr(new_addr) {} template ProxyPtr(const ProxyPtr &other) : _addr(other.addr()) {} ProxyPtr & operator = (Addr new_addr) { _addr = new_addr; return *this; } operator Addr() const { return _addr; } Addr addr() const { return _addr; } }; template typename std::enable_if_t, ProxyPtr> operator + (A a, const ProxyPtr &other) { return other + a; } namespace guest_abi { template struct Argument> { static ProxyPtr get(ThreadContext *tc, typename ABI::State &state) { return ProxyPtr( Argument::get(tc, state), tc); } }; template struct Argument> { static ConstProxyPtr get(ThreadContext *tc, typename ABI::State &state) { return ConstProxyPtr( Argument::get(tc, state), tc); } }; } // namespace guest_abi template std::ostream & operator << (std::ostream &os, const ConstProxyPtr &vptr) { ccprintf(os, "%#x", vptr.addr()); return os; } class SETranslatingPortProxy; template using ConstVPtr = ConstProxyPtr; template using VPtr = ProxyPtr; } // namespace gem5 #endif // __SIM_PROXY_PTR_HH__