xref: /qemu/hw/intc/arm_gicv3_its.c (revision 2d692e2b314e212664e9ce72787ce0ecea615c61)
118f6290aSShashi Mallela /*
218f6290aSShashi Mallela  * ITS emulation for a GICv3-based system
318f6290aSShashi Mallela  *
418f6290aSShashi Mallela  * Copyright Linaro.org 2021
518f6290aSShashi Mallela  *
618f6290aSShashi Mallela  * Authors:
718f6290aSShashi Mallela  *  Shashi Mallela <shashi.mallela@linaro.org>
818f6290aSShashi Mallela  *
918f6290aSShashi Mallela  * This work is licensed under the terms of the GNU GPL, version 2 or (at your
1018f6290aSShashi Mallela  * option) any later version.  See the COPYING file in the top-level directory.
1118f6290aSShashi Mallela  *
1218f6290aSShashi Mallela  */
1318f6290aSShashi Mallela 
1418f6290aSShashi Mallela #include "qemu/osdep.h"
1518f6290aSShashi Mallela #include "qemu/log.h"
16195209d3SPeter Maydell #include "trace.h"
1718f6290aSShashi Mallela #include "hw/qdev-properties.h"
1818f6290aSShashi Mallela #include "hw/intc/arm_gicv3_its_common.h"
1918f6290aSShashi Mallela #include "gicv3_internal.h"
2018f6290aSShashi Mallela #include "qom/object.h"
2118f6290aSShashi Mallela #include "qapi/error.h"
2218f6290aSShashi Mallela 
2318f6290aSShashi Mallela typedef struct GICv3ITSClass GICv3ITSClass;
2418f6290aSShashi Mallela /* This is reusing the GICv3ITSState typedef from ARM_GICV3_ITS_COMMON */
2518f6290aSShashi Mallela DECLARE_OBJ_CHECKERS(GICv3ITSState, GICv3ITSClass,
2618f6290aSShashi Mallela                      ARM_GICV3_ITS, TYPE_ARM_GICV3_ITS)
2718f6290aSShashi Mallela 
2818f6290aSShashi Mallela struct GICv3ITSClass {
2918f6290aSShashi Mallela     GICv3ITSCommonClass parent_class;
3018f6290aSShashi Mallela     void (*parent_reset)(DeviceState *dev);
3118f6290aSShashi Mallela };
3218f6290aSShashi Mallela 
33c694cb4cSShashi Mallela /*
34c694cb4cSShashi Mallela  * This is an internal enum used to distinguish between LPI triggered
35c694cb4cSShashi Mallela  * via command queue and LPI triggered via gits_translater write.
36c694cb4cSShashi Mallela  */
37c694cb4cSShashi Mallela typedef enum ItsCmdType {
38c694cb4cSShashi Mallela     NONE = 0, /* internal indication for GITS_TRANSLATER write */
39c694cb4cSShashi Mallela     CLEAR = 1,
40c694cb4cSShashi Mallela     DISCARD = 2,
41c694cb4cSShashi Mallela     INTERRUPT = 3,
42c694cb4cSShashi Mallela } ItsCmdType;
43c694cb4cSShashi Mallela 
444acf93e1SPeter Maydell typedef struct DTEntry {
454acf93e1SPeter Maydell     bool valid;
464acf93e1SPeter Maydell     unsigned size;
474acf93e1SPeter Maydell     uint64_t ittaddr;
484acf93e1SPeter Maydell } DTEntry;
494acf93e1SPeter Maydell 
50d37cf49bSPeter Maydell typedef struct CTEntry {
51d37cf49bSPeter Maydell     bool valid;
52d37cf49bSPeter Maydell     uint32_t rdbase;
53d37cf49bSPeter Maydell } CTEntry;
54d37cf49bSPeter Maydell 
55244194feSPeter Maydell typedef struct ITEntry {
56244194feSPeter Maydell     bool valid;
57244194feSPeter Maydell     int inttype;
58244194feSPeter Maydell     uint32_t intid;
59244194feSPeter Maydell     uint32_t doorbell;
60244194feSPeter Maydell     uint32_t icid;
61244194feSPeter Maydell     uint32_t vpeid;
62244194feSPeter Maydell } ITEntry;
63244194feSPeter Maydell 
640cdf7a5dSPeter Maydell typedef struct VTEntry {
650cdf7a5dSPeter Maydell     bool valid;
660cdf7a5dSPeter Maydell     unsigned vptsize;
670cdf7a5dSPeter Maydell     uint32_t rdbase;
680cdf7a5dSPeter Maydell     uint64_t vptaddr;
690cdf7a5dSPeter Maydell } VTEntry;
70244194feSPeter Maydell 
71ef011555SPeter Maydell /*
72ef011555SPeter Maydell  * The ITS spec permits a range of CONSTRAINED UNPREDICTABLE options
73ef011555SPeter Maydell  * if a command parameter is not correct. These include both "stall
74ef011555SPeter Maydell  * processing of the command queue" and "ignore this command, and
75ef011555SPeter Maydell  * keep processing the queue". In our implementation we choose that
76ef011555SPeter Maydell  * memory transaction errors reading the command packet provoke a
77ef011555SPeter Maydell  * stall, but errors in parameters cause us to ignore the command
78ef011555SPeter Maydell  * and continue processing.
79ef011555SPeter Maydell  * The process_* functions which handle individual ITS commands all
80ef011555SPeter Maydell  * return an ItsCmdResult which tells process_cmdq() whether it should
8193f4fdcdSPeter Maydell  * stall, keep going because of an error, or keep going because the
8293f4fdcdSPeter Maydell  * command was a success.
83ef011555SPeter Maydell  */
84ef011555SPeter Maydell typedef enum ItsCmdResult {
85ef011555SPeter Maydell     CMD_STALL = 0,
86ef011555SPeter Maydell     CMD_CONTINUE = 1,
8793f4fdcdSPeter Maydell     CMD_CONTINUE_OK = 2,
88ef011555SPeter Maydell } ItsCmdResult;
89ef011555SPeter Maydell 
9050d84584SPeter Maydell /* True if the ITS supports the GICv4 virtual LPI feature */
9150d84584SPeter Maydell static bool its_feature_virtual(GICv3ITSState *s)
9250d84584SPeter Maydell {
9350d84584SPeter Maydell     return s->typer & R_GITS_TYPER_VIRTUAL_MASK;
9450d84584SPeter Maydell }
9550d84584SPeter Maydell 
96c3c9a090SPeter Maydell static inline bool intid_in_lpi_range(uint32_t id)
97c3c9a090SPeter Maydell {
98c3c9a090SPeter Maydell     return id >= GICV3_LPI_INTID_START &&
99c3c9a090SPeter Maydell         id < (1 << (GICD_TYPER_IDBITS + 1));
100c3c9a090SPeter Maydell }
101c3c9a090SPeter Maydell 
1029de53de6SPeter Maydell static inline bool valid_doorbell(uint32_t id)
1039de53de6SPeter Maydell {
1049de53de6SPeter Maydell     /* Doorbell fields may be an LPI, or 1023 to mean "no doorbell" */
1059de53de6SPeter Maydell     return id == INTID_SPURIOUS || intid_in_lpi_range(id);
1069de53de6SPeter Maydell }
1079de53de6SPeter Maydell 
1081b08e436SShashi Mallela static uint64_t baser_base_addr(uint64_t value, uint32_t page_sz)
1091b08e436SShashi Mallela {
1101b08e436SShashi Mallela     uint64_t result = 0;
1111b08e436SShashi Mallela 
1121b08e436SShashi Mallela     switch (page_sz) {
1131b08e436SShashi Mallela     case GITS_PAGE_SIZE_4K:
1141b08e436SShashi Mallela     case GITS_PAGE_SIZE_16K:
1151b08e436SShashi Mallela         result = FIELD_EX64(value, GITS_BASER, PHYADDR) << 12;
1161b08e436SShashi Mallela         break;
1171b08e436SShashi Mallela 
1181b08e436SShashi Mallela     case GITS_PAGE_SIZE_64K:
1191b08e436SShashi Mallela         result = FIELD_EX64(value, GITS_BASER, PHYADDRL_64K) << 16;
1201b08e436SShashi Mallela         result |= FIELD_EX64(value, GITS_BASER, PHYADDRH_64K) << 48;
1211b08e436SShashi Mallela         break;
1221b08e436SShashi Mallela 
1231b08e436SShashi Mallela     default:
1241b08e436SShashi Mallela         break;
1251b08e436SShashi Mallela     }
1261b08e436SShashi Mallela     return result;
1271b08e436SShashi Mallela }
1281b08e436SShashi Mallela 
129d050f80fSPeter Maydell static uint64_t table_entry_addr(GICv3ITSState *s, TableDesc *td,
130d050f80fSPeter Maydell                                  uint32_t idx, MemTxResult *res)
131d050f80fSPeter Maydell {
132d050f80fSPeter Maydell     /*
133d050f80fSPeter Maydell      * Given a TableDesc describing one of the ITS in-guest-memory
134d050f80fSPeter Maydell      * tables and an index into it, return the guest address
135d050f80fSPeter Maydell      * corresponding to that table entry.
136d050f80fSPeter Maydell      * If there was a memory error reading the L1 table of an
137d050f80fSPeter Maydell      * indirect table, *res is set accordingly, and we return -1.
138d050f80fSPeter Maydell      * If the L1 table entry is marked not valid, we return -1 with
139d050f80fSPeter Maydell      * *res set to MEMTX_OK.
140d050f80fSPeter Maydell      *
141d050f80fSPeter Maydell      * The specification defines the format of level 1 entries of a
142d050f80fSPeter Maydell      * 2-level table, but the format of level 2 entries and the format
143d050f80fSPeter Maydell      * of flat-mapped tables is IMPDEF.
144d050f80fSPeter Maydell      */
145d050f80fSPeter Maydell     AddressSpace *as = &s->gicv3->dma_as;
146d050f80fSPeter Maydell     uint32_t l2idx;
147d050f80fSPeter Maydell     uint64_t l2;
148d050f80fSPeter Maydell     uint32_t num_l2_entries;
149d050f80fSPeter Maydell 
150d050f80fSPeter Maydell     *res = MEMTX_OK;
151d050f80fSPeter Maydell 
152d050f80fSPeter Maydell     if (!td->indirect) {
153d050f80fSPeter Maydell         /* Single level table */
154d050f80fSPeter Maydell         return td->base_addr + idx * td->entry_sz;
155d050f80fSPeter Maydell     }
156d050f80fSPeter Maydell 
157d050f80fSPeter Maydell     /* Two level table */
158d050f80fSPeter Maydell     l2idx = idx / (td->page_sz / L1TABLE_ENTRY_SIZE);
159d050f80fSPeter Maydell 
160d050f80fSPeter Maydell     l2 = address_space_ldq_le(as,
161d050f80fSPeter Maydell                               td->base_addr + (l2idx * L1TABLE_ENTRY_SIZE),
162d050f80fSPeter Maydell                               MEMTXATTRS_UNSPECIFIED, res);
163d050f80fSPeter Maydell     if (*res != MEMTX_OK) {
164d050f80fSPeter Maydell         return -1;
165d050f80fSPeter Maydell     }
166d050f80fSPeter Maydell     if (!(l2 & L2_TABLE_VALID_MASK)) {
167d050f80fSPeter Maydell         return -1;
168d050f80fSPeter Maydell     }
169d050f80fSPeter Maydell 
170d050f80fSPeter Maydell     num_l2_entries = td->page_sz / td->entry_sz;
171d050f80fSPeter Maydell     return (l2 & ((1ULL << 51) - 1)) + (idx % num_l2_entries) * td->entry_sz;
172d050f80fSPeter Maydell }
173d050f80fSPeter Maydell 
174d37cf49bSPeter Maydell /*
175d37cf49bSPeter Maydell  * Read the Collection Table entry at index @icid. On success (including
176d37cf49bSPeter Maydell  * successfully determining that there is no valid CTE for this index),
177d37cf49bSPeter Maydell  * we return MEMTX_OK and populate the CTEntry struct @cte accordingly.
178d37cf49bSPeter Maydell  * If there is an error reading memory then we return the error code.
179d37cf49bSPeter Maydell  */
180d37cf49bSPeter Maydell static MemTxResult get_cte(GICv3ITSState *s, uint16_t icid, CTEntry *cte)
181c694cb4cSShashi Mallela {
182c694cb4cSShashi Mallela     AddressSpace *as = &s->gicv3->dma_as;
183d37cf49bSPeter Maydell     MemTxResult res = MEMTX_OK;
184d37cf49bSPeter Maydell     uint64_t entry_addr = table_entry_addr(s, &s->ct, icid, &res);
185d37cf49bSPeter Maydell     uint64_t cteval;
186c694cb4cSShashi Mallela 
187d050f80fSPeter Maydell     if (entry_addr == -1) {
188d37cf49bSPeter Maydell         /* No L2 table entry, i.e. no valid CTE, or a memory error */
189d37cf49bSPeter Maydell         cte->valid = false;
190930f40e9SPeter Maydell         goto out;
191c694cb4cSShashi Mallela     }
192c694cb4cSShashi Mallela 
193d37cf49bSPeter Maydell     cteval = address_space_ldq_le(as, entry_addr, MEMTXATTRS_UNSPECIFIED, &res);
194d37cf49bSPeter Maydell     if (res != MEMTX_OK) {
195930f40e9SPeter Maydell         goto out;
196d37cf49bSPeter Maydell     }
197d37cf49bSPeter Maydell     cte->valid = FIELD_EX64(cteval, CTE, VALID);
198d37cf49bSPeter Maydell     cte->rdbase = FIELD_EX64(cteval, CTE, RDBASE);
199930f40e9SPeter Maydell out:
200930f40e9SPeter Maydell     if (res != MEMTX_OK) {
201930f40e9SPeter Maydell         trace_gicv3_its_cte_read_fault(icid);
202930f40e9SPeter Maydell     } else {
203930f40e9SPeter Maydell         trace_gicv3_its_cte_read(icid, cte->valid, cte->rdbase);
204930f40e9SPeter Maydell     }
205930f40e9SPeter Maydell     return res;
206c694cb4cSShashi Mallela }
207c694cb4cSShashi Mallela 
2087eb54267SPeter Maydell /*
2097eb54267SPeter Maydell  * Update the Interrupt Table entry at index @evinted in the table specified
2107eb54267SPeter Maydell  * by the dte @dte. Returns true on success, false if there was a memory
2117eb54267SPeter Maydell  * access error.
2127eb54267SPeter Maydell  */
2134acf93e1SPeter Maydell static bool update_ite(GICv3ITSState *s, uint32_t eventid, const DTEntry *dte,
2147eb54267SPeter Maydell                        const ITEntry *ite)
215c694cb4cSShashi Mallela {
216c694cb4cSShashi Mallela     AddressSpace *as = &s->gicv3->dma_as;
217c694cb4cSShashi Mallela     MemTxResult res = MEMTX_OK;
218a1ce993dSPeter Maydell     hwaddr iteaddr = dte->ittaddr + eventid * ITS_ITT_ENTRY_SIZE;
2197eb54267SPeter Maydell     uint64_t itel = 0;
2207eb54267SPeter Maydell     uint32_t iteh = 0;
221c694cb4cSShashi Mallela 
222930f40e9SPeter Maydell     trace_gicv3_its_ite_write(dte->ittaddr, eventid, ite->valid,
223930f40e9SPeter Maydell                               ite->inttype, ite->intid, ite->icid,
224930f40e9SPeter Maydell                               ite->vpeid, ite->doorbell);
225930f40e9SPeter Maydell 
2267eb54267SPeter Maydell     if (ite->valid) {
2277eb54267SPeter Maydell         itel = FIELD_DP64(itel, ITE_L, VALID, 1);
2287eb54267SPeter Maydell         itel = FIELD_DP64(itel, ITE_L, INTTYPE, ite->inttype);
2297eb54267SPeter Maydell         itel = FIELD_DP64(itel, ITE_L, INTID, ite->intid);
2307eb54267SPeter Maydell         itel = FIELD_DP64(itel, ITE_L, ICID, ite->icid);
2317eb54267SPeter Maydell         itel = FIELD_DP64(itel, ITE_L, VPEID, ite->vpeid);
2327eb54267SPeter Maydell         iteh = FIELD_DP32(iteh, ITE_H, DOORBELL, ite->doorbell);
233c694cb4cSShashi Mallela     }
2347eb54267SPeter Maydell 
2357eb54267SPeter Maydell     address_space_stq_le(as, iteaddr, itel, MEMTXATTRS_UNSPECIFIED, &res);
236c694cb4cSShashi Mallela     if (res != MEMTX_OK) {
237c694cb4cSShashi Mallela         return false;
238c694cb4cSShashi Mallela     }
2397eb54267SPeter Maydell     address_space_stl_le(as, iteaddr + 8, iteh, MEMTXATTRS_UNSPECIFIED, &res);
2407eb54267SPeter Maydell     return res == MEMTX_OK;
241c694cb4cSShashi Mallela }
242c694cb4cSShashi Mallela 
243244194feSPeter Maydell /*
244244194feSPeter Maydell  * Read the Interrupt Table entry at index @eventid from the table specified
245244194feSPeter Maydell  * by the DTE @dte. On success, we return MEMTX_OK and populate the ITEntry
246244194feSPeter Maydell  * struct @ite accordingly. If there is an error reading memory then we return
247244194feSPeter Maydell  * the error code.
248244194feSPeter Maydell  */
249244194feSPeter Maydell static MemTxResult get_ite(GICv3ITSState *s, uint32_t eventid,
250244194feSPeter Maydell                            const DTEntry *dte, ITEntry *ite)
251c694cb4cSShashi Mallela {
252c694cb4cSShashi Mallela     AddressSpace *as = &s->gicv3->dma_as;
253244194feSPeter Maydell     MemTxResult res = MEMTX_OK;
254244194feSPeter Maydell     uint64_t itel;
255244194feSPeter Maydell     uint32_t iteh;
256a1ce993dSPeter Maydell     hwaddr iteaddr = dte->ittaddr + eventid * ITS_ITT_ENTRY_SIZE;
257c694cb4cSShashi Mallela 
258244194feSPeter Maydell     itel = address_space_ldq_le(as, iteaddr, MEMTXATTRS_UNSPECIFIED, &res);
259244194feSPeter Maydell     if (res != MEMTX_OK) {
260930f40e9SPeter Maydell         trace_gicv3_its_ite_read_fault(dte->ittaddr, eventid);
261244194feSPeter Maydell         return res;
2622954b93fSPeter Maydell     }
263c694cb4cSShashi Mallela 
264244194feSPeter Maydell     iteh = address_space_ldl_le(as, iteaddr + 8, MEMTXATTRS_UNSPECIFIED, &res);
265244194feSPeter Maydell     if (res != MEMTX_OK) {
266930f40e9SPeter Maydell         trace_gicv3_its_ite_read_fault(dte->ittaddr, eventid);
267244194feSPeter Maydell         return res;
2682954b93fSPeter Maydell     }
269c694cb4cSShashi Mallela 
270244194feSPeter Maydell     ite->valid = FIELD_EX64(itel, ITE_L, VALID);
271244194feSPeter Maydell     ite->inttype = FIELD_EX64(itel, ITE_L, INTTYPE);
272244194feSPeter Maydell     ite->intid = FIELD_EX64(itel, ITE_L, INTID);
273244194feSPeter Maydell     ite->icid = FIELD_EX64(itel, ITE_L, ICID);
274244194feSPeter Maydell     ite->vpeid = FIELD_EX64(itel, ITE_L, VPEID);
275244194feSPeter Maydell     ite->doorbell = FIELD_EX64(iteh, ITE_H, DOORBELL);
276930f40e9SPeter Maydell     trace_gicv3_its_ite_read(dte->ittaddr, eventid, ite->valid,
277930f40e9SPeter Maydell                              ite->inttype, ite->intid, ite->icid,
278930f40e9SPeter Maydell                              ite->vpeid, ite->doorbell);
279244194feSPeter Maydell     return MEMTX_OK;
280c694cb4cSShashi Mallela }
281c694cb4cSShashi Mallela 
2824acf93e1SPeter Maydell /*
2834acf93e1SPeter Maydell  * Read the Device Table entry at index @devid. On success (including
2844acf93e1SPeter Maydell  * successfully determining that there is no valid DTE for this index),
2854acf93e1SPeter Maydell  * we return MEMTX_OK and populate the DTEntry struct accordingly.
2864acf93e1SPeter Maydell  * If there is an error reading memory then we return the error code.
2874acf93e1SPeter Maydell  */
2884acf93e1SPeter Maydell static MemTxResult get_dte(GICv3ITSState *s, uint32_t devid, DTEntry *dte)
289c694cb4cSShashi Mallela {
2904acf93e1SPeter Maydell     MemTxResult res = MEMTX_OK;
291c694cb4cSShashi Mallela     AddressSpace *as = &s->gicv3->dma_as;
2924acf93e1SPeter Maydell     uint64_t entry_addr = table_entry_addr(s, &s->dt, devid, &res);
2934acf93e1SPeter Maydell     uint64_t dteval;
294c694cb4cSShashi Mallela 
295d050f80fSPeter Maydell     if (entry_addr == -1) {
2964acf93e1SPeter Maydell         /* No L2 table entry, i.e. no valid DTE, or a memory error */
2974acf93e1SPeter Maydell         dte->valid = false;
298930f40e9SPeter Maydell         goto out;
299c694cb4cSShashi Mallela     }
3004acf93e1SPeter Maydell     dteval = address_space_ldq_le(as, entry_addr, MEMTXATTRS_UNSPECIFIED, &res);
3014acf93e1SPeter Maydell     if (res != MEMTX_OK) {
302930f40e9SPeter Maydell         goto out;
3034acf93e1SPeter Maydell     }
3044acf93e1SPeter Maydell     dte->valid = FIELD_EX64(dteval, DTE, VALID);
3054acf93e1SPeter Maydell     dte->size = FIELD_EX64(dteval, DTE, SIZE);
3064acf93e1SPeter Maydell     /* DTE word field stores bits [51:8] of the ITT address */
3074acf93e1SPeter Maydell     dte->ittaddr = FIELD_EX64(dteval, DTE, ITTADDR) << ITTADDR_SHIFT;
308930f40e9SPeter Maydell out:
309930f40e9SPeter Maydell     if (res != MEMTX_OK) {
310930f40e9SPeter Maydell         trace_gicv3_its_dte_read_fault(devid);
311930f40e9SPeter Maydell     } else {
312930f40e9SPeter Maydell         trace_gicv3_its_dte_read(devid, dte->valid, dte->size, dte->ittaddr);
313930f40e9SPeter Maydell     }
314930f40e9SPeter Maydell     return res;
315c694cb4cSShashi Mallela }
316c694cb4cSShashi Mallela 
317c694cb4cSShashi Mallela /*
318f0175135SPeter Maydell  * Given a (DeviceID, EventID), look up the corresponding ITE, including
319f0175135SPeter Maydell  * checking for the various invalid-value cases. If we find a valid ITE,
320f0175135SPeter Maydell  * fill in @ite and @dte and return CMD_CONTINUE_OK. Otherwise return
321f0175135SPeter Maydell  * CMD_STALL or CMD_CONTINUE as appropriate (and the contents of @ite
322f0175135SPeter Maydell  * should not be relied on).
323f0175135SPeter Maydell  *
324f0175135SPeter Maydell  * The string @who is purely for the LOG_GUEST_ERROR messages,
325f0175135SPeter Maydell  * and should indicate the name of the calling function or similar.
326f0175135SPeter Maydell  */
327f0175135SPeter Maydell static ItsCmdResult lookup_ite(GICv3ITSState *s, const char *who,
328f0175135SPeter Maydell                                uint32_t devid, uint32_t eventid, ITEntry *ite,
329f0175135SPeter Maydell                                DTEntry *dte)
330f0175135SPeter Maydell {
331f0175135SPeter Maydell     uint64_t num_eventids;
332f0175135SPeter Maydell 
333f0175135SPeter Maydell     if (devid >= s->dt.num_entries) {
334f0175135SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
335f0175135SPeter Maydell                       "%s: invalid command attributes: devid %d>=%d",
336f0175135SPeter Maydell                       who, devid, s->dt.num_entries);
337f0175135SPeter Maydell         return CMD_CONTINUE;
338f0175135SPeter Maydell     }
339f0175135SPeter Maydell 
340f0175135SPeter Maydell     if (get_dte(s, devid, dte) != MEMTX_OK) {
341f0175135SPeter Maydell         return CMD_STALL;
342f0175135SPeter Maydell     }
343f0175135SPeter Maydell     if (!dte->valid) {
344f0175135SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
345f0175135SPeter Maydell                       "%s: invalid command attributes: "
346f0175135SPeter Maydell                       "invalid dte for %d\n", who, devid);
347f0175135SPeter Maydell         return CMD_CONTINUE;
348f0175135SPeter Maydell     }
349f0175135SPeter Maydell 
350f0175135SPeter Maydell     num_eventids = 1ULL << (dte->size + 1);
351f0175135SPeter Maydell     if (eventid >= num_eventids) {
352f0175135SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
353f0175135SPeter Maydell                       "%s: invalid command attributes: eventid %d >= %"
354f0175135SPeter Maydell                       PRId64 "\n", who, eventid, num_eventids);
355f0175135SPeter Maydell         return CMD_CONTINUE;
356f0175135SPeter Maydell     }
357f0175135SPeter Maydell 
358f0175135SPeter Maydell     if (get_ite(s, eventid, dte, ite) != MEMTX_OK) {
359f0175135SPeter Maydell         return CMD_STALL;
360f0175135SPeter Maydell     }
361f0175135SPeter Maydell 
362f0175135SPeter Maydell     if (!ite->valid) {
363f0175135SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
364f0175135SPeter Maydell                       "%s: invalid command attributes: invalid ITE\n", who);
365f0175135SPeter Maydell         return CMD_CONTINUE;
366f0175135SPeter Maydell     }
367f0175135SPeter Maydell 
368f0175135SPeter Maydell     return CMD_CONTINUE_OK;
369f0175135SPeter Maydell }
370f0175135SPeter Maydell 
371f0175135SPeter Maydell /*
372c411db7bSPeter Maydell  * Given an ICID, look up the corresponding CTE, including checking for various
373c411db7bSPeter Maydell  * invalid-value cases. If we find a valid CTE, fill in @cte and return
374c411db7bSPeter Maydell  * CMD_CONTINUE_OK; otherwise return CMD_STALL or CMD_CONTINUE (and the
375c411db7bSPeter Maydell  * contents of @cte should not be relied on).
376c411db7bSPeter Maydell  *
377c411db7bSPeter Maydell  * The string @who is purely for the LOG_GUEST_ERROR messages,
378c411db7bSPeter Maydell  * and should indicate the name of the calling function or similar.
379c411db7bSPeter Maydell  */
380c411db7bSPeter Maydell static ItsCmdResult lookup_cte(GICv3ITSState *s, const char *who,
381c411db7bSPeter Maydell                                uint32_t icid, CTEntry *cte)
382c411db7bSPeter Maydell {
383c411db7bSPeter Maydell     if (icid >= s->ct.num_entries) {
384c411db7bSPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid ICID 0x%x\n", who, icid);
385c411db7bSPeter Maydell         return CMD_CONTINUE;
386c411db7bSPeter Maydell     }
387c411db7bSPeter Maydell     if (get_cte(s, icid, cte) != MEMTX_OK) {
388c411db7bSPeter Maydell         return CMD_STALL;
389c411db7bSPeter Maydell     }
390c411db7bSPeter Maydell     if (!cte->valid) {
391c411db7bSPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid CTE\n", who);
392c411db7bSPeter Maydell         return CMD_CONTINUE;
393c411db7bSPeter Maydell     }
394c411db7bSPeter Maydell     if (cte->rdbase >= s->gicv3->num_cpu) {
395c411db7bSPeter Maydell         return CMD_CONTINUE;
396c411db7bSPeter Maydell     }
397c411db7bSPeter Maydell     return CMD_CONTINUE_OK;
398c411db7bSPeter Maydell }
399c411db7bSPeter Maydell 
400*2d692e2bSPeter Maydell static ItsCmdResult process_its_cmd_phys(GICv3ITSState *s, const ITEntry *ite,
401*2d692e2bSPeter Maydell                                          int irqlevel)
402*2d692e2bSPeter Maydell {
403*2d692e2bSPeter Maydell     CTEntry cte;
404*2d692e2bSPeter Maydell     ItsCmdResult cmdres;
405*2d692e2bSPeter Maydell 
406*2d692e2bSPeter Maydell     cmdres = lookup_cte(s, __func__, ite->icid, &cte);
407*2d692e2bSPeter Maydell     if (cmdres != CMD_CONTINUE_OK) {
408*2d692e2bSPeter Maydell         return cmdres;
409*2d692e2bSPeter Maydell     }
410*2d692e2bSPeter Maydell     gicv3_redist_process_lpi(&s->gicv3->cpu[cte.rdbase], ite->intid, irqlevel);
411*2d692e2bSPeter Maydell     return CMD_CONTINUE_OK;
412*2d692e2bSPeter Maydell }
413c411db7bSPeter Maydell 
414c411db7bSPeter Maydell /*
415c694cb4cSShashi Mallela  * This function handles the processing of following commands based on
416c694cb4cSShashi Mallela  * the ItsCmdType parameter passed:-
417c694cb4cSShashi Mallela  * 1. triggering of lpi interrupt translation via ITS INT command
418c694cb4cSShashi Mallela  * 2. triggering of lpi interrupt translation via gits_translater register
419c694cb4cSShashi Mallela  * 3. handling of ITS CLEAR command
420c694cb4cSShashi Mallela  * 4. handling of ITS DISCARD command
421c694cb4cSShashi Mallela  */
422b6f96009SPeter Maydell static ItsCmdResult do_process_its_cmd(GICv3ITSState *s, uint32_t devid,
423b6f96009SPeter Maydell                                        uint32_t eventid, ItsCmdType cmd)
424c694cb4cSShashi Mallela {
4254acf93e1SPeter Maydell     DTEntry dte;
426244194feSPeter Maydell     ITEntry ite;
427f0175135SPeter Maydell     ItsCmdResult cmdres;
428*2d692e2bSPeter Maydell     int irqlevel;
429c694cb4cSShashi Mallela 
430f0175135SPeter Maydell     cmdres = lookup_ite(s, __func__, devid, eventid, &ite, &dte);
431f0175135SPeter Maydell     if (cmdres != CMD_CONTINUE_OK) {
432f0175135SPeter Maydell         return cmdres;
433b13148d9SPeter Maydell     }
434b13148d9SPeter Maydell 
435*2d692e2bSPeter Maydell     irqlevel = (cmd == CLEAR || cmd == DISCARD) ? 0 : 1;
436*2d692e2bSPeter Maydell 
437*2d692e2bSPeter Maydell     switch (ite.inttype) {
438*2d692e2bSPeter Maydell     case ITE_INTTYPE_PHYSICAL:
439*2d692e2bSPeter Maydell         cmdres = process_its_cmd_phys(s, &ite, irqlevel);
440*2d692e2bSPeter Maydell         break;
441*2d692e2bSPeter Maydell     case ITE_INTTYPE_VIRTUAL:
442*2d692e2bSPeter Maydell         if (!its_feature_virtual(s)) {
443*2d692e2bSPeter Maydell             /* Can't happen unless guest is illegally writing to table memory */
444be0ed8fbSPeter Maydell             qemu_log_mask(LOG_GUEST_ERROR,
445*2d692e2bSPeter Maydell                           "%s: invalid type %d in ITE (table corrupted?)\n",
446*2d692e2bSPeter Maydell                           __func__, ite.inttype);
447be0ed8fbSPeter Maydell             return CMD_CONTINUE;
448be0ed8fbSPeter Maydell         }
449*2d692e2bSPeter Maydell         /* The GICv4 virtual interrupt handling will go here */
450*2d692e2bSPeter Maydell         g_assert_not_reached();
451*2d692e2bSPeter Maydell     default:
452*2d692e2bSPeter Maydell         g_assert_not_reached();
45317fb5e36SShashi Mallela     }
45417fb5e36SShashi Mallela 
455*2d692e2bSPeter Maydell     if (cmdres == CMD_CONTINUE_OK && cmd == DISCARD) {
4567eb54267SPeter Maydell         ITEntry ite = {};
457c694cb4cSShashi Mallela         /* remove mapping from interrupt translation table */
4587eb54267SPeter Maydell         ite.valid = false;
45993f4fdcdSPeter Maydell         return update_ite(s, eventid, &dte, &ite) ? CMD_CONTINUE_OK : CMD_STALL;
460c694cb4cSShashi Mallela     }
46193f4fdcdSPeter Maydell     return CMD_CONTINUE_OK;
462c694cb4cSShashi Mallela }
4632a199036SPeter Maydell 
464b6f96009SPeter Maydell static ItsCmdResult process_its_cmd(GICv3ITSState *s, const uint64_t *cmdpkt,
465b6f96009SPeter Maydell                                     ItsCmdType cmd)
466c694cb4cSShashi Mallela {
467b6f96009SPeter Maydell     uint32_t devid, eventid;
468b6f96009SPeter Maydell 
469b6f96009SPeter Maydell     devid = (cmdpkt[0] & DEVID_MASK) >> DEVID_SHIFT;
470b6f96009SPeter Maydell     eventid = cmdpkt[1] & EVENTID_MASK;
471e4050980SPeter Maydell     switch (cmd) {
472e4050980SPeter Maydell     case INTERRUPT:
473e4050980SPeter Maydell         trace_gicv3_its_cmd_int(devid, eventid);
474e4050980SPeter Maydell         break;
475e4050980SPeter Maydell     case CLEAR:
476e4050980SPeter Maydell         trace_gicv3_its_cmd_clear(devid, eventid);
477e4050980SPeter Maydell         break;
478e4050980SPeter Maydell     case DISCARD:
479e4050980SPeter Maydell         trace_gicv3_its_cmd_discard(devid, eventid);
480e4050980SPeter Maydell         break;
481e4050980SPeter Maydell     default:
482e4050980SPeter Maydell         g_assert_not_reached();
483e4050980SPeter Maydell     }
484b6f96009SPeter Maydell     return do_process_its_cmd(s, devid, eventid, cmd);
485b6f96009SPeter Maydell }
486b6f96009SPeter Maydell 
487b6f96009SPeter Maydell static ItsCmdResult process_mapti(GICv3ITSState *s, const uint64_t *cmdpkt,
488b6f96009SPeter Maydell                                   bool ignore_pInt)
489b6f96009SPeter Maydell {
490c694cb4cSShashi Mallela     uint32_t devid, eventid;
491c694cb4cSShashi Mallela     uint32_t pIntid = 0;
4928f809f69SPeter Maydell     uint64_t num_eventids;
493c694cb4cSShashi Mallela     uint16_t icid = 0;
4944acf93e1SPeter Maydell     DTEntry dte;
4957eb54267SPeter Maydell     ITEntry ite;
496c694cb4cSShashi Mallela 
497b6f96009SPeter Maydell     devid = (cmdpkt[0] & DEVID_MASK) >> DEVID_SHIFT;
498b6f96009SPeter Maydell     eventid = cmdpkt[1] & EVENTID_MASK;
499e4050980SPeter Maydell     icid = cmdpkt[2] & ICID_MASK;
500c694cb4cSShashi Mallela 
501b87fab1cSPeter Maydell     if (ignore_pInt) {
502b87fab1cSPeter Maydell         pIntid = eventid;
503e4050980SPeter Maydell         trace_gicv3_its_cmd_mapi(devid, eventid, icid);
504b87fab1cSPeter Maydell     } else {
505b6f96009SPeter Maydell         pIntid = (cmdpkt[1] & pINTID_MASK) >> pINTID_SHIFT;
506e4050980SPeter Maydell         trace_gicv3_its_cmd_mapti(devid, eventid, icid, pIntid);
507c694cb4cSShashi Mallela     }
508c694cb4cSShashi Mallela 
5098b8bb014SPeter Maydell     if (devid >= s->dt.num_entries) {
510b13148d9SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
511b13148d9SPeter Maydell                       "%s: invalid command attributes: devid %d>=%d",
5128b8bb014SPeter Maydell                       __func__, devid, s->dt.num_entries);
513b13148d9SPeter Maydell         return CMD_CONTINUE;
514b13148d9SPeter Maydell     }
515b13148d9SPeter Maydell 
5164acf93e1SPeter Maydell     if (get_dte(s, devid, &dte) != MEMTX_OK) {
5170241f731SPeter Maydell         return CMD_STALL;
518c694cb4cSShashi Mallela     }
5194acf93e1SPeter Maydell     num_eventids = 1ULL << (dte.size + 1);
520c694cb4cSShashi Mallela 
521d7d359c4SPeter Maydell     if (icid >= s->ct.num_entries) {
522c694cb4cSShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
523d7d359c4SPeter Maydell                       "%s: invalid ICID 0x%x >= 0x%x\n",
524d7d359c4SPeter Maydell                       __func__, icid, s->ct.num_entries);
525d7d359c4SPeter Maydell         return CMD_CONTINUE;
526d7d359c4SPeter Maydell     }
527d7d359c4SPeter Maydell 
528d7d359c4SPeter Maydell     if (!dte.valid) {
529d7d359c4SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
530d7d359c4SPeter Maydell                       "%s: no valid DTE for devid 0x%x\n", __func__, devid);
531d7d359c4SPeter Maydell         return CMD_CONTINUE;
532d7d359c4SPeter Maydell     }
533d7d359c4SPeter Maydell 
534d7d359c4SPeter Maydell     if (eventid >= num_eventids) {
535d7d359c4SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
536d7d359c4SPeter Maydell                       "%s: invalid event ID 0x%x >= 0x%" PRIx64 "\n",
537d7d359c4SPeter Maydell                       __func__, eventid, num_eventids);
538d7d359c4SPeter Maydell         return CMD_CONTINUE;
539d7d359c4SPeter Maydell     }
540d7d359c4SPeter Maydell 
541c3c9a090SPeter Maydell     if (!intid_in_lpi_range(pIntid)) {
542d7d359c4SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
543d7d359c4SPeter Maydell                       "%s: invalid interrupt ID 0x%x\n", __func__, pIntid);
5440241f731SPeter Maydell         return CMD_CONTINUE;
5450241f731SPeter Maydell     }
5460241f731SPeter Maydell 
547c694cb4cSShashi Mallela     /* add ite entry to interrupt translation table */
5487eb54267SPeter Maydell     ite.valid = true;
5497eb54267SPeter Maydell     ite.inttype = ITE_INTTYPE_PHYSICAL;
5507eb54267SPeter Maydell     ite.intid = pIntid;
5517eb54267SPeter Maydell     ite.icid = icid;
5527eb54267SPeter Maydell     ite.doorbell = INTID_SPURIOUS;
5537eb54267SPeter Maydell     ite.vpeid = 0;
55493f4fdcdSPeter Maydell     return update_ite(s, eventid, &dte, &ite) ? CMD_CONTINUE_OK : CMD_STALL;
555c694cb4cSShashi Mallela }
556c694cb4cSShashi Mallela 
5579de53de6SPeter Maydell static ItsCmdResult process_vmapti(GICv3ITSState *s, const uint64_t *cmdpkt,
5589de53de6SPeter Maydell                                    bool ignore_vintid)
5599de53de6SPeter Maydell {
5609de53de6SPeter Maydell     uint32_t devid, eventid, vintid, doorbell, vpeid;
5619de53de6SPeter Maydell     uint32_t num_eventids;
5629de53de6SPeter Maydell     DTEntry dte;
5639de53de6SPeter Maydell     ITEntry ite;
5649de53de6SPeter Maydell 
5659de53de6SPeter Maydell     if (!its_feature_virtual(s)) {
5669de53de6SPeter Maydell         return CMD_CONTINUE;
5679de53de6SPeter Maydell     }
5689de53de6SPeter Maydell 
5699de53de6SPeter Maydell     devid = FIELD_EX64(cmdpkt[0], VMAPTI_0, DEVICEID);
5709de53de6SPeter Maydell     eventid = FIELD_EX64(cmdpkt[1], VMAPTI_1, EVENTID);
5719de53de6SPeter Maydell     vpeid = FIELD_EX64(cmdpkt[1], VMAPTI_1, VPEID);
5729de53de6SPeter Maydell     doorbell = FIELD_EX64(cmdpkt[2], VMAPTI_2, DOORBELL);
5739de53de6SPeter Maydell     if (ignore_vintid) {
5749de53de6SPeter Maydell         vintid = eventid;
5759de53de6SPeter Maydell         trace_gicv3_its_cmd_vmapi(devid, eventid, vpeid, doorbell);
5769de53de6SPeter Maydell     } else {
5779de53de6SPeter Maydell         vintid = FIELD_EX64(cmdpkt[2], VMAPTI_2, VINTID);
5789de53de6SPeter Maydell         trace_gicv3_its_cmd_vmapti(devid, eventid, vpeid, vintid, doorbell);
5799de53de6SPeter Maydell     }
5809de53de6SPeter Maydell 
5819de53de6SPeter Maydell     if (devid >= s->dt.num_entries) {
5829de53de6SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
5839de53de6SPeter Maydell                       "%s: invalid DeviceID 0x%x (must be less than 0x%x)\n",
5849de53de6SPeter Maydell                       __func__, devid, s->dt.num_entries);
5859de53de6SPeter Maydell         return CMD_CONTINUE;
5869de53de6SPeter Maydell     }
5879de53de6SPeter Maydell 
5889de53de6SPeter Maydell     if (get_dte(s, devid, &dte) != MEMTX_OK) {
5899de53de6SPeter Maydell         return CMD_STALL;
5909de53de6SPeter Maydell     }
5919de53de6SPeter Maydell 
5929de53de6SPeter Maydell     if (!dte.valid) {
5939de53de6SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
5949de53de6SPeter Maydell                       "%s: no entry in device table for DeviceID 0x%x\n",
5959de53de6SPeter Maydell                       __func__, devid);
5969de53de6SPeter Maydell         return CMD_CONTINUE;
5979de53de6SPeter Maydell     }
5989de53de6SPeter Maydell 
5999de53de6SPeter Maydell     num_eventids = 1ULL << (dte.size + 1);
6009de53de6SPeter Maydell 
6019de53de6SPeter Maydell     if (eventid >= num_eventids) {
6029de53de6SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
6039de53de6SPeter Maydell                       "%s: EventID 0x%x too large for DeviceID 0x%x "
6049de53de6SPeter Maydell                       "(must be less than 0x%x)\n",
6059de53de6SPeter Maydell                       __func__, eventid, devid, num_eventids);
6069de53de6SPeter Maydell         return CMD_CONTINUE;
6079de53de6SPeter Maydell     }
6089de53de6SPeter Maydell     if (!intid_in_lpi_range(vintid)) {
6099de53de6SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
6109de53de6SPeter Maydell                       "%s: VIntID 0x%x not a valid LPI\n",
6119de53de6SPeter Maydell                       __func__, vintid);
6129de53de6SPeter Maydell         return CMD_CONTINUE;
6139de53de6SPeter Maydell     }
6149de53de6SPeter Maydell     if (!valid_doorbell(doorbell)) {
6159de53de6SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
6169de53de6SPeter Maydell                       "%s: Doorbell %d not 1023 and not a valid LPI\n",
6179de53de6SPeter Maydell                       __func__, doorbell);
6189de53de6SPeter Maydell         return CMD_CONTINUE;
6199de53de6SPeter Maydell     }
6209de53de6SPeter Maydell     if (vpeid >= s->vpet.num_entries) {
6219de53de6SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
6229de53de6SPeter Maydell                       "%s: VPEID 0x%x out of range (must be less than 0x%x)\n",
6239de53de6SPeter Maydell                       __func__, vpeid, s->vpet.num_entries);
6249de53de6SPeter Maydell         return CMD_CONTINUE;
6259de53de6SPeter Maydell     }
6269de53de6SPeter Maydell     /* add ite entry to interrupt translation table */
6279de53de6SPeter Maydell     ite.valid = true;
6289de53de6SPeter Maydell     ite.inttype = ITE_INTTYPE_VIRTUAL;
6299de53de6SPeter Maydell     ite.intid = vintid;
6309de53de6SPeter Maydell     ite.icid = 0;
6319de53de6SPeter Maydell     ite.doorbell = doorbell;
6329de53de6SPeter Maydell     ite.vpeid = vpeid;
63393f4fdcdSPeter Maydell     return update_ite(s, eventid, &dte, &ite) ? CMD_CONTINUE_OK : CMD_STALL;
6349de53de6SPeter Maydell }
6359de53de6SPeter Maydell 
63606985cc3SPeter Maydell /*
63706985cc3SPeter Maydell  * Update the Collection Table entry for @icid to @cte. Returns true
63806985cc3SPeter Maydell  * on success, false if there was a memory access error.
63906985cc3SPeter Maydell  */
64006985cc3SPeter Maydell static bool update_cte(GICv3ITSState *s, uint16_t icid, const CTEntry *cte)
6417eca39e0SShashi Mallela {
6427eca39e0SShashi Mallela     AddressSpace *as = &s->gicv3->dma_as;
643d050f80fSPeter Maydell     uint64_t entry_addr;
64406985cc3SPeter Maydell     uint64_t cteval = 0;
6457eca39e0SShashi Mallela     MemTxResult res = MEMTX_OK;
6467eca39e0SShashi Mallela 
647930f40e9SPeter Maydell     trace_gicv3_its_cte_write(icid, cte->valid, cte->rdbase);
648930f40e9SPeter Maydell 
64906985cc3SPeter Maydell     if (cte->valid) {
6507eca39e0SShashi Mallela         /* add mapping entry to collection table */
65106985cc3SPeter Maydell         cteval = FIELD_DP64(cteval, CTE, VALID, 1);
65206985cc3SPeter Maydell         cteval = FIELD_DP64(cteval, CTE, RDBASE, cte->rdbase);
6537eca39e0SShashi Mallela     }
6547eca39e0SShashi Mallela 
655d050f80fSPeter Maydell     entry_addr = table_entry_addr(s, &s->ct, icid, &res);
6567eca39e0SShashi Mallela     if (res != MEMTX_OK) {
657d050f80fSPeter Maydell         /* memory access error: stall */
6587eca39e0SShashi Mallela         return false;
6597eca39e0SShashi Mallela     }
660d050f80fSPeter Maydell     if (entry_addr == -1) {
661d050f80fSPeter Maydell         /* No L2 table for this index: discard write and continue */
6627eca39e0SShashi Mallela         return true;
6637eca39e0SShashi Mallela     }
664d050f80fSPeter Maydell 
66506985cc3SPeter Maydell     address_space_stq_le(as, entry_addr, cteval, MEMTXATTRS_UNSPECIFIED, &res);
666d050f80fSPeter Maydell     return res == MEMTX_OK;
6677eca39e0SShashi Mallela }
6687eca39e0SShashi Mallela 
669b6f96009SPeter Maydell static ItsCmdResult process_mapc(GICv3ITSState *s, const uint64_t *cmdpkt)
6707eca39e0SShashi Mallela {
6717eca39e0SShashi Mallela     uint16_t icid;
67206985cc3SPeter Maydell     CTEntry cte;
6737eca39e0SShashi Mallela 
674b6f96009SPeter Maydell     icid = cmdpkt[2] & ICID_MASK;
67584d43d2eSPeter Maydell     cte.valid = cmdpkt[2] & CMD_FIELD_VALID_MASK;
67684d43d2eSPeter Maydell     if (cte.valid) {
67706985cc3SPeter Maydell         cte.rdbase = (cmdpkt[2] & R_MAPC_RDBASE_MASK) >> R_MAPC_RDBASE_SHIFT;
67806985cc3SPeter Maydell         cte.rdbase &= RDBASE_PROCNUM_MASK;
67984d43d2eSPeter Maydell     } else {
68084d43d2eSPeter Maydell         cte.rdbase = 0;
68184d43d2eSPeter Maydell     }
682e4050980SPeter Maydell     trace_gicv3_its_cmd_mapc(icid, cte.rdbase, cte.valid);
6837eca39e0SShashi Mallela 
68484d43d2eSPeter Maydell     if (icid >= s->ct.num_entries) {
685c7ca3ad5SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR, "ITS MAPC: invalid ICID 0x%x\n", icid);
68684d43d2eSPeter Maydell         return CMD_CONTINUE;
68784d43d2eSPeter Maydell     }
68884d43d2eSPeter Maydell     if (cte.valid && cte.rdbase >= s->gicv3->num_cpu) {
6897eca39e0SShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
690c7ca3ad5SPeter Maydell                       "ITS MAPC: invalid RDBASE %u\n", cte.rdbase);
691f6675196SPeter Maydell         return CMD_CONTINUE;
6927eca39e0SShashi Mallela     }
6937eca39e0SShashi Mallela 
69493f4fdcdSPeter Maydell     return update_cte(s, icid, &cte) ? CMD_CONTINUE_OK : CMD_STALL;
6957eca39e0SShashi Mallela }
6967eca39e0SShashi Mallela 
69722d62b08SPeter Maydell /*
69822d62b08SPeter Maydell  * Update the Device Table entry for @devid to @dte. Returns true
69922d62b08SPeter Maydell  * on success, false if there was a memory access error.
70022d62b08SPeter Maydell  */
70122d62b08SPeter Maydell static bool update_dte(GICv3ITSState *s, uint32_t devid, const DTEntry *dte)
7027eca39e0SShashi Mallela {
7037eca39e0SShashi Mallela     AddressSpace *as = &s->gicv3->dma_as;
704d050f80fSPeter Maydell     uint64_t entry_addr;
70522d62b08SPeter Maydell     uint64_t dteval = 0;
7067eca39e0SShashi Mallela     MemTxResult res = MEMTX_OK;
7077eca39e0SShashi Mallela 
708930f40e9SPeter Maydell     trace_gicv3_its_dte_write(devid, dte->valid, dte->size, dte->ittaddr);
709930f40e9SPeter Maydell 
71022d62b08SPeter Maydell     if (dte->valid) {
7117eca39e0SShashi Mallela         /* add mapping entry to device table */
71222d62b08SPeter Maydell         dteval = FIELD_DP64(dteval, DTE, VALID, 1);
71322d62b08SPeter Maydell         dteval = FIELD_DP64(dteval, DTE, SIZE, dte->size);
71422d62b08SPeter Maydell         dteval = FIELD_DP64(dteval, DTE, ITTADDR, dte->ittaddr);
7157eca39e0SShashi Mallela     }
7167eca39e0SShashi Mallela 
717d050f80fSPeter Maydell     entry_addr = table_entry_addr(s, &s->dt, devid, &res);
7187eca39e0SShashi Mallela     if (res != MEMTX_OK) {
719d050f80fSPeter Maydell         /* memory access error: stall */
7207eca39e0SShashi Mallela         return false;
7217eca39e0SShashi Mallela     }
722d050f80fSPeter Maydell     if (entry_addr == -1) {
723d050f80fSPeter Maydell         /* No L2 table for this index: discard write and continue */
7247eca39e0SShashi Mallela         return true;
7257eca39e0SShashi Mallela     }
72622d62b08SPeter Maydell     address_space_stq_le(as, entry_addr, dteval, MEMTXATTRS_UNSPECIFIED, &res);
727d050f80fSPeter Maydell     return res == MEMTX_OK;
7287eca39e0SShashi Mallela }
7297eca39e0SShashi Mallela 
730b6f96009SPeter Maydell static ItsCmdResult process_mapd(GICv3ITSState *s, const uint64_t *cmdpkt)
7317eca39e0SShashi Mallela {
7327eca39e0SShashi Mallela     uint32_t devid;
73322d62b08SPeter Maydell     DTEntry dte;
7347eca39e0SShashi Mallela 
735b6f96009SPeter Maydell     devid = (cmdpkt[0] & DEVID_MASK) >> DEVID_SHIFT;
73622d62b08SPeter Maydell     dte.size = cmdpkt[1] & SIZE_MASK;
73722d62b08SPeter Maydell     dte.ittaddr = (cmdpkt[2] & ITTADDR_MASK) >> ITTADDR_SHIFT;
73822d62b08SPeter Maydell     dte.valid = cmdpkt[2] & CMD_FIELD_VALID_MASK;
7397eca39e0SShashi Mallela 
740e4050980SPeter Maydell     trace_gicv3_its_cmd_mapd(devid, dte.size, dte.ittaddr, dte.valid);
741e4050980SPeter Maydell 
742d7d359c4SPeter Maydell     if (devid >= s->dt.num_entries) {
7437eca39e0SShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
744d7d359c4SPeter Maydell                       "ITS MAPD: invalid device ID field 0x%x >= 0x%x\n",
745d7d359c4SPeter Maydell                       devid, s->dt.num_entries);
746d7d359c4SPeter Maydell         return CMD_CONTINUE;
747d7d359c4SPeter Maydell     }
748d7d359c4SPeter Maydell 
749d7d359c4SPeter Maydell     if (dte.size > FIELD_EX64(s->typer, GITS_TYPER, IDBITS)) {
750d7d359c4SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
751d7d359c4SPeter Maydell                       "ITS MAPD: invalid size %d\n", dte.size);
75200d46e72SPeter Maydell         return CMD_CONTINUE;
7537eca39e0SShashi Mallela     }
7547eca39e0SShashi Mallela 
75593f4fdcdSPeter Maydell     return update_dte(s, devid, &dte) ? CMD_CONTINUE_OK : CMD_STALL;
7567eca39e0SShashi Mallela }
7577eca39e0SShashi Mallela 
758b6f96009SPeter Maydell static ItsCmdResult process_movall(GICv3ITSState *s, const uint64_t *cmdpkt)
759f6d1d9b4SPeter Maydell {
760f6d1d9b4SPeter Maydell     uint64_t rd1, rd2;
761f6d1d9b4SPeter Maydell 
762b6f96009SPeter Maydell     rd1 = FIELD_EX64(cmdpkt[2], MOVALL_2, RDBASE1);
763b6f96009SPeter Maydell     rd2 = FIELD_EX64(cmdpkt[3], MOVALL_3, RDBASE2);
764f6d1d9b4SPeter Maydell 
765e4050980SPeter Maydell     trace_gicv3_its_cmd_movall(rd1, rd2);
766e4050980SPeter Maydell 
767f6d1d9b4SPeter Maydell     if (rd1 >= s->gicv3->num_cpu) {
768f6d1d9b4SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
769f6d1d9b4SPeter Maydell                       "%s: RDBASE1 %" PRId64
770f6d1d9b4SPeter Maydell                       " out of range (must be less than %d)\n",
771f6d1d9b4SPeter Maydell                       __func__, rd1, s->gicv3->num_cpu);
772f6d1d9b4SPeter Maydell         return CMD_CONTINUE;
773f6d1d9b4SPeter Maydell     }
774f6d1d9b4SPeter Maydell     if (rd2 >= s->gicv3->num_cpu) {
775f6d1d9b4SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
776f6d1d9b4SPeter Maydell                       "%s: RDBASE2 %" PRId64
777f6d1d9b4SPeter Maydell                       " out of range (must be less than %d)\n",
778f6d1d9b4SPeter Maydell                       __func__, rd2, s->gicv3->num_cpu);
779f6d1d9b4SPeter Maydell         return CMD_CONTINUE;
780f6d1d9b4SPeter Maydell     }
781f6d1d9b4SPeter Maydell 
782f6d1d9b4SPeter Maydell     if (rd1 == rd2) {
783f6d1d9b4SPeter Maydell         /* Move to same target must succeed as a no-op */
78493f4fdcdSPeter Maydell         return CMD_CONTINUE_OK;
785f6d1d9b4SPeter Maydell     }
786f6d1d9b4SPeter Maydell 
787f6d1d9b4SPeter Maydell     /* Move all pending LPIs from redistributor 1 to redistributor 2 */
788f6d1d9b4SPeter Maydell     gicv3_redist_movall_lpis(&s->gicv3->cpu[rd1], &s->gicv3->cpu[rd2]);
789f6d1d9b4SPeter Maydell 
79093f4fdcdSPeter Maydell     return CMD_CONTINUE_OK;
791f6d1d9b4SPeter Maydell }
792f6d1d9b4SPeter Maydell 
793b6f96009SPeter Maydell static ItsCmdResult process_movi(GICv3ITSState *s, const uint64_t *cmdpkt)
794961b4912SPeter Maydell {
795244194feSPeter Maydell     uint32_t devid, eventid;
796244194feSPeter Maydell     uint16_t new_icid;
7974acf93e1SPeter Maydell     DTEntry dte;
798d37cf49bSPeter Maydell     CTEntry old_cte, new_cte;
799244194feSPeter Maydell     ITEntry old_ite;
800f0175135SPeter Maydell     ItsCmdResult cmdres;
801961b4912SPeter Maydell 
802b6f96009SPeter Maydell     devid = FIELD_EX64(cmdpkt[0], MOVI_0, DEVICEID);
803b6f96009SPeter Maydell     eventid = FIELD_EX64(cmdpkt[1], MOVI_1, EVENTID);
804b6f96009SPeter Maydell     new_icid = FIELD_EX64(cmdpkt[2], MOVI_2, ICID);
805961b4912SPeter Maydell 
806e4050980SPeter Maydell     trace_gicv3_its_cmd_movi(devid, eventid, new_icid);
807e4050980SPeter Maydell 
808f0175135SPeter Maydell     cmdres = lookup_ite(s, __func__, devid, eventid, &old_ite, &dte);
809f0175135SPeter Maydell     if (cmdres != CMD_CONTINUE_OK) {
810f0175135SPeter Maydell         return cmdres;
811961b4912SPeter Maydell     }
812961b4912SPeter Maydell 
813f0175135SPeter Maydell     if (old_ite.inttype != ITE_INTTYPE_PHYSICAL) {
814961b4912SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
815961b4912SPeter Maydell                       "%s: invalid command attributes: invalid ITE\n",
816961b4912SPeter Maydell                       __func__);
817961b4912SPeter Maydell         return CMD_CONTINUE;
818961b4912SPeter Maydell     }
819961b4912SPeter Maydell 
820c411db7bSPeter Maydell     cmdres = lookup_cte(s, __func__, old_ite.icid, &old_cte);
821c411db7bSPeter Maydell     if (cmdres != CMD_CONTINUE_OK) {
822c411db7bSPeter Maydell         return cmdres;
823961b4912SPeter Maydell     }
824c411db7bSPeter Maydell     cmdres = lookup_cte(s, __func__, new_icid, &new_cte);
825c411db7bSPeter Maydell     if (cmdres != CMD_CONTINUE_OK) {
826c411db7bSPeter Maydell         return cmdres;
827961b4912SPeter Maydell     }
828961b4912SPeter Maydell 
829d37cf49bSPeter Maydell     if (old_cte.rdbase != new_cte.rdbase) {
830961b4912SPeter Maydell         /* Move the LPI from the old redistributor to the new one */
831d37cf49bSPeter Maydell         gicv3_redist_mov_lpi(&s->gicv3->cpu[old_cte.rdbase],
832d37cf49bSPeter Maydell                              &s->gicv3->cpu[new_cte.rdbase],
833244194feSPeter Maydell                              old_ite.intid);
834961b4912SPeter Maydell     }
835961b4912SPeter Maydell 
836961b4912SPeter Maydell     /* Update the ICID field in the interrupt translation table entry */
8377eb54267SPeter Maydell     old_ite.icid = new_icid;
83893f4fdcdSPeter Maydell     return update_ite(s, eventid, &dte, &old_ite) ? CMD_CONTINUE_OK : CMD_STALL;
839961b4912SPeter Maydell }
840961b4912SPeter Maydell 
8417eca39e0SShashi Mallela /*
8420cdf7a5dSPeter Maydell  * Update the vPE Table entry at index @vpeid with the entry @vte.
8430cdf7a5dSPeter Maydell  * Returns true on success, false if there was a memory access error.
8440cdf7a5dSPeter Maydell  */
8450cdf7a5dSPeter Maydell static bool update_vte(GICv3ITSState *s, uint32_t vpeid, const VTEntry *vte)
8460cdf7a5dSPeter Maydell {
8470cdf7a5dSPeter Maydell     AddressSpace *as = &s->gicv3->dma_as;
8480cdf7a5dSPeter Maydell     uint64_t entry_addr;
8490cdf7a5dSPeter Maydell     uint64_t vteval = 0;
8500cdf7a5dSPeter Maydell     MemTxResult res = MEMTX_OK;
8510cdf7a5dSPeter Maydell 
8520cdf7a5dSPeter Maydell     trace_gicv3_its_vte_write(vpeid, vte->valid, vte->vptsize, vte->vptaddr,
8530cdf7a5dSPeter Maydell                               vte->rdbase);
8540cdf7a5dSPeter Maydell 
8550cdf7a5dSPeter Maydell     if (vte->valid) {
8560cdf7a5dSPeter Maydell         vteval = FIELD_DP64(vteval, VTE, VALID, 1);
8570cdf7a5dSPeter Maydell         vteval = FIELD_DP64(vteval, VTE, VPTSIZE, vte->vptsize);
8580cdf7a5dSPeter Maydell         vteval = FIELD_DP64(vteval, VTE, VPTADDR, vte->vptaddr);
8590cdf7a5dSPeter Maydell         vteval = FIELD_DP64(vteval, VTE, RDBASE, vte->rdbase);
8600cdf7a5dSPeter Maydell     }
8610cdf7a5dSPeter Maydell 
8620cdf7a5dSPeter Maydell     entry_addr = table_entry_addr(s, &s->vpet, vpeid, &res);
8630cdf7a5dSPeter Maydell     if (res != MEMTX_OK) {
8640cdf7a5dSPeter Maydell         return false;
8650cdf7a5dSPeter Maydell     }
8660cdf7a5dSPeter Maydell     if (entry_addr == -1) {
8670cdf7a5dSPeter Maydell         /* No L2 table for this index: discard write and continue */
8680cdf7a5dSPeter Maydell         return true;
8690cdf7a5dSPeter Maydell     }
8700cdf7a5dSPeter Maydell     address_space_stq_le(as, entry_addr, vteval, MEMTXATTRS_UNSPECIFIED, &res);
8710cdf7a5dSPeter Maydell     return res == MEMTX_OK;
8720cdf7a5dSPeter Maydell }
8730cdf7a5dSPeter Maydell 
8740cdf7a5dSPeter Maydell static ItsCmdResult process_vmapp(GICv3ITSState *s, const uint64_t *cmdpkt)
8750cdf7a5dSPeter Maydell {
8760cdf7a5dSPeter Maydell     VTEntry vte;
8770cdf7a5dSPeter Maydell     uint32_t vpeid;
8780cdf7a5dSPeter Maydell 
8790cdf7a5dSPeter Maydell     if (!its_feature_virtual(s)) {
8800cdf7a5dSPeter Maydell         return CMD_CONTINUE;
8810cdf7a5dSPeter Maydell     }
8820cdf7a5dSPeter Maydell 
8830cdf7a5dSPeter Maydell     vpeid = FIELD_EX64(cmdpkt[1], VMAPP_1, VPEID);
8840cdf7a5dSPeter Maydell     vte.rdbase = FIELD_EX64(cmdpkt[2], VMAPP_2, RDBASE);
8850cdf7a5dSPeter Maydell     vte.valid = FIELD_EX64(cmdpkt[2], VMAPP_2, V);
8860cdf7a5dSPeter Maydell     vte.vptsize = FIELD_EX64(cmdpkt[3], VMAPP_3, VPTSIZE);
8870cdf7a5dSPeter Maydell     vte.vptaddr = FIELD_EX64(cmdpkt[3], VMAPP_3, VPTADDR);
8880cdf7a5dSPeter Maydell 
8890cdf7a5dSPeter Maydell     trace_gicv3_its_cmd_vmapp(vpeid, vte.rdbase, vte.valid,
8900cdf7a5dSPeter Maydell                               vte.vptaddr, vte.vptsize);
8910cdf7a5dSPeter Maydell 
8920cdf7a5dSPeter Maydell     /*
8930cdf7a5dSPeter Maydell      * For GICv4.0 the VPT_size field is only 5 bits, whereas we
8940cdf7a5dSPeter Maydell      * define our field macros to include the full GICv4.1 8 bits.
8950cdf7a5dSPeter Maydell      * The range check on VPT_size will catch the cases where
8960cdf7a5dSPeter Maydell      * the guest set the RES0-in-GICv4.0 bits [7:6].
8970cdf7a5dSPeter Maydell      */
8980cdf7a5dSPeter Maydell     if (vte.vptsize > FIELD_EX64(s->typer, GITS_TYPER, IDBITS)) {
8990cdf7a5dSPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
9000cdf7a5dSPeter Maydell                       "%s: invalid VPT_size 0x%x\n", __func__, vte.vptsize);
9010cdf7a5dSPeter Maydell         return CMD_CONTINUE;
9020cdf7a5dSPeter Maydell     }
9030cdf7a5dSPeter Maydell 
9040cdf7a5dSPeter Maydell     if (vte.valid && vte.rdbase >= s->gicv3->num_cpu) {
9050cdf7a5dSPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
9060cdf7a5dSPeter Maydell                       "%s: invalid rdbase 0x%x\n", __func__, vte.rdbase);
9070cdf7a5dSPeter Maydell         return CMD_CONTINUE;
9080cdf7a5dSPeter Maydell     }
9090cdf7a5dSPeter Maydell 
9100cdf7a5dSPeter Maydell     if (vpeid >= s->vpet.num_entries) {
9110cdf7a5dSPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
9120cdf7a5dSPeter Maydell                       "%s: VPEID 0x%x out of range (must be less than 0x%x)\n",
9130cdf7a5dSPeter Maydell                       __func__, vpeid, s->vpet.num_entries);
9140cdf7a5dSPeter Maydell         return CMD_CONTINUE;
9150cdf7a5dSPeter Maydell     }
9160cdf7a5dSPeter Maydell 
91793f4fdcdSPeter Maydell     return update_vte(s, vpeid, &vte) ? CMD_CONTINUE_OK : CMD_STALL;
9180cdf7a5dSPeter Maydell }
9190cdf7a5dSPeter Maydell 
9200cdf7a5dSPeter Maydell /*
9217eca39e0SShashi Mallela  * Current implementation blocks until all
9227eca39e0SShashi Mallela  * commands are processed
9237eca39e0SShashi Mallela  */
9247eca39e0SShashi Mallela static void process_cmdq(GICv3ITSState *s)
9257eca39e0SShashi Mallela {
9267eca39e0SShashi Mallela     uint32_t wr_offset = 0;
9277eca39e0SShashi Mallela     uint32_t rd_offset = 0;
9287eca39e0SShashi Mallela     uint32_t cq_offset = 0;
9297eca39e0SShashi Mallela     AddressSpace *as = &s->gicv3->dma_as;
9307eca39e0SShashi Mallela     uint8_t cmd;
93117fb5e36SShashi Mallela     int i;
9327eca39e0SShashi Mallela 
9338d2d6dd9SPeter Maydell     if (!(s->ctlr & R_GITS_CTLR_ENABLED_MASK)) {
9347eca39e0SShashi Mallela         return;
9357eca39e0SShashi Mallela     }
9367eca39e0SShashi Mallela 
9377eca39e0SShashi Mallela     wr_offset = FIELD_EX64(s->cwriter, GITS_CWRITER, OFFSET);
9387eca39e0SShashi Mallela 
93980dcd37fSPeter Maydell     if (wr_offset >= s->cq.num_entries) {
9407eca39e0SShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
9417eca39e0SShashi Mallela                       "%s: invalid write offset "
9427eca39e0SShashi Mallela                       "%d\n", __func__, wr_offset);
9437eca39e0SShashi Mallela         return;
9447eca39e0SShashi Mallela     }
9457eca39e0SShashi Mallela 
9467eca39e0SShashi Mallela     rd_offset = FIELD_EX64(s->creadr, GITS_CREADR, OFFSET);
9477eca39e0SShashi Mallela 
94880dcd37fSPeter Maydell     if (rd_offset >= s->cq.num_entries) {
9497eca39e0SShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
9507eca39e0SShashi Mallela                       "%s: invalid read offset "
9517eca39e0SShashi Mallela                       "%d\n", __func__, rd_offset);
9527eca39e0SShashi Mallela         return;
9537eca39e0SShashi Mallela     }
9547eca39e0SShashi Mallela 
9557eca39e0SShashi Mallela     while (wr_offset != rd_offset) {
95693f4fdcdSPeter Maydell         ItsCmdResult result = CMD_CONTINUE_OK;
957b6f96009SPeter Maydell         void *hostmem;
958b6f96009SPeter Maydell         hwaddr buflen;
959b6f96009SPeter Maydell         uint64_t cmdpkt[GITS_CMDQ_ENTRY_WORDS];
960ef011555SPeter Maydell 
9617eca39e0SShashi Mallela         cq_offset = (rd_offset * GITS_CMDQ_ENTRY_SIZE);
962b6f96009SPeter Maydell 
963b6f96009SPeter Maydell         buflen = GITS_CMDQ_ENTRY_SIZE;
964b6f96009SPeter Maydell         hostmem = address_space_map(as, s->cq.base_addr + cq_offset,
965b6f96009SPeter Maydell                                     &buflen, false, MEMTXATTRS_UNSPECIFIED);
966b6f96009SPeter Maydell         if (!hostmem || buflen != GITS_CMDQ_ENTRY_SIZE) {
967b6f96009SPeter Maydell             if (hostmem) {
968b6f96009SPeter Maydell                 address_space_unmap(as, hostmem, buflen, false, 0);
969b6f96009SPeter Maydell             }
970f0b4b2a2SPeter Maydell             s->creadr = FIELD_DP64(s->creadr, GITS_CREADR, STALLED, 1);
971f0b4b2a2SPeter Maydell             qemu_log_mask(LOG_GUEST_ERROR,
972f0b4b2a2SPeter Maydell                           "%s: could not read command at 0x%" PRIx64 "\n",
973f0b4b2a2SPeter Maydell                           __func__, s->cq.base_addr + cq_offset);
974f0b4b2a2SPeter Maydell             break;
9757eca39e0SShashi Mallela         }
976b6f96009SPeter Maydell         for (i = 0; i < ARRAY_SIZE(cmdpkt); i++) {
977b6f96009SPeter Maydell             cmdpkt[i] = ldq_le_p(hostmem + i * sizeof(uint64_t));
978b6f96009SPeter Maydell         }
979b6f96009SPeter Maydell         address_space_unmap(as, hostmem, buflen, false, 0);
980f0b4b2a2SPeter Maydell 
981b6f96009SPeter Maydell         cmd = cmdpkt[0] & CMD_MASK;
9827eca39e0SShashi Mallela 
983195209d3SPeter Maydell         trace_gicv3_its_process_command(rd_offset, cmd);
984195209d3SPeter Maydell 
9857eca39e0SShashi Mallela         switch (cmd) {
9867eca39e0SShashi Mallela         case GITS_CMD_INT:
987b6f96009SPeter Maydell             result = process_its_cmd(s, cmdpkt, INTERRUPT);
9887eca39e0SShashi Mallela             break;
9897eca39e0SShashi Mallela         case GITS_CMD_CLEAR:
990b6f96009SPeter Maydell             result = process_its_cmd(s, cmdpkt, CLEAR);
9917eca39e0SShashi Mallela             break;
9927eca39e0SShashi Mallela         case GITS_CMD_SYNC:
9937eca39e0SShashi Mallela             /*
9947eca39e0SShashi Mallela              * Current implementation makes a blocking synchronous call
9957eca39e0SShashi Mallela              * for every command issued earlier, hence the internal state
9967eca39e0SShashi Mallela              * is already consistent by the time SYNC command is executed.
9977eca39e0SShashi Mallela              * Hence no further processing is required for SYNC command.
9987eca39e0SShashi Mallela              */
999e4050980SPeter Maydell             trace_gicv3_its_cmd_sync();
10007eca39e0SShashi Mallela             break;
10017eca39e0SShashi Mallela         case GITS_CMD_MAPD:
1002b6f96009SPeter Maydell             result = process_mapd(s, cmdpkt);
10037eca39e0SShashi Mallela             break;
10047eca39e0SShashi Mallela         case GITS_CMD_MAPC:
1005b6f96009SPeter Maydell             result = process_mapc(s, cmdpkt);
10067eca39e0SShashi Mallela             break;
10077eca39e0SShashi Mallela         case GITS_CMD_MAPTI:
1008b6f96009SPeter Maydell             result = process_mapti(s, cmdpkt, false);
10097eca39e0SShashi Mallela             break;
10107eca39e0SShashi Mallela         case GITS_CMD_MAPI:
1011b6f96009SPeter Maydell             result = process_mapti(s, cmdpkt, true);
10127eca39e0SShashi Mallela             break;
10137eca39e0SShashi Mallela         case GITS_CMD_DISCARD:
1014b6f96009SPeter Maydell             result = process_its_cmd(s, cmdpkt, DISCARD);
10157eca39e0SShashi Mallela             break;
10167eca39e0SShashi Mallela         case GITS_CMD_INV:
10177eca39e0SShashi Mallela         case GITS_CMD_INVALL:
101817fb5e36SShashi Mallela             /*
101917fb5e36SShashi Mallela              * Current implementation doesn't cache any ITS tables,
102017fb5e36SShashi Mallela              * but the calculated lpi priority information. We only
102117fb5e36SShashi Mallela              * need to trigger lpi priority re-calculation to be in
102217fb5e36SShashi Mallela              * sync with LPI config table or pending table changes.
102317fb5e36SShashi Mallela              */
1024e4050980SPeter Maydell             trace_gicv3_its_cmd_inv();
102517fb5e36SShashi Mallela             for (i = 0; i < s->gicv3->num_cpu; i++) {
102617fb5e36SShashi Mallela                 gicv3_redist_update_lpi(&s->gicv3->cpu[i]);
102717fb5e36SShashi Mallela             }
10287eca39e0SShashi Mallela             break;
1029961b4912SPeter Maydell         case GITS_CMD_MOVI:
1030b6f96009SPeter Maydell             result = process_movi(s, cmdpkt);
1031961b4912SPeter Maydell             break;
1032f6d1d9b4SPeter Maydell         case GITS_CMD_MOVALL:
1033b6f96009SPeter Maydell             result = process_movall(s, cmdpkt);
1034f6d1d9b4SPeter Maydell             break;
10359de53de6SPeter Maydell         case GITS_CMD_VMAPTI:
10369de53de6SPeter Maydell             result = process_vmapti(s, cmdpkt, false);
10379de53de6SPeter Maydell             break;
10389de53de6SPeter Maydell         case GITS_CMD_VMAPI:
10399de53de6SPeter Maydell             result = process_vmapti(s, cmdpkt, true);
10409de53de6SPeter Maydell             break;
10410cdf7a5dSPeter Maydell         case GITS_CMD_VMAPP:
10420cdf7a5dSPeter Maydell             result = process_vmapp(s, cmdpkt);
10430cdf7a5dSPeter Maydell             break;
10447eca39e0SShashi Mallela         default:
1045e4050980SPeter Maydell             trace_gicv3_its_cmd_unknown(cmd);
10467eca39e0SShashi Mallela             break;
10477eca39e0SShashi Mallela         }
104893f4fdcdSPeter Maydell         if (result != CMD_STALL) {
104993f4fdcdSPeter Maydell             /* CMD_CONTINUE or CMD_CONTINUE_OK */
10507eca39e0SShashi Mallela             rd_offset++;
105180dcd37fSPeter Maydell             rd_offset %= s->cq.num_entries;
10527eca39e0SShashi Mallela             s->creadr = FIELD_DP64(s->creadr, GITS_CREADR, OFFSET, rd_offset);
10537eca39e0SShashi Mallela         } else {
1054ef011555SPeter Maydell             /* CMD_STALL */
10557eca39e0SShashi Mallela             s->creadr = FIELD_DP64(s->creadr, GITS_CREADR, STALLED, 1);
10567eca39e0SShashi Mallela             qemu_log_mask(LOG_GUEST_ERROR,
1057ef011555SPeter Maydell                           "%s: 0x%x cmd processing failed, stalling\n",
1058ef011555SPeter Maydell                           __func__, cmd);
10597eca39e0SShashi Mallela             break;
10607eca39e0SShashi Mallela         }
10617eca39e0SShashi Mallela     }
10627eca39e0SShashi Mallela }
10637eca39e0SShashi Mallela 
10641b08e436SShashi Mallela /*
10651b08e436SShashi Mallela  * This function extracts the ITS Device and Collection table specific
10661b08e436SShashi Mallela  * parameters (like base_addr, size etc) from GITS_BASER register.
10671b08e436SShashi Mallela  * It is called during ITS enable and also during post_load migration
10681b08e436SShashi Mallela  */
10691b08e436SShashi Mallela static void extract_table_params(GICv3ITSState *s)
10701b08e436SShashi Mallela {
10711b08e436SShashi Mallela     uint16_t num_pages = 0;
10721b08e436SShashi Mallela     uint8_t  page_sz_type;
10731b08e436SShashi Mallela     uint8_t type;
10741b08e436SShashi Mallela     uint32_t page_sz = 0;
10751b08e436SShashi Mallela     uint64_t value;
10761b08e436SShashi Mallela 
10771b08e436SShashi Mallela     for (int i = 0; i < 8; i++) {
1078e5487a41SPeter Maydell         TableDesc *td;
1079e5487a41SPeter Maydell         int idbits;
1080e5487a41SPeter Maydell 
10811b08e436SShashi Mallela         value = s->baser[i];
10821b08e436SShashi Mallela 
10831b08e436SShashi Mallela         if (!value) {
10841b08e436SShashi Mallela             continue;
10851b08e436SShashi Mallela         }
10861b08e436SShashi Mallela 
10871b08e436SShashi Mallela         page_sz_type = FIELD_EX64(value, GITS_BASER, PAGESIZE);
10881b08e436SShashi Mallela 
10891b08e436SShashi Mallela         switch (page_sz_type) {
10901b08e436SShashi Mallela         case 0:
10911b08e436SShashi Mallela             page_sz = GITS_PAGE_SIZE_4K;
10921b08e436SShashi Mallela             break;
10931b08e436SShashi Mallela 
10941b08e436SShashi Mallela         case 1:
10951b08e436SShashi Mallela             page_sz = GITS_PAGE_SIZE_16K;
10961b08e436SShashi Mallela             break;
10971b08e436SShashi Mallela 
10981b08e436SShashi Mallela         case 2:
10991b08e436SShashi Mallela         case 3:
11001b08e436SShashi Mallela             page_sz = GITS_PAGE_SIZE_64K;
11011b08e436SShashi Mallela             break;
11021b08e436SShashi Mallela 
11031b08e436SShashi Mallela         default:
11041b08e436SShashi Mallela             g_assert_not_reached();
11051b08e436SShashi Mallela         }
11061b08e436SShashi Mallela 
11071b08e436SShashi Mallela         num_pages = FIELD_EX64(value, GITS_BASER, SIZE) + 1;
11081b08e436SShashi Mallela 
11091b08e436SShashi Mallela         type = FIELD_EX64(value, GITS_BASER, TYPE);
11101b08e436SShashi Mallela 
11111b08e436SShashi Mallela         switch (type) {
11121b08e436SShashi Mallela         case GITS_BASER_TYPE_DEVICE:
1113e5487a41SPeter Maydell             td = &s->dt;
1114e5487a41SPeter Maydell             idbits = FIELD_EX64(s->typer, GITS_TYPER, DEVBITS) + 1;
111562df780eSPeter Maydell             break;
11161b08e436SShashi Mallela         case GITS_BASER_TYPE_COLLECTION:
1117e5487a41SPeter Maydell             td = &s->ct;
11181b08e436SShashi Mallela             if (FIELD_EX64(s->typer, GITS_TYPER, CIL)) {
1119e5487a41SPeter Maydell                 idbits = FIELD_EX64(s->typer, GITS_TYPER, CIDBITS) + 1;
11201b08e436SShashi Mallela             } else {
11211b08e436SShashi Mallela                 /* 16-bit CollectionId supported when CIL == 0 */
1122e5487a41SPeter Maydell                 idbits = 16;
11231b08e436SShashi Mallela             }
11241b08e436SShashi Mallela             break;
112550d84584SPeter Maydell         case GITS_BASER_TYPE_VPE:
112650d84584SPeter Maydell             td = &s->vpet;
112750d84584SPeter Maydell             /*
112850d84584SPeter Maydell              * For QEMU vPEIDs are always 16 bits. (GICv4.1 allows an
112950d84584SPeter Maydell              * implementation to implement fewer bits and report this
113050d84584SPeter Maydell              * via GICD_TYPER2.)
113150d84584SPeter Maydell              */
113250d84584SPeter Maydell             idbits = 16;
113350d84584SPeter Maydell             break;
11341b08e436SShashi Mallela         default:
1135e5487a41SPeter Maydell             /*
1136e5487a41SPeter Maydell              * GITS_BASER<n>.TYPE is read-only, so GITS_BASER_RO_MASK
1137e5487a41SPeter Maydell              * ensures we will only see type values corresponding to
1138e5487a41SPeter Maydell              * the values set up in gicv3_its_reset().
1139e5487a41SPeter Maydell              */
1140e5487a41SPeter Maydell             g_assert_not_reached();
11411b08e436SShashi Mallela         }
1142e5487a41SPeter Maydell 
1143e5487a41SPeter Maydell         memset(td, 0, sizeof(*td));
1144e5487a41SPeter Maydell         /*
1145e5487a41SPeter Maydell          * If GITS_BASER<n>.Valid is 0 for any <n> then we will not process
1146e5487a41SPeter Maydell          * interrupts. (GITS_TYPER.HCC is 0 for this implementation, so we
1147e5487a41SPeter Maydell          * do not have a special case where the GITS_BASER<n>.Valid bit is 0
1148e5487a41SPeter Maydell          * for the register corresponding to the Collection table but we
1149e5487a41SPeter Maydell          * still have to process interrupts using non-memory-backed
1150e5487a41SPeter Maydell          * Collection table entries.)
1151da4680ceSPeter Maydell          * The specification makes it UNPREDICTABLE to enable the ITS without
1152da4680ceSPeter Maydell          * marking each BASER<n> as valid. We choose to handle these as if
1153da4680ceSPeter Maydell          * the table was zero-sized, so commands using the table will fail
1154da4680ceSPeter Maydell          * and interrupts requested via GITS_TRANSLATER writes will be ignored.
1155da4680ceSPeter Maydell          * This happens automatically by leaving the num_entries field at
1156da4680ceSPeter Maydell          * zero, which will be caught by the bounds checks we have before
1157da4680ceSPeter Maydell          * every table lookup anyway.
1158e5487a41SPeter Maydell          */
1159da4680ceSPeter Maydell         if (!FIELD_EX64(value, GITS_BASER, VALID)) {
1160e5487a41SPeter Maydell             continue;
1161e5487a41SPeter Maydell         }
1162e5487a41SPeter Maydell         td->page_sz = page_sz;
1163e5487a41SPeter Maydell         td->indirect = FIELD_EX64(value, GITS_BASER, INDIRECT);
11649ae85431SPeter Maydell         td->entry_sz = FIELD_EX64(value, GITS_BASER, ENTRYSIZE) + 1;
1165e5487a41SPeter Maydell         td->base_addr = baser_base_addr(value, page_sz);
1166e5487a41SPeter Maydell         if (!td->indirect) {
116780dcd37fSPeter Maydell             td->num_entries = (num_pages * page_sz) / td->entry_sz;
1168e5487a41SPeter Maydell         } else {
116980dcd37fSPeter Maydell             td->num_entries = (((num_pages * page_sz) /
1170e5487a41SPeter Maydell                                   L1TABLE_ENTRY_SIZE) *
1171e5487a41SPeter Maydell                                  (page_sz / td->entry_sz));
1172e5487a41SPeter Maydell         }
11738b8bb014SPeter Maydell         td->num_entries = MIN(td->num_entries, 1ULL << idbits);
11741b08e436SShashi Mallela     }
11751b08e436SShashi Mallela }
11761b08e436SShashi Mallela 
11771b08e436SShashi Mallela static void extract_cmdq_params(GICv3ITSState *s)
11781b08e436SShashi Mallela {
11791b08e436SShashi Mallela     uint16_t num_pages = 0;
11801b08e436SShashi Mallela     uint64_t value = s->cbaser;
11811b08e436SShashi Mallela 
11821b08e436SShashi Mallela     num_pages = FIELD_EX64(value, GITS_CBASER, SIZE) + 1;
11831b08e436SShashi Mallela 
11841b08e436SShashi Mallela     memset(&s->cq, 0 , sizeof(s->cq));
11851b08e436SShashi Mallela 
1186da4680ceSPeter Maydell     if (FIELD_EX64(value, GITS_CBASER, VALID)) {
118780dcd37fSPeter Maydell         s->cq.num_entries = (num_pages * GITS_PAGE_SIZE_4K) /
11881b08e436SShashi Mallela                              GITS_CMDQ_ENTRY_SIZE;
11891b08e436SShashi Mallela         s->cq.base_addr = FIELD_EX64(value, GITS_CBASER, PHYADDR);
11901b08e436SShashi Mallela         s->cq.base_addr <<= R_GITS_CBASER_PHYADDR_SHIFT;
11911b08e436SShashi Mallela     }
11921b08e436SShashi Mallela }
11931b08e436SShashi Mallela 
11947e062b98SPeter Maydell static MemTxResult gicv3_its_translation_read(void *opaque, hwaddr offset,
11957e062b98SPeter Maydell                                               uint64_t *data, unsigned size,
11967e062b98SPeter Maydell                                               MemTxAttrs attrs)
11977e062b98SPeter Maydell {
11987e062b98SPeter Maydell     /*
11997e062b98SPeter Maydell      * GITS_TRANSLATER is write-only, and all other addresses
12007e062b98SPeter Maydell      * in the interrupt translation space frame are RES0.
12017e062b98SPeter Maydell      */
12027e062b98SPeter Maydell     *data = 0;
12037e062b98SPeter Maydell     return MEMTX_OK;
12047e062b98SPeter Maydell }
12057e062b98SPeter Maydell 
120618f6290aSShashi Mallela static MemTxResult gicv3_its_translation_write(void *opaque, hwaddr offset,
120718f6290aSShashi Mallela                                                uint64_t data, unsigned size,
120818f6290aSShashi Mallela                                                MemTxAttrs attrs)
120918f6290aSShashi Mallela {
1210c694cb4cSShashi Mallela     GICv3ITSState *s = (GICv3ITSState *)opaque;
1211c694cb4cSShashi Mallela     bool result = true;
1212c694cb4cSShashi Mallela 
1213195209d3SPeter Maydell     trace_gicv3_its_translation_write(offset, data, size, attrs.requester_id);
1214195209d3SPeter Maydell 
1215c694cb4cSShashi Mallela     switch (offset) {
1216c694cb4cSShashi Mallela     case GITS_TRANSLATER:
12178d2d6dd9SPeter Maydell         if (s->ctlr & R_GITS_CTLR_ENABLED_MASK) {
1218b6f96009SPeter Maydell             result = do_process_its_cmd(s, attrs.requester_id, data, NONE);
1219c694cb4cSShashi Mallela         }
1220c694cb4cSShashi Mallela         break;
1221c694cb4cSShashi Mallela     default:
1222c694cb4cSShashi Mallela         break;
1223c694cb4cSShashi Mallela     }
1224c694cb4cSShashi Mallela 
1225c694cb4cSShashi Mallela     if (result) {
122618f6290aSShashi Mallela         return MEMTX_OK;
1227c694cb4cSShashi Mallela     } else {
1228c694cb4cSShashi Mallela         return MEMTX_ERROR;
1229c694cb4cSShashi Mallela     }
123018f6290aSShashi Mallela }
123118f6290aSShashi Mallela 
123218f6290aSShashi Mallela static bool its_writel(GICv3ITSState *s, hwaddr offset,
123318f6290aSShashi Mallela                               uint64_t value, MemTxAttrs attrs)
123418f6290aSShashi Mallela {
123518f6290aSShashi Mallela     bool result = true;
12361b08e436SShashi Mallela     int index;
123718f6290aSShashi Mallela 
12381b08e436SShashi Mallela     switch (offset) {
12391b08e436SShashi Mallela     case GITS_CTLR:
12402f459cd1SShashi Mallela         if (value & R_GITS_CTLR_ENABLED_MASK) {
12418d2d6dd9SPeter Maydell             s->ctlr |= R_GITS_CTLR_ENABLED_MASK;
12421b08e436SShashi Mallela             extract_table_params(s);
12431b08e436SShashi Mallela             extract_cmdq_params(s);
12447eca39e0SShashi Mallela             process_cmdq(s);
12452f459cd1SShashi Mallela         } else {
12468d2d6dd9SPeter Maydell             s->ctlr &= ~R_GITS_CTLR_ENABLED_MASK;
12471b08e436SShashi Mallela         }
12481b08e436SShashi Mallela         break;
12491b08e436SShashi Mallela     case GITS_CBASER:
12501b08e436SShashi Mallela         /*
12511b08e436SShashi Mallela          * IMPDEF choice:- GITS_CBASER register becomes RO if ITS is
12521b08e436SShashi Mallela          *                 already enabled
12531b08e436SShashi Mallela          */
12548d2d6dd9SPeter Maydell         if (!(s->ctlr & R_GITS_CTLR_ENABLED_MASK)) {
12551b08e436SShashi Mallela             s->cbaser = deposit64(s->cbaser, 0, 32, value);
12561b08e436SShashi Mallela             s->creadr = 0;
12571b08e436SShashi Mallela         }
12581b08e436SShashi Mallela         break;
12591b08e436SShashi Mallela     case GITS_CBASER + 4:
12601b08e436SShashi Mallela         /*
12611b08e436SShashi Mallela          * IMPDEF choice:- GITS_CBASER register becomes RO if ITS is
12621b08e436SShashi Mallela          *                 already enabled
12631b08e436SShashi Mallela          */
12648d2d6dd9SPeter Maydell         if (!(s->ctlr & R_GITS_CTLR_ENABLED_MASK)) {
12651b08e436SShashi Mallela             s->cbaser = deposit64(s->cbaser, 32, 32, value);
12661b08e436SShashi Mallela             s->creadr = 0;
12671b08e436SShashi Mallela         }
12681b08e436SShashi Mallela         break;
12691b08e436SShashi Mallela     case GITS_CWRITER:
12701b08e436SShashi Mallela         s->cwriter = deposit64(s->cwriter, 0, 32,
12711b08e436SShashi Mallela                                (value & ~R_GITS_CWRITER_RETRY_MASK));
12727eca39e0SShashi Mallela         if (s->cwriter != s->creadr) {
12737eca39e0SShashi Mallela             process_cmdq(s);
12747eca39e0SShashi Mallela         }
12751b08e436SShashi Mallela         break;
12761b08e436SShashi Mallela     case GITS_CWRITER + 4:
12771b08e436SShashi Mallela         s->cwriter = deposit64(s->cwriter, 32, 32, value);
12781b08e436SShashi Mallela         break;
12791b08e436SShashi Mallela     case GITS_CREADR:
12801b08e436SShashi Mallela         if (s->gicv3->gicd_ctlr & GICD_CTLR_DS) {
12811b08e436SShashi Mallela             s->creadr = deposit64(s->creadr, 0, 32,
12821b08e436SShashi Mallela                                   (value & ~R_GITS_CREADR_STALLED_MASK));
12831b08e436SShashi Mallela         } else {
12841b08e436SShashi Mallela             /* RO register, ignore the write */
12851b08e436SShashi Mallela             qemu_log_mask(LOG_GUEST_ERROR,
12861b08e436SShashi Mallela                           "%s: invalid guest write to RO register at offset "
12871b08e436SShashi Mallela                           TARGET_FMT_plx "\n", __func__, offset);
12881b08e436SShashi Mallela         }
12891b08e436SShashi Mallela         break;
12901b08e436SShashi Mallela     case GITS_CREADR + 4:
12911b08e436SShashi Mallela         if (s->gicv3->gicd_ctlr & GICD_CTLR_DS) {
12921b08e436SShashi Mallela             s->creadr = deposit64(s->creadr, 32, 32, value);
12931b08e436SShashi Mallela         } else {
12941b08e436SShashi Mallela             /* RO register, ignore the write */
12951b08e436SShashi Mallela             qemu_log_mask(LOG_GUEST_ERROR,
12961b08e436SShashi Mallela                           "%s: invalid guest write to RO register at offset "
12971b08e436SShashi Mallela                           TARGET_FMT_plx "\n", __func__, offset);
12981b08e436SShashi Mallela         }
12991b08e436SShashi Mallela         break;
13001b08e436SShashi Mallela     case GITS_BASER ... GITS_BASER + 0x3f:
13011b08e436SShashi Mallela         /*
13021b08e436SShashi Mallela          * IMPDEF choice:- GITS_BASERn register becomes RO if ITS is
13031b08e436SShashi Mallela          *                 already enabled
13041b08e436SShashi Mallela          */
13058d2d6dd9SPeter Maydell         if (!(s->ctlr & R_GITS_CTLR_ENABLED_MASK)) {
13061b08e436SShashi Mallela             index = (offset - GITS_BASER) / 8;
13071b08e436SShashi Mallela 
13080ffe88e6SPeter Maydell             if (s->baser[index] == 0) {
13090ffe88e6SPeter Maydell                 /* Unimplemented GITS_BASERn: RAZ/WI */
13100ffe88e6SPeter Maydell                 break;
13110ffe88e6SPeter Maydell             }
13121b08e436SShashi Mallela             if (offset & 7) {
13131b08e436SShashi Mallela                 value <<= 32;
13141b08e436SShashi Mallela                 value &= ~GITS_BASER_RO_MASK;
13151b08e436SShashi Mallela                 s->baser[index] &= GITS_BASER_RO_MASK | MAKE_64BIT_MASK(0, 32);
13161b08e436SShashi Mallela                 s->baser[index] |= value;
13171b08e436SShashi Mallela             } else {
13181b08e436SShashi Mallela                 value &= ~GITS_BASER_RO_MASK;
13191b08e436SShashi Mallela                 s->baser[index] &= GITS_BASER_RO_MASK | MAKE_64BIT_MASK(32, 32);
13201b08e436SShashi Mallela                 s->baser[index] |= value;
13211b08e436SShashi Mallela             }
13221b08e436SShashi Mallela         }
13231b08e436SShashi Mallela         break;
13241b08e436SShashi Mallela     case GITS_IIDR:
13251b08e436SShashi Mallela     case GITS_IDREGS ... GITS_IDREGS + 0x2f:
13261b08e436SShashi Mallela         /* RO registers, ignore the write */
13271b08e436SShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
13281b08e436SShashi Mallela                       "%s: invalid guest write to RO register at offset "
13291b08e436SShashi Mallela                       TARGET_FMT_plx "\n", __func__, offset);
13301b08e436SShashi Mallela         break;
13311b08e436SShashi Mallela     default:
13321b08e436SShashi Mallela         result = false;
13331b08e436SShashi Mallela         break;
13341b08e436SShashi Mallela     }
133518f6290aSShashi Mallela     return result;
133618f6290aSShashi Mallela }
133718f6290aSShashi Mallela 
133818f6290aSShashi Mallela static bool its_readl(GICv3ITSState *s, hwaddr offset,
133918f6290aSShashi Mallela                              uint64_t *data, MemTxAttrs attrs)
134018f6290aSShashi Mallela {
134118f6290aSShashi Mallela     bool result = true;
13421b08e436SShashi Mallela     int index;
134318f6290aSShashi Mallela 
13441b08e436SShashi Mallela     switch (offset) {
13451b08e436SShashi Mallela     case GITS_CTLR:
13461b08e436SShashi Mallela         *data = s->ctlr;
13471b08e436SShashi Mallela         break;
13481b08e436SShashi Mallela     case GITS_IIDR:
13491b08e436SShashi Mallela         *data = gicv3_iidr();
13501b08e436SShashi Mallela         break;
13511b08e436SShashi Mallela     case GITS_IDREGS ... GITS_IDREGS + 0x2f:
13521b08e436SShashi Mallela         /* ID registers */
135350a3a309SPeter Maydell         *data = gicv3_idreg(offset - GITS_IDREGS, GICV3_PIDR0_ITS);
13541b08e436SShashi Mallela         break;
13551b08e436SShashi Mallela     case GITS_TYPER:
13561b08e436SShashi Mallela         *data = extract64(s->typer, 0, 32);
13571b08e436SShashi Mallela         break;
13581b08e436SShashi Mallela     case GITS_TYPER + 4:
13591b08e436SShashi Mallela         *data = extract64(s->typer, 32, 32);
13601b08e436SShashi Mallela         break;
13611b08e436SShashi Mallela     case GITS_CBASER:
13621b08e436SShashi Mallela         *data = extract64(s->cbaser, 0, 32);
13631b08e436SShashi Mallela         break;
13641b08e436SShashi Mallela     case GITS_CBASER + 4:
13651b08e436SShashi Mallela         *data = extract64(s->cbaser, 32, 32);
13661b08e436SShashi Mallela         break;
13671b08e436SShashi Mallela     case GITS_CREADR:
13681b08e436SShashi Mallela         *data = extract64(s->creadr, 0, 32);
13691b08e436SShashi Mallela         break;
13701b08e436SShashi Mallela     case GITS_CREADR + 4:
13711b08e436SShashi Mallela         *data = extract64(s->creadr, 32, 32);
13721b08e436SShashi Mallela         break;
13731b08e436SShashi Mallela     case GITS_CWRITER:
13741b08e436SShashi Mallela         *data = extract64(s->cwriter, 0, 32);
13751b08e436SShashi Mallela         break;
13761b08e436SShashi Mallela     case GITS_CWRITER + 4:
13771b08e436SShashi Mallela         *data = extract64(s->cwriter, 32, 32);
13781b08e436SShashi Mallela         break;
13791b08e436SShashi Mallela     case GITS_BASER ... GITS_BASER + 0x3f:
13801b08e436SShashi Mallela         index = (offset - GITS_BASER) / 8;
13811b08e436SShashi Mallela         if (offset & 7) {
13821b08e436SShashi Mallela             *data = extract64(s->baser[index], 32, 32);
13831b08e436SShashi Mallela         } else {
13841b08e436SShashi Mallela             *data = extract64(s->baser[index], 0, 32);
13851b08e436SShashi Mallela         }
13861b08e436SShashi Mallela         break;
13871b08e436SShashi Mallela     default:
13881b08e436SShashi Mallela         result = false;
13891b08e436SShashi Mallela         break;
13901b08e436SShashi Mallela     }
139118f6290aSShashi Mallela     return result;
139218f6290aSShashi Mallela }
139318f6290aSShashi Mallela 
139418f6290aSShashi Mallela static bool its_writell(GICv3ITSState *s, hwaddr offset,
139518f6290aSShashi Mallela                                uint64_t value, MemTxAttrs attrs)
139618f6290aSShashi Mallela {
139718f6290aSShashi Mallela     bool result = true;
13981b08e436SShashi Mallela     int index;
139918f6290aSShashi Mallela 
14001b08e436SShashi Mallela     switch (offset) {
14011b08e436SShashi Mallela     case GITS_BASER ... GITS_BASER + 0x3f:
14021b08e436SShashi Mallela         /*
14031b08e436SShashi Mallela          * IMPDEF choice:- GITS_BASERn register becomes RO if ITS is
14041b08e436SShashi Mallela          *                 already enabled
14051b08e436SShashi Mallela          */
14068d2d6dd9SPeter Maydell         if (!(s->ctlr & R_GITS_CTLR_ENABLED_MASK)) {
14071b08e436SShashi Mallela             index = (offset - GITS_BASER) / 8;
14080ffe88e6SPeter Maydell             if (s->baser[index] == 0) {
14090ffe88e6SPeter Maydell                 /* Unimplemented GITS_BASERn: RAZ/WI */
14100ffe88e6SPeter Maydell                 break;
14110ffe88e6SPeter Maydell             }
14121b08e436SShashi Mallela             s->baser[index] &= GITS_BASER_RO_MASK;
14131b08e436SShashi Mallela             s->baser[index] |= (value & ~GITS_BASER_RO_MASK);
14141b08e436SShashi Mallela         }
14151b08e436SShashi Mallela         break;
14161b08e436SShashi Mallela     case GITS_CBASER:
14171b08e436SShashi Mallela         /*
14181b08e436SShashi Mallela          * IMPDEF choice:- GITS_CBASER register becomes RO if ITS is
14191b08e436SShashi Mallela          *                 already enabled
14201b08e436SShashi Mallela          */
14218d2d6dd9SPeter Maydell         if (!(s->ctlr & R_GITS_CTLR_ENABLED_MASK)) {
14221b08e436SShashi Mallela             s->cbaser = value;
14231b08e436SShashi Mallela             s->creadr = 0;
14241b08e436SShashi Mallela         }
14251b08e436SShashi Mallela         break;
14261b08e436SShashi Mallela     case GITS_CWRITER:
14271b08e436SShashi Mallela         s->cwriter = value & ~R_GITS_CWRITER_RETRY_MASK;
14287eca39e0SShashi Mallela         if (s->cwriter != s->creadr) {
14297eca39e0SShashi Mallela             process_cmdq(s);
14307eca39e0SShashi Mallela         }
14311b08e436SShashi Mallela         break;
14321b08e436SShashi Mallela     case GITS_CREADR:
14331b08e436SShashi Mallela         if (s->gicv3->gicd_ctlr & GICD_CTLR_DS) {
14341b08e436SShashi Mallela             s->creadr = value & ~R_GITS_CREADR_STALLED_MASK;
14351b08e436SShashi Mallela         } else {
14361b08e436SShashi Mallela             /* RO register, ignore the write */
14371b08e436SShashi Mallela             qemu_log_mask(LOG_GUEST_ERROR,
14381b08e436SShashi Mallela                           "%s: invalid guest write to RO register at offset "
14391b08e436SShashi Mallela                           TARGET_FMT_plx "\n", __func__, offset);
14401b08e436SShashi Mallela         }
14411b08e436SShashi Mallela         break;
14421b08e436SShashi Mallela     case GITS_TYPER:
14431b08e436SShashi Mallela         /* RO registers, ignore the write */
14441b08e436SShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
14451b08e436SShashi Mallela                       "%s: invalid guest write to RO register at offset "
14461b08e436SShashi Mallela                       TARGET_FMT_plx "\n", __func__, offset);
14471b08e436SShashi Mallela         break;
14481b08e436SShashi Mallela     default:
14491b08e436SShashi Mallela         result = false;
14501b08e436SShashi Mallela         break;
14511b08e436SShashi Mallela     }
145218f6290aSShashi Mallela     return result;
145318f6290aSShashi Mallela }
145418f6290aSShashi Mallela 
145518f6290aSShashi Mallela static bool its_readll(GICv3ITSState *s, hwaddr offset,
145618f6290aSShashi Mallela                               uint64_t *data, MemTxAttrs attrs)
145718f6290aSShashi Mallela {
145818f6290aSShashi Mallela     bool result = true;
14591b08e436SShashi Mallela     int index;
146018f6290aSShashi Mallela 
14611b08e436SShashi Mallela     switch (offset) {
14621b08e436SShashi Mallela     case GITS_TYPER:
14631b08e436SShashi Mallela         *data = s->typer;
14641b08e436SShashi Mallela         break;
14651b08e436SShashi Mallela     case GITS_BASER ... GITS_BASER + 0x3f:
14661b08e436SShashi Mallela         index = (offset - GITS_BASER) / 8;
14671b08e436SShashi Mallela         *data = s->baser[index];
14681b08e436SShashi Mallela         break;
14691b08e436SShashi Mallela     case GITS_CBASER:
14701b08e436SShashi Mallela         *data = s->cbaser;
14711b08e436SShashi Mallela         break;
14721b08e436SShashi Mallela     case GITS_CREADR:
14731b08e436SShashi Mallela         *data = s->creadr;
14741b08e436SShashi Mallela         break;
14751b08e436SShashi Mallela     case GITS_CWRITER:
14761b08e436SShashi Mallela         *data = s->cwriter;
14771b08e436SShashi Mallela         break;
14781b08e436SShashi Mallela     default:
14791b08e436SShashi Mallela         result = false;
14801b08e436SShashi Mallela         break;
14811b08e436SShashi Mallela     }
148218f6290aSShashi Mallela     return result;
148318f6290aSShashi Mallela }
148418f6290aSShashi Mallela 
148518f6290aSShashi Mallela static MemTxResult gicv3_its_read(void *opaque, hwaddr offset, uint64_t *data,
148618f6290aSShashi Mallela                                   unsigned size, MemTxAttrs attrs)
148718f6290aSShashi Mallela {
148818f6290aSShashi Mallela     GICv3ITSState *s = (GICv3ITSState *)opaque;
148918f6290aSShashi Mallela     bool result;
149018f6290aSShashi Mallela 
149118f6290aSShashi Mallela     switch (size) {
149218f6290aSShashi Mallela     case 4:
149318f6290aSShashi Mallela         result = its_readl(s, offset, data, attrs);
149418f6290aSShashi Mallela         break;
149518f6290aSShashi Mallela     case 8:
149618f6290aSShashi Mallela         result = its_readll(s, offset, data, attrs);
149718f6290aSShashi Mallela         break;
149818f6290aSShashi Mallela     default:
149918f6290aSShashi Mallela         result = false;
150018f6290aSShashi Mallela         break;
150118f6290aSShashi Mallela     }
150218f6290aSShashi Mallela 
150318f6290aSShashi Mallela     if (!result) {
150418f6290aSShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
150518f6290aSShashi Mallela                       "%s: invalid guest read at offset " TARGET_FMT_plx
150618f6290aSShashi Mallela                       " size %u\n", __func__, offset, size);
1507195209d3SPeter Maydell         trace_gicv3_its_badread(offset, size);
150818f6290aSShashi Mallela         /*
150918f6290aSShashi Mallela          * The spec requires that reserved registers are RAZ/WI;
151018f6290aSShashi Mallela          * so use false returns from leaf functions as a way to
151118f6290aSShashi Mallela          * trigger the guest-error logging but don't return it to
151218f6290aSShashi Mallela          * the caller, or we'll cause a spurious guest data abort.
151318f6290aSShashi Mallela          */
151418f6290aSShashi Mallela         *data = 0;
1515195209d3SPeter Maydell     } else {
1516195209d3SPeter Maydell         trace_gicv3_its_read(offset, *data, size);
151718f6290aSShashi Mallela     }
151818f6290aSShashi Mallela     return MEMTX_OK;
151918f6290aSShashi Mallela }
152018f6290aSShashi Mallela 
152118f6290aSShashi Mallela static MemTxResult gicv3_its_write(void *opaque, hwaddr offset, uint64_t data,
152218f6290aSShashi Mallela                                    unsigned size, MemTxAttrs attrs)
152318f6290aSShashi Mallela {
152418f6290aSShashi Mallela     GICv3ITSState *s = (GICv3ITSState *)opaque;
152518f6290aSShashi Mallela     bool result;
152618f6290aSShashi Mallela 
152718f6290aSShashi Mallela     switch (size) {
152818f6290aSShashi Mallela     case 4:
152918f6290aSShashi Mallela         result = its_writel(s, offset, data, attrs);
153018f6290aSShashi Mallela         break;
153118f6290aSShashi Mallela     case 8:
153218f6290aSShashi Mallela         result = its_writell(s, offset, data, attrs);
153318f6290aSShashi Mallela         break;
153418f6290aSShashi Mallela     default:
153518f6290aSShashi Mallela         result = false;
153618f6290aSShashi Mallela         break;
153718f6290aSShashi Mallela     }
153818f6290aSShashi Mallela 
153918f6290aSShashi Mallela     if (!result) {
154018f6290aSShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
154118f6290aSShashi Mallela                       "%s: invalid guest write at offset " TARGET_FMT_plx
154218f6290aSShashi Mallela                       " size %u\n", __func__, offset, size);
1543195209d3SPeter Maydell         trace_gicv3_its_badwrite(offset, data, size);
154418f6290aSShashi Mallela         /*
154518f6290aSShashi Mallela          * The spec requires that reserved registers are RAZ/WI;
154618f6290aSShashi Mallela          * so use false returns from leaf functions as a way to
154718f6290aSShashi Mallela          * trigger the guest-error logging but don't return it to
154818f6290aSShashi Mallela          * the caller, or we'll cause a spurious guest data abort.
154918f6290aSShashi Mallela          */
1550195209d3SPeter Maydell     } else {
1551195209d3SPeter Maydell         trace_gicv3_its_write(offset, data, size);
155218f6290aSShashi Mallela     }
155318f6290aSShashi Mallela     return MEMTX_OK;
155418f6290aSShashi Mallela }
155518f6290aSShashi Mallela 
155618f6290aSShashi Mallela static const MemoryRegionOps gicv3_its_control_ops = {
155718f6290aSShashi Mallela     .read_with_attrs = gicv3_its_read,
155818f6290aSShashi Mallela     .write_with_attrs = gicv3_its_write,
155918f6290aSShashi Mallela     .valid.min_access_size = 4,
156018f6290aSShashi Mallela     .valid.max_access_size = 8,
156118f6290aSShashi Mallela     .impl.min_access_size = 4,
156218f6290aSShashi Mallela     .impl.max_access_size = 8,
156318f6290aSShashi Mallela     .endianness = DEVICE_NATIVE_ENDIAN,
156418f6290aSShashi Mallela };
156518f6290aSShashi Mallela 
156618f6290aSShashi Mallela static const MemoryRegionOps gicv3_its_translation_ops = {
15677e062b98SPeter Maydell     .read_with_attrs = gicv3_its_translation_read,
156818f6290aSShashi Mallela     .write_with_attrs = gicv3_its_translation_write,
156918f6290aSShashi Mallela     .valid.min_access_size = 2,
157018f6290aSShashi Mallela     .valid.max_access_size = 4,
157118f6290aSShashi Mallela     .impl.min_access_size = 2,
157218f6290aSShashi Mallela     .impl.max_access_size = 4,
157318f6290aSShashi Mallela     .endianness = DEVICE_NATIVE_ENDIAN,
157418f6290aSShashi Mallela };
157518f6290aSShashi Mallela 
157618f6290aSShashi Mallela static void gicv3_arm_its_realize(DeviceState *dev, Error **errp)
157718f6290aSShashi Mallela {
157818f6290aSShashi Mallela     GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev);
157918f6290aSShashi Mallela     int i;
158018f6290aSShashi Mallela 
158118f6290aSShashi Mallela     for (i = 0; i < s->gicv3->num_cpu; i++) {
158218f6290aSShashi Mallela         if (!(s->gicv3->cpu[i].gicr_typer & GICR_TYPER_PLPIS)) {
158318f6290aSShashi Mallela             error_setg(errp, "Physical LPI not supported by CPU %d", i);
158418f6290aSShashi Mallela             return;
158518f6290aSShashi Mallela         }
158618f6290aSShashi Mallela     }
158718f6290aSShashi Mallela 
158818f6290aSShashi Mallela     gicv3_its_init_mmio(s, &gicv3_its_control_ops, &gicv3_its_translation_ops);
158918f6290aSShashi Mallela 
159018f6290aSShashi Mallela     /* set the ITS default features supported */
1591764d6ba1SPeter Maydell     s->typer = FIELD_DP64(s->typer, GITS_TYPER, PHYSICAL, 1);
159218f6290aSShashi Mallela     s->typer = FIELD_DP64(s->typer, GITS_TYPER, ITT_ENTRY_SIZE,
159318f6290aSShashi Mallela                           ITS_ITT_ENTRY_SIZE - 1);
159418f6290aSShashi Mallela     s->typer = FIELD_DP64(s->typer, GITS_TYPER, IDBITS, ITS_IDBITS);
159518f6290aSShashi Mallela     s->typer = FIELD_DP64(s->typer, GITS_TYPER, DEVBITS, ITS_DEVBITS);
159618f6290aSShashi Mallela     s->typer = FIELD_DP64(s->typer, GITS_TYPER, CIL, 1);
159718f6290aSShashi Mallela     s->typer = FIELD_DP64(s->typer, GITS_TYPER, CIDBITS, ITS_CIDBITS);
159818f6290aSShashi Mallela }
159918f6290aSShashi Mallela 
160018f6290aSShashi Mallela static void gicv3_its_reset(DeviceState *dev)
160118f6290aSShashi Mallela {
160218f6290aSShashi Mallela     GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev);
160318f6290aSShashi Mallela     GICv3ITSClass *c = ARM_GICV3_ITS_GET_CLASS(s);
160418f6290aSShashi Mallela 
160518f6290aSShashi Mallela     c->parent_reset(dev);
160618f6290aSShashi Mallela 
160718f6290aSShashi Mallela     /* Quiescent bit reset to 1 */
160818f6290aSShashi Mallela     s->ctlr = FIELD_DP32(s->ctlr, GITS_CTLR, QUIESCENT, 1);
160918f6290aSShashi Mallela 
161018f6290aSShashi Mallela     /*
161118f6290aSShashi Mallela      * setting GITS_BASER0.Type = 0b001 (Device)
161218f6290aSShashi Mallela      *         GITS_BASER1.Type = 0b100 (Collection Table)
161350d84584SPeter Maydell      *         GITS_BASER2.Type = 0b010 (vPE) for GICv4 and later
161418f6290aSShashi Mallela      *         GITS_BASER<n>.Type,where n = 3 to 7 are 0b00 (Unimplemented)
161518f6290aSShashi Mallela      *         GITS_BASER<0,1>.Page_Size = 64KB
161618f6290aSShashi Mallela      * and default translation table entry size to 16 bytes
161718f6290aSShashi Mallela      */
161818f6290aSShashi Mallela     s->baser[0] = FIELD_DP64(s->baser[0], GITS_BASER, TYPE,
161918f6290aSShashi Mallela                              GITS_BASER_TYPE_DEVICE);
162018f6290aSShashi Mallela     s->baser[0] = FIELD_DP64(s->baser[0], GITS_BASER, PAGESIZE,
162118f6290aSShashi Mallela                              GITS_BASER_PAGESIZE_64K);
162218f6290aSShashi Mallela     s->baser[0] = FIELD_DP64(s->baser[0], GITS_BASER, ENTRYSIZE,
162318f6290aSShashi Mallela                              GITS_DTE_SIZE - 1);
162418f6290aSShashi Mallela 
162518f6290aSShashi Mallela     s->baser[1] = FIELD_DP64(s->baser[1], GITS_BASER, TYPE,
162618f6290aSShashi Mallela                              GITS_BASER_TYPE_COLLECTION);
162718f6290aSShashi Mallela     s->baser[1] = FIELD_DP64(s->baser[1], GITS_BASER, PAGESIZE,
162818f6290aSShashi Mallela                              GITS_BASER_PAGESIZE_64K);
162918f6290aSShashi Mallela     s->baser[1] = FIELD_DP64(s->baser[1], GITS_BASER, ENTRYSIZE,
163018f6290aSShashi Mallela                              GITS_CTE_SIZE - 1);
163150d84584SPeter Maydell 
163250d84584SPeter Maydell     if (its_feature_virtual(s)) {
163350d84584SPeter Maydell         s->baser[2] = FIELD_DP64(s->baser[2], GITS_BASER, TYPE,
163450d84584SPeter Maydell                                  GITS_BASER_TYPE_VPE);
163550d84584SPeter Maydell         s->baser[2] = FIELD_DP64(s->baser[2], GITS_BASER, PAGESIZE,
163650d84584SPeter Maydell                                  GITS_BASER_PAGESIZE_64K);
163750d84584SPeter Maydell         s->baser[2] = FIELD_DP64(s->baser[2], GITS_BASER, ENTRYSIZE,
163850d84584SPeter Maydell                                  GITS_VPE_SIZE - 1);
163950d84584SPeter Maydell     }
164018f6290aSShashi Mallela }
164118f6290aSShashi Mallela 
16421b08e436SShashi Mallela static void gicv3_its_post_load(GICv3ITSState *s)
16431b08e436SShashi Mallela {
16448d2d6dd9SPeter Maydell     if (s->ctlr & R_GITS_CTLR_ENABLED_MASK) {
16451b08e436SShashi Mallela         extract_table_params(s);
16461b08e436SShashi Mallela         extract_cmdq_params(s);
16471b08e436SShashi Mallela     }
16481b08e436SShashi Mallela }
16491b08e436SShashi Mallela 
165018f6290aSShashi Mallela static Property gicv3_its_props[] = {
165118f6290aSShashi Mallela     DEFINE_PROP_LINK("parent-gicv3", GICv3ITSState, gicv3, "arm-gicv3",
165218f6290aSShashi Mallela                      GICv3State *),
165318f6290aSShashi Mallela     DEFINE_PROP_END_OF_LIST(),
165418f6290aSShashi Mallela };
165518f6290aSShashi Mallela 
165618f6290aSShashi Mallela static void gicv3_its_class_init(ObjectClass *klass, void *data)
165718f6290aSShashi Mallela {
165818f6290aSShashi Mallela     DeviceClass *dc = DEVICE_CLASS(klass);
165918f6290aSShashi Mallela     GICv3ITSClass *ic = ARM_GICV3_ITS_CLASS(klass);
16601b08e436SShashi Mallela     GICv3ITSCommonClass *icc = ARM_GICV3_ITS_COMMON_CLASS(klass);
166118f6290aSShashi Mallela 
166218f6290aSShashi Mallela     dc->realize = gicv3_arm_its_realize;
166318f6290aSShashi Mallela     device_class_set_props(dc, gicv3_its_props);
166418f6290aSShashi Mallela     device_class_set_parent_reset(dc, gicv3_its_reset, &ic->parent_reset);
16651b08e436SShashi Mallela     icc->post_load = gicv3_its_post_load;
166618f6290aSShashi Mallela }
166718f6290aSShashi Mallela 
166818f6290aSShashi Mallela static const TypeInfo gicv3_its_info = {
166918f6290aSShashi Mallela     .name = TYPE_ARM_GICV3_ITS,
167018f6290aSShashi Mallela     .parent = TYPE_ARM_GICV3_ITS_COMMON,
167118f6290aSShashi Mallela     .instance_size = sizeof(GICv3ITSState),
167218f6290aSShashi Mallela     .class_init = gicv3_its_class_init,
167318f6290aSShashi Mallela     .class_size = sizeof(GICv3ITSClass),
167418f6290aSShashi Mallela };
167518f6290aSShashi Mallela 
167618f6290aSShashi Mallela static void gicv3_its_register_types(void)
167718f6290aSShashi Mallela {
167818f6290aSShashi Mallela     type_register_static(&gicv3_its_info);
167918f6290aSShashi Mallela }
168018f6290aSShashi Mallela 
168118f6290aSShashi Mallela type_init(gicv3_its_register_types)
1682