diff options
Diffstat (limited to 'src/dev/arm/gic_v3_its.hh')
-rw-r--r-- | src/dev/arm/gic_v3_its.hh | 518 |
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 |