xref: /qemu/hw/intc/arm_gicv3_its.c (revision c411db7bf75d0a2ecd7249533c74babf2af51afe)
118f6290aSShashi Mallela /*
218f6290aSShashi Mallela  * ITS emulation for a GICv3-based system
318f6290aSShashi Mallela  *
418f6290aSShashi Mallela  * Copyright Linaro.org 2021
518f6290aSShashi Mallela  *
618f6290aSShashi Mallela  * Authors:
718f6290aSShashi Mallela  *  Shashi Mallela <shashi.mallela@linaro.org>
818f6290aSShashi Mallela  *
918f6290aSShashi Mallela  * This work is licensed under the terms of the GNU GPL, version 2 or (at your
1018f6290aSShashi Mallela  * option) any later version.  See the COPYING file in the top-level directory.
1118f6290aSShashi Mallela  *
1218f6290aSShashi Mallela  */
1318f6290aSShashi Mallela 
1418f6290aSShashi Mallela #include "qemu/osdep.h"
1518f6290aSShashi Mallela #include "qemu/log.h"
16195209d3SPeter Maydell #include "trace.h"
1718f6290aSShashi Mallela #include "hw/qdev-properties.h"
1818f6290aSShashi Mallela #include "hw/intc/arm_gicv3_its_common.h"
1918f6290aSShashi Mallela #include "gicv3_internal.h"
2018f6290aSShashi Mallela #include "qom/object.h"
2118f6290aSShashi Mallela #include "qapi/error.h"
2218f6290aSShashi Mallela 
2318f6290aSShashi Mallela typedef struct GICv3ITSClass GICv3ITSClass;
2418f6290aSShashi Mallela /* This is reusing the GICv3ITSState typedef from ARM_GICV3_ITS_COMMON */
2518f6290aSShashi Mallela DECLARE_OBJ_CHECKERS(GICv3ITSState, GICv3ITSClass,
2618f6290aSShashi Mallela                      ARM_GICV3_ITS, TYPE_ARM_GICV3_ITS)
2718f6290aSShashi Mallela 
2818f6290aSShashi Mallela struct GICv3ITSClass {
2918f6290aSShashi Mallela     GICv3ITSCommonClass parent_class;
3018f6290aSShashi Mallela     void (*parent_reset)(DeviceState *dev);
3118f6290aSShashi Mallela };
3218f6290aSShashi Mallela 
33c694cb4cSShashi Mallela /*
34c694cb4cSShashi Mallela  * This is an internal enum used to distinguish between LPI triggered
35c694cb4cSShashi Mallela  * via command queue and LPI triggered via gits_translater write.
36c694cb4cSShashi Mallela  */
37c694cb4cSShashi Mallela typedef enum ItsCmdType {
38c694cb4cSShashi Mallela     NONE = 0, /* internal indication for GITS_TRANSLATER write */
39c694cb4cSShashi Mallela     CLEAR = 1,
40c694cb4cSShashi Mallela     DISCARD = 2,
41c694cb4cSShashi Mallela     INTERRUPT = 3,
42c694cb4cSShashi Mallela } ItsCmdType;
43c694cb4cSShashi Mallela 
444acf93e1SPeter Maydell typedef struct DTEntry {
454acf93e1SPeter Maydell     bool valid;
464acf93e1SPeter Maydell     unsigned size;
474acf93e1SPeter Maydell     uint64_t ittaddr;
484acf93e1SPeter Maydell } DTEntry;
494acf93e1SPeter Maydell 
50d37cf49bSPeter Maydell typedef struct CTEntry {
51d37cf49bSPeter Maydell     bool valid;
52d37cf49bSPeter Maydell     uint32_t rdbase;
53d37cf49bSPeter Maydell } CTEntry;
54d37cf49bSPeter Maydell 
55244194feSPeter Maydell typedef struct ITEntry {
56244194feSPeter Maydell     bool valid;
57244194feSPeter Maydell     int inttype;
58244194feSPeter Maydell     uint32_t intid;
59244194feSPeter Maydell     uint32_t doorbell;
60244194feSPeter Maydell     uint32_t icid;
61244194feSPeter Maydell     uint32_t vpeid;
62244194feSPeter Maydell } ITEntry;
63244194feSPeter Maydell 
640cdf7a5dSPeter Maydell typedef struct VTEntry {
650cdf7a5dSPeter Maydell     bool valid;
660cdf7a5dSPeter Maydell     unsigned vptsize;
670cdf7a5dSPeter Maydell     uint32_t rdbase;
680cdf7a5dSPeter Maydell     uint64_t vptaddr;
690cdf7a5dSPeter Maydell } VTEntry;
70244194feSPeter Maydell 
71ef011555SPeter Maydell /*
72ef011555SPeter Maydell  * The ITS spec permits a range of CONSTRAINED UNPREDICTABLE options
73ef011555SPeter Maydell  * if a command parameter is not correct. These include both "stall
74ef011555SPeter Maydell  * processing of the command queue" and "ignore this command, and
75ef011555SPeter Maydell  * keep processing the queue". In our implementation we choose that
76ef011555SPeter Maydell  * memory transaction errors reading the command packet provoke a
77ef011555SPeter Maydell  * stall, but errors in parameters cause us to ignore the command
78ef011555SPeter Maydell  * and continue processing.
79ef011555SPeter Maydell  * The process_* functions which handle individual ITS commands all
80ef011555SPeter Maydell  * return an ItsCmdResult which tells process_cmdq() whether it should
8193f4fdcdSPeter Maydell  * stall, keep going because of an error, or keep going because the
8293f4fdcdSPeter Maydell  * command was a success.
83ef011555SPeter Maydell  */
84ef011555SPeter Maydell typedef enum ItsCmdResult {
85ef011555SPeter Maydell     CMD_STALL = 0,
86ef011555SPeter Maydell     CMD_CONTINUE = 1,
8793f4fdcdSPeter Maydell     CMD_CONTINUE_OK = 2,
88ef011555SPeter Maydell } ItsCmdResult;
89ef011555SPeter Maydell 
9050d84584SPeter Maydell /* True if the ITS supports the GICv4 virtual LPI feature */
9150d84584SPeter Maydell static bool its_feature_virtual(GICv3ITSState *s)
9250d84584SPeter Maydell {
9350d84584SPeter Maydell     return s->typer & R_GITS_TYPER_VIRTUAL_MASK;
9450d84584SPeter Maydell }
9550d84584SPeter Maydell 
96c3c9a090SPeter Maydell static inline bool intid_in_lpi_range(uint32_t id)
97c3c9a090SPeter Maydell {
98c3c9a090SPeter Maydell     return id >= GICV3_LPI_INTID_START &&
99c3c9a090SPeter Maydell         id < (1 << (GICD_TYPER_IDBITS + 1));
100c3c9a090SPeter Maydell }
101c3c9a090SPeter Maydell 
1029de53de6SPeter Maydell static inline bool valid_doorbell(uint32_t id)
1039de53de6SPeter Maydell {
1049de53de6SPeter Maydell     /* Doorbell fields may be an LPI, or 1023 to mean "no doorbell" */
1059de53de6SPeter Maydell     return id == INTID_SPURIOUS || intid_in_lpi_range(id);
1069de53de6SPeter Maydell }
1079de53de6SPeter Maydell 
1081b08e436SShashi Mallela static uint64_t baser_base_addr(uint64_t value, uint32_t page_sz)
1091b08e436SShashi Mallela {
1101b08e436SShashi Mallela     uint64_t result = 0;
1111b08e436SShashi Mallela 
1121b08e436SShashi Mallela     switch (page_sz) {
1131b08e436SShashi Mallela     case GITS_PAGE_SIZE_4K:
1141b08e436SShashi Mallela     case GITS_PAGE_SIZE_16K:
1151b08e436SShashi Mallela         result = FIELD_EX64(value, GITS_BASER, PHYADDR) << 12;
1161b08e436SShashi Mallela         break;
1171b08e436SShashi Mallela 
1181b08e436SShashi Mallela     case GITS_PAGE_SIZE_64K:
1191b08e436SShashi Mallela         result = FIELD_EX64(value, GITS_BASER, PHYADDRL_64K) << 16;
1201b08e436SShashi Mallela         result |= FIELD_EX64(value, GITS_BASER, PHYADDRH_64K) << 48;
1211b08e436SShashi Mallela         break;
1221b08e436SShashi Mallela 
1231b08e436SShashi Mallela     default:
1241b08e436SShashi Mallela         break;
1251b08e436SShashi Mallela     }
1261b08e436SShashi Mallela     return result;
1271b08e436SShashi Mallela }
1281b08e436SShashi Mallela 
129d050f80fSPeter Maydell static uint64_t table_entry_addr(GICv3ITSState *s, TableDesc *td,
130d050f80fSPeter Maydell                                  uint32_t idx, MemTxResult *res)
131d050f80fSPeter Maydell {
132d050f80fSPeter Maydell     /*
133d050f80fSPeter Maydell      * Given a TableDesc describing one of the ITS in-guest-memory
134d050f80fSPeter Maydell      * tables and an index into it, return the guest address
135d050f80fSPeter Maydell      * corresponding to that table entry.
136d050f80fSPeter Maydell      * If there was a memory error reading the L1 table of an
137d050f80fSPeter Maydell      * indirect table, *res is set accordingly, and we return -1.
138d050f80fSPeter Maydell      * If the L1 table entry is marked not valid, we return -1 with
139d050f80fSPeter Maydell      * *res set to MEMTX_OK.
140d050f80fSPeter Maydell      *
141d050f80fSPeter Maydell      * The specification defines the format of level 1 entries of a
142d050f80fSPeter Maydell      * 2-level table, but the format of level 2 entries and the format
143d050f80fSPeter Maydell      * of flat-mapped tables is IMPDEF.
144d050f80fSPeter Maydell      */
145d050f80fSPeter Maydell     AddressSpace *as = &s->gicv3->dma_as;
146d050f80fSPeter Maydell     uint32_t l2idx;
147d050f80fSPeter Maydell     uint64_t l2;
148d050f80fSPeter Maydell     uint32_t num_l2_entries;
149d050f80fSPeter Maydell 
150d050f80fSPeter Maydell     *res = MEMTX_OK;
151d050f80fSPeter Maydell 
152d050f80fSPeter Maydell     if (!td->indirect) {
153d050f80fSPeter Maydell         /* Single level table */
154d050f80fSPeter Maydell         return td->base_addr + idx * td->entry_sz;
155d050f80fSPeter Maydell     }
156d050f80fSPeter Maydell 
157d050f80fSPeter Maydell     /* Two level table */
158d050f80fSPeter Maydell     l2idx = idx / (td->page_sz / L1TABLE_ENTRY_SIZE);
159d050f80fSPeter Maydell 
160d050f80fSPeter Maydell     l2 = address_space_ldq_le(as,
161d050f80fSPeter Maydell                               td->base_addr + (l2idx * L1TABLE_ENTRY_SIZE),
162d050f80fSPeter Maydell                               MEMTXATTRS_UNSPECIFIED, res);
163d050f80fSPeter Maydell     if (*res != MEMTX_OK) {
164d050f80fSPeter Maydell         return -1;
165d050f80fSPeter Maydell     }
166d050f80fSPeter Maydell     if (!(l2 & L2_TABLE_VALID_MASK)) {
167d050f80fSPeter Maydell         return -1;
168d050f80fSPeter Maydell     }
169d050f80fSPeter Maydell 
170d050f80fSPeter Maydell     num_l2_entries = td->page_sz / td->entry_sz;
171d050f80fSPeter Maydell     return (l2 & ((1ULL << 51) - 1)) + (idx % num_l2_entries) * td->entry_sz;
172d050f80fSPeter Maydell }
173d050f80fSPeter Maydell 
174d37cf49bSPeter Maydell /*
175d37cf49bSPeter Maydell  * Read the Collection Table entry at index @icid. On success (including
176d37cf49bSPeter Maydell  * successfully determining that there is no valid CTE for this index),
177d37cf49bSPeter Maydell  * we return MEMTX_OK and populate the CTEntry struct @cte accordingly.
178d37cf49bSPeter Maydell  * If there is an error reading memory then we return the error code.
179d37cf49bSPeter Maydell  */
180d37cf49bSPeter Maydell static MemTxResult get_cte(GICv3ITSState *s, uint16_t icid, CTEntry *cte)
181c694cb4cSShashi Mallela {
182c694cb4cSShashi Mallela     AddressSpace *as = &s->gicv3->dma_as;
183d37cf49bSPeter Maydell     MemTxResult res = MEMTX_OK;
184d37cf49bSPeter Maydell     uint64_t entry_addr = table_entry_addr(s, &s->ct, icid, &res);
185d37cf49bSPeter Maydell     uint64_t cteval;
186c694cb4cSShashi Mallela 
187d050f80fSPeter Maydell     if (entry_addr == -1) {
188d37cf49bSPeter Maydell         /* No L2 table entry, i.e. no valid CTE, or a memory error */
189d37cf49bSPeter Maydell         cte->valid = false;
190930f40e9SPeter Maydell         goto out;
191c694cb4cSShashi Mallela     }
192c694cb4cSShashi Mallela 
193d37cf49bSPeter Maydell     cteval = address_space_ldq_le(as, entry_addr, MEMTXATTRS_UNSPECIFIED, &res);
194d37cf49bSPeter Maydell     if (res != MEMTX_OK) {
195930f40e9SPeter Maydell         goto out;
196d37cf49bSPeter Maydell     }
197d37cf49bSPeter Maydell     cte->valid = FIELD_EX64(cteval, CTE, VALID);
198d37cf49bSPeter Maydell     cte->rdbase = FIELD_EX64(cteval, CTE, RDBASE);
199930f40e9SPeter Maydell out:
200930f40e9SPeter Maydell     if (res != MEMTX_OK) {
201930f40e9SPeter Maydell         trace_gicv3_its_cte_read_fault(icid);
202930f40e9SPeter Maydell     } else {
203930f40e9SPeter Maydell         trace_gicv3_its_cte_read(icid, cte->valid, cte->rdbase);
204930f40e9SPeter Maydell     }
205930f40e9SPeter Maydell     return res;
206c694cb4cSShashi Mallela }
207c694cb4cSShashi Mallela 
2087eb54267SPeter Maydell /*
2097eb54267SPeter Maydell  * Update the Interrupt Table entry at index @evinted in the table specified
2107eb54267SPeter Maydell  * by the dte @dte. Returns true on success, false if there was a memory
2117eb54267SPeter Maydell  * access error.
2127eb54267SPeter Maydell  */
2134acf93e1SPeter Maydell static bool update_ite(GICv3ITSState *s, uint32_t eventid, const DTEntry *dte,
2147eb54267SPeter Maydell                        const ITEntry *ite)
215c694cb4cSShashi Mallela {
216c694cb4cSShashi Mallela     AddressSpace *as = &s->gicv3->dma_as;
217c694cb4cSShashi Mallela     MemTxResult res = MEMTX_OK;
218a1ce993dSPeter Maydell     hwaddr iteaddr = dte->ittaddr + eventid * ITS_ITT_ENTRY_SIZE;
2197eb54267SPeter Maydell     uint64_t itel = 0;
2207eb54267SPeter Maydell     uint32_t iteh = 0;
221c694cb4cSShashi Mallela 
222930f40e9SPeter Maydell     trace_gicv3_its_ite_write(dte->ittaddr, eventid, ite->valid,
223930f40e9SPeter Maydell                               ite->inttype, ite->intid, ite->icid,
224930f40e9SPeter Maydell                               ite->vpeid, ite->doorbell);
225930f40e9SPeter Maydell 
2267eb54267SPeter Maydell     if (ite->valid) {
2277eb54267SPeter Maydell         itel = FIELD_DP64(itel, ITE_L, VALID, 1);
2287eb54267SPeter Maydell         itel = FIELD_DP64(itel, ITE_L, INTTYPE, ite->inttype);
2297eb54267SPeter Maydell         itel = FIELD_DP64(itel, ITE_L, INTID, ite->intid);
2307eb54267SPeter Maydell         itel = FIELD_DP64(itel, ITE_L, ICID, ite->icid);
2317eb54267SPeter Maydell         itel = FIELD_DP64(itel, ITE_L, VPEID, ite->vpeid);
2327eb54267SPeter Maydell         iteh = FIELD_DP32(iteh, ITE_H, DOORBELL, ite->doorbell);
233c694cb4cSShashi Mallela     }
2347eb54267SPeter Maydell 
2357eb54267SPeter Maydell     address_space_stq_le(as, iteaddr, itel, MEMTXATTRS_UNSPECIFIED, &res);
236c694cb4cSShashi Mallela     if (res != MEMTX_OK) {
237c694cb4cSShashi Mallela         return false;
238c694cb4cSShashi Mallela     }
2397eb54267SPeter Maydell     address_space_stl_le(as, iteaddr + 8, iteh, MEMTXATTRS_UNSPECIFIED, &res);
2407eb54267SPeter Maydell     return res == MEMTX_OK;
241c694cb4cSShashi Mallela }
242c694cb4cSShashi Mallela 
243244194feSPeter Maydell /*
244244194feSPeter Maydell  * Read the Interrupt Table entry at index @eventid from the table specified
245244194feSPeter Maydell  * by the DTE @dte. On success, we return MEMTX_OK and populate the ITEntry
246244194feSPeter Maydell  * struct @ite accordingly. If there is an error reading memory then we return
247244194feSPeter Maydell  * the error code.
248244194feSPeter Maydell  */
249244194feSPeter Maydell static MemTxResult get_ite(GICv3ITSState *s, uint32_t eventid,
250244194feSPeter Maydell                            const DTEntry *dte, ITEntry *ite)
251c694cb4cSShashi Mallela {
252c694cb4cSShashi Mallela     AddressSpace *as = &s->gicv3->dma_as;
253244194feSPeter Maydell     MemTxResult res = MEMTX_OK;
254244194feSPeter Maydell     uint64_t itel;
255244194feSPeter Maydell     uint32_t iteh;
256a1ce993dSPeter Maydell     hwaddr iteaddr = dte->ittaddr + eventid * ITS_ITT_ENTRY_SIZE;
257c694cb4cSShashi Mallela 
258244194feSPeter Maydell     itel = address_space_ldq_le(as, iteaddr, MEMTXATTRS_UNSPECIFIED, &res);
259244194feSPeter Maydell     if (res != MEMTX_OK) {
260930f40e9SPeter Maydell         trace_gicv3_its_ite_read_fault(dte->ittaddr, eventid);
261244194feSPeter Maydell         return res;
2622954b93fSPeter Maydell     }
263c694cb4cSShashi Mallela 
264244194feSPeter Maydell     iteh = address_space_ldl_le(as, iteaddr + 8, MEMTXATTRS_UNSPECIFIED, &res);
265244194feSPeter Maydell     if (res != MEMTX_OK) {
266930f40e9SPeter Maydell         trace_gicv3_its_ite_read_fault(dte->ittaddr, eventid);
267244194feSPeter Maydell         return res;
2682954b93fSPeter Maydell     }
269c694cb4cSShashi Mallela 
270244194feSPeter Maydell     ite->valid = FIELD_EX64(itel, ITE_L, VALID);
271244194feSPeter Maydell     ite->inttype = FIELD_EX64(itel, ITE_L, INTTYPE);
272244194feSPeter Maydell     ite->intid = FIELD_EX64(itel, ITE_L, INTID);
273244194feSPeter Maydell     ite->icid = FIELD_EX64(itel, ITE_L, ICID);
274244194feSPeter Maydell     ite->vpeid = FIELD_EX64(itel, ITE_L, VPEID);
275244194feSPeter Maydell     ite->doorbell = FIELD_EX64(iteh, ITE_H, DOORBELL);
276930f40e9SPeter Maydell     trace_gicv3_its_ite_read(dte->ittaddr, eventid, ite->valid,
277930f40e9SPeter Maydell                              ite->inttype, ite->intid, ite->icid,
278930f40e9SPeter Maydell                              ite->vpeid, ite->doorbell);
279244194feSPeter Maydell     return MEMTX_OK;
280c694cb4cSShashi Mallela }
281c694cb4cSShashi Mallela 
2824acf93e1SPeter Maydell /*
2834acf93e1SPeter Maydell  * Read the Device Table entry at index @devid. On success (including
2844acf93e1SPeter Maydell  * successfully determining that there is no valid DTE for this index),
2854acf93e1SPeter Maydell  * we return MEMTX_OK and populate the DTEntry struct accordingly.
2864acf93e1SPeter Maydell  * If there is an error reading memory then we return the error code.
2874acf93e1SPeter Maydell  */
2884acf93e1SPeter Maydell static MemTxResult get_dte(GICv3ITSState *s, uint32_t devid, DTEntry *dte)
289c694cb4cSShashi Mallela {
2904acf93e1SPeter Maydell     MemTxResult res = MEMTX_OK;
291c694cb4cSShashi Mallela     AddressSpace *as = &s->gicv3->dma_as;
2924acf93e1SPeter Maydell     uint64_t entry_addr = table_entry_addr(s, &s->dt, devid, &res);
2934acf93e1SPeter Maydell     uint64_t dteval;
294c694cb4cSShashi Mallela 
295d050f80fSPeter Maydell     if (entry_addr == -1) {
2964acf93e1SPeter Maydell         /* No L2 table entry, i.e. no valid DTE, or a memory error */
2974acf93e1SPeter Maydell         dte->valid = false;
298930f40e9SPeter Maydell         goto out;
299c694cb4cSShashi Mallela     }
3004acf93e1SPeter Maydell     dteval = address_space_ldq_le(as, entry_addr, MEMTXATTRS_UNSPECIFIED, &res);
3014acf93e1SPeter Maydell     if (res != MEMTX_OK) {
302930f40e9SPeter Maydell         goto out;
3034acf93e1SPeter Maydell     }
3044acf93e1SPeter Maydell     dte->valid = FIELD_EX64(dteval, DTE, VALID);
3054acf93e1SPeter Maydell     dte->size = FIELD_EX64(dteval, DTE, SIZE);
3064acf93e1SPeter Maydell     /* DTE word field stores bits [51:8] of the ITT address */
3074acf93e1SPeter Maydell     dte->ittaddr = FIELD_EX64(dteval, DTE, ITTADDR) << ITTADDR_SHIFT;
308930f40e9SPeter Maydell out:
309930f40e9SPeter Maydell     if (res != MEMTX_OK) {
310930f40e9SPeter Maydell         trace_gicv3_its_dte_read_fault(devid);
311930f40e9SPeter Maydell     } else {
312930f40e9SPeter Maydell         trace_gicv3_its_dte_read(devid, dte->valid, dte->size, dte->ittaddr);
313930f40e9SPeter Maydell     }
314930f40e9SPeter Maydell     return res;
315c694cb4cSShashi Mallela }
316c694cb4cSShashi Mallela 
317c694cb4cSShashi Mallela /*
318f0175135SPeter Maydell  * Given a (DeviceID, EventID), look up the corresponding ITE, including
319f0175135SPeter Maydell  * checking for the various invalid-value cases. If we find a valid ITE,
320f0175135SPeter Maydell  * fill in @ite and @dte and return CMD_CONTINUE_OK. Otherwise return
321f0175135SPeter Maydell  * CMD_STALL or CMD_CONTINUE as appropriate (and the contents of @ite
322f0175135SPeter Maydell  * should not be relied on).
323f0175135SPeter Maydell  *
324f0175135SPeter Maydell  * The string @who is purely for the LOG_GUEST_ERROR messages,
325f0175135SPeter Maydell  * and should indicate the name of the calling function or similar.
326f0175135SPeter Maydell  */
327f0175135SPeter Maydell static ItsCmdResult lookup_ite(GICv3ITSState *s, const char *who,
328f0175135SPeter Maydell                                uint32_t devid, uint32_t eventid, ITEntry *ite,
329f0175135SPeter Maydell                                DTEntry *dte)
330f0175135SPeter Maydell {
331f0175135SPeter Maydell     uint64_t num_eventids;
332f0175135SPeter Maydell 
333f0175135SPeter Maydell     if (devid >= s->dt.num_entries) {
334f0175135SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
335f0175135SPeter Maydell                       "%s: invalid command attributes: devid %d>=%d",
336f0175135SPeter Maydell                       who, devid, s->dt.num_entries);
337f0175135SPeter Maydell         return CMD_CONTINUE;
338f0175135SPeter Maydell     }
339f0175135SPeter Maydell 
340f0175135SPeter Maydell     if (get_dte(s, devid, dte) != MEMTX_OK) {
341f0175135SPeter Maydell         return CMD_STALL;
342f0175135SPeter Maydell     }
343f0175135SPeter Maydell     if (!dte->valid) {
344f0175135SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
345f0175135SPeter Maydell                       "%s: invalid command attributes: "
346f0175135SPeter Maydell                       "invalid dte for %d\n", who, devid);
347f0175135SPeter Maydell         return CMD_CONTINUE;
348f0175135SPeter Maydell     }
349f0175135SPeter Maydell 
350f0175135SPeter Maydell     num_eventids = 1ULL << (dte->size + 1);
351f0175135SPeter Maydell     if (eventid >= num_eventids) {
352f0175135SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
353f0175135SPeter Maydell                       "%s: invalid command attributes: eventid %d >= %"
354f0175135SPeter Maydell                       PRId64 "\n", who, eventid, num_eventids);
355f0175135SPeter Maydell         return CMD_CONTINUE;
356f0175135SPeter Maydell     }
357f0175135SPeter Maydell 
358f0175135SPeter Maydell     if (get_ite(s, eventid, dte, ite) != MEMTX_OK) {
359f0175135SPeter Maydell         return CMD_STALL;
360f0175135SPeter Maydell     }
361f0175135SPeter Maydell 
362f0175135SPeter Maydell     if (!ite->valid) {
363f0175135SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
364f0175135SPeter Maydell                       "%s: invalid command attributes: invalid ITE\n", who);
365f0175135SPeter Maydell         return CMD_CONTINUE;
366f0175135SPeter Maydell     }
367f0175135SPeter Maydell 
368f0175135SPeter Maydell     return CMD_CONTINUE_OK;
369f0175135SPeter Maydell }
370f0175135SPeter Maydell 
371f0175135SPeter Maydell /*
372*c411db7bSPeter Maydell  * Given an ICID, look up the corresponding CTE, including checking for various
373*c411db7bSPeter Maydell  * invalid-value cases. If we find a valid CTE, fill in @cte and return
374*c411db7bSPeter Maydell  * CMD_CONTINUE_OK; otherwise return CMD_STALL or CMD_CONTINUE (and the
375*c411db7bSPeter Maydell  * contents of @cte should not be relied on).
376*c411db7bSPeter Maydell  *
377*c411db7bSPeter Maydell  * The string @who is purely for the LOG_GUEST_ERROR messages,
378*c411db7bSPeter Maydell  * and should indicate the name of the calling function or similar.
379*c411db7bSPeter Maydell  */
380*c411db7bSPeter Maydell static ItsCmdResult lookup_cte(GICv3ITSState *s, const char *who,
381*c411db7bSPeter Maydell                                uint32_t icid, CTEntry *cte)
382*c411db7bSPeter Maydell {
383*c411db7bSPeter Maydell     if (icid >= s->ct.num_entries) {
384*c411db7bSPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid ICID 0x%x\n", who, icid);
385*c411db7bSPeter Maydell         return CMD_CONTINUE;
386*c411db7bSPeter Maydell     }
387*c411db7bSPeter Maydell     if (get_cte(s, icid, cte) != MEMTX_OK) {
388*c411db7bSPeter Maydell         return CMD_STALL;
389*c411db7bSPeter Maydell     }
390*c411db7bSPeter Maydell     if (!cte->valid) {
391*c411db7bSPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid CTE\n", who);
392*c411db7bSPeter Maydell         return CMD_CONTINUE;
393*c411db7bSPeter Maydell     }
394*c411db7bSPeter Maydell     if (cte->rdbase >= s->gicv3->num_cpu) {
395*c411db7bSPeter Maydell         return CMD_CONTINUE;
396*c411db7bSPeter Maydell     }
397*c411db7bSPeter Maydell     return CMD_CONTINUE_OK;
398*c411db7bSPeter Maydell }
399*c411db7bSPeter Maydell 
400*c411db7bSPeter Maydell 
401*c411db7bSPeter Maydell /*
402c694cb4cSShashi Mallela  * This function handles the processing of following commands based on
403c694cb4cSShashi Mallela  * the ItsCmdType parameter passed:-
404c694cb4cSShashi Mallela  * 1. triggering of lpi interrupt translation via ITS INT command
405c694cb4cSShashi Mallela  * 2. triggering of lpi interrupt translation via gits_translater register
406c694cb4cSShashi Mallela  * 3. handling of ITS CLEAR command
407c694cb4cSShashi Mallela  * 4. handling of ITS DISCARD command
408c694cb4cSShashi Mallela  */
409b6f96009SPeter Maydell static ItsCmdResult do_process_its_cmd(GICv3ITSState *s, uint32_t devid,
410b6f96009SPeter Maydell                                        uint32_t eventid, ItsCmdType cmd)
411c694cb4cSShashi Mallela {
4124acf93e1SPeter Maydell     DTEntry dte;
413d37cf49bSPeter Maydell     CTEntry cte;
414244194feSPeter Maydell     ITEntry ite;
415f0175135SPeter Maydell     ItsCmdResult cmdres;
416c694cb4cSShashi Mallela 
417f0175135SPeter Maydell     cmdres = lookup_ite(s, __func__, devid, eventid, &ite, &dte);
418f0175135SPeter Maydell     if (cmdres != CMD_CONTINUE_OK) {
419f0175135SPeter Maydell         return cmdres;
420b13148d9SPeter Maydell     }
421b13148d9SPeter Maydell 
422f0175135SPeter Maydell     if (ite.inttype != ITE_INTTYPE_PHYSICAL) {
423be0ed8fbSPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
424be0ed8fbSPeter Maydell                       "%s: invalid command attributes: invalid ITE\n",
425be0ed8fbSPeter Maydell                       __func__);
426be0ed8fbSPeter Maydell         return CMD_CONTINUE;
427be0ed8fbSPeter Maydell     }
428be0ed8fbSPeter Maydell 
429*c411db7bSPeter Maydell     cmdres = lookup_cte(s, __func__, ite.icid, &cte);
430*c411db7bSPeter Maydell     if (cmdres != CMD_CONTINUE_OK) {
431*c411db7bSPeter Maydell         return cmdres;
43217fb5e36SShashi Mallela     }
43317fb5e36SShashi Mallela 
43417fb5e36SShashi Mallela     if ((cmd == CLEAR) || (cmd == DISCARD)) {
435244194feSPeter Maydell         gicv3_redist_process_lpi(&s->gicv3->cpu[cte.rdbase], ite.intid, 0);
43617fb5e36SShashi Mallela     } else {
437244194feSPeter Maydell         gicv3_redist_process_lpi(&s->gicv3->cpu[cte.rdbase], ite.intid, 1);
43817fb5e36SShashi Mallela     }
43917fb5e36SShashi Mallela 
440c694cb4cSShashi Mallela     if (cmd == DISCARD) {
4417eb54267SPeter Maydell         ITEntry ite = {};
442c694cb4cSShashi Mallela         /* remove mapping from interrupt translation table */
4437eb54267SPeter Maydell         ite.valid = false;
44493f4fdcdSPeter Maydell         return update_ite(s, eventid, &dte, &ite) ? CMD_CONTINUE_OK : CMD_STALL;
445c694cb4cSShashi Mallela     }
44693f4fdcdSPeter Maydell     return CMD_CONTINUE_OK;
447c694cb4cSShashi Mallela }
4482a199036SPeter Maydell 
449b6f96009SPeter Maydell static ItsCmdResult process_its_cmd(GICv3ITSState *s, const uint64_t *cmdpkt,
450b6f96009SPeter Maydell                                     ItsCmdType cmd)
451c694cb4cSShashi Mallela {
452b6f96009SPeter Maydell     uint32_t devid, eventid;
453b6f96009SPeter Maydell 
454b6f96009SPeter Maydell     devid = (cmdpkt[0] & DEVID_MASK) >> DEVID_SHIFT;
455b6f96009SPeter Maydell     eventid = cmdpkt[1] & EVENTID_MASK;
456e4050980SPeter Maydell     switch (cmd) {
457e4050980SPeter Maydell     case INTERRUPT:
458e4050980SPeter Maydell         trace_gicv3_its_cmd_int(devid, eventid);
459e4050980SPeter Maydell         break;
460e4050980SPeter Maydell     case CLEAR:
461e4050980SPeter Maydell         trace_gicv3_its_cmd_clear(devid, eventid);
462e4050980SPeter Maydell         break;
463e4050980SPeter Maydell     case DISCARD:
464e4050980SPeter Maydell         trace_gicv3_its_cmd_discard(devid, eventid);
465e4050980SPeter Maydell         break;
466e4050980SPeter Maydell     default:
467e4050980SPeter Maydell         g_assert_not_reached();
468e4050980SPeter Maydell     }
469b6f96009SPeter Maydell     return do_process_its_cmd(s, devid, eventid, cmd);
470b6f96009SPeter Maydell }
471b6f96009SPeter Maydell 
472b6f96009SPeter Maydell static ItsCmdResult process_mapti(GICv3ITSState *s, const uint64_t *cmdpkt,
473b6f96009SPeter Maydell                                   bool ignore_pInt)
474b6f96009SPeter Maydell {
475c694cb4cSShashi Mallela     uint32_t devid, eventid;
476c694cb4cSShashi Mallela     uint32_t pIntid = 0;
4778f809f69SPeter Maydell     uint64_t num_eventids;
478c694cb4cSShashi Mallela     uint16_t icid = 0;
4794acf93e1SPeter Maydell     DTEntry dte;
4807eb54267SPeter Maydell     ITEntry ite;
481c694cb4cSShashi Mallela 
482b6f96009SPeter Maydell     devid = (cmdpkt[0] & DEVID_MASK) >> DEVID_SHIFT;
483b6f96009SPeter Maydell     eventid = cmdpkt[1] & EVENTID_MASK;
484e4050980SPeter Maydell     icid = cmdpkt[2] & ICID_MASK;
485c694cb4cSShashi Mallela 
486b87fab1cSPeter Maydell     if (ignore_pInt) {
487b87fab1cSPeter Maydell         pIntid = eventid;
488e4050980SPeter Maydell         trace_gicv3_its_cmd_mapi(devid, eventid, icid);
489b87fab1cSPeter Maydell     } else {
490b6f96009SPeter Maydell         pIntid = (cmdpkt[1] & pINTID_MASK) >> pINTID_SHIFT;
491e4050980SPeter Maydell         trace_gicv3_its_cmd_mapti(devid, eventid, icid, pIntid);
492c694cb4cSShashi Mallela     }
493c694cb4cSShashi Mallela 
4948b8bb014SPeter Maydell     if (devid >= s->dt.num_entries) {
495b13148d9SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
496b13148d9SPeter Maydell                       "%s: invalid command attributes: devid %d>=%d",
4978b8bb014SPeter Maydell                       __func__, devid, s->dt.num_entries);
498b13148d9SPeter Maydell         return CMD_CONTINUE;
499b13148d9SPeter Maydell     }
500b13148d9SPeter Maydell 
5014acf93e1SPeter Maydell     if (get_dte(s, devid, &dte) != MEMTX_OK) {
5020241f731SPeter Maydell         return CMD_STALL;
503c694cb4cSShashi Mallela     }
5044acf93e1SPeter Maydell     num_eventids = 1ULL << (dte.size + 1);
505c694cb4cSShashi Mallela 
506d7d359c4SPeter Maydell     if (icid >= s->ct.num_entries) {
507c694cb4cSShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
508d7d359c4SPeter Maydell                       "%s: invalid ICID 0x%x >= 0x%x\n",
509d7d359c4SPeter Maydell                       __func__, icid, s->ct.num_entries);
510d7d359c4SPeter Maydell         return CMD_CONTINUE;
511d7d359c4SPeter Maydell     }
512d7d359c4SPeter Maydell 
513d7d359c4SPeter Maydell     if (!dte.valid) {
514d7d359c4SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
515d7d359c4SPeter Maydell                       "%s: no valid DTE for devid 0x%x\n", __func__, devid);
516d7d359c4SPeter Maydell         return CMD_CONTINUE;
517d7d359c4SPeter Maydell     }
518d7d359c4SPeter Maydell 
519d7d359c4SPeter Maydell     if (eventid >= num_eventids) {
520d7d359c4SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
521d7d359c4SPeter Maydell                       "%s: invalid event ID 0x%x >= 0x%" PRIx64 "\n",
522d7d359c4SPeter Maydell                       __func__, eventid, num_eventids);
523d7d359c4SPeter Maydell         return CMD_CONTINUE;
524d7d359c4SPeter Maydell     }
525d7d359c4SPeter Maydell 
526c3c9a090SPeter Maydell     if (!intid_in_lpi_range(pIntid)) {
527d7d359c4SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
528d7d359c4SPeter Maydell                       "%s: invalid interrupt ID 0x%x\n", __func__, pIntid);
5290241f731SPeter Maydell         return CMD_CONTINUE;
5300241f731SPeter Maydell     }
5310241f731SPeter Maydell 
532c694cb4cSShashi Mallela     /* add ite entry to interrupt translation table */
5337eb54267SPeter Maydell     ite.valid = true;
5347eb54267SPeter Maydell     ite.inttype = ITE_INTTYPE_PHYSICAL;
5357eb54267SPeter Maydell     ite.intid = pIntid;
5367eb54267SPeter Maydell     ite.icid = icid;
5377eb54267SPeter Maydell     ite.doorbell = INTID_SPURIOUS;
5387eb54267SPeter Maydell     ite.vpeid = 0;
53993f4fdcdSPeter Maydell     return update_ite(s, eventid, &dte, &ite) ? CMD_CONTINUE_OK : CMD_STALL;
540c694cb4cSShashi Mallela }
541c694cb4cSShashi Mallela 
5429de53de6SPeter Maydell static ItsCmdResult process_vmapti(GICv3ITSState *s, const uint64_t *cmdpkt,
5439de53de6SPeter Maydell                                    bool ignore_vintid)
5449de53de6SPeter Maydell {
5459de53de6SPeter Maydell     uint32_t devid, eventid, vintid, doorbell, vpeid;
5469de53de6SPeter Maydell     uint32_t num_eventids;
5479de53de6SPeter Maydell     DTEntry dte;
5489de53de6SPeter Maydell     ITEntry ite;
5499de53de6SPeter Maydell 
5509de53de6SPeter Maydell     if (!its_feature_virtual(s)) {
5519de53de6SPeter Maydell         return CMD_CONTINUE;
5529de53de6SPeter Maydell     }
5539de53de6SPeter Maydell 
5549de53de6SPeter Maydell     devid = FIELD_EX64(cmdpkt[0], VMAPTI_0, DEVICEID);
5559de53de6SPeter Maydell     eventid = FIELD_EX64(cmdpkt[1], VMAPTI_1, EVENTID);
5569de53de6SPeter Maydell     vpeid = FIELD_EX64(cmdpkt[1], VMAPTI_1, VPEID);
5579de53de6SPeter Maydell     doorbell = FIELD_EX64(cmdpkt[2], VMAPTI_2, DOORBELL);
5589de53de6SPeter Maydell     if (ignore_vintid) {
5599de53de6SPeter Maydell         vintid = eventid;
5609de53de6SPeter Maydell         trace_gicv3_its_cmd_vmapi(devid, eventid, vpeid, doorbell);
5619de53de6SPeter Maydell     } else {
5629de53de6SPeter Maydell         vintid = FIELD_EX64(cmdpkt[2], VMAPTI_2, VINTID);
5639de53de6SPeter Maydell         trace_gicv3_its_cmd_vmapti(devid, eventid, vpeid, vintid, doorbell);
5649de53de6SPeter Maydell     }
5659de53de6SPeter Maydell 
5669de53de6SPeter Maydell     if (devid >= s->dt.num_entries) {
5679de53de6SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
5689de53de6SPeter Maydell                       "%s: invalid DeviceID 0x%x (must be less than 0x%x)\n",
5699de53de6SPeter Maydell                       __func__, devid, s->dt.num_entries);
5709de53de6SPeter Maydell         return CMD_CONTINUE;
5719de53de6SPeter Maydell     }
5729de53de6SPeter Maydell 
5739de53de6SPeter Maydell     if (get_dte(s, devid, &dte) != MEMTX_OK) {
5749de53de6SPeter Maydell         return CMD_STALL;
5759de53de6SPeter Maydell     }
5769de53de6SPeter Maydell 
5779de53de6SPeter Maydell     if (!dte.valid) {
5789de53de6SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
5799de53de6SPeter Maydell                       "%s: no entry in device table for DeviceID 0x%x\n",
5809de53de6SPeter Maydell                       __func__, devid);
5819de53de6SPeter Maydell         return CMD_CONTINUE;
5829de53de6SPeter Maydell     }
5839de53de6SPeter Maydell 
5849de53de6SPeter Maydell     num_eventids = 1ULL << (dte.size + 1);
5859de53de6SPeter Maydell 
5869de53de6SPeter Maydell     if (eventid >= num_eventids) {
5879de53de6SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
5889de53de6SPeter Maydell                       "%s: EventID 0x%x too large for DeviceID 0x%x "
5899de53de6SPeter Maydell                       "(must be less than 0x%x)\n",
5909de53de6SPeter Maydell                       __func__, eventid, devid, num_eventids);
5919de53de6SPeter Maydell         return CMD_CONTINUE;
5929de53de6SPeter Maydell     }
5939de53de6SPeter Maydell     if (!intid_in_lpi_range(vintid)) {
5949de53de6SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
5959de53de6SPeter Maydell                       "%s: VIntID 0x%x not a valid LPI\n",
5969de53de6SPeter Maydell                       __func__, vintid);
5979de53de6SPeter Maydell         return CMD_CONTINUE;
5989de53de6SPeter Maydell     }
5999de53de6SPeter Maydell     if (!valid_doorbell(doorbell)) {
6009de53de6SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
6019de53de6SPeter Maydell                       "%s: Doorbell %d not 1023 and not a valid LPI\n",
6029de53de6SPeter Maydell                       __func__, doorbell);
6039de53de6SPeter Maydell         return CMD_CONTINUE;
6049de53de6SPeter Maydell     }
6059de53de6SPeter Maydell     if (vpeid >= s->vpet.num_entries) {
6069de53de6SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
6079de53de6SPeter Maydell                       "%s: VPEID 0x%x out of range (must be less than 0x%x)\n",
6089de53de6SPeter Maydell                       __func__, vpeid, s->vpet.num_entries);
6099de53de6SPeter Maydell         return CMD_CONTINUE;
6109de53de6SPeter Maydell     }
6119de53de6SPeter Maydell     /* add ite entry to interrupt translation table */
6129de53de6SPeter Maydell     ite.valid = true;
6139de53de6SPeter Maydell     ite.inttype = ITE_INTTYPE_VIRTUAL;
6149de53de6SPeter Maydell     ite.intid = vintid;
6159de53de6SPeter Maydell     ite.icid = 0;
6169de53de6SPeter Maydell     ite.doorbell = doorbell;
6179de53de6SPeter Maydell     ite.vpeid = vpeid;
61893f4fdcdSPeter Maydell     return update_ite(s, eventid, &dte, &ite) ? CMD_CONTINUE_OK : CMD_STALL;
6199de53de6SPeter Maydell }
6209de53de6SPeter Maydell 
62106985cc3SPeter Maydell /*
62206985cc3SPeter Maydell  * Update the Collection Table entry for @icid to @cte. Returns true
62306985cc3SPeter Maydell  * on success, false if there was a memory access error.
62406985cc3SPeter Maydell  */
62506985cc3SPeter Maydell static bool update_cte(GICv3ITSState *s, uint16_t icid, const CTEntry *cte)
6267eca39e0SShashi Mallela {
6277eca39e0SShashi Mallela     AddressSpace *as = &s->gicv3->dma_as;
628d050f80fSPeter Maydell     uint64_t entry_addr;
62906985cc3SPeter Maydell     uint64_t cteval = 0;
6307eca39e0SShashi Mallela     MemTxResult res = MEMTX_OK;
6317eca39e0SShashi Mallela 
632930f40e9SPeter Maydell     trace_gicv3_its_cte_write(icid, cte->valid, cte->rdbase);
633930f40e9SPeter Maydell 
63406985cc3SPeter Maydell     if (cte->valid) {
6357eca39e0SShashi Mallela         /* add mapping entry to collection table */
63606985cc3SPeter Maydell         cteval = FIELD_DP64(cteval, CTE, VALID, 1);
63706985cc3SPeter Maydell         cteval = FIELD_DP64(cteval, CTE, RDBASE, cte->rdbase);
6387eca39e0SShashi Mallela     }
6397eca39e0SShashi Mallela 
640d050f80fSPeter Maydell     entry_addr = table_entry_addr(s, &s->ct, icid, &res);
6417eca39e0SShashi Mallela     if (res != MEMTX_OK) {
642d050f80fSPeter Maydell         /* memory access error: stall */
6437eca39e0SShashi Mallela         return false;
6447eca39e0SShashi Mallela     }
645d050f80fSPeter Maydell     if (entry_addr == -1) {
646d050f80fSPeter Maydell         /* No L2 table for this index: discard write and continue */
6477eca39e0SShashi Mallela         return true;
6487eca39e0SShashi Mallela     }
649d050f80fSPeter Maydell 
65006985cc3SPeter Maydell     address_space_stq_le(as, entry_addr, cteval, MEMTXATTRS_UNSPECIFIED, &res);
651d050f80fSPeter Maydell     return res == MEMTX_OK;
6527eca39e0SShashi Mallela }
6537eca39e0SShashi Mallela 
654b6f96009SPeter Maydell static ItsCmdResult process_mapc(GICv3ITSState *s, const uint64_t *cmdpkt)
6557eca39e0SShashi Mallela {
6567eca39e0SShashi Mallela     uint16_t icid;
65706985cc3SPeter Maydell     CTEntry cte;
6587eca39e0SShashi Mallela 
659b6f96009SPeter Maydell     icid = cmdpkt[2] & ICID_MASK;
66084d43d2eSPeter Maydell     cte.valid = cmdpkt[2] & CMD_FIELD_VALID_MASK;
66184d43d2eSPeter Maydell     if (cte.valid) {
66206985cc3SPeter Maydell         cte.rdbase = (cmdpkt[2] & R_MAPC_RDBASE_MASK) >> R_MAPC_RDBASE_SHIFT;
66306985cc3SPeter Maydell         cte.rdbase &= RDBASE_PROCNUM_MASK;
66484d43d2eSPeter Maydell     } else {
66584d43d2eSPeter Maydell         cte.rdbase = 0;
66684d43d2eSPeter Maydell     }
667e4050980SPeter Maydell     trace_gicv3_its_cmd_mapc(icid, cte.rdbase, cte.valid);
6687eca39e0SShashi Mallela 
66984d43d2eSPeter Maydell     if (icid >= s->ct.num_entries) {
670c7ca3ad5SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR, "ITS MAPC: invalid ICID 0x%x\n", icid);
67184d43d2eSPeter Maydell         return CMD_CONTINUE;
67284d43d2eSPeter Maydell     }
67384d43d2eSPeter Maydell     if (cte.valid && cte.rdbase >= s->gicv3->num_cpu) {
6747eca39e0SShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
675c7ca3ad5SPeter Maydell                       "ITS MAPC: invalid RDBASE %u\n", cte.rdbase);
676f6675196SPeter Maydell         return CMD_CONTINUE;
6777eca39e0SShashi Mallela     }
6787eca39e0SShashi Mallela 
67993f4fdcdSPeter Maydell     return update_cte(s, icid, &cte) ? CMD_CONTINUE_OK : CMD_STALL;
6807eca39e0SShashi Mallela }
6817eca39e0SShashi Mallela 
68222d62b08SPeter Maydell /*
68322d62b08SPeter Maydell  * Update the Device Table entry for @devid to @dte. Returns true
68422d62b08SPeter Maydell  * on success, false if there was a memory access error.
68522d62b08SPeter Maydell  */
68622d62b08SPeter Maydell static bool update_dte(GICv3ITSState *s, uint32_t devid, const DTEntry *dte)
6877eca39e0SShashi Mallela {
6887eca39e0SShashi Mallela     AddressSpace *as = &s->gicv3->dma_as;
689d050f80fSPeter Maydell     uint64_t entry_addr;
69022d62b08SPeter Maydell     uint64_t dteval = 0;
6917eca39e0SShashi Mallela     MemTxResult res = MEMTX_OK;
6927eca39e0SShashi Mallela 
693930f40e9SPeter Maydell     trace_gicv3_its_dte_write(devid, dte->valid, dte->size, dte->ittaddr);
694930f40e9SPeter Maydell 
69522d62b08SPeter Maydell     if (dte->valid) {
6967eca39e0SShashi Mallela         /* add mapping entry to device table */
69722d62b08SPeter Maydell         dteval = FIELD_DP64(dteval, DTE, VALID, 1);
69822d62b08SPeter Maydell         dteval = FIELD_DP64(dteval, DTE, SIZE, dte->size);
69922d62b08SPeter Maydell         dteval = FIELD_DP64(dteval, DTE, ITTADDR, dte->ittaddr);
7007eca39e0SShashi Mallela     }
7017eca39e0SShashi Mallela 
702d050f80fSPeter Maydell     entry_addr = table_entry_addr(s, &s->dt, devid, &res);
7037eca39e0SShashi Mallela     if (res != MEMTX_OK) {
704d050f80fSPeter Maydell         /* memory access error: stall */
7057eca39e0SShashi Mallela         return false;
7067eca39e0SShashi Mallela     }
707d050f80fSPeter Maydell     if (entry_addr == -1) {
708d050f80fSPeter Maydell         /* No L2 table for this index: discard write and continue */
7097eca39e0SShashi Mallela         return true;
7107eca39e0SShashi Mallela     }
71122d62b08SPeter Maydell     address_space_stq_le(as, entry_addr, dteval, MEMTXATTRS_UNSPECIFIED, &res);
712d050f80fSPeter Maydell     return res == MEMTX_OK;
7137eca39e0SShashi Mallela }
7147eca39e0SShashi Mallela 
715b6f96009SPeter Maydell static ItsCmdResult process_mapd(GICv3ITSState *s, const uint64_t *cmdpkt)
7167eca39e0SShashi Mallela {
7177eca39e0SShashi Mallela     uint32_t devid;
71822d62b08SPeter Maydell     DTEntry dte;
7197eca39e0SShashi Mallela 
720b6f96009SPeter Maydell     devid = (cmdpkt[0] & DEVID_MASK) >> DEVID_SHIFT;
72122d62b08SPeter Maydell     dte.size = cmdpkt[1] & SIZE_MASK;
72222d62b08SPeter Maydell     dte.ittaddr = (cmdpkt[2] & ITTADDR_MASK) >> ITTADDR_SHIFT;
72322d62b08SPeter Maydell     dte.valid = cmdpkt[2] & CMD_FIELD_VALID_MASK;
7247eca39e0SShashi Mallela 
725e4050980SPeter Maydell     trace_gicv3_its_cmd_mapd(devid, dte.size, dte.ittaddr, dte.valid);
726e4050980SPeter Maydell 
727d7d359c4SPeter Maydell     if (devid >= s->dt.num_entries) {
7287eca39e0SShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
729d7d359c4SPeter Maydell                       "ITS MAPD: invalid device ID field 0x%x >= 0x%x\n",
730d7d359c4SPeter Maydell                       devid, s->dt.num_entries);
731d7d359c4SPeter Maydell         return CMD_CONTINUE;
732d7d359c4SPeter Maydell     }
733d7d359c4SPeter Maydell 
734d7d359c4SPeter Maydell     if (dte.size > FIELD_EX64(s->typer, GITS_TYPER, IDBITS)) {
735d7d359c4SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
736d7d359c4SPeter Maydell                       "ITS MAPD: invalid size %d\n", dte.size);
73700d46e72SPeter Maydell         return CMD_CONTINUE;
7387eca39e0SShashi Mallela     }
7397eca39e0SShashi Mallela 
74093f4fdcdSPeter Maydell     return update_dte(s, devid, &dte) ? CMD_CONTINUE_OK : CMD_STALL;
7417eca39e0SShashi Mallela }
7427eca39e0SShashi Mallela 
743b6f96009SPeter Maydell static ItsCmdResult process_movall(GICv3ITSState *s, const uint64_t *cmdpkt)
744f6d1d9b4SPeter Maydell {
745f6d1d9b4SPeter Maydell     uint64_t rd1, rd2;
746f6d1d9b4SPeter Maydell 
747b6f96009SPeter Maydell     rd1 = FIELD_EX64(cmdpkt[2], MOVALL_2, RDBASE1);
748b6f96009SPeter Maydell     rd2 = FIELD_EX64(cmdpkt[3], MOVALL_3, RDBASE2);
749f6d1d9b4SPeter Maydell 
750e4050980SPeter Maydell     trace_gicv3_its_cmd_movall(rd1, rd2);
751e4050980SPeter Maydell 
752f6d1d9b4SPeter Maydell     if (rd1 >= s->gicv3->num_cpu) {
753f6d1d9b4SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
754f6d1d9b4SPeter Maydell                       "%s: RDBASE1 %" PRId64
755f6d1d9b4SPeter Maydell                       " out of range (must be less than %d)\n",
756f6d1d9b4SPeter Maydell                       __func__, rd1, s->gicv3->num_cpu);
757f6d1d9b4SPeter Maydell         return CMD_CONTINUE;
758f6d1d9b4SPeter Maydell     }
759f6d1d9b4SPeter Maydell     if (rd2 >= s->gicv3->num_cpu) {
760f6d1d9b4SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
761f6d1d9b4SPeter Maydell                       "%s: RDBASE2 %" PRId64
762f6d1d9b4SPeter Maydell                       " out of range (must be less than %d)\n",
763f6d1d9b4SPeter Maydell                       __func__, rd2, s->gicv3->num_cpu);
764f6d1d9b4SPeter Maydell         return CMD_CONTINUE;
765f6d1d9b4SPeter Maydell     }
766f6d1d9b4SPeter Maydell 
767f6d1d9b4SPeter Maydell     if (rd1 == rd2) {
768f6d1d9b4SPeter Maydell         /* Move to same target must succeed as a no-op */
76993f4fdcdSPeter Maydell         return CMD_CONTINUE_OK;
770f6d1d9b4SPeter Maydell     }
771f6d1d9b4SPeter Maydell 
772f6d1d9b4SPeter Maydell     /* Move all pending LPIs from redistributor 1 to redistributor 2 */
773f6d1d9b4SPeter Maydell     gicv3_redist_movall_lpis(&s->gicv3->cpu[rd1], &s->gicv3->cpu[rd2]);
774f6d1d9b4SPeter Maydell 
77593f4fdcdSPeter Maydell     return CMD_CONTINUE_OK;
776f6d1d9b4SPeter Maydell }
777f6d1d9b4SPeter Maydell 
778b6f96009SPeter Maydell static ItsCmdResult process_movi(GICv3ITSState *s, const uint64_t *cmdpkt)
779961b4912SPeter Maydell {
780244194feSPeter Maydell     uint32_t devid, eventid;
781244194feSPeter Maydell     uint16_t new_icid;
7824acf93e1SPeter Maydell     DTEntry dte;
783d37cf49bSPeter Maydell     CTEntry old_cte, new_cte;
784244194feSPeter Maydell     ITEntry old_ite;
785f0175135SPeter Maydell     ItsCmdResult cmdres;
786961b4912SPeter Maydell 
787b6f96009SPeter Maydell     devid = FIELD_EX64(cmdpkt[0], MOVI_0, DEVICEID);
788b6f96009SPeter Maydell     eventid = FIELD_EX64(cmdpkt[1], MOVI_1, EVENTID);
789b6f96009SPeter Maydell     new_icid = FIELD_EX64(cmdpkt[2], MOVI_2, ICID);
790961b4912SPeter Maydell 
791e4050980SPeter Maydell     trace_gicv3_its_cmd_movi(devid, eventid, new_icid);
792e4050980SPeter Maydell 
793f0175135SPeter Maydell     cmdres = lookup_ite(s, __func__, devid, eventid, &old_ite, &dte);
794f0175135SPeter Maydell     if (cmdres != CMD_CONTINUE_OK) {
795f0175135SPeter Maydell         return cmdres;
796961b4912SPeter Maydell     }
797961b4912SPeter Maydell 
798f0175135SPeter Maydell     if (old_ite.inttype != ITE_INTTYPE_PHYSICAL) {
799961b4912SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
800961b4912SPeter Maydell                       "%s: invalid command attributes: invalid ITE\n",
801961b4912SPeter Maydell                       __func__);
802961b4912SPeter Maydell         return CMD_CONTINUE;
803961b4912SPeter Maydell     }
804961b4912SPeter Maydell 
805*c411db7bSPeter Maydell     cmdres = lookup_cte(s, __func__, old_ite.icid, &old_cte);
806*c411db7bSPeter Maydell     if (cmdres != CMD_CONTINUE_OK) {
807*c411db7bSPeter Maydell         return cmdres;
808961b4912SPeter Maydell     }
809*c411db7bSPeter Maydell     cmdres = lookup_cte(s, __func__, new_icid, &new_cte);
810*c411db7bSPeter Maydell     if (cmdres != CMD_CONTINUE_OK) {
811*c411db7bSPeter Maydell         return cmdres;
812961b4912SPeter Maydell     }
813961b4912SPeter Maydell 
814d37cf49bSPeter Maydell     if (old_cte.rdbase != new_cte.rdbase) {
815961b4912SPeter Maydell         /* Move the LPI from the old redistributor to the new one */
816d37cf49bSPeter Maydell         gicv3_redist_mov_lpi(&s->gicv3->cpu[old_cte.rdbase],
817d37cf49bSPeter Maydell                              &s->gicv3->cpu[new_cte.rdbase],
818244194feSPeter Maydell                              old_ite.intid);
819961b4912SPeter Maydell     }
820961b4912SPeter Maydell 
821961b4912SPeter Maydell     /* Update the ICID field in the interrupt translation table entry */
8227eb54267SPeter Maydell     old_ite.icid = new_icid;
82393f4fdcdSPeter Maydell     return update_ite(s, eventid, &dte, &old_ite) ? CMD_CONTINUE_OK : CMD_STALL;
824961b4912SPeter Maydell }
825961b4912SPeter Maydell 
8267eca39e0SShashi Mallela /*
8270cdf7a5dSPeter Maydell  * Update the vPE Table entry at index @vpeid with the entry @vte.
8280cdf7a5dSPeter Maydell  * Returns true on success, false if there was a memory access error.
8290cdf7a5dSPeter Maydell  */
8300cdf7a5dSPeter Maydell static bool update_vte(GICv3ITSState *s, uint32_t vpeid, const VTEntry *vte)
8310cdf7a5dSPeter Maydell {
8320cdf7a5dSPeter Maydell     AddressSpace *as = &s->gicv3->dma_as;
8330cdf7a5dSPeter Maydell     uint64_t entry_addr;
8340cdf7a5dSPeter Maydell     uint64_t vteval = 0;
8350cdf7a5dSPeter Maydell     MemTxResult res = MEMTX_OK;
8360cdf7a5dSPeter Maydell 
8370cdf7a5dSPeter Maydell     trace_gicv3_its_vte_write(vpeid, vte->valid, vte->vptsize, vte->vptaddr,
8380cdf7a5dSPeter Maydell                               vte->rdbase);
8390cdf7a5dSPeter Maydell 
8400cdf7a5dSPeter Maydell     if (vte->valid) {
8410cdf7a5dSPeter Maydell         vteval = FIELD_DP64(vteval, VTE, VALID, 1);
8420cdf7a5dSPeter Maydell         vteval = FIELD_DP64(vteval, VTE, VPTSIZE, vte->vptsize);
8430cdf7a5dSPeter Maydell         vteval = FIELD_DP64(vteval, VTE, VPTADDR, vte->vptaddr);
8440cdf7a5dSPeter Maydell         vteval = FIELD_DP64(vteval, VTE, RDBASE, vte->rdbase);
8450cdf7a5dSPeter Maydell     }
8460cdf7a5dSPeter Maydell 
8470cdf7a5dSPeter Maydell     entry_addr = table_entry_addr(s, &s->vpet, vpeid, &res);
8480cdf7a5dSPeter Maydell     if (res != MEMTX_OK) {
8490cdf7a5dSPeter Maydell         return false;
8500cdf7a5dSPeter Maydell     }
8510cdf7a5dSPeter Maydell     if (entry_addr == -1) {
8520cdf7a5dSPeter Maydell         /* No L2 table for this index: discard write and continue */
8530cdf7a5dSPeter Maydell         return true;
8540cdf7a5dSPeter Maydell     }
8550cdf7a5dSPeter Maydell     address_space_stq_le(as, entry_addr, vteval, MEMTXATTRS_UNSPECIFIED, &res);
8560cdf7a5dSPeter Maydell     return res == MEMTX_OK;
8570cdf7a5dSPeter Maydell }
8580cdf7a5dSPeter Maydell 
8590cdf7a5dSPeter Maydell static ItsCmdResult process_vmapp(GICv3ITSState *s, const uint64_t *cmdpkt)
8600cdf7a5dSPeter Maydell {
8610cdf7a5dSPeter Maydell     VTEntry vte;
8620cdf7a5dSPeter Maydell     uint32_t vpeid;
8630cdf7a5dSPeter Maydell 
8640cdf7a5dSPeter Maydell     if (!its_feature_virtual(s)) {
8650cdf7a5dSPeter Maydell         return CMD_CONTINUE;
8660cdf7a5dSPeter Maydell     }
8670cdf7a5dSPeter Maydell 
8680cdf7a5dSPeter Maydell     vpeid = FIELD_EX64(cmdpkt[1], VMAPP_1, VPEID);
8690cdf7a5dSPeter Maydell     vte.rdbase = FIELD_EX64(cmdpkt[2], VMAPP_2, RDBASE);
8700cdf7a5dSPeter Maydell     vte.valid = FIELD_EX64(cmdpkt[2], VMAPP_2, V);
8710cdf7a5dSPeter Maydell     vte.vptsize = FIELD_EX64(cmdpkt[3], VMAPP_3, VPTSIZE);
8720cdf7a5dSPeter Maydell     vte.vptaddr = FIELD_EX64(cmdpkt[3], VMAPP_3, VPTADDR);
8730cdf7a5dSPeter Maydell 
8740cdf7a5dSPeter Maydell     trace_gicv3_its_cmd_vmapp(vpeid, vte.rdbase, vte.valid,
8750cdf7a5dSPeter Maydell                               vte.vptaddr, vte.vptsize);
8760cdf7a5dSPeter Maydell 
8770cdf7a5dSPeter Maydell     /*
8780cdf7a5dSPeter Maydell      * For GICv4.0 the VPT_size field is only 5 bits, whereas we
8790cdf7a5dSPeter Maydell      * define our field macros to include the full GICv4.1 8 bits.
8800cdf7a5dSPeter Maydell      * The range check on VPT_size will catch the cases where
8810cdf7a5dSPeter Maydell      * the guest set the RES0-in-GICv4.0 bits [7:6].
8820cdf7a5dSPeter Maydell      */
8830cdf7a5dSPeter Maydell     if (vte.vptsize > FIELD_EX64(s->typer, GITS_TYPER, IDBITS)) {
8840cdf7a5dSPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
8850cdf7a5dSPeter Maydell                       "%s: invalid VPT_size 0x%x\n", __func__, vte.vptsize);
8860cdf7a5dSPeter Maydell         return CMD_CONTINUE;
8870cdf7a5dSPeter Maydell     }
8880cdf7a5dSPeter Maydell 
8890cdf7a5dSPeter Maydell     if (vte.valid && vte.rdbase >= s->gicv3->num_cpu) {
8900cdf7a5dSPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
8910cdf7a5dSPeter Maydell                       "%s: invalid rdbase 0x%x\n", __func__, vte.rdbase);
8920cdf7a5dSPeter Maydell         return CMD_CONTINUE;
8930cdf7a5dSPeter Maydell     }
8940cdf7a5dSPeter Maydell 
8950cdf7a5dSPeter Maydell     if (vpeid >= s->vpet.num_entries) {
8960cdf7a5dSPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
8970cdf7a5dSPeter Maydell                       "%s: VPEID 0x%x out of range (must be less than 0x%x)\n",
8980cdf7a5dSPeter Maydell                       __func__, vpeid, s->vpet.num_entries);
8990cdf7a5dSPeter Maydell         return CMD_CONTINUE;
9000cdf7a5dSPeter Maydell     }
9010cdf7a5dSPeter Maydell 
90293f4fdcdSPeter Maydell     return update_vte(s, vpeid, &vte) ? CMD_CONTINUE_OK : CMD_STALL;
9030cdf7a5dSPeter Maydell }
9040cdf7a5dSPeter Maydell 
9050cdf7a5dSPeter Maydell /*
9067eca39e0SShashi Mallela  * Current implementation blocks until all
9077eca39e0SShashi Mallela  * commands are processed
9087eca39e0SShashi Mallela  */
9097eca39e0SShashi Mallela static void process_cmdq(GICv3ITSState *s)
9107eca39e0SShashi Mallela {
9117eca39e0SShashi Mallela     uint32_t wr_offset = 0;
9127eca39e0SShashi Mallela     uint32_t rd_offset = 0;
9137eca39e0SShashi Mallela     uint32_t cq_offset = 0;
9147eca39e0SShashi Mallela     AddressSpace *as = &s->gicv3->dma_as;
9157eca39e0SShashi Mallela     uint8_t cmd;
91617fb5e36SShashi Mallela     int i;
9177eca39e0SShashi Mallela 
9188d2d6dd9SPeter Maydell     if (!(s->ctlr & R_GITS_CTLR_ENABLED_MASK)) {
9197eca39e0SShashi Mallela         return;
9207eca39e0SShashi Mallela     }
9217eca39e0SShashi Mallela 
9227eca39e0SShashi Mallela     wr_offset = FIELD_EX64(s->cwriter, GITS_CWRITER, OFFSET);
9237eca39e0SShashi Mallela 
92480dcd37fSPeter Maydell     if (wr_offset >= s->cq.num_entries) {
9257eca39e0SShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
9267eca39e0SShashi Mallela                       "%s: invalid write offset "
9277eca39e0SShashi Mallela                       "%d\n", __func__, wr_offset);
9287eca39e0SShashi Mallela         return;
9297eca39e0SShashi Mallela     }
9307eca39e0SShashi Mallela 
9317eca39e0SShashi Mallela     rd_offset = FIELD_EX64(s->creadr, GITS_CREADR, OFFSET);
9327eca39e0SShashi Mallela 
93380dcd37fSPeter Maydell     if (rd_offset >= s->cq.num_entries) {
9347eca39e0SShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
9357eca39e0SShashi Mallela                       "%s: invalid read offset "
9367eca39e0SShashi Mallela                       "%d\n", __func__, rd_offset);
9377eca39e0SShashi Mallela         return;
9387eca39e0SShashi Mallela     }
9397eca39e0SShashi Mallela 
9407eca39e0SShashi Mallela     while (wr_offset != rd_offset) {
94193f4fdcdSPeter Maydell         ItsCmdResult result = CMD_CONTINUE_OK;
942b6f96009SPeter Maydell         void *hostmem;
943b6f96009SPeter Maydell         hwaddr buflen;
944b6f96009SPeter Maydell         uint64_t cmdpkt[GITS_CMDQ_ENTRY_WORDS];
945ef011555SPeter Maydell 
9467eca39e0SShashi Mallela         cq_offset = (rd_offset * GITS_CMDQ_ENTRY_SIZE);
947b6f96009SPeter Maydell 
948b6f96009SPeter Maydell         buflen = GITS_CMDQ_ENTRY_SIZE;
949b6f96009SPeter Maydell         hostmem = address_space_map(as, s->cq.base_addr + cq_offset,
950b6f96009SPeter Maydell                                     &buflen, false, MEMTXATTRS_UNSPECIFIED);
951b6f96009SPeter Maydell         if (!hostmem || buflen != GITS_CMDQ_ENTRY_SIZE) {
952b6f96009SPeter Maydell             if (hostmem) {
953b6f96009SPeter Maydell                 address_space_unmap(as, hostmem, buflen, false, 0);
954b6f96009SPeter Maydell             }
955f0b4b2a2SPeter Maydell             s->creadr = FIELD_DP64(s->creadr, GITS_CREADR, STALLED, 1);
956f0b4b2a2SPeter Maydell             qemu_log_mask(LOG_GUEST_ERROR,
957f0b4b2a2SPeter Maydell                           "%s: could not read command at 0x%" PRIx64 "\n",
958f0b4b2a2SPeter Maydell                           __func__, s->cq.base_addr + cq_offset);
959f0b4b2a2SPeter Maydell             break;
9607eca39e0SShashi Mallela         }
961b6f96009SPeter Maydell         for (i = 0; i < ARRAY_SIZE(cmdpkt); i++) {
962b6f96009SPeter Maydell             cmdpkt[i] = ldq_le_p(hostmem + i * sizeof(uint64_t));
963b6f96009SPeter Maydell         }
964b6f96009SPeter Maydell         address_space_unmap(as, hostmem, buflen, false, 0);
965f0b4b2a2SPeter Maydell 
966b6f96009SPeter Maydell         cmd = cmdpkt[0] & CMD_MASK;
9677eca39e0SShashi Mallela 
968195209d3SPeter Maydell         trace_gicv3_its_process_command(rd_offset, cmd);
969195209d3SPeter Maydell 
9707eca39e0SShashi Mallela         switch (cmd) {
9717eca39e0SShashi Mallela         case GITS_CMD_INT:
972b6f96009SPeter Maydell             result = process_its_cmd(s, cmdpkt, INTERRUPT);
9737eca39e0SShashi Mallela             break;
9747eca39e0SShashi Mallela         case GITS_CMD_CLEAR:
975b6f96009SPeter Maydell             result = process_its_cmd(s, cmdpkt, CLEAR);
9767eca39e0SShashi Mallela             break;
9777eca39e0SShashi Mallela         case GITS_CMD_SYNC:
9787eca39e0SShashi Mallela             /*
9797eca39e0SShashi Mallela              * Current implementation makes a blocking synchronous call
9807eca39e0SShashi Mallela              * for every command issued earlier, hence the internal state
9817eca39e0SShashi Mallela              * is already consistent by the time SYNC command is executed.
9827eca39e0SShashi Mallela              * Hence no further processing is required for SYNC command.
9837eca39e0SShashi Mallela              */
984e4050980SPeter Maydell             trace_gicv3_its_cmd_sync();
9857eca39e0SShashi Mallela             break;
9867eca39e0SShashi Mallela         case GITS_CMD_MAPD:
987b6f96009SPeter Maydell             result = process_mapd(s, cmdpkt);
9887eca39e0SShashi Mallela             break;
9897eca39e0SShashi Mallela         case GITS_CMD_MAPC:
990b6f96009SPeter Maydell             result = process_mapc(s, cmdpkt);
9917eca39e0SShashi Mallela             break;
9927eca39e0SShashi Mallela         case GITS_CMD_MAPTI:
993b6f96009SPeter Maydell             result = process_mapti(s, cmdpkt, false);
9947eca39e0SShashi Mallela             break;
9957eca39e0SShashi Mallela         case GITS_CMD_MAPI:
996b6f96009SPeter Maydell             result = process_mapti(s, cmdpkt, true);
9977eca39e0SShashi Mallela             break;
9987eca39e0SShashi Mallela         case GITS_CMD_DISCARD:
999b6f96009SPeter Maydell             result = process_its_cmd(s, cmdpkt, DISCARD);
10007eca39e0SShashi Mallela             break;
10017eca39e0SShashi Mallela         case GITS_CMD_INV:
10027eca39e0SShashi Mallela         case GITS_CMD_INVALL:
100317fb5e36SShashi Mallela             /*
100417fb5e36SShashi Mallela              * Current implementation doesn't cache any ITS tables,
100517fb5e36SShashi Mallela              * but the calculated lpi priority information. We only
100617fb5e36SShashi Mallela              * need to trigger lpi priority re-calculation to be in
100717fb5e36SShashi Mallela              * sync with LPI config table or pending table changes.
100817fb5e36SShashi Mallela              */
1009e4050980SPeter Maydell             trace_gicv3_its_cmd_inv();
101017fb5e36SShashi Mallela             for (i = 0; i < s->gicv3->num_cpu; i++) {
101117fb5e36SShashi Mallela                 gicv3_redist_update_lpi(&s->gicv3->cpu[i]);
101217fb5e36SShashi Mallela             }
10137eca39e0SShashi Mallela             break;
1014961b4912SPeter Maydell         case GITS_CMD_MOVI:
1015b6f96009SPeter Maydell             result = process_movi(s, cmdpkt);
1016961b4912SPeter Maydell             break;
1017f6d1d9b4SPeter Maydell         case GITS_CMD_MOVALL:
1018b6f96009SPeter Maydell             result = process_movall(s, cmdpkt);
1019f6d1d9b4SPeter Maydell             break;
10209de53de6SPeter Maydell         case GITS_CMD_VMAPTI:
10219de53de6SPeter Maydell             result = process_vmapti(s, cmdpkt, false);
10229de53de6SPeter Maydell             break;
10239de53de6SPeter Maydell         case GITS_CMD_VMAPI:
10249de53de6SPeter Maydell             result = process_vmapti(s, cmdpkt, true);
10259de53de6SPeter Maydell             break;
10260cdf7a5dSPeter Maydell         case GITS_CMD_VMAPP:
10270cdf7a5dSPeter Maydell             result = process_vmapp(s, cmdpkt);
10280cdf7a5dSPeter Maydell             break;
10297eca39e0SShashi Mallela         default:
1030e4050980SPeter Maydell             trace_gicv3_its_cmd_unknown(cmd);
10317eca39e0SShashi Mallela             break;
10327eca39e0SShashi Mallela         }
103393f4fdcdSPeter Maydell         if (result != CMD_STALL) {
103493f4fdcdSPeter Maydell             /* CMD_CONTINUE or CMD_CONTINUE_OK */
10357eca39e0SShashi Mallela             rd_offset++;
103680dcd37fSPeter Maydell             rd_offset %= s->cq.num_entries;
10377eca39e0SShashi Mallela             s->creadr = FIELD_DP64(s->creadr, GITS_CREADR, OFFSET, rd_offset);
10387eca39e0SShashi Mallela         } else {
1039ef011555SPeter Maydell             /* CMD_STALL */
10407eca39e0SShashi Mallela             s->creadr = FIELD_DP64(s->creadr, GITS_CREADR, STALLED, 1);
10417eca39e0SShashi Mallela             qemu_log_mask(LOG_GUEST_ERROR,
1042ef011555SPeter Maydell                           "%s: 0x%x cmd processing failed, stalling\n",
1043ef011555SPeter Maydell                           __func__, cmd);
10447eca39e0SShashi Mallela             break;
10457eca39e0SShashi Mallela         }
10467eca39e0SShashi Mallela     }
10477eca39e0SShashi Mallela }
10487eca39e0SShashi Mallela 
10491b08e436SShashi Mallela /*
10501b08e436SShashi Mallela  * This function extracts the ITS Device and Collection table specific
10511b08e436SShashi Mallela  * parameters (like base_addr, size etc) from GITS_BASER register.
10521b08e436SShashi Mallela  * It is called during ITS enable and also during post_load migration
10531b08e436SShashi Mallela  */
10541b08e436SShashi Mallela static void extract_table_params(GICv3ITSState *s)
10551b08e436SShashi Mallela {
10561b08e436SShashi Mallela     uint16_t num_pages = 0;
10571b08e436SShashi Mallela     uint8_t  page_sz_type;
10581b08e436SShashi Mallela     uint8_t type;
10591b08e436SShashi Mallela     uint32_t page_sz = 0;
10601b08e436SShashi Mallela     uint64_t value;
10611b08e436SShashi Mallela 
10621b08e436SShashi Mallela     for (int i = 0; i < 8; i++) {
1063e5487a41SPeter Maydell         TableDesc *td;
1064e5487a41SPeter Maydell         int idbits;
1065e5487a41SPeter Maydell 
10661b08e436SShashi Mallela         value = s->baser[i];
10671b08e436SShashi Mallela 
10681b08e436SShashi Mallela         if (!value) {
10691b08e436SShashi Mallela             continue;
10701b08e436SShashi Mallela         }
10711b08e436SShashi Mallela 
10721b08e436SShashi Mallela         page_sz_type = FIELD_EX64(value, GITS_BASER, PAGESIZE);
10731b08e436SShashi Mallela 
10741b08e436SShashi Mallela         switch (page_sz_type) {
10751b08e436SShashi Mallela         case 0:
10761b08e436SShashi Mallela             page_sz = GITS_PAGE_SIZE_4K;
10771b08e436SShashi Mallela             break;
10781b08e436SShashi Mallela 
10791b08e436SShashi Mallela         case 1:
10801b08e436SShashi Mallela             page_sz = GITS_PAGE_SIZE_16K;
10811b08e436SShashi Mallela             break;
10821b08e436SShashi Mallela 
10831b08e436SShashi Mallela         case 2:
10841b08e436SShashi Mallela         case 3:
10851b08e436SShashi Mallela             page_sz = GITS_PAGE_SIZE_64K;
10861b08e436SShashi Mallela             break;
10871b08e436SShashi Mallela 
10881b08e436SShashi Mallela         default:
10891b08e436SShashi Mallela             g_assert_not_reached();
10901b08e436SShashi Mallela         }
10911b08e436SShashi Mallela 
10921b08e436SShashi Mallela         num_pages = FIELD_EX64(value, GITS_BASER, SIZE) + 1;
10931b08e436SShashi Mallela 
10941b08e436SShashi Mallela         type = FIELD_EX64(value, GITS_BASER, TYPE);
10951b08e436SShashi Mallela 
10961b08e436SShashi Mallela         switch (type) {
10971b08e436SShashi Mallela         case GITS_BASER_TYPE_DEVICE:
1098e5487a41SPeter Maydell             td = &s->dt;
1099e5487a41SPeter Maydell             idbits = FIELD_EX64(s->typer, GITS_TYPER, DEVBITS) + 1;
110062df780eSPeter Maydell             break;
11011b08e436SShashi Mallela         case GITS_BASER_TYPE_COLLECTION:
1102e5487a41SPeter Maydell             td = &s->ct;
11031b08e436SShashi Mallela             if (FIELD_EX64(s->typer, GITS_TYPER, CIL)) {
1104e5487a41SPeter Maydell                 idbits = FIELD_EX64(s->typer, GITS_TYPER, CIDBITS) + 1;
11051b08e436SShashi Mallela             } else {
11061b08e436SShashi Mallela                 /* 16-bit CollectionId supported when CIL == 0 */
1107e5487a41SPeter Maydell                 idbits = 16;
11081b08e436SShashi Mallela             }
11091b08e436SShashi Mallela             break;
111050d84584SPeter Maydell         case GITS_BASER_TYPE_VPE:
111150d84584SPeter Maydell             td = &s->vpet;
111250d84584SPeter Maydell             /*
111350d84584SPeter Maydell              * For QEMU vPEIDs are always 16 bits. (GICv4.1 allows an
111450d84584SPeter Maydell              * implementation to implement fewer bits and report this
111550d84584SPeter Maydell              * via GICD_TYPER2.)
111650d84584SPeter Maydell              */
111750d84584SPeter Maydell             idbits = 16;
111850d84584SPeter Maydell             break;
11191b08e436SShashi Mallela         default:
1120e5487a41SPeter Maydell             /*
1121e5487a41SPeter Maydell              * GITS_BASER<n>.TYPE is read-only, so GITS_BASER_RO_MASK
1122e5487a41SPeter Maydell              * ensures we will only see type values corresponding to
1123e5487a41SPeter Maydell              * the values set up in gicv3_its_reset().
1124e5487a41SPeter Maydell              */
1125e5487a41SPeter Maydell             g_assert_not_reached();
11261b08e436SShashi Mallela         }
1127e5487a41SPeter Maydell 
1128e5487a41SPeter Maydell         memset(td, 0, sizeof(*td));
1129e5487a41SPeter Maydell         /*
1130e5487a41SPeter Maydell          * If GITS_BASER<n>.Valid is 0 for any <n> then we will not process
1131e5487a41SPeter Maydell          * interrupts. (GITS_TYPER.HCC is 0 for this implementation, so we
1132e5487a41SPeter Maydell          * do not have a special case where the GITS_BASER<n>.Valid bit is 0
1133e5487a41SPeter Maydell          * for the register corresponding to the Collection table but we
1134e5487a41SPeter Maydell          * still have to process interrupts using non-memory-backed
1135e5487a41SPeter Maydell          * Collection table entries.)
1136da4680ceSPeter Maydell          * The specification makes it UNPREDICTABLE to enable the ITS without
1137da4680ceSPeter Maydell          * marking each BASER<n> as valid. We choose to handle these as if
1138da4680ceSPeter Maydell          * the table was zero-sized, so commands using the table will fail
1139da4680ceSPeter Maydell          * and interrupts requested via GITS_TRANSLATER writes will be ignored.
1140da4680ceSPeter Maydell          * This happens automatically by leaving the num_entries field at
1141da4680ceSPeter Maydell          * zero, which will be caught by the bounds checks we have before
1142da4680ceSPeter Maydell          * every table lookup anyway.
1143e5487a41SPeter Maydell          */
1144da4680ceSPeter Maydell         if (!FIELD_EX64(value, GITS_BASER, VALID)) {
1145e5487a41SPeter Maydell             continue;
1146e5487a41SPeter Maydell         }
1147e5487a41SPeter Maydell         td->page_sz = page_sz;
1148e5487a41SPeter Maydell         td->indirect = FIELD_EX64(value, GITS_BASER, INDIRECT);
11499ae85431SPeter Maydell         td->entry_sz = FIELD_EX64(value, GITS_BASER, ENTRYSIZE) + 1;
1150e5487a41SPeter Maydell         td->base_addr = baser_base_addr(value, page_sz);
1151e5487a41SPeter Maydell         if (!td->indirect) {
115280dcd37fSPeter Maydell             td->num_entries = (num_pages * page_sz) / td->entry_sz;
1153e5487a41SPeter Maydell         } else {
115480dcd37fSPeter Maydell             td->num_entries = (((num_pages * page_sz) /
1155e5487a41SPeter Maydell                                   L1TABLE_ENTRY_SIZE) *
1156e5487a41SPeter Maydell                                  (page_sz / td->entry_sz));
1157e5487a41SPeter Maydell         }
11588b8bb014SPeter Maydell         td->num_entries = MIN(td->num_entries, 1ULL << idbits);
11591b08e436SShashi Mallela     }
11601b08e436SShashi Mallela }
11611b08e436SShashi Mallela 
11621b08e436SShashi Mallela static void extract_cmdq_params(GICv3ITSState *s)
11631b08e436SShashi Mallela {
11641b08e436SShashi Mallela     uint16_t num_pages = 0;
11651b08e436SShashi Mallela     uint64_t value = s->cbaser;
11661b08e436SShashi Mallela 
11671b08e436SShashi Mallela     num_pages = FIELD_EX64(value, GITS_CBASER, SIZE) + 1;
11681b08e436SShashi Mallela 
11691b08e436SShashi Mallela     memset(&s->cq, 0 , sizeof(s->cq));
11701b08e436SShashi Mallela 
1171da4680ceSPeter Maydell     if (FIELD_EX64(value, GITS_CBASER, VALID)) {
117280dcd37fSPeter Maydell         s->cq.num_entries = (num_pages * GITS_PAGE_SIZE_4K) /
11731b08e436SShashi Mallela                              GITS_CMDQ_ENTRY_SIZE;
11741b08e436SShashi Mallela         s->cq.base_addr = FIELD_EX64(value, GITS_CBASER, PHYADDR);
11751b08e436SShashi Mallela         s->cq.base_addr <<= R_GITS_CBASER_PHYADDR_SHIFT;
11761b08e436SShashi Mallela     }
11771b08e436SShashi Mallela }
11781b08e436SShashi Mallela 
11797e062b98SPeter Maydell static MemTxResult gicv3_its_translation_read(void *opaque, hwaddr offset,
11807e062b98SPeter Maydell                                               uint64_t *data, unsigned size,
11817e062b98SPeter Maydell                                               MemTxAttrs attrs)
11827e062b98SPeter Maydell {
11837e062b98SPeter Maydell     /*
11847e062b98SPeter Maydell      * GITS_TRANSLATER is write-only, and all other addresses
11857e062b98SPeter Maydell      * in the interrupt translation space frame are RES0.
11867e062b98SPeter Maydell      */
11877e062b98SPeter Maydell     *data = 0;
11887e062b98SPeter Maydell     return MEMTX_OK;
11897e062b98SPeter Maydell }
11907e062b98SPeter Maydell 
119118f6290aSShashi Mallela static MemTxResult gicv3_its_translation_write(void *opaque, hwaddr offset,
119218f6290aSShashi Mallela                                                uint64_t data, unsigned size,
119318f6290aSShashi Mallela                                                MemTxAttrs attrs)
119418f6290aSShashi Mallela {
1195c694cb4cSShashi Mallela     GICv3ITSState *s = (GICv3ITSState *)opaque;
1196c694cb4cSShashi Mallela     bool result = true;
1197c694cb4cSShashi Mallela 
1198195209d3SPeter Maydell     trace_gicv3_its_translation_write(offset, data, size, attrs.requester_id);
1199195209d3SPeter Maydell 
1200c694cb4cSShashi Mallela     switch (offset) {
1201c694cb4cSShashi Mallela     case GITS_TRANSLATER:
12028d2d6dd9SPeter Maydell         if (s->ctlr & R_GITS_CTLR_ENABLED_MASK) {
1203b6f96009SPeter Maydell             result = do_process_its_cmd(s, attrs.requester_id, data, NONE);
1204c694cb4cSShashi Mallela         }
1205c694cb4cSShashi Mallela         break;
1206c694cb4cSShashi Mallela     default:
1207c694cb4cSShashi Mallela         break;
1208c694cb4cSShashi Mallela     }
1209c694cb4cSShashi Mallela 
1210c694cb4cSShashi Mallela     if (result) {
121118f6290aSShashi Mallela         return MEMTX_OK;
1212c694cb4cSShashi Mallela     } else {
1213c694cb4cSShashi Mallela         return MEMTX_ERROR;
1214c694cb4cSShashi Mallela     }
121518f6290aSShashi Mallela }
121618f6290aSShashi Mallela 
121718f6290aSShashi Mallela static bool its_writel(GICv3ITSState *s, hwaddr offset,
121818f6290aSShashi Mallela                               uint64_t value, MemTxAttrs attrs)
121918f6290aSShashi Mallela {
122018f6290aSShashi Mallela     bool result = true;
12211b08e436SShashi Mallela     int index;
122218f6290aSShashi Mallela 
12231b08e436SShashi Mallela     switch (offset) {
12241b08e436SShashi Mallela     case GITS_CTLR:
12252f459cd1SShashi Mallela         if (value & R_GITS_CTLR_ENABLED_MASK) {
12268d2d6dd9SPeter Maydell             s->ctlr |= R_GITS_CTLR_ENABLED_MASK;
12271b08e436SShashi Mallela             extract_table_params(s);
12281b08e436SShashi Mallela             extract_cmdq_params(s);
12297eca39e0SShashi Mallela             process_cmdq(s);
12302f459cd1SShashi Mallela         } else {
12318d2d6dd9SPeter Maydell             s->ctlr &= ~R_GITS_CTLR_ENABLED_MASK;
12321b08e436SShashi Mallela         }
12331b08e436SShashi Mallela         break;
12341b08e436SShashi Mallela     case GITS_CBASER:
12351b08e436SShashi Mallela         /*
12361b08e436SShashi Mallela          * IMPDEF choice:- GITS_CBASER register becomes RO if ITS is
12371b08e436SShashi Mallela          *                 already enabled
12381b08e436SShashi Mallela          */
12398d2d6dd9SPeter Maydell         if (!(s->ctlr & R_GITS_CTLR_ENABLED_MASK)) {
12401b08e436SShashi Mallela             s->cbaser = deposit64(s->cbaser, 0, 32, value);
12411b08e436SShashi Mallela             s->creadr = 0;
12421b08e436SShashi Mallela         }
12431b08e436SShashi Mallela         break;
12441b08e436SShashi Mallela     case GITS_CBASER + 4:
12451b08e436SShashi Mallela         /*
12461b08e436SShashi Mallela          * IMPDEF choice:- GITS_CBASER register becomes RO if ITS is
12471b08e436SShashi Mallela          *                 already enabled
12481b08e436SShashi Mallela          */
12498d2d6dd9SPeter Maydell         if (!(s->ctlr & R_GITS_CTLR_ENABLED_MASK)) {
12501b08e436SShashi Mallela             s->cbaser = deposit64(s->cbaser, 32, 32, value);
12511b08e436SShashi Mallela             s->creadr = 0;
12521b08e436SShashi Mallela         }
12531b08e436SShashi Mallela         break;
12541b08e436SShashi Mallela     case GITS_CWRITER:
12551b08e436SShashi Mallela         s->cwriter = deposit64(s->cwriter, 0, 32,
12561b08e436SShashi Mallela                                (value & ~R_GITS_CWRITER_RETRY_MASK));
12577eca39e0SShashi Mallela         if (s->cwriter != s->creadr) {
12587eca39e0SShashi Mallela             process_cmdq(s);
12597eca39e0SShashi Mallela         }
12601b08e436SShashi Mallela         break;
12611b08e436SShashi Mallela     case GITS_CWRITER + 4:
12621b08e436SShashi Mallela         s->cwriter = deposit64(s->cwriter, 32, 32, value);
12631b08e436SShashi Mallela         break;
12641b08e436SShashi Mallela     case GITS_CREADR:
12651b08e436SShashi Mallela         if (s->gicv3->gicd_ctlr & GICD_CTLR_DS) {
12661b08e436SShashi Mallela             s->creadr = deposit64(s->creadr, 0, 32,
12671b08e436SShashi Mallela                                   (value & ~R_GITS_CREADR_STALLED_MASK));
12681b08e436SShashi Mallela         } else {
12691b08e436SShashi Mallela             /* RO register, ignore the write */
12701b08e436SShashi Mallela             qemu_log_mask(LOG_GUEST_ERROR,
12711b08e436SShashi Mallela                           "%s: invalid guest write to RO register at offset "
12721b08e436SShashi Mallela                           TARGET_FMT_plx "\n", __func__, offset);
12731b08e436SShashi Mallela         }
12741b08e436SShashi Mallela         break;
12751b08e436SShashi Mallela     case GITS_CREADR + 4:
12761b08e436SShashi Mallela         if (s->gicv3->gicd_ctlr & GICD_CTLR_DS) {
12771b08e436SShashi Mallela             s->creadr = deposit64(s->creadr, 32, 32, value);
12781b08e436SShashi Mallela         } else {
12791b08e436SShashi Mallela             /* RO register, ignore the write */
12801b08e436SShashi Mallela             qemu_log_mask(LOG_GUEST_ERROR,
12811b08e436SShashi Mallela                           "%s: invalid guest write to RO register at offset "
12821b08e436SShashi Mallela                           TARGET_FMT_plx "\n", __func__, offset);
12831b08e436SShashi Mallela         }
12841b08e436SShashi Mallela         break;
12851b08e436SShashi Mallela     case GITS_BASER ... GITS_BASER + 0x3f:
12861b08e436SShashi Mallela         /*
12871b08e436SShashi Mallela          * IMPDEF choice:- GITS_BASERn register becomes RO if ITS is
12881b08e436SShashi Mallela          *                 already enabled
12891b08e436SShashi Mallela          */
12908d2d6dd9SPeter Maydell         if (!(s->ctlr & R_GITS_CTLR_ENABLED_MASK)) {
12911b08e436SShashi Mallela             index = (offset - GITS_BASER) / 8;
12921b08e436SShashi Mallela 
12930ffe88e6SPeter Maydell             if (s->baser[index] == 0) {
12940ffe88e6SPeter Maydell                 /* Unimplemented GITS_BASERn: RAZ/WI */
12950ffe88e6SPeter Maydell                 break;
12960ffe88e6SPeter Maydell             }
12971b08e436SShashi Mallela             if (offset & 7) {
12981b08e436SShashi Mallela                 value <<= 32;
12991b08e436SShashi Mallela                 value &= ~GITS_BASER_RO_MASK;
13001b08e436SShashi Mallela                 s->baser[index] &= GITS_BASER_RO_MASK | MAKE_64BIT_MASK(0, 32);
13011b08e436SShashi Mallela                 s->baser[index] |= value;
13021b08e436SShashi Mallela             } else {
13031b08e436SShashi Mallela                 value &= ~GITS_BASER_RO_MASK;
13041b08e436SShashi Mallela                 s->baser[index] &= GITS_BASER_RO_MASK | MAKE_64BIT_MASK(32, 32);
13051b08e436SShashi Mallela                 s->baser[index] |= value;
13061b08e436SShashi Mallela             }
13071b08e436SShashi Mallela         }
13081b08e436SShashi Mallela         break;
13091b08e436SShashi Mallela     case GITS_IIDR:
13101b08e436SShashi Mallela     case GITS_IDREGS ... GITS_IDREGS + 0x2f:
13111b08e436SShashi Mallela         /* RO registers, ignore the write */
13121b08e436SShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
13131b08e436SShashi Mallela                       "%s: invalid guest write to RO register at offset "
13141b08e436SShashi Mallela                       TARGET_FMT_plx "\n", __func__, offset);
13151b08e436SShashi Mallela         break;
13161b08e436SShashi Mallela     default:
13171b08e436SShashi Mallela         result = false;
13181b08e436SShashi Mallela         break;
13191b08e436SShashi Mallela     }
132018f6290aSShashi Mallela     return result;
132118f6290aSShashi Mallela }
132218f6290aSShashi Mallela 
132318f6290aSShashi Mallela static bool its_readl(GICv3ITSState *s, hwaddr offset,
132418f6290aSShashi Mallela                              uint64_t *data, MemTxAttrs attrs)
132518f6290aSShashi Mallela {
132618f6290aSShashi Mallela     bool result = true;
13271b08e436SShashi Mallela     int index;
132818f6290aSShashi Mallela 
13291b08e436SShashi Mallela     switch (offset) {
13301b08e436SShashi Mallela     case GITS_CTLR:
13311b08e436SShashi Mallela         *data = s->ctlr;
13321b08e436SShashi Mallela         break;
13331b08e436SShashi Mallela     case GITS_IIDR:
13341b08e436SShashi Mallela         *data = gicv3_iidr();
13351b08e436SShashi Mallela         break;
13361b08e436SShashi Mallela     case GITS_IDREGS ... GITS_IDREGS + 0x2f:
13371b08e436SShashi Mallela         /* ID registers */
133850a3a309SPeter Maydell         *data = gicv3_idreg(offset - GITS_IDREGS, GICV3_PIDR0_ITS);
13391b08e436SShashi Mallela         break;
13401b08e436SShashi Mallela     case GITS_TYPER:
13411b08e436SShashi Mallela         *data = extract64(s->typer, 0, 32);
13421b08e436SShashi Mallela         break;
13431b08e436SShashi Mallela     case GITS_TYPER + 4:
13441b08e436SShashi Mallela         *data = extract64(s->typer, 32, 32);
13451b08e436SShashi Mallela         break;
13461b08e436SShashi Mallela     case GITS_CBASER:
13471b08e436SShashi Mallela         *data = extract64(s->cbaser, 0, 32);
13481b08e436SShashi Mallela         break;
13491b08e436SShashi Mallela     case GITS_CBASER + 4:
13501b08e436SShashi Mallela         *data = extract64(s->cbaser, 32, 32);
13511b08e436SShashi Mallela         break;
13521b08e436SShashi Mallela     case GITS_CREADR:
13531b08e436SShashi Mallela         *data = extract64(s->creadr, 0, 32);
13541b08e436SShashi Mallela         break;
13551b08e436SShashi Mallela     case GITS_CREADR + 4:
13561b08e436SShashi Mallela         *data = extract64(s->creadr, 32, 32);
13571b08e436SShashi Mallela         break;
13581b08e436SShashi Mallela     case GITS_CWRITER:
13591b08e436SShashi Mallela         *data = extract64(s->cwriter, 0, 32);
13601b08e436SShashi Mallela         break;
13611b08e436SShashi Mallela     case GITS_CWRITER + 4:
13621b08e436SShashi Mallela         *data = extract64(s->cwriter, 32, 32);
13631b08e436SShashi Mallela         break;
13641b08e436SShashi Mallela     case GITS_BASER ... GITS_BASER + 0x3f:
13651b08e436SShashi Mallela         index = (offset - GITS_BASER) / 8;
13661b08e436SShashi Mallela         if (offset & 7) {
13671b08e436SShashi Mallela             *data = extract64(s->baser[index], 32, 32);
13681b08e436SShashi Mallela         } else {
13691b08e436SShashi Mallela             *data = extract64(s->baser[index], 0, 32);
13701b08e436SShashi Mallela         }
13711b08e436SShashi Mallela         break;
13721b08e436SShashi Mallela     default:
13731b08e436SShashi Mallela         result = false;
13741b08e436SShashi Mallela         break;
13751b08e436SShashi Mallela     }
137618f6290aSShashi Mallela     return result;
137718f6290aSShashi Mallela }
137818f6290aSShashi Mallela 
137918f6290aSShashi Mallela static bool its_writell(GICv3ITSState *s, hwaddr offset,
138018f6290aSShashi Mallela                                uint64_t value, MemTxAttrs attrs)
138118f6290aSShashi Mallela {
138218f6290aSShashi Mallela     bool result = true;
13831b08e436SShashi Mallela     int index;
138418f6290aSShashi Mallela 
13851b08e436SShashi Mallela     switch (offset) {
13861b08e436SShashi Mallela     case GITS_BASER ... GITS_BASER + 0x3f:
13871b08e436SShashi Mallela         /*
13881b08e436SShashi Mallela          * IMPDEF choice:- GITS_BASERn register becomes RO if ITS is
13891b08e436SShashi Mallela          *                 already enabled
13901b08e436SShashi Mallela          */
13918d2d6dd9SPeter Maydell         if (!(s->ctlr & R_GITS_CTLR_ENABLED_MASK)) {
13921b08e436SShashi Mallela             index = (offset - GITS_BASER) / 8;
13930ffe88e6SPeter Maydell             if (s->baser[index] == 0) {
13940ffe88e6SPeter Maydell                 /* Unimplemented GITS_BASERn: RAZ/WI */
13950ffe88e6SPeter Maydell                 break;
13960ffe88e6SPeter Maydell             }
13971b08e436SShashi Mallela             s->baser[index] &= GITS_BASER_RO_MASK;
13981b08e436SShashi Mallela             s->baser[index] |= (value & ~GITS_BASER_RO_MASK);
13991b08e436SShashi Mallela         }
14001b08e436SShashi Mallela         break;
14011b08e436SShashi Mallela     case GITS_CBASER:
14021b08e436SShashi Mallela         /*
14031b08e436SShashi Mallela          * IMPDEF choice:- GITS_CBASER register becomes RO if ITS is
14041b08e436SShashi Mallela          *                 already enabled
14051b08e436SShashi Mallela          */
14068d2d6dd9SPeter Maydell         if (!(s->ctlr & R_GITS_CTLR_ENABLED_MASK)) {
14071b08e436SShashi Mallela             s->cbaser = value;
14081b08e436SShashi Mallela             s->creadr = 0;
14091b08e436SShashi Mallela         }
14101b08e436SShashi Mallela         break;
14111b08e436SShashi Mallela     case GITS_CWRITER:
14121b08e436SShashi Mallela         s->cwriter = value & ~R_GITS_CWRITER_RETRY_MASK;
14137eca39e0SShashi Mallela         if (s->cwriter != s->creadr) {
14147eca39e0SShashi Mallela             process_cmdq(s);
14157eca39e0SShashi Mallela         }
14161b08e436SShashi Mallela         break;
14171b08e436SShashi Mallela     case GITS_CREADR:
14181b08e436SShashi Mallela         if (s->gicv3->gicd_ctlr & GICD_CTLR_DS) {
14191b08e436SShashi Mallela             s->creadr = value & ~R_GITS_CREADR_STALLED_MASK;
14201b08e436SShashi Mallela         } else {
14211b08e436SShashi Mallela             /* RO register, ignore the write */
14221b08e436SShashi Mallela             qemu_log_mask(LOG_GUEST_ERROR,
14231b08e436SShashi Mallela                           "%s: invalid guest write to RO register at offset "
14241b08e436SShashi Mallela                           TARGET_FMT_plx "\n", __func__, offset);
14251b08e436SShashi Mallela         }
14261b08e436SShashi Mallela         break;
14271b08e436SShashi Mallela     case GITS_TYPER:
14281b08e436SShashi Mallela         /* RO registers, ignore the write */
14291b08e436SShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
14301b08e436SShashi Mallela                       "%s: invalid guest write to RO register at offset "
14311b08e436SShashi Mallela                       TARGET_FMT_plx "\n", __func__, offset);
14321b08e436SShashi Mallela         break;
14331b08e436SShashi Mallela     default:
14341b08e436SShashi Mallela         result = false;
14351b08e436SShashi Mallela         break;
14361b08e436SShashi Mallela     }
143718f6290aSShashi Mallela     return result;
143818f6290aSShashi Mallela }
143918f6290aSShashi Mallela 
144018f6290aSShashi Mallela static bool its_readll(GICv3ITSState *s, hwaddr offset,
144118f6290aSShashi Mallela                               uint64_t *data, MemTxAttrs attrs)
144218f6290aSShashi Mallela {
144318f6290aSShashi Mallela     bool result = true;
14441b08e436SShashi Mallela     int index;
144518f6290aSShashi Mallela 
14461b08e436SShashi Mallela     switch (offset) {
14471b08e436SShashi Mallela     case GITS_TYPER:
14481b08e436SShashi Mallela         *data = s->typer;
14491b08e436SShashi Mallela         break;
14501b08e436SShashi Mallela     case GITS_BASER ... GITS_BASER + 0x3f:
14511b08e436SShashi Mallela         index = (offset - GITS_BASER) / 8;
14521b08e436SShashi Mallela         *data = s->baser[index];
14531b08e436SShashi Mallela         break;
14541b08e436SShashi Mallela     case GITS_CBASER:
14551b08e436SShashi Mallela         *data = s->cbaser;
14561b08e436SShashi Mallela         break;
14571b08e436SShashi Mallela     case GITS_CREADR:
14581b08e436SShashi Mallela         *data = s->creadr;
14591b08e436SShashi Mallela         break;
14601b08e436SShashi Mallela     case GITS_CWRITER:
14611b08e436SShashi Mallela         *data = s->cwriter;
14621b08e436SShashi Mallela         break;
14631b08e436SShashi Mallela     default:
14641b08e436SShashi Mallela         result = false;
14651b08e436SShashi Mallela         break;
14661b08e436SShashi Mallela     }
146718f6290aSShashi Mallela     return result;
146818f6290aSShashi Mallela }
146918f6290aSShashi Mallela 
147018f6290aSShashi Mallela static MemTxResult gicv3_its_read(void *opaque, hwaddr offset, uint64_t *data,
147118f6290aSShashi Mallela                                   unsigned size, MemTxAttrs attrs)
147218f6290aSShashi Mallela {
147318f6290aSShashi Mallela     GICv3ITSState *s = (GICv3ITSState *)opaque;
147418f6290aSShashi Mallela     bool result;
147518f6290aSShashi Mallela 
147618f6290aSShashi Mallela     switch (size) {
147718f6290aSShashi Mallela     case 4:
147818f6290aSShashi Mallela         result = its_readl(s, offset, data, attrs);
147918f6290aSShashi Mallela         break;
148018f6290aSShashi Mallela     case 8:
148118f6290aSShashi Mallela         result = its_readll(s, offset, data, attrs);
148218f6290aSShashi Mallela         break;
148318f6290aSShashi Mallela     default:
148418f6290aSShashi Mallela         result = false;
148518f6290aSShashi Mallela         break;
148618f6290aSShashi Mallela     }
148718f6290aSShashi Mallela 
148818f6290aSShashi Mallela     if (!result) {
148918f6290aSShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
149018f6290aSShashi Mallela                       "%s: invalid guest read at offset " TARGET_FMT_plx
149118f6290aSShashi Mallela                       " size %u\n", __func__, offset, size);
1492195209d3SPeter Maydell         trace_gicv3_its_badread(offset, size);
149318f6290aSShashi Mallela         /*
149418f6290aSShashi Mallela          * The spec requires that reserved registers are RAZ/WI;
149518f6290aSShashi Mallela          * so use false returns from leaf functions as a way to
149618f6290aSShashi Mallela          * trigger the guest-error logging but don't return it to
149718f6290aSShashi Mallela          * the caller, or we'll cause a spurious guest data abort.
149818f6290aSShashi Mallela          */
149918f6290aSShashi Mallela         *data = 0;
1500195209d3SPeter Maydell     } else {
1501195209d3SPeter Maydell         trace_gicv3_its_read(offset, *data, size);
150218f6290aSShashi Mallela     }
150318f6290aSShashi Mallela     return MEMTX_OK;
150418f6290aSShashi Mallela }
150518f6290aSShashi Mallela 
150618f6290aSShashi Mallela static MemTxResult gicv3_its_write(void *opaque, hwaddr offset, uint64_t data,
150718f6290aSShashi Mallela                                    unsigned size, MemTxAttrs attrs)
150818f6290aSShashi Mallela {
150918f6290aSShashi Mallela     GICv3ITSState *s = (GICv3ITSState *)opaque;
151018f6290aSShashi Mallela     bool result;
151118f6290aSShashi Mallela 
151218f6290aSShashi Mallela     switch (size) {
151318f6290aSShashi Mallela     case 4:
151418f6290aSShashi Mallela         result = its_writel(s, offset, data, attrs);
151518f6290aSShashi Mallela         break;
151618f6290aSShashi Mallela     case 8:
151718f6290aSShashi Mallela         result = its_writell(s, offset, data, attrs);
151818f6290aSShashi Mallela         break;
151918f6290aSShashi Mallela     default:
152018f6290aSShashi Mallela         result = false;
152118f6290aSShashi Mallela         break;
152218f6290aSShashi Mallela     }
152318f6290aSShashi Mallela 
152418f6290aSShashi Mallela     if (!result) {
152518f6290aSShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
152618f6290aSShashi Mallela                       "%s: invalid guest write at offset " TARGET_FMT_plx
152718f6290aSShashi Mallela                       " size %u\n", __func__, offset, size);
1528195209d3SPeter Maydell         trace_gicv3_its_badwrite(offset, data, size);
152918f6290aSShashi Mallela         /*
153018f6290aSShashi Mallela          * The spec requires that reserved registers are RAZ/WI;
153118f6290aSShashi Mallela          * so use false returns from leaf functions as a way to
153218f6290aSShashi Mallela          * trigger the guest-error logging but don't return it to
153318f6290aSShashi Mallela          * the caller, or we'll cause a spurious guest data abort.
153418f6290aSShashi Mallela          */
1535195209d3SPeter Maydell     } else {
1536195209d3SPeter Maydell         trace_gicv3_its_write(offset, data, size);
153718f6290aSShashi Mallela     }
153818f6290aSShashi Mallela     return MEMTX_OK;
153918f6290aSShashi Mallela }
154018f6290aSShashi Mallela 
154118f6290aSShashi Mallela static const MemoryRegionOps gicv3_its_control_ops = {
154218f6290aSShashi Mallela     .read_with_attrs = gicv3_its_read,
154318f6290aSShashi Mallela     .write_with_attrs = gicv3_its_write,
154418f6290aSShashi Mallela     .valid.min_access_size = 4,
154518f6290aSShashi Mallela     .valid.max_access_size = 8,
154618f6290aSShashi Mallela     .impl.min_access_size = 4,
154718f6290aSShashi Mallela     .impl.max_access_size = 8,
154818f6290aSShashi Mallela     .endianness = DEVICE_NATIVE_ENDIAN,
154918f6290aSShashi Mallela };
155018f6290aSShashi Mallela 
155118f6290aSShashi Mallela static const MemoryRegionOps gicv3_its_translation_ops = {
15527e062b98SPeter Maydell     .read_with_attrs = gicv3_its_translation_read,
155318f6290aSShashi Mallela     .write_with_attrs = gicv3_its_translation_write,
155418f6290aSShashi Mallela     .valid.min_access_size = 2,
155518f6290aSShashi Mallela     .valid.max_access_size = 4,
155618f6290aSShashi Mallela     .impl.min_access_size = 2,
155718f6290aSShashi Mallela     .impl.max_access_size = 4,
155818f6290aSShashi Mallela     .endianness = DEVICE_NATIVE_ENDIAN,
155918f6290aSShashi Mallela };
156018f6290aSShashi Mallela 
156118f6290aSShashi Mallela static void gicv3_arm_its_realize(DeviceState *dev, Error **errp)
156218f6290aSShashi Mallela {
156318f6290aSShashi Mallela     GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev);
156418f6290aSShashi Mallela     int i;
156518f6290aSShashi Mallela 
156618f6290aSShashi Mallela     for (i = 0; i < s->gicv3->num_cpu; i++) {
156718f6290aSShashi Mallela         if (!(s->gicv3->cpu[i].gicr_typer & GICR_TYPER_PLPIS)) {
156818f6290aSShashi Mallela             error_setg(errp, "Physical LPI not supported by CPU %d", i);
156918f6290aSShashi Mallela             return;
157018f6290aSShashi Mallela         }
157118f6290aSShashi Mallela     }
157218f6290aSShashi Mallela 
157318f6290aSShashi Mallela     gicv3_its_init_mmio(s, &gicv3_its_control_ops, &gicv3_its_translation_ops);
157418f6290aSShashi Mallela 
157518f6290aSShashi Mallela     /* set the ITS default features supported */
1576764d6ba1SPeter Maydell     s->typer = FIELD_DP64(s->typer, GITS_TYPER, PHYSICAL, 1);
157718f6290aSShashi Mallela     s->typer = FIELD_DP64(s->typer, GITS_TYPER, ITT_ENTRY_SIZE,
157818f6290aSShashi Mallela                           ITS_ITT_ENTRY_SIZE - 1);
157918f6290aSShashi Mallela     s->typer = FIELD_DP64(s->typer, GITS_TYPER, IDBITS, ITS_IDBITS);
158018f6290aSShashi Mallela     s->typer = FIELD_DP64(s->typer, GITS_TYPER, DEVBITS, ITS_DEVBITS);
158118f6290aSShashi Mallela     s->typer = FIELD_DP64(s->typer, GITS_TYPER, CIL, 1);
158218f6290aSShashi Mallela     s->typer = FIELD_DP64(s->typer, GITS_TYPER, CIDBITS, ITS_CIDBITS);
158318f6290aSShashi Mallela }
158418f6290aSShashi Mallela 
158518f6290aSShashi Mallela static void gicv3_its_reset(DeviceState *dev)
158618f6290aSShashi Mallela {
158718f6290aSShashi Mallela     GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev);
158818f6290aSShashi Mallela     GICv3ITSClass *c = ARM_GICV3_ITS_GET_CLASS(s);
158918f6290aSShashi Mallela 
159018f6290aSShashi Mallela     c->parent_reset(dev);
159118f6290aSShashi Mallela 
159218f6290aSShashi Mallela     /* Quiescent bit reset to 1 */
159318f6290aSShashi Mallela     s->ctlr = FIELD_DP32(s->ctlr, GITS_CTLR, QUIESCENT, 1);
159418f6290aSShashi Mallela 
159518f6290aSShashi Mallela     /*
159618f6290aSShashi Mallela      * setting GITS_BASER0.Type = 0b001 (Device)
159718f6290aSShashi Mallela      *         GITS_BASER1.Type = 0b100 (Collection Table)
159850d84584SPeter Maydell      *         GITS_BASER2.Type = 0b010 (vPE) for GICv4 and later
159918f6290aSShashi Mallela      *         GITS_BASER<n>.Type,where n = 3 to 7 are 0b00 (Unimplemented)
160018f6290aSShashi Mallela      *         GITS_BASER<0,1>.Page_Size = 64KB
160118f6290aSShashi Mallela      * and default translation table entry size to 16 bytes
160218f6290aSShashi Mallela      */
160318f6290aSShashi Mallela     s->baser[0] = FIELD_DP64(s->baser[0], GITS_BASER, TYPE,
160418f6290aSShashi Mallela                              GITS_BASER_TYPE_DEVICE);
160518f6290aSShashi Mallela     s->baser[0] = FIELD_DP64(s->baser[0], GITS_BASER, PAGESIZE,
160618f6290aSShashi Mallela                              GITS_BASER_PAGESIZE_64K);
160718f6290aSShashi Mallela     s->baser[0] = FIELD_DP64(s->baser[0], GITS_BASER, ENTRYSIZE,
160818f6290aSShashi Mallela                              GITS_DTE_SIZE - 1);
160918f6290aSShashi Mallela 
161018f6290aSShashi Mallela     s->baser[1] = FIELD_DP64(s->baser[1], GITS_BASER, TYPE,
161118f6290aSShashi Mallela                              GITS_BASER_TYPE_COLLECTION);
161218f6290aSShashi Mallela     s->baser[1] = FIELD_DP64(s->baser[1], GITS_BASER, PAGESIZE,
161318f6290aSShashi Mallela                              GITS_BASER_PAGESIZE_64K);
161418f6290aSShashi Mallela     s->baser[1] = FIELD_DP64(s->baser[1], GITS_BASER, ENTRYSIZE,
161518f6290aSShashi Mallela                              GITS_CTE_SIZE - 1);
161650d84584SPeter Maydell 
161750d84584SPeter Maydell     if (its_feature_virtual(s)) {
161850d84584SPeter Maydell         s->baser[2] = FIELD_DP64(s->baser[2], GITS_BASER, TYPE,
161950d84584SPeter Maydell                                  GITS_BASER_TYPE_VPE);
162050d84584SPeter Maydell         s->baser[2] = FIELD_DP64(s->baser[2], GITS_BASER, PAGESIZE,
162150d84584SPeter Maydell                                  GITS_BASER_PAGESIZE_64K);
162250d84584SPeter Maydell         s->baser[2] = FIELD_DP64(s->baser[2], GITS_BASER, ENTRYSIZE,
162350d84584SPeter Maydell                                  GITS_VPE_SIZE - 1);
162450d84584SPeter Maydell     }
162518f6290aSShashi Mallela }
162618f6290aSShashi Mallela 
16271b08e436SShashi Mallela static void gicv3_its_post_load(GICv3ITSState *s)
16281b08e436SShashi Mallela {
16298d2d6dd9SPeter Maydell     if (s->ctlr & R_GITS_CTLR_ENABLED_MASK) {
16301b08e436SShashi Mallela         extract_table_params(s);
16311b08e436SShashi Mallela         extract_cmdq_params(s);
16321b08e436SShashi Mallela     }
16331b08e436SShashi Mallela }
16341b08e436SShashi Mallela 
163518f6290aSShashi Mallela static Property gicv3_its_props[] = {
163618f6290aSShashi Mallela     DEFINE_PROP_LINK("parent-gicv3", GICv3ITSState, gicv3, "arm-gicv3",
163718f6290aSShashi Mallela                      GICv3State *),
163818f6290aSShashi Mallela     DEFINE_PROP_END_OF_LIST(),
163918f6290aSShashi Mallela };
164018f6290aSShashi Mallela 
164118f6290aSShashi Mallela static void gicv3_its_class_init(ObjectClass *klass, void *data)
164218f6290aSShashi Mallela {
164318f6290aSShashi Mallela     DeviceClass *dc = DEVICE_CLASS(klass);
164418f6290aSShashi Mallela     GICv3ITSClass *ic = ARM_GICV3_ITS_CLASS(klass);
16451b08e436SShashi Mallela     GICv3ITSCommonClass *icc = ARM_GICV3_ITS_COMMON_CLASS(klass);
164618f6290aSShashi Mallela 
164718f6290aSShashi Mallela     dc->realize = gicv3_arm_its_realize;
164818f6290aSShashi Mallela     device_class_set_props(dc, gicv3_its_props);
164918f6290aSShashi Mallela     device_class_set_parent_reset(dc, gicv3_its_reset, &ic->parent_reset);
16501b08e436SShashi Mallela     icc->post_load = gicv3_its_post_load;
165118f6290aSShashi Mallela }
165218f6290aSShashi Mallela 
165318f6290aSShashi Mallela static const TypeInfo gicv3_its_info = {
165418f6290aSShashi Mallela     .name = TYPE_ARM_GICV3_ITS,
165518f6290aSShashi Mallela     .parent = TYPE_ARM_GICV3_ITS_COMMON,
165618f6290aSShashi Mallela     .instance_size = sizeof(GICv3ITSState),
165718f6290aSShashi Mallela     .class_init = gicv3_its_class_init,
165818f6290aSShashi Mallela     .class_size = sizeof(GICv3ITSClass),
165918f6290aSShashi Mallela };
166018f6290aSShashi Mallela 
166118f6290aSShashi Mallela static void gicv3_its_register_types(void)
166218f6290aSShashi Mallela {
166318f6290aSShashi Mallela     type_register_static(&gicv3_its_info);
166418f6290aSShashi Mallela }
166518f6290aSShashi Mallela 
166618f6290aSShashi Mallela type_init(gicv3_its_register_types)
1667