/* * Copyright (c) 2020 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall * not be construed as granting a license to any other intellectual * property including but not limited to intellectual property relating * to a hardware implementation of the functionality of the software * licensed hereunder. You may use the software subject to the license * terms below provided that you ensure that this notice is replicated * unmodified and in its entirety in all distributions of the software, * modified or unmodified, in source code or in binary form. * * 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. */ /* * Gem5 Hardware Transactional Memory (HTM) * * Here we provide a brief note describing HTM support in Gem5 at * a high level. * * HTM is an architectural feature that enables speculative * concurrency in a shared-memory system; groups of instructions known as * transactions are executed as an atomic unit. The system allows that * transactions be executed concurrently but intervenes if a transaction's * atomicity/isolation is jeapordised and takes corrective action. In this * implementation, corrective active explicitely means rolling back a thread's * architectural state and reverting any memory updates to a point just * before the transaction began. * * This HTM implementation relies on-- * (1) A checkpointing mechanism for architectural register state. * (2) Buffering speculative memory updates. * * The checkpointing mechanism is architecture dependent. Each ISA leveraging * HTM support must define a class HTMCheckpoint in src/arch/theISA/htm.hh. * Instances of this class live in O3's ThreadState and Atomic's SimpleThread. * It is up to the ISA to populate this instance when executing an instruction * that begins a new transaction. * * The buffering of speculative memory updates is currently implemented in * the MESI_Three_Level Ruby protocol. The core notifies the L0 cache * controller that a new transaction has started and the controller in turn * places itself in transactional state (htmTransactionalState := true). * When operating in transactional state, the usual MESI protocol changes * slightly. Lines loaded or stored are marked as part of a transaction's * read and write set respectively. If there is an invalidation request to * cache line in the read/write set, the transaction is marked as failed. * Similarly, if there is a read request by another core to a speculatively * written cache line, i.e. in the write set, the transaction is marked as * failed. If failed, all subsequent loads and stores from the core are * made benign, i.e. made into NOPS at the cache controller, and responses are * marked to indicate that the transactional state has failed. When the core * receives these marked responses, it generates a HtmFailureFault with the * reason for the transaction failure. Servicing this fault does two things-- * (a) Restores the architectural checkpoint * (b) Sends an HTM abort signal to the cache controller * * The restoration includes all registers in the checkpoint as well as the * program counter of the instruction before the transaction started. * * The abort signal is sent to the L0 cache controller and resets the * failed transactional state. It resets the transactional read and write sets * and invalidates any speculatively written cache lines. It also exits * the transactional state so that the MESI protocol operates as usual. * * Alternatively, if the instructions within a transaction complete without * triggering a HtmFailureFault, the transaction can be committed. The core * is responsible for notifying the cache controller that the transaction is * complete and the cache controller makes all speculative writes visible * to the rest of the system and exits the transactional state. * * Notifting the cache controller is done through HtmCmd Requests which are * a subtype of Load Requests. * * Most HTMs allow for a limited number of nested transactions, e.g. a nesting * depth of two would be inside a transaction started within another * transaction. The ExecContext class is extended with * getHtmTransactionalDepth() to return the current depth. For the * TimingSimpleCPU it is straightforward to track this, whereas for * O3DerivCPU it must be tracked in the frontend and commit stages as well as * be corrected on branch mispredictions. This is done in iew_impl.hh. */ #ifndef __ARCH_GENERIC_HTM_HH__ #define __ARCH_GENERIC_HTM_HH__ #include #include #include "mem/htm.hh" namespace gem5 { /** * @file * * Generic definitions for hardware transactional memory. */ class ThreadContext; class BaseHTMCheckpoint; typedef std::unique_ptr BaseHTMCheckpointPtr; /** * Transactional Memory checkpoint. */ class BaseHTMCheckpoint { private: static uint64_t globalHtmUid; uint64_t localHtmUid; public: BaseHTMCheckpoint() : localHtmUid(0), _valid(false) { reset(); } virtual ~BaseHTMCheckpoint() {} /** * Every ISA implementing HTM support should override the * save method. This is called once a transaction starts * and the architectural state needs to be saved. * This will checkpoint the arch state. * * @param tc: thread context state to be saved */ virtual void save(ThreadContext *tc) { _valid = true; } /** * Every ISA implementing HTM support should override the * restore method. This is called once a transaction gets * aborted and the architectural state needs to be reverted. * This will restore the checkpointed arch state. * * @param tc: thread context to be restored * @param cause: the reason why the transaction has been aborted */ virtual void restore(ThreadContext *tc, HtmFailureFaultCause cause) { reset(); } bool valid() const { return _valid; } /** * Generates a new HTM identifier (used when starting a new transaction) */ uint64_t newHtmUid() { localHtmUid = ++ globalHtmUid; return localHtmUid; } /** * Returns the current HTM identifier */ uint64_t getHtmUid() const { return localHtmUid; } /** * Sets the current HTM identifier */ void setHtmUid(uint64_t new_htm_uid) { localHtmUid = new_htm_uid; } protected: /** * Resets the checkpoint once a transaction has completed. * The method is bringing up the checkpoint to a known * reset state so that it can be reused. * ISA specific checkpoints inheriting from this class should * override this method so that they can reset their own * ISA specific state. */ virtual void reset() { _valid = false; } bool _valid; }; } // namespace gem5 #endif // __ARCH_GENERIC_HTM_HH__