xref: /qemu/hw/intc/arm_gicv3_its.c (revision f0175135e74bc979573f170e83abfc536aed03de)
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 /*
318*f0175135SPeter Maydell  * Given a (DeviceID, EventID), look up the corresponding ITE, including
319*f0175135SPeter Maydell  * checking for the various invalid-value cases. If we find a valid ITE,
320*f0175135SPeter Maydell  * fill in @ite and @dte and return CMD_CONTINUE_OK. Otherwise return
321*f0175135SPeter Maydell  * CMD_STALL or CMD_CONTINUE as appropriate (and the contents of @ite
322*f0175135SPeter Maydell  * should not be relied on).
323*f0175135SPeter Maydell  *
324*f0175135SPeter Maydell  * The string @who is purely for the LOG_GUEST_ERROR messages,
325*f0175135SPeter Maydell  * and should indicate the name of the calling function or similar.
326*f0175135SPeter Maydell  */
327*f0175135SPeter Maydell static ItsCmdResult lookup_ite(GICv3ITSState *s, const char *who,
328*f0175135SPeter Maydell                                uint32_t devid, uint32_t eventid, ITEntry *ite,
329*f0175135SPeter Maydell                                DTEntry *dte)
330*f0175135SPeter Maydell {
331*f0175135SPeter Maydell     uint64_t num_eventids;
332*f0175135SPeter Maydell 
333*f0175135SPeter Maydell     if (devid >= s->dt.num_entries) {
334*f0175135SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
335*f0175135SPeter Maydell                       "%s: invalid command attributes: devid %d>=%d",
336*f0175135SPeter Maydell                       who, devid, s->dt.num_entries);
337*f0175135SPeter Maydell         return CMD_CONTINUE;
338*f0175135SPeter Maydell     }
339*f0175135SPeter Maydell 
340*f0175135SPeter Maydell     if (get_dte(s, devid, dte) != MEMTX_OK) {
341*f0175135SPeter Maydell         return CMD_STALL;
342*f0175135SPeter Maydell     }
343*f0175135SPeter Maydell     if (!dte->valid) {
344*f0175135SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
345*f0175135SPeter Maydell                       "%s: invalid command attributes: "
346*f0175135SPeter Maydell                       "invalid dte for %d\n", who, devid);
347*f0175135SPeter Maydell         return CMD_CONTINUE;
348*f0175135SPeter Maydell     }
349*f0175135SPeter Maydell 
350*f0175135SPeter Maydell     num_eventids = 1ULL << (dte->size + 1);
351*f0175135SPeter Maydell     if (eventid >= num_eventids) {
352*f0175135SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
353*f0175135SPeter Maydell                       "%s: invalid command attributes: eventid %d >= %"
354*f0175135SPeter Maydell                       PRId64 "\n", who, eventid, num_eventids);
355*f0175135SPeter Maydell         return CMD_CONTINUE;
356*f0175135SPeter Maydell     }
357*f0175135SPeter Maydell 
358*f0175135SPeter Maydell     if (get_ite(s, eventid, dte, ite) != MEMTX_OK) {
359*f0175135SPeter Maydell         return CMD_STALL;
360*f0175135SPeter Maydell     }
361*f0175135SPeter Maydell 
362*f0175135SPeter Maydell     if (!ite->valid) {
363*f0175135SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
364*f0175135SPeter Maydell                       "%s: invalid command attributes: invalid ITE\n", who);
365*f0175135SPeter Maydell         return CMD_CONTINUE;
366*f0175135SPeter Maydell     }
367*f0175135SPeter Maydell 
368*f0175135SPeter Maydell     return CMD_CONTINUE_OK;
369*f0175135SPeter Maydell }
370*f0175135SPeter Maydell 
371*f0175135SPeter Maydell /*
372c694cb4cSShashi Mallela  * This function handles the processing of following commands based on
373c694cb4cSShashi Mallela  * the ItsCmdType parameter passed:-
374c694cb4cSShashi Mallela  * 1. triggering of lpi interrupt translation via ITS INT command
375c694cb4cSShashi Mallela  * 2. triggering of lpi interrupt translation via gits_translater register
376c694cb4cSShashi Mallela  * 3. handling of ITS CLEAR command
377c694cb4cSShashi Mallela  * 4. handling of ITS DISCARD command
378c694cb4cSShashi Mallela  */
379b6f96009SPeter Maydell static ItsCmdResult do_process_its_cmd(GICv3ITSState *s, uint32_t devid,
380b6f96009SPeter Maydell                                        uint32_t eventid, ItsCmdType cmd)
381c694cb4cSShashi Mallela {
3824acf93e1SPeter Maydell     DTEntry dte;
383d37cf49bSPeter Maydell     CTEntry cte;
384244194feSPeter Maydell     ITEntry ite;
385*f0175135SPeter Maydell     ItsCmdResult cmdres;
386c694cb4cSShashi Mallela 
387*f0175135SPeter Maydell     cmdres = lookup_ite(s, __func__, devid, eventid, &ite, &dte);
388*f0175135SPeter Maydell     if (cmdres != CMD_CONTINUE_OK) {
389*f0175135SPeter Maydell         return cmdres;
390b13148d9SPeter Maydell     }
391b13148d9SPeter Maydell 
392*f0175135SPeter Maydell     if (ite.inttype != ITE_INTTYPE_PHYSICAL) {
393be0ed8fbSPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
394be0ed8fbSPeter Maydell                       "%s: invalid command attributes: invalid ITE\n",
395be0ed8fbSPeter Maydell                       __func__);
396be0ed8fbSPeter Maydell         return CMD_CONTINUE;
397be0ed8fbSPeter Maydell     }
398be0ed8fbSPeter Maydell 
399244194feSPeter Maydell     if (ite.icid >= s->ct.num_entries) {
40058b88779SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
40158b88779SPeter Maydell                       "%s: invalid ICID 0x%x in ITE (table corrupted?)\n",
402244194feSPeter Maydell                       __func__, ite.icid);
40358b88779SPeter Maydell         return CMD_CONTINUE;
40458b88779SPeter Maydell     }
40558b88779SPeter Maydell 
406244194feSPeter Maydell     if (get_cte(s, ite.icid, &cte) != MEMTX_OK) {
407be0ed8fbSPeter Maydell         return CMD_STALL;
408be0ed8fbSPeter Maydell     }
409d37cf49bSPeter Maydell     if (!cte.valid) {
410be0ed8fbSPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
411d37cf49bSPeter Maydell                       "%s: invalid command attributes: invalid CTE\n",
412d37cf49bSPeter Maydell                       __func__);
413be0ed8fbSPeter Maydell         return CMD_CONTINUE;
414be0ed8fbSPeter Maydell     }
415be0ed8fbSPeter Maydell 
416c694cb4cSShashi Mallela     /*
417c694cb4cSShashi Mallela      * Current implementation only supports rdbase == procnum
418c694cb4cSShashi Mallela      * Hence rdbase physical address is ignored
419c694cb4cSShashi Mallela      */
420d37cf49bSPeter Maydell     if (cte.rdbase >= s->gicv3->num_cpu) {
421593a7cc2SPeter Maydell         return CMD_CONTINUE;
42217fb5e36SShashi Mallela     }
42317fb5e36SShashi Mallela 
42417fb5e36SShashi Mallela     if ((cmd == CLEAR) || (cmd == DISCARD)) {
425244194feSPeter Maydell         gicv3_redist_process_lpi(&s->gicv3->cpu[cte.rdbase], ite.intid, 0);
42617fb5e36SShashi Mallela     } else {
427244194feSPeter Maydell         gicv3_redist_process_lpi(&s->gicv3->cpu[cte.rdbase], ite.intid, 1);
42817fb5e36SShashi Mallela     }
42917fb5e36SShashi Mallela 
430c694cb4cSShashi Mallela     if (cmd == DISCARD) {
4317eb54267SPeter Maydell         ITEntry ite = {};
432c694cb4cSShashi Mallela         /* remove mapping from interrupt translation table */
4337eb54267SPeter Maydell         ite.valid = false;
43493f4fdcdSPeter Maydell         return update_ite(s, eventid, &dte, &ite) ? CMD_CONTINUE_OK : CMD_STALL;
435c694cb4cSShashi Mallela     }
43693f4fdcdSPeter Maydell     return CMD_CONTINUE_OK;
437c694cb4cSShashi Mallela }
4382a199036SPeter Maydell 
439b6f96009SPeter Maydell static ItsCmdResult process_its_cmd(GICv3ITSState *s, const uint64_t *cmdpkt,
440b6f96009SPeter Maydell                                     ItsCmdType cmd)
441c694cb4cSShashi Mallela {
442b6f96009SPeter Maydell     uint32_t devid, eventid;
443b6f96009SPeter Maydell 
444b6f96009SPeter Maydell     devid = (cmdpkt[0] & DEVID_MASK) >> DEVID_SHIFT;
445b6f96009SPeter Maydell     eventid = cmdpkt[1] & EVENTID_MASK;
446e4050980SPeter Maydell     switch (cmd) {
447e4050980SPeter Maydell     case INTERRUPT:
448e4050980SPeter Maydell         trace_gicv3_its_cmd_int(devid, eventid);
449e4050980SPeter Maydell         break;
450e4050980SPeter Maydell     case CLEAR:
451e4050980SPeter Maydell         trace_gicv3_its_cmd_clear(devid, eventid);
452e4050980SPeter Maydell         break;
453e4050980SPeter Maydell     case DISCARD:
454e4050980SPeter Maydell         trace_gicv3_its_cmd_discard(devid, eventid);
455e4050980SPeter Maydell         break;
456e4050980SPeter Maydell     default:
457e4050980SPeter Maydell         g_assert_not_reached();
458e4050980SPeter Maydell     }
459b6f96009SPeter Maydell     return do_process_its_cmd(s, devid, eventid, cmd);
460b6f96009SPeter Maydell }
461b6f96009SPeter Maydell 
462b6f96009SPeter Maydell static ItsCmdResult process_mapti(GICv3ITSState *s, const uint64_t *cmdpkt,
463b6f96009SPeter Maydell                                   bool ignore_pInt)
464b6f96009SPeter Maydell {
465c694cb4cSShashi Mallela     uint32_t devid, eventid;
466c694cb4cSShashi Mallela     uint32_t pIntid = 0;
4678f809f69SPeter Maydell     uint64_t num_eventids;
468c694cb4cSShashi Mallela     uint16_t icid = 0;
4694acf93e1SPeter Maydell     DTEntry dte;
4707eb54267SPeter Maydell     ITEntry ite;
471c694cb4cSShashi Mallela 
472b6f96009SPeter Maydell     devid = (cmdpkt[0] & DEVID_MASK) >> DEVID_SHIFT;
473b6f96009SPeter Maydell     eventid = cmdpkt[1] & EVENTID_MASK;
474e4050980SPeter Maydell     icid = cmdpkt[2] & ICID_MASK;
475c694cb4cSShashi Mallela 
476b87fab1cSPeter Maydell     if (ignore_pInt) {
477b87fab1cSPeter Maydell         pIntid = eventid;
478e4050980SPeter Maydell         trace_gicv3_its_cmd_mapi(devid, eventid, icid);
479b87fab1cSPeter Maydell     } else {
480b6f96009SPeter Maydell         pIntid = (cmdpkt[1] & pINTID_MASK) >> pINTID_SHIFT;
481e4050980SPeter Maydell         trace_gicv3_its_cmd_mapti(devid, eventid, icid, pIntid);
482c694cb4cSShashi Mallela     }
483c694cb4cSShashi Mallela 
4848b8bb014SPeter Maydell     if (devid >= s->dt.num_entries) {
485b13148d9SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
486b13148d9SPeter Maydell                       "%s: invalid command attributes: devid %d>=%d",
4878b8bb014SPeter Maydell                       __func__, devid, s->dt.num_entries);
488b13148d9SPeter Maydell         return CMD_CONTINUE;
489b13148d9SPeter Maydell     }
490b13148d9SPeter Maydell 
4914acf93e1SPeter Maydell     if (get_dte(s, devid, &dte) != MEMTX_OK) {
4920241f731SPeter Maydell         return CMD_STALL;
493c694cb4cSShashi Mallela     }
4944acf93e1SPeter Maydell     num_eventids = 1ULL << (dte.size + 1);
495c694cb4cSShashi Mallela 
496d7d359c4SPeter Maydell     if (icid >= s->ct.num_entries) {
497c694cb4cSShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
498d7d359c4SPeter Maydell                       "%s: invalid ICID 0x%x >= 0x%x\n",
499d7d359c4SPeter Maydell                       __func__, icid, s->ct.num_entries);
500d7d359c4SPeter Maydell         return CMD_CONTINUE;
501d7d359c4SPeter Maydell     }
502d7d359c4SPeter Maydell 
503d7d359c4SPeter Maydell     if (!dte.valid) {
504d7d359c4SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
505d7d359c4SPeter Maydell                       "%s: no valid DTE for devid 0x%x\n", __func__, devid);
506d7d359c4SPeter Maydell         return CMD_CONTINUE;
507d7d359c4SPeter Maydell     }
508d7d359c4SPeter Maydell 
509d7d359c4SPeter Maydell     if (eventid >= num_eventids) {
510d7d359c4SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
511d7d359c4SPeter Maydell                       "%s: invalid event ID 0x%x >= 0x%" PRIx64 "\n",
512d7d359c4SPeter Maydell                       __func__, eventid, num_eventids);
513d7d359c4SPeter Maydell         return CMD_CONTINUE;
514d7d359c4SPeter Maydell     }
515d7d359c4SPeter Maydell 
516c3c9a090SPeter Maydell     if (!intid_in_lpi_range(pIntid)) {
517d7d359c4SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
518d7d359c4SPeter Maydell                       "%s: invalid interrupt ID 0x%x\n", __func__, pIntid);
5190241f731SPeter Maydell         return CMD_CONTINUE;
5200241f731SPeter Maydell     }
5210241f731SPeter Maydell 
522c694cb4cSShashi Mallela     /* add ite entry to interrupt translation table */
5237eb54267SPeter Maydell     ite.valid = true;
5247eb54267SPeter Maydell     ite.inttype = ITE_INTTYPE_PHYSICAL;
5257eb54267SPeter Maydell     ite.intid = pIntid;
5267eb54267SPeter Maydell     ite.icid = icid;
5277eb54267SPeter Maydell     ite.doorbell = INTID_SPURIOUS;
5287eb54267SPeter Maydell     ite.vpeid = 0;
52993f4fdcdSPeter Maydell     return update_ite(s, eventid, &dte, &ite) ? CMD_CONTINUE_OK : CMD_STALL;
530c694cb4cSShashi Mallela }
531c694cb4cSShashi Mallela 
5329de53de6SPeter Maydell static ItsCmdResult process_vmapti(GICv3ITSState *s, const uint64_t *cmdpkt,
5339de53de6SPeter Maydell                                    bool ignore_vintid)
5349de53de6SPeter Maydell {
5359de53de6SPeter Maydell     uint32_t devid, eventid, vintid, doorbell, vpeid;
5369de53de6SPeter Maydell     uint32_t num_eventids;
5379de53de6SPeter Maydell     DTEntry dte;
5389de53de6SPeter Maydell     ITEntry ite;
5399de53de6SPeter Maydell 
5409de53de6SPeter Maydell     if (!its_feature_virtual(s)) {
5419de53de6SPeter Maydell         return CMD_CONTINUE;
5429de53de6SPeter Maydell     }
5439de53de6SPeter Maydell 
5449de53de6SPeter Maydell     devid = FIELD_EX64(cmdpkt[0], VMAPTI_0, DEVICEID);
5459de53de6SPeter Maydell     eventid = FIELD_EX64(cmdpkt[1], VMAPTI_1, EVENTID);
5469de53de6SPeter Maydell     vpeid = FIELD_EX64(cmdpkt[1], VMAPTI_1, VPEID);
5479de53de6SPeter Maydell     doorbell = FIELD_EX64(cmdpkt[2], VMAPTI_2, DOORBELL);
5489de53de6SPeter Maydell     if (ignore_vintid) {
5499de53de6SPeter Maydell         vintid = eventid;
5509de53de6SPeter Maydell         trace_gicv3_its_cmd_vmapi(devid, eventid, vpeid, doorbell);
5519de53de6SPeter Maydell     } else {
5529de53de6SPeter Maydell         vintid = FIELD_EX64(cmdpkt[2], VMAPTI_2, VINTID);
5539de53de6SPeter Maydell         trace_gicv3_its_cmd_vmapti(devid, eventid, vpeid, vintid, doorbell);
5549de53de6SPeter Maydell     }
5559de53de6SPeter Maydell 
5569de53de6SPeter Maydell     if (devid >= s->dt.num_entries) {
5579de53de6SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
5589de53de6SPeter Maydell                       "%s: invalid DeviceID 0x%x (must be less than 0x%x)\n",
5599de53de6SPeter Maydell                       __func__, devid, s->dt.num_entries);
5609de53de6SPeter Maydell         return CMD_CONTINUE;
5619de53de6SPeter Maydell     }
5629de53de6SPeter Maydell 
5639de53de6SPeter Maydell     if (get_dte(s, devid, &dte) != MEMTX_OK) {
5649de53de6SPeter Maydell         return CMD_STALL;
5659de53de6SPeter Maydell     }
5669de53de6SPeter Maydell 
5679de53de6SPeter Maydell     if (!dte.valid) {
5689de53de6SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
5699de53de6SPeter Maydell                       "%s: no entry in device table for DeviceID 0x%x\n",
5709de53de6SPeter Maydell                       __func__, devid);
5719de53de6SPeter Maydell         return CMD_CONTINUE;
5729de53de6SPeter Maydell     }
5739de53de6SPeter Maydell 
5749de53de6SPeter Maydell     num_eventids = 1ULL << (dte.size + 1);
5759de53de6SPeter Maydell 
5769de53de6SPeter Maydell     if (eventid >= num_eventids) {
5779de53de6SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
5789de53de6SPeter Maydell                       "%s: EventID 0x%x too large for DeviceID 0x%x "
5799de53de6SPeter Maydell                       "(must be less than 0x%x)\n",
5809de53de6SPeter Maydell                       __func__, eventid, devid, num_eventids);
5819de53de6SPeter Maydell         return CMD_CONTINUE;
5829de53de6SPeter Maydell     }
5839de53de6SPeter Maydell     if (!intid_in_lpi_range(vintid)) {
5849de53de6SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
5859de53de6SPeter Maydell                       "%s: VIntID 0x%x not a valid LPI\n",
5869de53de6SPeter Maydell                       __func__, vintid);
5879de53de6SPeter Maydell         return CMD_CONTINUE;
5889de53de6SPeter Maydell     }
5899de53de6SPeter Maydell     if (!valid_doorbell(doorbell)) {
5909de53de6SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
5919de53de6SPeter Maydell                       "%s: Doorbell %d not 1023 and not a valid LPI\n",
5929de53de6SPeter Maydell                       __func__, doorbell);
5939de53de6SPeter Maydell         return CMD_CONTINUE;
5949de53de6SPeter Maydell     }
5959de53de6SPeter Maydell     if (vpeid >= s->vpet.num_entries) {
5969de53de6SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
5979de53de6SPeter Maydell                       "%s: VPEID 0x%x out of range (must be less than 0x%x)\n",
5989de53de6SPeter Maydell                       __func__, vpeid, s->vpet.num_entries);
5999de53de6SPeter Maydell         return CMD_CONTINUE;
6009de53de6SPeter Maydell     }
6019de53de6SPeter Maydell     /* add ite entry to interrupt translation table */
6029de53de6SPeter Maydell     ite.valid = true;
6039de53de6SPeter Maydell     ite.inttype = ITE_INTTYPE_VIRTUAL;
6049de53de6SPeter Maydell     ite.intid = vintid;
6059de53de6SPeter Maydell     ite.icid = 0;
6069de53de6SPeter Maydell     ite.doorbell = doorbell;
6079de53de6SPeter Maydell     ite.vpeid = vpeid;
60893f4fdcdSPeter Maydell     return update_ite(s, eventid, &dte, &ite) ? CMD_CONTINUE_OK : CMD_STALL;
6099de53de6SPeter Maydell }
6109de53de6SPeter Maydell 
61106985cc3SPeter Maydell /*
61206985cc3SPeter Maydell  * Update the Collection Table entry for @icid to @cte. Returns true
61306985cc3SPeter Maydell  * on success, false if there was a memory access error.
61406985cc3SPeter Maydell  */
61506985cc3SPeter Maydell static bool update_cte(GICv3ITSState *s, uint16_t icid, const CTEntry *cte)
6167eca39e0SShashi Mallela {
6177eca39e0SShashi Mallela     AddressSpace *as = &s->gicv3->dma_as;
618d050f80fSPeter Maydell     uint64_t entry_addr;
61906985cc3SPeter Maydell     uint64_t cteval = 0;
6207eca39e0SShashi Mallela     MemTxResult res = MEMTX_OK;
6217eca39e0SShashi Mallela 
622930f40e9SPeter Maydell     trace_gicv3_its_cte_write(icid, cte->valid, cte->rdbase);
623930f40e9SPeter Maydell 
62406985cc3SPeter Maydell     if (cte->valid) {
6257eca39e0SShashi Mallela         /* add mapping entry to collection table */
62606985cc3SPeter Maydell         cteval = FIELD_DP64(cteval, CTE, VALID, 1);
62706985cc3SPeter Maydell         cteval = FIELD_DP64(cteval, CTE, RDBASE, cte->rdbase);
6287eca39e0SShashi Mallela     }
6297eca39e0SShashi Mallela 
630d050f80fSPeter Maydell     entry_addr = table_entry_addr(s, &s->ct, icid, &res);
6317eca39e0SShashi Mallela     if (res != MEMTX_OK) {
632d050f80fSPeter Maydell         /* memory access error: stall */
6337eca39e0SShashi Mallela         return false;
6347eca39e0SShashi Mallela     }
635d050f80fSPeter Maydell     if (entry_addr == -1) {
636d050f80fSPeter Maydell         /* No L2 table for this index: discard write and continue */
6377eca39e0SShashi Mallela         return true;
6387eca39e0SShashi Mallela     }
639d050f80fSPeter Maydell 
64006985cc3SPeter Maydell     address_space_stq_le(as, entry_addr, cteval, MEMTXATTRS_UNSPECIFIED, &res);
641d050f80fSPeter Maydell     return res == MEMTX_OK;
6427eca39e0SShashi Mallela }
6437eca39e0SShashi Mallela 
644b6f96009SPeter Maydell static ItsCmdResult process_mapc(GICv3ITSState *s, const uint64_t *cmdpkt)
6457eca39e0SShashi Mallela {
6467eca39e0SShashi Mallela     uint16_t icid;
64706985cc3SPeter Maydell     CTEntry cte;
6487eca39e0SShashi Mallela 
649b6f96009SPeter Maydell     icid = cmdpkt[2] & ICID_MASK;
65084d43d2eSPeter Maydell     cte.valid = cmdpkt[2] & CMD_FIELD_VALID_MASK;
65184d43d2eSPeter Maydell     if (cte.valid) {
65206985cc3SPeter Maydell         cte.rdbase = (cmdpkt[2] & R_MAPC_RDBASE_MASK) >> R_MAPC_RDBASE_SHIFT;
65306985cc3SPeter Maydell         cte.rdbase &= RDBASE_PROCNUM_MASK;
65484d43d2eSPeter Maydell     } else {
65584d43d2eSPeter Maydell         cte.rdbase = 0;
65684d43d2eSPeter Maydell     }
657e4050980SPeter Maydell     trace_gicv3_its_cmd_mapc(icid, cte.rdbase, cte.valid);
6587eca39e0SShashi Mallela 
65984d43d2eSPeter Maydell     if (icid >= s->ct.num_entries) {
660c7ca3ad5SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR, "ITS MAPC: invalid ICID 0x%x\n", icid);
66184d43d2eSPeter Maydell         return CMD_CONTINUE;
66284d43d2eSPeter Maydell     }
66384d43d2eSPeter Maydell     if (cte.valid && cte.rdbase >= s->gicv3->num_cpu) {
6647eca39e0SShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
665c7ca3ad5SPeter Maydell                       "ITS MAPC: invalid RDBASE %u\n", cte.rdbase);
666f6675196SPeter Maydell         return CMD_CONTINUE;
6677eca39e0SShashi Mallela     }
6687eca39e0SShashi Mallela 
66993f4fdcdSPeter Maydell     return update_cte(s, icid, &cte) ? CMD_CONTINUE_OK : CMD_STALL;
6707eca39e0SShashi Mallela }
6717eca39e0SShashi Mallela 
67222d62b08SPeter Maydell /*
67322d62b08SPeter Maydell  * Update the Device Table entry for @devid to @dte. Returns true
67422d62b08SPeter Maydell  * on success, false if there was a memory access error.
67522d62b08SPeter Maydell  */
67622d62b08SPeter Maydell static bool update_dte(GICv3ITSState *s, uint32_t devid, const DTEntry *dte)
6777eca39e0SShashi Mallela {
6787eca39e0SShashi Mallela     AddressSpace *as = &s->gicv3->dma_as;
679d050f80fSPeter Maydell     uint64_t entry_addr;
68022d62b08SPeter Maydell     uint64_t dteval = 0;
6817eca39e0SShashi Mallela     MemTxResult res = MEMTX_OK;
6827eca39e0SShashi Mallela 
683930f40e9SPeter Maydell     trace_gicv3_its_dte_write(devid, dte->valid, dte->size, dte->ittaddr);
684930f40e9SPeter Maydell 
68522d62b08SPeter Maydell     if (dte->valid) {
6867eca39e0SShashi Mallela         /* add mapping entry to device table */
68722d62b08SPeter Maydell         dteval = FIELD_DP64(dteval, DTE, VALID, 1);
68822d62b08SPeter Maydell         dteval = FIELD_DP64(dteval, DTE, SIZE, dte->size);
68922d62b08SPeter Maydell         dteval = FIELD_DP64(dteval, DTE, ITTADDR, dte->ittaddr);
6907eca39e0SShashi Mallela     }
6917eca39e0SShashi Mallela 
692d050f80fSPeter Maydell     entry_addr = table_entry_addr(s, &s->dt, devid, &res);
6937eca39e0SShashi Mallela     if (res != MEMTX_OK) {
694d050f80fSPeter Maydell         /* memory access error: stall */
6957eca39e0SShashi Mallela         return false;
6967eca39e0SShashi Mallela     }
697d050f80fSPeter Maydell     if (entry_addr == -1) {
698d050f80fSPeter Maydell         /* No L2 table for this index: discard write and continue */
6997eca39e0SShashi Mallela         return true;
7007eca39e0SShashi Mallela     }
70122d62b08SPeter Maydell     address_space_stq_le(as, entry_addr, dteval, MEMTXATTRS_UNSPECIFIED, &res);
702d050f80fSPeter Maydell     return res == MEMTX_OK;
7037eca39e0SShashi Mallela }
7047eca39e0SShashi Mallela 
705b6f96009SPeter Maydell static ItsCmdResult process_mapd(GICv3ITSState *s, const uint64_t *cmdpkt)
7067eca39e0SShashi Mallela {
7077eca39e0SShashi Mallela     uint32_t devid;
70822d62b08SPeter Maydell     DTEntry dte;
7097eca39e0SShashi Mallela 
710b6f96009SPeter Maydell     devid = (cmdpkt[0] & DEVID_MASK) >> DEVID_SHIFT;
71122d62b08SPeter Maydell     dte.size = cmdpkt[1] & SIZE_MASK;
71222d62b08SPeter Maydell     dte.ittaddr = (cmdpkt[2] & ITTADDR_MASK) >> ITTADDR_SHIFT;
71322d62b08SPeter Maydell     dte.valid = cmdpkt[2] & CMD_FIELD_VALID_MASK;
7147eca39e0SShashi Mallela 
715e4050980SPeter Maydell     trace_gicv3_its_cmd_mapd(devid, dte.size, dte.ittaddr, dte.valid);
716e4050980SPeter Maydell 
717d7d359c4SPeter Maydell     if (devid >= s->dt.num_entries) {
7187eca39e0SShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
719d7d359c4SPeter Maydell                       "ITS MAPD: invalid device ID field 0x%x >= 0x%x\n",
720d7d359c4SPeter Maydell                       devid, s->dt.num_entries);
721d7d359c4SPeter Maydell         return CMD_CONTINUE;
722d7d359c4SPeter Maydell     }
723d7d359c4SPeter Maydell 
724d7d359c4SPeter Maydell     if (dte.size > FIELD_EX64(s->typer, GITS_TYPER, IDBITS)) {
725d7d359c4SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
726d7d359c4SPeter Maydell                       "ITS MAPD: invalid size %d\n", dte.size);
72700d46e72SPeter Maydell         return CMD_CONTINUE;
7287eca39e0SShashi Mallela     }
7297eca39e0SShashi Mallela 
73093f4fdcdSPeter Maydell     return update_dte(s, devid, &dte) ? CMD_CONTINUE_OK : CMD_STALL;
7317eca39e0SShashi Mallela }
7327eca39e0SShashi Mallela 
733b6f96009SPeter Maydell static ItsCmdResult process_movall(GICv3ITSState *s, const uint64_t *cmdpkt)
734f6d1d9b4SPeter Maydell {
735f6d1d9b4SPeter Maydell     uint64_t rd1, rd2;
736f6d1d9b4SPeter Maydell 
737b6f96009SPeter Maydell     rd1 = FIELD_EX64(cmdpkt[2], MOVALL_2, RDBASE1);
738b6f96009SPeter Maydell     rd2 = FIELD_EX64(cmdpkt[3], MOVALL_3, RDBASE2);
739f6d1d9b4SPeter Maydell 
740e4050980SPeter Maydell     trace_gicv3_its_cmd_movall(rd1, rd2);
741e4050980SPeter Maydell 
742f6d1d9b4SPeter Maydell     if (rd1 >= s->gicv3->num_cpu) {
743f6d1d9b4SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
744f6d1d9b4SPeter Maydell                       "%s: RDBASE1 %" PRId64
745f6d1d9b4SPeter Maydell                       " out of range (must be less than %d)\n",
746f6d1d9b4SPeter Maydell                       __func__, rd1, s->gicv3->num_cpu);
747f6d1d9b4SPeter Maydell         return CMD_CONTINUE;
748f6d1d9b4SPeter Maydell     }
749f6d1d9b4SPeter Maydell     if (rd2 >= s->gicv3->num_cpu) {
750f6d1d9b4SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
751f6d1d9b4SPeter Maydell                       "%s: RDBASE2 %" PRId64
752f6d1d9b4SPeter Maydell                       " out of range (must be less than %d)\n",
753f6d1d9b4SPeter Maydell                       __func__, rd2, s->gicv3->num_cpu);
754f6d1d9b4SPeter Maydell         return CMD_CONTINUE;
755f6d1d9b4SPeter Maydell     }
756f6d1d9b4SPeter Maydell 
757f6d1d9b4SPeter Maydell     if (rd1 == rd2) {
758f6d1d9b4SPeter Maydell         /* Move to same target must succeed as a no-op */
75993f4fdcdSPeter Maydell         return CMD_CONTINUE_OK;
760f6d1d9b4SPeter Maydell     }
761f6d1d9b4SPeter Maydell 
762f6d1d9b4SPeter Maydell     /* Move all pending LPIs from redistributor 1 to redistributor 2 */
763f6d1d9b4SPeter Maydell     gicv3_redist_movall_lpis(&s->gicv3->cpu[rd1], &s->gicv3->cpu[rd2]);
764f6d1d9b4SPeter Maydell 
76593f4fdcdSPeter Maydell     return CMD_CONTINUE_OK;
766f6d1d9b4SPeter Maydell }
767f6d1d9b4SPeter Maydell 
768b6f96009SPeter Maydell static ItsCmdResult process_movi(GICv3ITSState *s, const uint64_t *cmdpkt)
769961b4912SPeter Maydell {
770244194feSPeter Maydell     uint32_t devid, eventid;
771244194feSPeter Maydell     uint16_t new_icid;
7724acf93e1SPeter Maydell     DTEntry dte;
773d37cf49bSPeter Maydell     CTEntry old_cte, new_cte;
774244194feSPeter Maydell     ITEntry old_ite;
775*f0175135SPeter Maydell     ItsCmdResult cmdres;
776961b4912SPeter Maydell 
777b6f96009SPeter Maydell     devid = FIELD_EX64(cmdpkt[0], MOVI_0, DEVICEID);
778b6f96009SPeter Maydell     eventid = FIELD_EX64(cmdpkt[1], MOVI_1, EVENTID);
779b6f96009SPeter Maydell     new_icid = FIELD_EX64(cmdpkt[2], MOVI_2, ICID);
780961b4912SPeter Maydell 
781e4050980SPeter Maydell     trace_gicv3_its_cmd_movi(devid, eventid, new_icid);
782e4050980SPeter Maydell 
783*f0175135SPeter Maydell     cmdres = lookup_ite(s, __func__, devid, eventid, &old_ite, &dte);
784*f0175135SPeter Maydell     if (cmdres != CMD_CONTINUE_OK) {
785*f0175135SPeter Maydell         return cmdres;
786961b4912SPeter Maydell     }
787961b4912SPeter Maydell 
788*f0175135SPeter Maydell     if (old_ite.inttype != ITE_INTTYPE_PHYSICAL) {
789961b4912SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
790961b4912SPeter Maydell                       "%s: invalid command attributes: invalid ITE\n",
791961b4912SPeter Maydell                       __func__);
792961b4912SPeter Maydell         return CMD_CONTINUE;
793961b4912SPeter Maydell     }
794961b4912SPeter Maydell 
795244194feSPeter Maydell     if (old_ite.icid >= s->ct.num_entries) {
796961b4912SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
797961b4912SPeter Maydell                       "%s: invalid ICID 0x%x in ITE (table corrupted?)\n",
798244194feSPeter Maydell                       __func__, old_ite.icid);
799961b4912SPeter Maydell         return CMD_CONTINUE;
800961b4912SPeter Maydell     }
801961b4912SPeter Maydell 
802961b4912SPeter Maydell     if (new_icid >= s->ct.num_entries) {
803961b4912SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
804961b4912SPeter Maydell                       "%s: invalid command attributes: ICID 0x%x\n",
805961b4912SPeter Maydell                       __func__, new_icid);
806961b4912SPeter Maydell         return CMD_CONTINUE;
807961b4912SPeter Maydell     }
808961b4912SPeter Maydell 
809244194feSPeter Maydell     if (get_cte(s, old_ite.icid, &old_cte) != MEMTX_OK) {
810961b4912SPeter Maydell         return CMD_STALL;
811961b4912SPeter Maydell     }
812d37cf49bSPeter Maydell     if (!old_cte.valid) {
813961b4912SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
814961b4912SPeter Maydell                       "%s: invalid command attributes: "
815d37cf49bSPeter Maydell                       "invalid CTE for old ICID 0x%x\n",
816244194feSPeter Maydell                       __func__, old_ite.icid);
817961b4912SPeter Maydell         return CMD_CONTINUE;
818961b4912SPeter Maydell     }
819961b4912SPeter Maydell 
820d37cf49bSPeter Maydell     if (get_cte(s, new_icid, &new_cte) != MEMTX_OK) {
821961b4912SPeter Maydell         return CMD_STALL;
822961b4912SPeter Maydell     }
823d37cf49bSPeter Maydell     if (!new_cte.valid) {
824961b4912SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
825961b4912SPeter Maydell                       "%s: invalid command attributes: "
826d37cf49bSPeter Maydell                       "invalid CTE for new ICID 0x%x\n",
827d37cf49bSPeter Maydell                       __func__, new_icid);
828961b4912SPeter Maydell         return CMD_CONTINUE;
829961b4912SPeter Maydell     }
830961b4912SPeter Maydell 
831d37cf49bSPeter Maydell     if (old_cte.rdbase >= s->gicv3->num_cpu) {
832961b4912SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
833d37cf49bSPeter Maydell                       "%s: CTE has invalid rdbase 0x%x\n",
834d37cf49bSPeter Maydell                       __func__, old_cte.rdbase);
835961b4912SPeter Maydell         return CMD_CONTINUE;
836961b4912SPeter Maydell     }
837961b4912SPeter Maydell 
838d37cf49bSPeter Maydell     if (new_cte.rdbase >= s->gicv3->num_cpu) {
839961b4912SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
840d37cf49bSPeter Maydell                       "%s: CTE has invalid rdbase 0x%x\n",
841d37cf49bSPeter Maydell                       __func__, new_cte.rdbase);
842961b4912SPeter Maydell         return CMD_CONTINUE;
843961b4912SPeter Maydell     }
844961b4912SPeter Maydell 
845d37cf49bSPeter Maydell     if (old_cte.rdbase != new_cte.rdbase) {
846961b4912SPeter Maydell         /* Move the LPI from the old redistributor to the new one */
847d37cf49bSPeter Maydell         gicv3_redist_mov_lpi(&s->gicv3->cpu[old_cte.rdbase],
848d37cf49bSPeter Maydell                              &s->gicv3->cpu[new_cte.rdbase],
849244194feSPeter Maydell                              old_ite.intid);
850961b4912SPeter Maydell     }
851961b4912SPeter Maydell 
852961b4912SPeter Maydell     /* Update the ICID field in the interrupt translation table entry */
8537eb54267SPeter Maydell     old_ite.icid = new_icid;
85493f4fdcdSPeter Maydell     return update_ite(s, eventid, &dte, &old_ite) ? CMD_CONTINUE_OK : CMD_STALL;
855961b4912SPeter Maydell }
856961b4912SPeter Maydell 
8577eca39e0SShashi Mallela /*
8580cdf7a5dSPeter Maydell  * Update the vPE Table entry at index @vpeid with the entry @vte.
8590cdf7a5dSPeter Maydell  * Returns true on success, false if there was a memory access error.
8600cdf7a5dSPeter Maydell  */
8610cdf7a5dSPeter Maydell static bool update_vte(GICv3ITSState *s, uint32_t vpeid, const VTEntry *vte)
8620cdf7a5dSPeter Maydell {
8630cdf7a5dSPeter Maydell     AddressSpace *as = &s->gicv3->dma_as;
8640cdf7a5dSPeter Maydell     uint64_t entry_addr;
8650cdf7a5dSPeter Maydell     uint64_t vteval = 0;
8660cdf7a5dSPeter Maydell     MemTxResult res = MEMTX_OK;
8670cdf7a5dSPeter Maydell 
8680cdf7a5dSPeter Maydell     trace_gicv3_its_vte_write(vpeid, vte->valid, vte->vptsize, vte->vptaddr,
8690cdf7a5dSPeter Maydell                               vte->rdbase);
8700cdf7a5dSPeter Maydell 
8710cdf7a5dSPeter Maydell     if (vte->valid) {
8720cdf7a5dSPeter Maydell         vteval = FIELD_DP64(vteval, VTE, VALID, 1);
8730cdf7a5dSPeter Maydell         vteval = FIELD_DP64(vteval, VTE, VPTSIZE, vte->vptsize);
8740cdf7a5dSPeter Maydell         vteval = FIELD_DP64(vteval, VTE, VPTADDR, vte->vptaddr);
8750cdf7a5dSPeter Maydell         vteval = FIELD_DP64(vteval, VTE, RDBASE, vte->rdbase);
8760cdf7a5dSPeter Maydell     }
8770cdf7a5dSPeter Maydell 
8780cdf7a5dSPeter Maydell     entry_addr = table_entry_addr(s, &s->vpet, vpeid, &res);
8790cdf7a5dSPeter Maydell     if (res != MEMTX_OK) {
8800cdf7a5dSPeter Maydell         return false;
8810cdf7a5dSPeter Maydell     }
8820cdf7a5dSPeter Maydell     if (entry_addr == -1) {
8830cdf7a5dSPeter Maydell         /* No L2 table for this index: discard write and continue */
8840cdf7a5dSPeter Maydell         return true;
8850cdf7a5dSPeter Maydell     }
8860cdf7a5dSPeter Maydell     address_space_stq_le(as, entry_addr, vteval, MEMTXATTRS_UNSPECIFIED, &res);
8870cdf7a5dSPeter Maydell     return res == MEMTX_OK;
8880cdf7a5dSPeter Maydell }
8890cdf7a5dSPeter Maydell 
8900cdf7a5dSPeter Maydell static ItsCmdResult process_vmapp(GICv3ITSState *s, const uint64_t *cmdpkt)
8910cdf7a5dSPeter Maydell {
8920cdf7a5dSPeter Maydell     VTEntry vte;
8930cdf7a5dSPeter Maydell     uint32_t vpeid;
8940cdf7a5dSPeter Maydell 
8950cdf7a5dSPeter Maydell     if (!its_feature_virtual(s)) {
8960cdf7a5dSPeter Maydell         return CMD_CONTINUE;
8970cdf7a5dSPeter Maydell     }
8980cdf7a5dSPeter Maydell 
8990cdf7a5dSPeter Maydell     vpeid = FIELD_EX64(cmdpkt[1], VMAPP_1, VPEID);
9000cdf7a5dSPeter Maydell     vte.rdbase = FIELD_EX64(cmdpkt[2], VMAPP_2, RDBASE);
9010cdf7a5dSPeter Maydell     vte.valid = FIELD_EX64(cmdpkt[2], VMAPP_2, V);
9020cdf7a5dSPeter Maydell     vte.vptsize = FIELD_EX64(cmdpkt[3], VMAPP_3, VPTSIZE);
9030cdf7a5dSPeter Maydell     vte.vptaddr = FIELD_EX64(cmdpkt[3], VMAPP_3, VPTADDR);
9040cdf7a5dSPeter Maydell 
9050cdf7a5dSPeter Maydell     trace_gicv3_its_cmd_vmapp(vpeid, vte.rdbase, vte.valid,
9060cdf7a5dSPeter Maydell                               vte.vptaddr, vte.vptsize);
9070cdf7a5dSPeter Maydell 
9080cdf7a5dSPeter Maydell     /*
9090cdf7a5dSPeter Maydell      * For GICv4.0 the VPT_size field is only 5 bits, whereas we
9100cdf7a5dSPeter Maydell      * define our field macros to include the full GICv4.1 8 bits.
9110cdf7a5dSPeter Maydell      * The range check on VPT_size will catch the cases where
9120cdf7a5dSPeter Maydell      * the guest set the RES0-in-GICv4.0 bits [7:6].
9130cdf7a5dSPeter Maydell      */
9140cdf7a5dSPeter Maydell     if (vte.vptsize > FIELD_EX64(s->typer, GITS_TYPER, IDBITS)) {
9150cdf7a5dSPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
9160cdf7a5dSPeter Maydell                       "%s: invalid VPT_size 0x%x\n", __func__, vte.vptsize);
9170cdf7a5dSPeter Maydell         return CMD_CONTINUE;
9180cdf7a5dSPeter Maydell     }
9190cdf7a5dSPeter Maydell 
9200cdf7a5dSPeter Maydell     if (vte.valid && vte.rdbase >= s->gicv3->num_cpu) {
9210cdf7a5dSPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
9220cdf7a5dSPeter Maydell                       "%s: invalid rdbase 0x%x\n", __func__, vte.rdbase);
9230cdf7a5dSPeter Maydell         return CMD_CONTINUE;
9240cdf7a5dSPeter Maydell     }
9250cdf7a5dSPeter Maydell 
9260cdf7a5dSPeter Maydell     if (vpeid >= s->vpet.num_entries) {
9270cdf7a5dSPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
9280cdf7a5dSPeter Maydell                       "%s: VPEID 0x%x out of range (must be less than 0x%x)\n",
9290cdf7a5dSPeter Maydell                       __func__, vpeid, s->vpet.num_entries);
9300cdf7a5dSPeter Maydell         return CMD_CONTINUE;
9310cdf7a5dSPeter Maydell     }
9320cdf7a5dSPeter Maydell 
93393f4fdcdSPeter Maydell     return update_vte(s, vpeid, &vte) ? CMD_CONTINUE_OK : CMD_STALL;
9340cdf7a5dSPeter Maydell }
9350cdf7a5dSPeter Maydell 
9360cdf7a5dSPeter Maydell /*
9377eca39e0SShashi Mallela  * Current implementation blocks until all
9387eca39e0SShashi Mallela  * commands are processed
9397eca39e0SShashi Mallela  */
9407eca39e0SShashi Mallela static void process_cmdq(GICv3ITSState *s)
9417eca39e0SShashi Mallela {
9427eca39e0SShashi Mallela     uint32_t wr_offset = 0;
9437eca39e0SShashi Mallela     uint32_t rd_offset = 0;
9447eca39e0SShashi Mallela     uint32_t cq_offset = 0;
9457eca39e0SShashi Mallela     AddressSpace *as = &s->gicv3->dma_as;
9467eca39e0SShashi Mallela     uint8_t cmd;
94717fb5e36SShashi Mallela     int i;
9487eca39e0SShashi Mallela 
9498d2d6dd9SPeter Maydell     if (!(s->ctlr & R_GITS_CTLR_ENABLED_MASK)) {
9507eca39e0SShashi Mallela         return;
9517eca39e0SShashi Mallela     }
9527eca39e0SShashi Mallela 
9537eca39e0SShashi Mallela     wr_offset = FIELD_EX64(s->cwriter, GITS_CWRITER, OFFSET);
9547eca39e0SShashi Mallela 
95580dcd37fSPeter Maydell     if (wr_offset >= s->cq.num_entries) {
9567eca39e0SShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
9577eca39e0SShashi Mallela                       "%s: invalid write offset "
9587eca39e0SShashi Mallela                       "%d\n", __func__, wr_offset);
9597eca39e0SShashi Mallela         return;
9607eca39e0SShashi Mallela     }
9617eca39e0SShashi Mallela 
9627eca39e0SShashi Mallela     rd_offset = FIELD_EX64(s->creadr, GITS_CREADR, OFFSET);
9637eca39e0SShashi Mallela 
96480dcd37fSPeter Maydell     if (rd_offset >= s->cq.num_entries) {
9657eca39e0SShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
9667eca39e0SShashi Mallela                       "%s: invalid read offset "
9677eca39e0SShashi Mallela                       "%d\n", __func__, rd_offset);
9687eca39e0SShashi Mallela         return;
9697eca39e0SShashi Mallela     }
9707eca39e0SShashi Mallela 
9717eca39e0SShashi Mallela     while (wr_offset != rd_offset) {
97293f4fdcdSPeter Maydell         ItsCmdResult result = CMD_CONTINUE_OK;
973b6f96009SPeter Maydell         void *hostmem;
974b6f96009SPeter Maydell         hwaddr buflen;
975b6f96009SPeter Maydell         uint64_t cmdpkt[GITS_CMDQ_ENTRY_WORDS];
976ef011555SPeter Maydell 
9777eca39e0SShashi Mallela         cq_offset = (rd_offset * GITS_CMDQ_ENTRY_SIZE);
978b6f96009SPeter Maydell 
979b6f96009SPeter Maydell         buflen = GITS_CMDQ_ENTRY_SIZE;
980b6f96009SPeter Maydell         hostmem = address_space_map(as, s->cq.base_addr + cq_offset,
981b6f96009SPeter Maydell                                     &buflen, false, MEMTXATTRS_UNSPECIFIED);
982b6f96009SPeter Maydell         if (!hostmem || buflen != GITS_CMDQ_ENTRY_SIZE) {
983b6f96009SPeter Maydell             if (hostmem) {
984b6f96009SPeter Maydell                 address_space_unmap(as, hostmem, buflen, false, 0);
985b6f96009SPeter Maydell             }
986f0b4b2a2SPeter Maydell             s->creadr = FIELD_DP64(s->creadr, GITS_CREADR, STALLED, 1);
987f0b4b2a2SPeter Maydell             qemu_log_mask(LOG_GUEST_ERROR,
988f0b4b2a2SPeter Maydell                           "%s: could not read command at 0x%" PRIx64 "\n",
989f0b4b2a2SPeter Maydell                           __func__, s->cq.base_addr + cq_offset);
990f0b4b2a2SPeter Maydell             break;
9917eca39e0SShashi Mallela         }
992b6f96009SPeter Maydell         for (i = 0; i < ARRAY_SIZE(cmdpkt); i++) {
993b6f96009SPeter Maydell             cmdpkt[i] = ldq_le_p(hostmem + i * sizeof(uint64_t));
994b6f96009SPeter Maydell         }
995b6f96009SPeter Maydell         address_space_unmap(as, hostmem, buflen, false, 0);
996f0b4b2a2SPeter Maydell 
997b6f96009SPeter Maydell         cmd = cmdpkt[0] & CMD_MASK;
9987eca39e0SShashi Mallela 
999195209d3SPeter Maydell         trace_gicv3_its_process_command(rd_offset, cmd);
1000195209d3SPeter Maydell 
10017eca39e0SShashi Mallela         switch (cmd) {
10027eca39e0SShashi Mallela         case GITS_CMD_INT:
1003b6f96009SPeter Maydell             result = process_its_cmd(s, cmdpkt, INTERRUPT);
10047eca39e0SShashi Mallela             break;
10057eca39e0SShashi Mallela         case GITS_CMD_CLEAR:
1006b6f96009SPeter Maydell             result = process_its_cmd(s, cmdpkt, CLEAR);
10077eca39e0SShashi Mallela             break;
10087eca39e0SShashi Mallela         case GITS_CMD_SYNC:
10097eca39e0SShashi Mallela             /*
10107eca39e0SShashi Mallela              * Current implementation makes a blocking synchronous call
10117eca39e0SShashi Mallela              * for every command issued earlier, hence the internal state
10127eca39e0SShashi Mallela              * is already consistent by the time SYNC command is executed.
10137eca39e0SShashi Mallela              * Hence no further processing is required for SYNC command.
10147eca39e0SShashi Mallela              */
1015e4050980SPeter Maydell             trace_gicv3_its_cmd_sync();
10167eca39e0SShashi Mallela             break;
10177eca39e0SShashi Mallela         case GITS_CMD_MAPD:
1018b6f96009SPeter Maydell             result = process_mapd(s, cmdpkt);
10197eca39e0SShashi Mallela             break;
10207eca39e0SShashi Mallela         case GITS_CMD_MAPC:
1021b6f96009SPeter Maydell             result = process_mapc(s, cmdpkt);
10227eca39e0SShashi Mallela             break;
10237eca39e0SShashi Mallela         case GITS_CMD_MAPTI:
1024b6f96009SPeter Maydell             result = process_mapti(s, cmdpkt, false);
10257eca39e0SShashi Mallela             break;
10267eca39e0SShashi Mallela         case GITS_CMD_MAPI:
1027b6f96009SPeter Maydell             result = process_mapti(s, cmdpkt, true);
10287eca39e0SShashi Mallela             break;
10297eca39e0SShashi Mallela         case GITS_CMD_DISCARD:
1030b6f96009SPeter Maydell             result = process_its_cmd(s, cmdpkt, DISCARD);
10317eca39e0SShashi Mallela             break;
10327eca39e0SShashi Mallela         case GITS_CMD_INV:
10337eca39e0SShashi Mallela         case GITS_CMD_INVALL:
103417fb5e36SShashi Mallela             /*
103517fb5e36SShashi Mallela              * Current implementation doesn't cache any ITS tables,
103617fb5e36SShashi Mallela              * but the calculated lpi priority information. We only
103717fb5e36SShashi Mallela              * need to trigger lpi priority re-calculation to be in
103817fb5e36SShashi Mallela              * sync with LPI config table or pending table changes.
103917fb5e36SShashi Mallela              */
1040e4050980SPeter Maydell             trace_gicv3_its_cmd_inv();
104117fb5e36SShashi Mallela             for (i = 0; i < s->gicv3->num_cpu; i++) {
104217fb5e36SShashi Mallela                 gicv3_redist_update_lpi(&s->gicv3->cpu[i]);
104317fb5e36SShashi Mallela             }
10447eca39e0SShashi Mallela             break;
1045961b4912SPeter Maydell         case GITS_CMD_MOVI:
1046b6f96009SPeter Maydell             result = process_movi(s, cmdpkt);
1047961b4912SPeter Maydell             break;
1048f6d1d9b4SPeter Maydell         case GITS_CMD_MOVALL:
1049b6f96009SPeter Maydell             result = process_movall(s, cmdpkt);
1050f6d1d9b4SPeter Maydell             break;
10519de53de6SPeter Maydell         case GITS_CMD_VMAPTI:
10529de53de6SPeter Maydell             result = process_vmapti(s, cmdpkt, false);
10539de53de6SPeter Maydell             break;
10549de53de6SPeter Maydell         case GITS_CMD_VMAPI:
10559de53de6SPeter Maydell             result = process_vmapti(s, cmdpkt, true);
10569de53de6SPeter Maydell             break;
10570cdf7a5dSPeter Maydell         case GITS_CMD_VMAPP:
10580cdf7a5dSPeter Maydell             result = process_vmapp(s, cmdpkt);
10590cdf7a5dSPeter Maydell             break;
10607eca39e0SShashi Mallela         default:
1061e4050980SPeter Maydell             trace_gicv3_its_cmd_unknown(cmd);
10627eca39e0SShashi Mallela             break;
10637eca39e0SShashi Mallela         }
106493f4fdcdSPeter Maydell         if (result != CMD_STALL) {
106593f4fdcdSPeter Maydell             /* CMD_CONTINUE or CMD_CONTINUE_OK */
10667eca39e0SShashi Mallela             rd_offset++;
106780dcd37fSPeter Maydell             rd_offset %= s->cq.num_entries;
10687eca39e0SShashi Mallela             s->creadr = FIELD_DP64(s->creadr, GITS_CREADR, OFFSET, rd_offset);
10697eca39e0SShashi Mallela         } else {
1070ef011555SPeter Maydell             /* CMD_STALL */
10717eca39e0SShashi Mallela             s->creadr = FIELD_DP64(s->creadr, GITS_CREADR, STALLED, 1);
10727eca39e0SShashi Mallela             qemu_log_mask(LOG_GUEST_ERROR,
1073ef011555SPeter Maydell                           "%s: 0x%x cmd processing failed, stalling\n",
1074ef011555SPeter Maydell                           __func__, cmd);
10757eca39e0SShashi Mallela             break;
10767eca39e0SShashi Mallela         }
10777eca39e0SShashi Mallela     }
10787eca39e0SShashi Mallela }
10797eca39e0SShashi Mallela 
10801b08e436SShashi Mallela /*
10811b08e436SShashi Mallela  * This function extracts the ITS Device and Collection table specific
10821b08e436SShashi Mallela  * parameters (like base_addr, size etc) from GITS_BASER register.
10831b08e436SShashi Mallela  * It is called during ITS enable and also during post_load migration
10841b08e436SShashi Mallela  */
10851b08e436SShashi Mallela static void extract_table_params(GICv3ITSState *s)
10861b08e436SShashi Mallela {
10871b08e436SShashi Mallela     uint16_t num_pages = 0;
10881b08e436SShashi Mallela     uint8_t  page_sz_type;
10891b08e436SShashi Mallela     uint8_t type;
10901b08e436SShashi Mallela     uint32_t page_sz = 0;
10911b08e436SShashi Mallela     uint64_t value;
10921b08e436SShashi Mallela 
10931b08e436SShashi Mallela     for (int i = 0; i < 8; i++) {
1094e5487a41SPeter Maydell         TableDesc *td;
1095e5487a41SPeter Maydell         int idbits;
1096e5487a41SPeter Maydell 
10971b08e436SShashi Mallela         value = s->baser[i];
10981b08e436SShashi Mallela 
10991b08e436SShashi Mallela         if (!value) {
11001b08e436SShashi Mallela             continue;
11011b08e436SShashi Mallela         }
11021b08e436SShashi Mallela 
11031b08e436SShashi Mallela         page_sz_type = FIELD_EX64(value, GITS_BASER, PAGESIZE);
11041b08e436SShashi Mallela 
11051b08e436SShashi Mallela         switch (page_sz_type) {
11061b08e436SShashi Mallela         case 0:
11071b08e436SShashi Mallela             page_sz = GITS_PAGE_SIZE_4K;
11081b08e436SShashi Mallela             break;
11091b08e436SShashi Mallela 
11101b08e436SShashi Mallela         case 1:
11111b08e436SShashi Mallela             page_sz = GITS_PAGE_SIZE_16K;
11121b08e436SShashi Mallela             break;
11131b08e436SShashi Mallela 
11141b08e436SShashi Mallela         case 2:
11151b08e436SShashi Mallela         case 3:
11161b08e436SShashi Mallela             page_sz = GITS_PAGE_SIZE_64K;
11171b08e436SShashi Mallela             break;
11181b08e436SShashi Mallela 
11191b08e436SShashi Mallela         default:
11201b08e436SShashi Mallela             g_assert_not_reached();
11211b08e436SShashi Mallela         }
11221b08e436SShashi Mallela 
11231b08e436SShashi Mallela         num_pages = FIELD_EX64(value, GITS_BASER, SIZE) + 1;
11241b08e436SShashi Mallela 
11251b08e436SShashi Mallela         type = FIELD_EX64(value, GITS_BASER, TYPE);
11261b08e436SShashi Mallela 
11271b08e436SShashi Mallela         switch (type) {
11281b08e436SShashi Mallela         case GITS_BASER_TYPE_DEVICE:
1129e5487a41SPeter Maydell             td = &s->dt;
1130e5487a41SPeter Maydell             idbits = FIELD_EX64(s->typer, GITS_TYPER, DEVBITS) + 1;
113162df780eSPeter Maydell             break;
11321b08e436SShashi Mallela         case GITS_BASER_TYPE_COLLECTION:
1133e5487a41SPeter Maydell             td = &s->ct;
11341b08e436SShashi Mallela             if (FIELD_EX64(s->typer, GITS_TYPER, CIL)) {
1135e5487a41SPeter Maydell                 idbits = FIELD_EX64(s->typer, GITS_TYPER, CIDBITS) + 1;
11361b08e436SShashi Mallela             } else {
11371b08e436SShashi Mallela                 /* 16-bit CollectionId supported when CIL == 0 */
1138e5487a41SPeter Maydell                 idbits = 16;
11391b08e436SShashi Mallela             }
11401b08e436SShashi Mallela             break;
114150d84584SPeter Maydell         case GITS_BASER_TYPE_VPE:
114250d84584SPeter Maydell             td = &s->vpet;
114350d84584SPeter Maydell             /*
114450d84584SPeter Maydell              * For QEMU vPEIDs are always 16 bits. (GICv4.1 allows an
114550d84584SPeter Maydell              * implementation to implement fewer bits and report this
114650d84584SPeter Maydell              * via GICD_TYPER2.)
114750d84584SPeter Maydell              */
114850d84584SPeter Maydell             idbits = 16;
114950d84584SPeter Maydell             break;
11501b08e436SShashi Mallela         default:
1151e5487a41SPeter Maydell             /*
1152e5487a41SPeter Maydell              * GITS_BASER<n>.TYPE is read-only, so GITS_BASER_RO_MASK
1153e5487a41SPeter Maydell              * ensures we will only see type values corresponding to
1154e5487a41SPeter Maydell              * the values set up in gicv3_its_reset().
1155e5487a41SPeter Maydell              */
1156e5487a41SPeter Maydell             g_assert_not_reached();
11571b08e436SShashi Mallela         }
1158e5487a41SPeter Maydell 
1159e5487a41SPeter Maydell         memset(td, 0, sizeof(*td));
1160e5487a41SPeter Maydell         /*
1161e5487a41SPeter Maydell          * If GITS_BASER<n>.Valid is 0 for any <n> then we will not process
1162e5487a41SPeter Maydell          * interrupts. (GITS_TYPER.HCC is 0 for this implementation, so we
1163e5487a41SPeter Maydell          * do not have a special case where the GITS_BASER<n>.Valid bit is 0
1164e5487a41SPeter Maydell          * for the register corresponding to the Collection table but we
1165e5487a41SPeter Maydell          * still have to process interrupts using non-memory-backed
1166e5487a41SPeter Maydell          * Collection table entries.)
1167da4680ceSPeter Maydell          * The specification makes it UNPREDICTABLE to enable the ITS without
1168da4680ceSPeter Maydell          * marking each BASER<n> as valid. We choose to handle these as if
1169da4680ceSPeter Maydell          * the table was zero-sized, so commands using the table will fail
1170da4680ceSPeter Maydell          * and interrupts requested via GITS_TRANSLATER writes will be ignored.
1171da4680ceSPeter Maydell          * This happens automatically by leaving the num_entries field at
1172da4680ceSPeter Maydell          * zero, which will be caught by the bounds checks we have before
1173da4680ceSPeter Maydell          * every table lookup anyway.
1174e5487a41SPeter Maydell          */
1175da4680ceSPeter Maydell         if (!FIELD_EX64(value, GITS_BASER, VALID)) {
1176e5487a41SPeter Maydell             continue;
1177e5487a41SPeter Maydell         }
1178e5487a41SPeter Maydell         td->page_sz = page_sz;
1179e5487a41SPeter Maydell         td->indirect = FIELD_EX64(value, GITS_BASER, INDIRECT);
11809ae85431SPeter Maydell         td->entry_sz = FIELD_EX64(value, GITS_BASER, ENTRYSIZE) + 1;
1181e5487a41SPeter Maydell         td->base_addr = baser_base_addr(value, page_sz);
1182e5487a41SPeter Maydell         if (!td->indirect) {
118380dcd37fSPeter Maydell             td->num_entries = (num_pages * page_sz) / td->entry_sz;
1184e5487a41SPeter Maydell         } else {
118580dcd37fSPeter Maydell             td->num_entries = (((num_pages * page_sz) /
1186e5487a41SPeter Maydell                                   L1TABLE_ENTRY_SIZE) *
1187e5487a41SPeter Maydell                                  (page_sz / td->entry_sz));
1188e5487a41SPeter Maydell         }
11898b8bb014SPeter Maydell         td->num_entries = MIN(td->num_entries, 1ULL << idbits);
11901b08e436SShashi Mallela     }
11911b08e436SShashi Mallela }
11921b08e436SShashi Mallela 
11931b08e436SShashi Mallela static void extract_cmdq_params(GICv3ITSState *s)
11941b08e436SShashi Mallela {
11951b08e436SShashi Mallela     uint16_t num_pages = 0;
11961b08e436SShashi Mallela     uint64_t value = s->cbaser;
11971b08e436SShashi Mallela 
11981b08e436SShashi Mallela     num_pages = FIELD_EX64(value, GITS_CBASER, SIZE) + 1;
11991b08e436SShashi Mallela 
12001b08e436SShashi Mallela     memset(&s->cq, 0 , sizeof(s->cq));
12011b08e436SShashi Mallela 
1202da4680ceSPeter Maydell     if (FIELD_EX64(value, GITS_CBASER, VALID)) {
120380dcd37fSPeter Maydell         s->cq.num_entries = (num_pages * GITS_PAGE_SIZE_4K) /
12041b08e436SShashi Mallela                              GITS_CMDQ_ENTRY_SIZE;
12051b08e436SShashi Mallela         s->cq.base_addr = FIELD_EX64(value, GITS_CBASER, PHYADDR);
12061b08e436SShashi Mallela         s->cq.base_addr <<= R_GITS_CBASER_PHYADDR_SHIFT;
12071b08e436SShashi Mallela     }
12081b08e436SShashi Mallela }
12091b08e436SShashi Mallela 
12107e062b98SPeter Maydell static MemTxResult gicv3_its_translation_read(void *opaque, hwaddr offset,
12117e062b98SPeter Maydell                                               uint64_t *data, unsigned size,
12127e062b98SPeter Maydell                                               MemTxAttrs attrs)
12137e062b98SPeter Maydell {
12147e062b98SPeter Maydell     /*
12157e062b98SPeter Maydell      * GITS_TRANSLATER is write-only, and all other addresses
12167e062b98SPeter Maydell      * in the interrupt translation space frame are RES0.
12177e062b98SPeter Maydell      */
12187e062b98SPeter Maydell     *data = 0;
12197e062b98SPeter Maydell     return MEMTX_OK;
12207e062b98SPeter Maydell }
12217e062b98SPeter Maydell 
122218f6290aSShashi Mallela static MemTxResult gicv3_its_translation_write(void *opaque, hwaddr offset,
122318f6290aSShashi Mallela                                                uint64_t data, unsigned size,
122418f6290aSShashi Mallela                                                MemTxAttrs attrs)
122518f6290aSShashi Mallela {
1226c694cb4cSShashi Mallela     GICv3ITSState *s = (GICv3ITSState *)opaque;
1227c694cb4cSShashi Mallela     bool result = true;
1228c694cb4cSShashi Mallela 
1229195209d3SPeter Maydell     trace_gicv3_its_translation_write(offset, data, size, attrs.requester_id);
1230195209d3SPeter Maydell 
1231c694cb4cSShashi Mallela     switch (offset) {
1232c694cb4cSShashi Mallela     case GITS_TRANSLATER:
12338d2d6dd9SPeter Maydell         if (s->ctlr & R_GITS_CTLR_ENABLED_MASK) {
1234b6f96009SPeter Maydell             result = do_process_its_cmd(s, attrs.requester_id, data, NONE);
1235c694cb4cSShashi Mallela         }
1236c694cb4cSShashi Mallela         break;
1237c694cb4cSShashi Mallela     default:
1238c694cb4cSShashi Mallela         break;
1239c694cb4cSShashi Mallela     }
1240c694cb4cSShashi Mallela 
1241c694cb4cSShashi Mallela     if (result) {
124218f6290aSShashi Mallela         return MEMTX_OK;
1243c694cb4cSShashi Mallela     } else {
1244c694cb4cSShashi Mallela         return MEMTX_ERROR;
1245c694cb4cSShashi Mallela     }
124618f6290aSShashi Mallela }
124718f6290aSShashi Mallela 
124818f6290aSShashi Mallela static bool its_writel(GICv3ITSState *s, hwaddr offset,
124918f6290aSShashi Mallela                               uint64_t value, MemTxAttrs attrs)
125018f6290aSShashi Mallela {
125118f6290aSShashi Mallela     bool result = true;
12521b08e436SShashi Mallela     int index;
125318f6290aSShashi Mallela 
12541b08e436SShashi Mallela     switch (offset) {
12551b08e436SShashi Mallela     case GITS_CTLR:
12562f459cd1SShashi Mallela         if (value & R_GITS_CTLR_ENABLED_MASK) {
12578d2d6dd9SPeter Maydell             s->ctlr |= R_GITS_CTLR_ENABLED_MASK;
12581b08e436SShashi Mallela             extract_table_params(s);
12591b08e436SShashi Mallela             extract_cmdq_params(s);
12607eca39e0SShashi Mallela             process_cmdq(s);
12612f459cd1SShashi Mallela         } else {
12628d2d6dd9SPeter Maydell             s->ctlr &= ~R_GITS_CTLR_ENABLED_MASK;
12631b08e436SShashi Mallela         }
12641b08e436SShashi Mallela         break;
12651b08e436SShashi Mallela     case GITS_CBASER:
12661b08e436SShashi Mallela         /*
12671b08e436SShashi Mallela          * IMPDEF choice:- GITS_CBASER register becomes RO if ITS is
12681b08e436SShashi Mallela          *                 already enabled
12691b08e436SShashi Mallela          */
12708d2d6dd9SPeter Maydell         if (!(s->ctlr & R_GITS_CTLR_ENABLED_MASK)) {
12711b08e436SShashi Mallela             s->cbaser = deposit64(s->cbaser, 0, 32, value);
12721b08e436SShashi Mallela             s->creadr = 0;
12731b08e436SShashi Mallela         }
12741b08e436SShashi Mallela         break;
12751b08e436SShashi Mallela     case GITS_CBASER + 4:
12761b08e436SShashi Mallela         /*
12771b08e436SShashi Mallela          * IMPDEF choice:- GITS_CBASER register becomes RO if ITS is
12781b08e436SShashi Mallela          *                 already enabled
12791b08e436SShashi Mallela          */
12808d2d6dd9SPeter Maydell         if (!(s->ctlr & R_GITS_CTLR_ENABLED_MASK)) {
12811b08e436SShashi Mallela             s->cbaser = deposit64(s->cbaser, 32, 32, value);
12821b08e436SShashi Mallela             s->creadr = 0;
12831b08e436SShashi Mallela         }
12841b08e436SShashi Mallela         break;
12851b08e436SShashi Mallela     case GITS_CWRITER:
12861b08e436SShashi Mallela         s->cwriter = deposit64(s->cwriter, 0, 32,
12871b08e436SShashi Mallela                                (value & ~R_GITS_CWRITER_RETRY_MASK));
12887eca39e0SShashi Mallela         if (s->cwriter != s->creadr) {
12897eca39e0SShashi Mallela             process_cmdq(s);
12907eca39e0SShashi Mallela         }
12911b08e436SShashi Mallela         break;
12921b08e436SShashi Mallela     case GITS_CWRITER + 4:
12931b08e436SShashi Mallela         s->cwriter = deposit64(s->cwriter, 32, 32, value);
12941b08e436SShashi Mallela         break;
12951b08e436SShashi Mallela     case GITS_CREADR:
12961b08e436SShashi Mallela         if (s->gicv3->gicd_ctlr & GICD_CTLR_DS) {
12971b08e436SShashi Mallela             s->creadr = deposit64(s->creadr, 0, 32,
12981b08e436SShashi Mallela                                   (value & ~R_GITS_CREADR_STALLED_MASK));
12991b08e436SShashi Mallela         } else {
13001b08e436SShashi Mallela             /* RO register, ignore the write */
13011b08e436SShashi Mallela             qemu_log_mask(LOG_GUEST_ERROR,
13021b08e436SShashi Mallela                           "%s: invalid guest write to RO register at offset "
13031b08e436SShashi Mallela                           TARGET_FMT_plx "\n", __func__, offset);
13041b08e436SShashi Mallela         }
13051b08e436SShashi Mallela         break;
13061b08e436SShashi Mallela     case GITS_CREADR + 4:
13071b08e436SShashi Mallela         if (s->gicv3->gicd_ctlr & GICD_CTLR_DS) {
13081b08e436SShashi Mallela             s->creadr = deposit64(s->creadr, 32, 32, value);
13091b08e436SShashi Mallela         } else {
13101b08e436SShashi Mallela             /* RO register, ignore the write */
13111b08e436SShashi Mallela             qemu_log_mask(LOG_GUEST_ERROR,
13121b08e436SShashi Mallela                           "%s: invalid guest write to RO register at offset "
13131b08e436SShashi Mallela                           TARGET_FMT_plx "\n", __func__, offset);
13141b08e436SShashi Mallela         }
13151b08e436SShashi Mallela         break;
13161b08e436SShashi Mallela     case GITS_BASER ... GITS_BASER + 0x3f:
13171b08e436SShashi Mallela         /*
13181b08e436SShashi Mallela          * IMPDEF choice:- GITS_BASERn register becomes RO if ITS is
13191b08e436SShashi Mallela          *                 already enabled
13201b08e436SShashi Mallela          */
13218d2d6dd9SPeter Maydell         if (!(s->ctlr & R_GITS_CTLR_ENABLED_MASK)) {
13221b08e436SShashi Mallela             index = (offset - GITS_BASER) / 8;
13231b08e436SShashi Mallela 
13240ffe88e6SPeter Maydell             if (s->baser[index] == 0) {
13250ffe88e6SPeter Maydell                 /* Unimplemented GITS_BASERn: RAZ/WI */
13260ffe88e6SPeter Maydell                 break;
13270ffe88e6SPeter Maydell             }
13281b08e436SShashi Mallela             if (offset & 7) {
13291b08e436SShashi Mallela                 value <<= 32;
13301b08e436SShashi Mallela                 value &= ~GITS_BASER_RO_MASK;
13311b08e436SShashi Mallela                 s->baser[index] &= GITS_BASER_RO_MASK | MAKE_64BIT_MASK(0, 32);
13321b08e436SShashi Mallela                 s->baser[index] |= value;
13331b08e436SShashi Mallela             } else {
13341b08e436SShashi Mallela                 value &= ~GITS_BASER_RO_MASK;
13351b08e436SShashi Mallela                 s->baser[index] &= GITS_BASER_RO_MASK | MAKE_64BIT_MASK(32, 32);
13361b08e436SShashi Mallela                 s->baser[index] |= value;
13371b08e436SShashi Mallela             }
13381b08e436SShashi Mallela         }
13391b08e436SShashi Mallela         break;
13401b08e436SShashi Mallela     case GITS_IIDR:
13411b08e436SShashi Mallela     case GITS_IDREGS ... GITS_IDREGS + 0x2f:
13421b08e436SShashi Mallela         /* RO registers, ignore the write */
13431b08e436SShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
13441b08e436SShashi Mallela                       "%s: invalid guest write to RO register at offset "
13451b08e436SShashi Mallela                       TARGET_FMT_plx "\n", __func__, offset);
13461b08e436SShashi Mallela         break;
13471b08e436SShashi Mallela     default:
13481b08e436SShashi Mallela         result = false;
13491b08e436SShashi Mallela         break;
13501b08e436SShashi Mallela     }
135118f6290aSShashi Mallela     return result;
135218f6290aSShashi Mallela }
135318f6290aSShashi Mallela 
135418f6290aSShashi Mallela static bool its_readl(GICv3ITSState *s, hwaddr offset,
135518f6290aSShashi Mallela                              uint64_t *data, MemTxAttrs attrs)
135618f6290aSShashi Mallela {
135718f6290aSShashi Mallela     bool result = true;
13581b08e436SShashi Mallela     int index;
135918f6290aSShashi Mallela 
13601b08e436SShashi Mallela     switch (offset) {
13611b08e436SShashi Mallela     case GITS_CTLR:
13621b08e436SShashi Mallela         *data = s->ctlr;
13631b08e436SShashi Mallela         break;
13641b08e436SShashi Mallela     case GITS_IIDR:
13651b08e436SShashi Mallela         *data = gicv3_iidr();
13661b08e436SShashi Mallela         break;
13671b08e436SShashi Mallela     case GITS_IDREGS ... GITS_IDREGS + 0x2f:
13681b08e436SShashi Mallela         /* ID registers */
136950a3a309SPeter Maydell         *data = gicv3_idreg(offset - GITS_IDREGS, GICV3_PIDR0_ITS);
13701b08e436SShashi Mallela         break;
13711b08e436SShashi Mallela     case GITS_TYPER:
13721b08e436SShashi Mallela         *data = extract64(s->typer, 0, 32);
13731b08e436SShashi Mallela         break;
13741b08e436SShashi Mallela     case GITS_TYPER + 4:
13751b08e436SShashi Mallela         *data = extract64(s->typer, 32, 32);
13761b08e436SShashi Mallela         break;
13771b08e436SShashi Mallela     case GITS_CBASER:
13781b08e436SShashi Mallela         *data = extract64(s->cbaser, 0, 32);
13791b08e436SShashi Mallela         break;
13801b08e436SShashi Mallela     case GITS_CBASER + 4:
13811b08e436SShashi Mallela         *data = extract64(s->cbaser, 32, 32);
13821b08e436SShashi Mallela         break;
13831b08e436SShashi Mallela     case GITS_CREADR:
13841b08e436SShashi Mallela         *data = extract64(s->creadr, 0, 32);
13851b08e436SShashi Mallela         break;
13861b08e436SShashi Mallela     case GITS_CREADR + 4:
13871b08e436SShashi Mallela         *data = extract64(s->creadr, 32, 32);
13881b08e436SShashi Mallela         break;
13891b08e436SShashi Mallela     case GITS_CWRITER:
13901b08e436SShashi Mallela         *data = extract64(s->cwriter, 0, 32);
13911b08e436SShashi Mallela         break;
13921b08e436SShashi Mallela     case GITS_CWRITER + 4:
13931b08e436SShashi Mallela         *data = extract64(s->cwriter, 32, 32);
13941b08e436SShashi Mallela         break;
13951b08e436SShashi Mallela     case GITS_BASER ... GITS_BASER + 0x3f:
13961b08e436SShashi Mallela         index = (offset - GITS_BASER) / 8;
13971b08e436SShashi Mallela         if (offset & 7) {
13981b08e436SShashi Mallela             *data = extract64(s->baser[index], 32, 32);
13991b08e436SShashi Mallela         } else {
14001b08e436SShashi Mallela             *data = extract64(s->baser[index], 0, 32);
14011b08e436SShashi Mallela         }
14021b08e436SShashi Mallela         break;
14031b08e436SShashi Mallela     default:
14041b08e436SShashi Mallela         result = false;
14051b08e436SShashi Mallela         break;
14061b08e436SShashi Mallela     }
140718f6290aSShashi Mallela     return result;
140818f6290aSShashi Mallela }
140918f6290aSShashi Mallela 
141018f6290aSShashi Mallela static bool its_writell(GICv3ITSState *s, hwaddr offset,
141118f6290aSShashi Mallela                                uint64_t value, MemTxAttrs attrs)
141218f6290aSShashi Mallela {
141318f6290aSShashi Mallela     bool result = true;
14141b08e436SShashi Mallela     int index;
141518f6290aSShashi Mallela 
14161b08e436SShashi Mallela     switch (offset) {
14171b08e436SShashi Mallela     case GITS_BASER ... GITS_BASER + 0x3f:
14181b08e436SShashi Mallela         /*
14191b08e436SShashi Mallela          * IMPDEF choice:- GITS_BASERn register becomes RO if ITS is
14201b08e436SShashi Mallela          *                 already enabled
14211b08e436SShashi Mallela          */
14228d2d6dd9SPeter Maydell         if (!(s->ctlr & R_GITS_CTLR_ENABLED_MASK)) {
14231b08e436SShashi Mallela             index = (offset - GITS_BASER) / 8;
14240ffe88e6SPeter Maydell             if (s->baser[index] == 0) {
14250ffe88e6SPeter Maydell                 /* Unimplemented GITS_BASERn: RAZ/WI */
14260ffe88e6SPeter Maydell                 break;
14270ffe88e6SPeter Maydell             }
14281b08e436SShashi Mallela             s->baser[index] &= GITS_BASER_RO_MASK;
14291b08e436SShashi Mallela             s->baser[index] |= (value & ~GITS_BASER_RO_MASK);
14301b08e436SShashi Mallela         }
14311b08e436SShashi Mallela         break;
14321b08e436SShashi Mallela     case GITS_CBASER:
14331b08e436SShashi Mallela         /*
14341b08e436SShashi Mallela          * IMPDEF choice:- GITS_CBASER register becomes RO if ITS is
14351b08e436SShashi Mallela          *                 already enabled
14361b08e436SShashi Mallela          */
14378d2d6dd9SPeter Maydell         if (!(s->ctlr & R_GITS_CTLR_ENABLED_MASK)) {
14381b08e436SShashi Mallela             s->cbaser = value;
14391b08e436SShashi Mallela             s->creadr = 0;
14401b08e436SShashi Mallela         }
14411b08e436SShashi Mallela         break;
14421b08e436SShashi Mallela     case GITS_CWRITER:
14431b08e436SShashi Mallela         s->cwriter = value & ~R_GITS_CWRITER_RETRY_MASK;
14447eca39e0SShashi Mallela         if (s->cwriter != s->creadr) {
14457eca39e0SShashi Mallela             process_cmdq(s);
14467eca39e0SShashi Mallela         }
14471b08e436SShashi Mallela         break;
14481b08e436SShashi Mallela     case GITS_CREADR:
14491b08e436SShashi Mallela         if (s->gicv3->gicd_ctlr & GICD_CTLR_DS) {
14501b08e436SShashi Mallela             s->creadr = value & ~R_GITS_CREADR_STALLED_MASK;
14511b08e436SShashi Mallela         } else {
14521b08e436SShashi Mallela             /* RO register, ignore the write */
14531b08e436SShashi Mallela             qemu_log_mask(LOG_GUEST_ERROR,
14541b08e436SShashi Mallela                           "%s: invalid guest write to RO register at offset "
14551b08e436SShashi Mallela                           TARGET_FMT_plx "\n", __func__, offset);
14561b08e436SShashi Mallela         }
14571b08e436SShashi Mallela         break;
14581b08e436SShashi Mallela     case GITS_TYPER:
14591b08e436SShashi Mallela         /* RO registers, ignore the write */
14601b08e436SShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
14611b08e436SShashi Mallela                       "%s: invalid guest write to RO register at offset "
14621b08e436SShashi Mallela                       TARGET_FMT_plx "\n", __func__, offset);
14631b08e436SShashi Mallela         break;
14641b08e436SShashi Mallela     default:
14651b08e436SShashi Mallela         result = false;
14661b08e436SShashi Mallela         break;
14671b08e436SShashi Mallela     }
146818f6290aSShashi Mallela     return result;
146918f6290aSShashi Mallela }
147018f6290aSShashi Mallela 
147118f6290aSShashi Mallela static bool its_readll(GICv3ITSState *s, hwaddr offset,
147218f6290aSShashi Mallela                               uint64_t *data, MemTxAttrs attrs)
147318f6290aSShashi Mallela {
147418f6290aSShashi Mallela     bool result = true;
14751b08e436SShashi Mallela     int index;
147618f6290aSShashi Mallela 
14771b08e436SShashi Mallela     switch (offset) {
14781b08e436SShashi Mallela     case GITS_TYPER:
14791b08e436SShashi Mallela         *data = s->typer;
14801b08e436SShashi Mallela         break;
14811b08e436SShashi Mallela     case GITS_BASER ... GITS_BASER + 0x3f:
14821b08e436SShashi Mallela         index = (offset - GITS_BASER) / 8;
14831b08e436SShashi Mallela         *data = s->baser[index];
14841b08e436SShashi Mallela         break;
14851b08e436SShashi Mallela     case GITS_CBASER:
14861b08e436SShashi Mallela         *data = s->cbaser;
14871b08e436SShashi Mallela         break;
14881b08e436SShashi Mallela     case GITS_CREADR:
14891b08e436SShashi Mallela         *data = s->creadr;
14901b08e436SShashi Mallela         break;
14911b08e436SShashi Mallela     case GITS_CWRITER:
14921b08e436SShashi Mallela         *data = s->cwriter;
14931b08e436SShashi Mallela         break;
14941b08e436SShashi Mallela     default:
14951b08e436SShashi Mallela         result = false;
14961b08e436SShashi Mallela         break;
14971b08e436SShashi Mallela     }
149818f6290aSShashi Mallela     return result;
149918f6290aSShashi Mallela }
150018f6290aSShashi Mallela 
150118f6290aSShashi Mallela static MemTxResult gicv3_its_read(void *opaque, hwaddr offset, uint64_t *data,
150218f6290aSShashi Mallela                                   unsigned size, MemTxAttrs attrs)
150318f6290aSShashi Mallela {
150418f6290aSShashi Mallela     GICv3ITSState *s = (GICv3ITSState *)opaque;
150518f6290aSShashi Mallela     bool result;
150618f6290aSShashi Mallela 
150718f6290aSShashi Mallela     switch (size) {
150818f6290aSShashi Mallela     case 4:
150918f6290aSShashi Mallela         result = its_readl(s, offset, data, attrs);
151018f6290aSShashi Mallela         break;
151118f6290aSShashi Mallela     case 8:
151218f6290aSShashi Mallela         result = its_readll(s, offset, data, attrs);
151318f6290aSShashi Mallela         break;
151418f6290aSShashi Mallela     default:
151518f6290aSShashi Mallela         result = false;
151618f6290aSShashi Mallela         break;
151718f6290aSShashi Mallela     }
151818f6290aSShashi Mallela 
151918f6290aSShashi Mallela     if (!result) {
152018f6290aSShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
152118f6290aSShashi Mallela                       "%s: invalid guest read at offset " TARGET_FMT_plx
152218f6290aSShashi Mallela                       " size %u\n", __func__, offset, size);
1523195209d3SPeter Maydell         trace_gicv3_its_badread(offset, size);
152418f6290aSShashi Mallela         /*
152518f6290aSShashi Mallela          * The spec requires that reserved registers are RAZ/WI;
152618f6290aSShashi Mallela          * so use false returns from leaf functions as a way to
152718f6290aSShashi Mallela          * trigger the guest-error logging but don't return it to
152818f6290aSShashi Mallela          * the caller, or we'll cause a spurious guest data abort.
152918f6290aSShashi Mallela          */
153018f6290aSShashi Mallela         *data = 0;
1531195209d3SPeter Maydell     } else {
1532195209d3SPeter Maydell         trace_gicv3_its_read(offset, *data, size);
153318f6290aSShashi Mallela     }
153418f6290aSShashi Mallela     return MEMTX_OK;
153518f6290aSShashi Mallela }
153618f6290aSShashi Mallela 
153718f6290aSShashi Mallela static MemTxResult gicv3_its_write(void *opaque, hwaddr offset, uint64_t data,
153818f6290aSShashi Mallela                                    unsigned size, MemTxAttrs attrs)
153918f6290aSShashi Mallela {
154018f6290aSShashi Mallela     GICv3ITSState *s = (GICv3ITSState *)opaque;
154118f6290aSShashi Mallela     bool result;
154218f6290aSShashi Mallela 
154318f6290aSShashi Mallela     switch (size) {
154418f6290aSShashi Mallela     case 4:
154518f6290aSShashi Mallela         result = its_writel(s, offset, data, attrs);
154618f6290aSShashi Mallela         break;
154718f6290aSShashi Mallela     case 8:
154818f6290aSShashi Mallela         result = its_writell(s, offset, data, attrs);
154918f6290aSShashi Mallela         break;
155018f6290aSShashi Mallela     default:
155118f6290aSShashi Mallela         result = false;
155218f6290aSShashi Mallela         break;
155318f6290aSShashi Mallela     }
155418f6290aSShashi Mallela 
155518f6290aSShashi Mallela     if (!result) {
155618f6290aSShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
155718f6290aSShashi Mallela                       "%s: invalid guest write at offset " TARGET_FMT_plx
155818f6290aSShashi Mallela                       " size %u\n", __func__, offset, size);
1559195209d3SPeter Maydell         trace_gicv3_its_badwrite(offset, data, size);
156018f6290aSShashi Mallela         /*
156118f6290aSShashi Mallela          * The spec requires that reserved registers are RAZ/WI;
156218f6290aSShashi Mallela          * so use false returns from leaf functions as a way to
156318f6290aSShashi Mallela          * trigger the guest-error logging but don't return it to
156418f6290aSShashi Mallela          * the caller, or we'll cause a spurious guest data abort.
156518f6290aSShashi Mallela          */
1566195209d3SPeter Maydell     } else {
1567195209d3SPeter Maydell         trace_gicv3_its_write(offset, data, size);
156818f6290aSShashi Mallela     }
156918f6290aSShashi Mallela     return MEMTX_OK;
157018f6290aSShashi Mallela }
157118f6290aSShashi Mallela 
157218f6290aSShashi Mallela static const MemoryRegionOps gicv3_its_control_ops = {
157318f6290aSShashi Mallela     .read_with_attrs = gicv3_its_read,
157418f6290aSShashi Mallela     .write_with_attrs = gicv3_its_write,
157518f6290aSShashi Mallela     .valid.min_access_size = 4,
157618f6290aSShashi Mallela     .valid.max_access_size = 8,
157718f6290aSShashi Mallela     .impl.min_access_size = 4,
157818f6290aSShashi Mallela     .impl.max_access_size = 8,
157918f6290aSShashi Mallela     .endianness = DEVICE_NATIVE_ENDIAN,
158018f6290aSShashi Mallela };
158118f6290aSShashi Mallela 
158218f6290aSShashi Mallela static const MemoryRegionOps gicv3_its_translation_ops = {
15837e062b98SPeter Maydell     .read_with_attrs = gicv3_its_translation_read,
158418f6290aSShashi Mallela     .write_with_attrs = gicv3_its_translation_write,
158518f6290aSShashi Mallela     .valid.min_access_size = 2,
158618f6290aSShashi Mallela     .valid.max_access_size = 4,
158718f6290aSShashi Mallela     .impl.min_access_size = 2,
158818f6290aSShashi Mallela     .impl.max_access_size = 4,
158918f6290aSShashi Mallela     .endianness = DEVICE_NATIVE_ENDIAN,
159018f6290aSShashi Mallela };
159118f6290aSShashi Mallela 
159218f6290aSShashi Mallela static void gicv3_arm_its_realize(DeviceState *dev, Error **errp)
159318f6290aSShashi Mallela {
159418f6290aSShashi Mallela     GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev);
159518f6290aSShashi Mallela     int i;
159618f6290aSShashi Mallela 
159718f6290aSShashi Mallela     for (i = 0; i < s->gicv3->num_cpu; i++) {
159818f6290aSShashi Mallela         if (!(s->gicv3->cpu[i].gicr_typer & GICR_TYPER_PLPIS)) {
159918f6290aSShashi Mallela             error_setg(errp, "Physical LPI not supported by CPU %d", i);
160018f6290aSShashi Mallela             return;
160118f6290aSShashi Mallela         }
160218f6290aSShashi Mallela     }
160318f6290aSShashi Mallela 
160418f6290aSShashi Mallela     gicv3_its_init_mmio(s, &gicv3_its_control_ops, &gicv3_its_translation_ops);
160518f6290aSShashi Mallela 
160618f6290aSShashi Mallela     /* set the ITS default features supported */
1607764d6ba1SPeter Maydell     s->typer = FIELD_DP64(s->typer, GITS_TYPER, PHYSICAL, 1);
160818f6290aSShashi Mallela     s->typer = FIELD_DP64(s->typer, GITS_TYPER, ITT_ENTRY_SIZE,
160918f6290aSShashi Mallela                           ITS_ITT_ENTRY_SIZE - 1);
161018f6290aSShashi Mallela     s->typer = FIELD_DP64(s->typer, GITS_TYPER, IDBITS, ITS_IDBITS);
161118f6290aSShashi Mallela     s->typer = FIELD_DP64(s->typer, GITS_TYPER, DEVBITS, ITS_DEVBITS);
161218f6290aSShashi Mallela     s->typer = FIELD_DP64(s->typer, GITS_TYPER, CIL, 1);
161318f6290aSShashi Mallela     s->typer = FIELD_DP64(s->typer, GITS_TYPER, CIDBITS, ITS_CIDBITS);
161418f6290aSShashi Mallela }
161518f6290aSShashi Mallela 
161618f6290aSShashi Mallela static void gicv3_its_reset(DeviceState *dev)
161718f6290aSShashi Mallela {
161818f6290aSShashi Mallela     GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev);
161918f6290aSShashi Mallela     GICv3ITSClass *c = ARM_GICV3_ITS_GET_CLASS(s);
162018f6290aSShashi Mallela 
162118f6290aSShashi Mallela     c->parent_reset(dev);
162218f6290aSShashi Mallela 
162318f6290aSShashi Mallela     /* Quiescent bit reset to 1 */
162418f6290aSShashi Mallela     s->ctlr = FIELD_DP32(s->ctlr, GITS_CTLR, QUIESCENT, 1);
162518f6290aSShashi Mallela 
162618f6290aSShashi Mallela     /*
162718f6290aSShashi Mallela      * setting GITS_BASER0.Type = 0b001 (Device)
162818f6290aSShashi Mallela      *         GITS_BASER1.Type = 0b100 (Collection Table)
162950d84584SPeter Maydell      *         GITS_BASER2.Type = 0b010 (vPE) for GICv4 and later
163018f6290aSShashi Mallela      *         GITS_BASER<n>.Type,where n = 3 to 7 are 0b00 (Unimplemented)
163118f6290aSShashi Mallela      *         GITS_BASER<0,1>.Page_Size = 64KB
163218f6290aSShashi Mallela      * and default translation table entry size to 16 bytes
163318f6290aSShashi Mallela      */
163418f6290aSShashi Mallela     s->baser[0] = FIELD_DP64(s->baser[0], GITS_BASER, TYPE,
163518f6290aSShashi Mallela                              GITS_BASER_TYPE_DEVICE);
163618f6290aSShashi Mallela     s->baser[0] = FIELD_DP64(s->baser[0], GITS_BASER, PAGESIZE,
163718f6290aSShashi Mallela                              GITS_BASER_PAGESIZE_64K);
163818f6290aSShashi Mallela     s->baser[0] = FIELD_DP64(s->baser[0], GITS_BASER, ENTRYSIZE,
163918f6290aSShashi Mallela                              GITS_DTE_SIZE - 1);
164018f6290aSShashi Mallela 
164118f6290aSShashi Mallela     s->baser[1] = FIELD_DP64(s->baser[1], GITS_BASER, TYPE,
164218f6290aSShashi Mallela                              GITS_BASER_TYPE_COLLECTION);
164318f6290aSShashi Mallela     s->baser[1] = FIELD_DP64(s->baser[1], GITS_BASER, PAGESIZE,
164418f6290aSShashi Mallela                              GITS_BASER_PAGESIZE_64K);
164518f6290aSShashi Mallela     s->baser[1] = FIELD_DP64(s->baser[1], GITS_BASER, ENTRYSIZE,
164618f6290aSShashi Mallela                              GITS_CTE_SIZE - 1);
164750d84584SPeter Maydell 
164850d84584SPeter Maydell     if (its_feature_virtual(s)) {
164950d84584SPeter Maydell         s->baser[2] = FIELD_DP64(s->baser[2], GITS_BASER, TYPE,
165050d84584SPeter Maydell                                  GITS_BASER_TYPE_VPE);
165150d84584SPeter Maydell         s->baser[2] = FIELD_DP64(s->baser[2], GITS_BASER, PAGESIZE,
165250d84584SPeter Maydell                                  GITS_BASER_PAGESIZE_64K);
165350d84584SPeter Maydell         s->baser[2] = FIELD_DP64(s->baser[2], GITS_BASER, ENTRYSIZE,
165450d84584SPeter Maydell                                  GITS_VPE_SIZE - 1);
165550d84584SPeter Maydell     }
165618f6290aSShashi Mallela }
165718f6290aSShashi Mallela 
16581b08e436SShashi Mallela static void gicv3_its_post_load(GICv3ITSState *s)
16591b08e436SShashi Mallela {
16608d2d6dd9SPeter Maydell     if (s->ctlr & R_GITS_CTLR_ENABLED_MASK) {
16611b08e436SShashi Mallela         extract_table_params(s);
16621b08e436SShashi Mallela         extract_cmdq_params(s);
16631b08e436SShashi Mallela     }
16641b08e436SShashi Mallela }
16651b08e436SShashi Mallela 
166618f6290aSShashi Mallela static Property gicv3_its_props[] = {
166718f6290aSShashi Mallela     DEFINE_PROP_LINK("parent-gicv3", GICv3ITSState, gicv3, "arm-gicv3",
166818f6290aSShashi Mallela                      GICv3State *),
166918f6290aSShashi Mallela     DEFINE_PROP_END_OF_LIST(),
167018f6290aSShashi Mallela };
167118f6290aSShashi Mallela 
167218f6290aSShashi Mallela static void gicv3_its_class_init(ObjectClass *klass, void *data)
167318f6290aSShashi Mallela {
167418f6290aSShashi Mallela     DeviceClass *dc = DEVICE_CLASS(klass);
167518f6290aSShashi Mallela     GICv3ITSClass *ic = ARM_GICV3_ITS_CLASS(klass);
16761b08e436SShashi Mallela     GICv3ITSCommonClass *icc = ARM_GICV3_ITS_COMMON_CLASS(klass);
167718f6290aSShashi Mallela 
167818f6290aSShashi Mallela     dc->realize = gicv3_arm_its_realize;
167918f6290aSShashi Mallela     device_class_set_props(dc, gicv3_its_props);
168018f6290aSShashi Mallela     device_class_set_parent_reset(dc, gicv3_its_reset, &ic->parent_reset);
16811b08e436SShashi Mallela     icc->post_load = gicv3_its_post_load;
168218f6290aSShashi Mallela }
168318f6290aSShashi Mallela 
168418f6290aSShashi Mallela static const TypeInfo gicv3_its_info = {
168518f6290aSShashi Mallela     .name = TYPE_ARM_GICV3_ITS,
168618f6290aSShashi Mallela     .parent = TYPE_ARM_GICV3_ITS_COMMON,
168718f6290aSShashi Mallela     .instance_size = sizeof(GICv3ITSState),
168818f6290aSShashi Mallela     .class_init = gicv3_its_class_init,
168918f6290aSShashi Mallela     .class_size = sizeof(GICv3ITSClass),
169018f6290aSShashi Mallela };
169118f6290aSShashi Mallela 
169218f6290aSShashi Mallela static void gicv3_its_register_types(void)
169318f6290aSShashi Mallela {
169418f6290aSShashi Mallela     type_register_static(&gicv3_its_info);
169518f6290aSShashi Mallela }
169618f6290aSShashi Mallela 
169718f6290aSShashi Mallela type_init(gicv3_its_register_types)
1698