summaryrefslogtreecommitdiff
path: root/src/dev/arm/gic_v3_its.hh
diff options
context:
space:
mode:
Diffstat (limited to 'src/dev/arm/gic_v3_its.hh')
-rw-r--r--src/dev/arm/gic_v3_its.hh518
1 files changed, 518 insertions, 0 deletions
diff --git a/src/dev/arm/gic_v3_its.hh b/src/dev/arm/gic_v3_its.hh
new file mode 100644
index 000000000..aa0b8c805
--- /dev/null
+++ b/src/dev/arm/gic_v3_its.hh
@@ -0,0 +1,518 @@
+/*
+ * Copyright (c) 2019 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.
+ *
+ * Authors: Giacomo Travaglini
+ */
+
+#ifndef __DEV_ARM_GICV3_ITS_H__
+#define __DEV_ARM_GICV3_ITS_H__
+
+#include <queue>
+
+#include "base/coroutine.hh"
+#include "dev/dma_device.hh"
+#include "params/Gicv3Its.hh"
+
+class Gicv3;
+class Gicv3Redistributor;
+class ItsProcess;
+class ItsTranslation;
+class ItsCommand;
+
+enum class ItsActionType
+{
+ INITIAL_NOP,
+ SEND_REQ,
+ TERMINATE,
+};
+
+struct ItsAction
+{
+ ItsActionType type;
+ PacketPtr pkt;
+ Tick delay;
+};
+
+/**
+ * GICv3 ITS module. This class is just modelling a pio device with its
+ * memory mapped registers. Most of the ITS functionalities are
+ * implemented as processes (ItsProcess) objects, like ItsTranslation or
+ * ItsCommand.
+ * Main job of Gicv3Its is to spawn those processes upon receival of packets.
+ */
+class Gicv3Its : public BasicPioDevice
+{
+ friend class ::ItsProcess;
+ friend class ::ItsTranslation;
+ friend class ::ItsCommand;
+ public:
+ class DataPort : public MasterPort
+ {
+ protected:
+ Gicv3Its &its;
+
+ public:
+ DataPort(const std::string &_name, Gicv3Its &_its) :
+ MasterPort(_name, &_its),
+ its(_its)
+ {}
+
+ virtual ~DataPort() {}
+
+ bool recvTimingResp(PacketPtr pkt) { return its.recvTimingResp(pkt); }
+ void recvReqRetry() { return its.recvReqRetry(); }
+ };
+
+ DataPort dmaPort;
+
+ Port & getPort(const std::string &if_name, PortID idx) override;
+ bool recvTimingResp(PacketPtr pkt);
+ void recvReqRetry();
+
+ Gicv3Its(const Gicv3ItsParams *params);
+
+ void setGIC(Gicv3 *_gic);
+
+ static const uint32_t itsControl = 0x0;
+ static const uint32_t itsTranslate = 0x10000;
+
+ // Address range part of Control frame
+ static const AddrRange GITS_BASER;
+
+ static const uint32_t NUM_BASER_REGS = 8;
+
+ enum : Addr
+ {
+ // Control frame
+ GITS_CTLR = itsControl + 0x0000,
+ GITS_IIDR = itsControl + 0x0004,
+ GITS_TYPER = itsControl + 0x0008,
+ GITS_CBASER = itsControl + 0x0080,
+ GITS_CWRITER = itsControl + 0x0088,
+ GITS_CREADR = itsControl + 0x0090,
+
+ // Translation frame
+ GITS_TRANSLATER = itsTranslate + 0x0040
+ };
+
+ AddrRangeList getAddrRanges() const override;
+
+ Tick read(PacketPtr pkt) override;
+ Tick write(PacketPtr pkt) override;
+
+ DrainState drain() override;
+ void serialize(CheckpointOut & cp) const override;
+ void unserialize(CheckpointIn & cp) override;
+
+ void translate(PacketPtr pkt);
+
+ BitUnion32(CTLR)
+ Bitfield<31> quiescent;
+ Bitfield<7, 4> itsNumber;
+ Bitfield<1> imDe;
+ Bitfield<0> enabled;
+ EndBitUnion(CTLR)
+
+ // Command read/write, (CREADR, CWRITER)
+ BitUnion64(CRDWR)
+ Bitfield<19, 5> offset;
+ Bitfield<0> retry;
+ Bitfield<0> stalled;
+ EndBitUnion(CRDWR)
+
+ BitUnion64(CBASER)
+ Bitfield<63> valid;
+ Bitfield<61, 59> innerCache;
+ Bitfield<55, 53> outerCache;
+ Bitfield<51, 12> physAddr;
+ Bitfield<11, 10> shareability;
+ Bitfield<7, 0> size;
+ EndBitUnion(CBASER)
+
+ BitUnion64(BASER)
+ Bitfield<63> valid;
+ Bitfield<62> indirect;
+ Bitfield<61, 59> innerCache;
+ Bitfield<58, 56> type;
+ Bitfield<55, 53> outerCache;
+ Bitfield<52, 48> entrySize;
+ Bitfield<47, 12> physAddr;
+ Bitfield<11, 10> shareability;
+ Bitfield<9, 8> pageSize;
+ Bitfield<7, 0> size;
+ EndBitUnion(BASER)
+
+ BitUnion64(TYPER)
+ Bitfield<37> vmovp;
+ Bitfield<36> cil;
+ Bitfield<35, 32> cidBits;
+ Bitfield<31, 24> hcc;
+ Bitfield<19> pta;
+ Bitfield<18> seis;
+ Bitfield<17, 13> devBits;
+ Bitfield<12, 8> idBits;
+ Bitfield<7, 4> ittEntrySize;
+ Bitfield<2> cct;
+ Bitfield<1> _virtual;
+ Bitfield<0> physical;
+ EndBitUnion(TYPER)
+
+ CTLR gitsControl;
+ TYPER gitsTyper;
+ CBASER gitsCbaser;
+ CRDWR gitsCreadr;
+ CRDWR gitsCwriter;
+ uint32_t gitsIidr;
+ uint32_t gitsTranslater;
+
+ std::vector<BASER> tableBases;
+
+ /**
+ * Returns TRUE if the eventID supplied has bits above the implemented
+ * size or above the itt_range
+ */
+ bool idOutOfRange(uint32_t event_id, uint8_t itt_range) const;
+
+ /**
+ * Returns TRUE if the value supplied has bits above the implemented range
+ * or if the value supplied exceeds the maximum configured size in the
+ * appropriate GITS_BASER<n>
+ */
+ bool deviceOutOfRange(uint32_t device_id) const;
+
+ /**
+ * Returns TRUE if the value (size) supplied exceeds the maximum
+ * allowed by GITS_TYPER.ID_bits. Size is the parameter which is
+ * passed to the ITS via the MAPD command and is stored in the
+ * DTE.ittRange field.
+ */
+ bool sizeOutOfRange(uint32_t size) const;
+
+ /**
+ * Returns TRUE if the value supplied has bits above the implemented range
+ * or if the value exceeds the total number of collections supported in
+ * hardware and external memory
+ */
+ bool collectionOutOfRange(uint32_t collection_id) const;
+
+ /**
+ * Returns TRUE if the value supplied is larger than that permitted by
+ * GICD_TYPER.IDbits or not in the LPI range and is not 1023
+ */
+ bool lpiOutOfRange(uint32_t intid) const;
+
+ private: // Command
+ void checkCommandQueue();
+ void incrementReadPointer();
+
+ public: // TableWalk
+ BitUnion64(DTE)
+ Bitfield<57, 53> ittRange;
+ Bitfield<52, 1> ittAddress;
+ Bitfield<0> valid;
+ EndBitUnion(DTE)
+
+ BitUnion64(ITTE)
+ Bitfield<59, 46> vpeid;
+ Bitfield<45, 30> icid;
+ Bitfield<29, 16> intNumHyp;
+ Bitfield<15, 2> intNum;
+ Bitfield<1> intType;
+ Bitfield<0> valid;
+ EndBitUnion(ITTE)
+
+ BitUnion64(CTE)
+ Bitfield<40, 1> rdBase;
+ Bitfield<0> valid;
+ EndBitUnion(CTE)
+
+ enum InterruptType
+ {
+ VIRTUAL_INTERRUPT = 0,
+ PHYSICAL_INTERRUPT = 1
+ };
+
+ private:
+ Gicv3Redistributor* getRedistributor(uint64_t rd_base);
+ Gicv3Redistributor* getRedistributor(CTE cte)
+ {
+ return getRedistributor(cte.rdBase);
+ }
+
+ ItsAction runProcess(ItsProcess *proc, PacketPtr pkt);
+ ItsAction runProcessTiming(ItsProcess *proc, PacketPtr pkt);
+ ItsAction runProcessAtomic(ItsProcess *proc, PacketPtr pkt);
+
+ enum ItsTables
+ {
+ DEVICE_TABLE = 1,
+ VPE_TABLE = 2,
+ TRANSLATION_TABLE = 3,
+ COLLECTION_TABLE = 4
+ };
+
+ enum PageSize
+ {
+ SIZE_4K,
+ SIZE_16K,
+ SIZE_64K
+ };
+
+ Addr pageAddress(enum ItsTables table);
+
+ void moveAllPendingState(
+ Gicv3Redistributor *rd1, Gicv3Redistributor *rd2);
+
+ private:
+ std::queue<ItsAction> packetsToRetry;
+ uint32_t masterId;
+ Gicv3 *gic;
+ EventFunctionWrapper commandEvent;
+
+ bool pendingCommands;
+ uint32_t pendingTranslations;
+};
+
+/**
+ * ItsProcess is a base coroutine wrapper which is spawned by
+ * the Gicv3Its module when the latter needs to perform different
+ * actions, like translating a peripheral's MSI into an LPI
+ * (See derived ItsTranslation) or processing a Command from the
+ * ITS queue (ItsCommand).
+ * The action to take is implemented by the method:
+ *
+ * virtual void main(Yield &yield) = 0;
+ * It's inheriting from Packet::SenderState since the generic process
+ * will be stopped (we are using coroutines) and sent with the packet
+ * to memory when doing table walks.
+ * When Gicv3Its receives a response, it will resume the coroutine from
+ * the point it stopped when yielding.
+ */
+class ItsProcess : public Packet::SenderState
+{
+ public:
+ using DTE = Gicv3Its::DTE;
+ using ITTE = Gicv3Its::ITTE;
+ using CTE = Gicv3Its::CTE;
+ using Coroutine = m5::Coroutine<PacketPtr, ItsAction>;
+ using Yield = Coroutine::CallerType;
+
+ ItsProcess(Gicv3Its &_its);
+ virtual ~ItsProcess();
+
+ /** Returns the Gicv3Its name. Mainly used for DPRINTS */
+ const std::string name() const;
+
+ ItsAction run(PacketPtr pkt);
+
+ protected:
+ void reinit();
+ virtual void main(Yield &yield) = 0;
+
+ void writeDeviceTable(Yield &yield, uint32_t device_id, DTE dte);
+
+ void writeIrqTranslationTable(
+ Yield &yield, const Addr itt_base, uint32_t event_id, ITTE itte);
+
+ void writeIrqCollectionTable(
+ Yield &yield, uint32_t collection_id, CTE cte);
+
+ uint64_t readDeviceTable(
+ Yield &yield, uint32_t device_id);
+
+ uint64_t readIrqTranslationTable(
+ Yield &yield, const Addr itt_base, uint32_t event_id);
+
+ uint64_t readIrqCollectionTable(Yield &yield, uint32_t collection_id);
+
+ void doRead(Yield &yield, Addr addr, void *ptr, size_t size);
+ void doWrite(Yield &yield, Addr addr, void *ptr, size_t size);
+ void terminate(Yield &yield);
+
+ protected:
+ Gicv3Its &its;
+
+ private:
+ std::unique_ptr<Coroutine> coroutine;
+};
+
+/**
+ * An ItsTranslation is created whenever a peripheral writes a message in
+ * GITS_TRANSLATER (MSI). In this case main will simply do the table walks
+ * until it gets a redistributor and an INTID. It will then raise the
+ * LPI interrupt to the target redistributor.
+ */
+class ItsTranslation : public ItsProcess
+{
+ public:
+ ItsTranslation(Gicv3Its &_its);
+ ~ItsTranslation();
+
+ protected:
+ void main(Yield &yield) override;
+
+ std::pair<uint32_t, Gicv3Redistributor *>
+ translateLPI(Yield &yield, uint32_t device_id, uint32_t event_id);
+};
+
+/**
+ * An ItsCommand is created whenever there is a new command in the command
+ * queue. Only one command can be executed per time.
+ * main will firstly read the command from memory and then it will process
+ * it.
+ */
+class ItsCommand : public ItsProcess
+{
+ public:
+ union CommandEntry
+ {
+ struct
+ {
+ uint32_t type;
+ uint32_t deviceId;
+ uint32_t eventId;
+ uint32_t pintId;
+
+ uint32_t data[4];
+ };
+ uint64_t raw[4];
+ };
+
+ enum CommandType : uint32_t
+ {
+ CLEAR = 0x04,
+ DISCARD = 0x0F,
+ INT = 0x03,
+ INV = 0x0C,
+ INVALL = 0x0D,
+ MAPC = 0x09,
+ MAPD = 0x08,
+ MAPI = 0x0B,
+ MAPTI = 0x0A,
+ MOVALL = 0x0E,
+ MOVI = 0x01,
+ SYNC = 0x05,
+ VINVALL = 0x2D,
+ VMAPI = 0x2B,
+ VMAPP = 0x29,
+ VMAPTI = 0x2A,
+ VMOVI = 0x21,
+ VMOVP = 0x22,
+ VSYNC = 0x25
+ };
+
+ ItsCommand(Gicv3Its &_its);
+ ~ItsCommand();
+
+ protected:
+ /**
+ * Dispatch entry is a metadata struct which contains information about
+ * the command (like the name) and the function object implementing
+ * the command.
+ */
+ struct DispatchEntry
+ {
+ using ExecFn = std::function<void(ItsCommand*, Yield&, CommandEntry&)>;
+
+ DispatchEntry(std::string _name, ExecFn _exec)
+ : name(_name), exec(_exec)
+ {}
+
+ std::string name;
+ ExecFn exec;
+ };
+
+ using DispatchTable = std::unordered_map<
+ std::underlying_type<enum CommandType>::type, DispatchEntry>;
+
+ static DispatchTable cmdDispatcher;
+
+ static std::string commandName(uint32_t cmd);
+
+ void main(Yield &yield) override;
+
+ void readCommand(Yield &yield, CommandEntry &command);
+ void processCommand(Yield &yield, CommandEntry &command);
+
+ // Commands
+ void clear(Yield &yield, CommandEntry &command);
+ void discard(Yield &yield, CommandEntry &command);
+ void mapc(Yield &yield, CommandEntry &command);
+ void mapd(Yield &yield, CommandEntry &command);
+ void mapi(Yield &yield, CommandEntry &command);
+ void mapti(Yield &yield, CommandEntry &command);
+ void movall(Yield &yield, CommandEntry &command);
+ void movi(Yield &yield, CommandEntry &command);
+ void sync(Yield &yield, CommandEntry &command);
+ void doInt(Yield &yield, CommandEntry &command);
+ void inv(Yield &yield, CommandEntry &command);
+ void invall(Yield &yield, CommandEntry &command);
+ void vinvall(Yield &yield, CommandEntry &command);
+ void vmapi(Yield &yield, CommandEntry &command);
+ void vmapp(Yield &yield, CommandEntry &command);
+ void vmapti(Yield &yield, CommandEntry &command);
+ void vmovi(Yield &yield, CommandEntry &command);
+ void vmovp(Yield &yield, CommandEntry &command);
+ void vsync(Yield &yield, CommandEntry &command);
+
+ protected: // Helpers
+ bool idOutOfRange(CommandEntry &command, DTE dte) const
+ {
+ return its.idOutOfRange(command.eventId, dte.ittRange);
+ }
+
+ bool deviceOutOfRange(CommandEntry &command) const
+ {
+ return its.deviceOutOfRange(command.deviceId);
+ }
+
+ bool sizeOutOfRange(CommandEntry &command) const
+ {
+ const auto size = bits(command.raw[1], 4, 0);
+ const auto valid = bits(command.raw[2], 63);
+ if (valid)
+ return its.sizeOutOfRange(size);
+ else
+ return false;
+ }
+
+ bool collectionOutOfRange(CommandEntry &command) const
+ {
+ return its.collectionOutOfRange(bits(command.raw[2], 15, 0));
+ }
+};
+
+#endif